From 0f9eada36653f013f1a5684d984716dbbe16e760 Mon Sep 17 00:00:00 2001 From: SPM Date: Thu, 16 Nov 2017 11:21:16 +0000 Subject: [PATCH] SPM12 r7219 --- @file_array/Contents.m | 8 +- @file_array/cat.m | 20 +- @file_array/ctranspose.m | 6 +- @file_array/disp.m | 29 +- @file_array/display.m | 6 +- @file_array/double.m | 8 +- @file_array/end.m | 13 +- @file_array/fieldnames.m | 7 +- @file_array/file_array.m | 29 +- @file_array/horzcat.m | 9 +- @file_array/initialise.m | 4 +- @file_array/isnan.m | 10 +- @file_array/length.m | 7 +- @file_array/loadobj.m | 9 +- @file_array/ndims.m | 7 +- @file_array/numel.m | 6 +- @file_array/numeric.m | 7 +- @file_array/permute.m | 8 +- @file_array/private/datatypes.m | 20 +- @file_array/private/dim.m | 29 +- @file_array/private/dtype.m | 9 +- @file_array/private/file2mat.c | 34 +- @file_array/private/file2mat.m | 12 +- @file_array/private/file2mat.mexa64 | Bin 18881 -> 18881 bytes @file_array/private/file2mat.mexmaci64 | Bin 18928 -> 18836 bytes @file_array/private/file2mat.mexw32 | Bin 13312 -> 13312 bytes @file_array/private/file2mat.mexw64 | Bin 17408 -> 17408 bytes @file_array/private/fname.m | 27 +- @file_array/private/init.m | 6 +- @file_array/private/init.mexmaci64 | Bin 9384 -> 9420 bytes @file_array/private/init.mexw32 | Bin 9216 -> 9216 bytes @file_array/private/init.mexw64 | Bin 10240 -> 10240 bytes @file_array/private/mat2file.c | 13 +- @file_array/private/mat2file.m | 10 +- @file_array/private/mat2file.mexa64 | Bin 18468 -> 18433 bytes @file_array/private/mat2file.mexmaci64 | Bin 14560 -> 14444 bytes @file_array/private/mat2file.mexw32 | Bin 28672 -> 28672 bytes @file_array/private/mat2file.mexw64 | Bin 13824 -> 13824 bytes @file_array/private/mystruct.m | 15 +- @file_array/private/offset.m | 29 +- @file_array/private/permission.m | 39 +- @file_array/private/resize_scales.m | 5 +- @file_array/private/scl_inter.m | 31 +- @file_array/private/scl_slope.m | 29 +- @file_array/reshape.m | 17 +- @file_array/size.m | 4 +- @file_array/subsasgn.m | 4 +- @file_array/subsref.m | 15 +- @file_array/transpose.m | 8 +- @file_array/vertcat.m | 7 +- @gifti/gifti.m | 17 +- @gifti/private/obj_read.m | 85 ++ @gifti/private/zstream.mexmaci64 | Bin 39608 -> 39860 bytes @gifti/private/zstream.mexw32 | Bin 0 -> 27136 bytes @gifti/private/zstream.mexw64 | Bin 32768 -> 32768 bytes @gifti/saveas.m | 31 +- @meeg/badsamples.m | 13 +- @meeg/indtrial.m | 9 +- @meeg/montage.m | 26 +- @meeg/rmdata.m | 4 +- @nifti/Contents.m | 4 +- @nifti/create.m | 4 +- @nifti/disp.m | 19 +- @nifti/display.m | 6 +- @nifti/fieldnames.m | 8 +- @nifti/nifti.m | 6 +- @nifti/private/M2Q.m | 24 +- @nifti/private/Q2M.m | 12 +- @nifti/private/decode_qform0.m | 20 +- @nifti/private/empty_hdr.m | 4 +- @nifti/private/encode_qform0.m | 14 +- @nifti/private/findindict.m | 8 +- @nifti/private/getdict.m | 6 +- @nifti/private/mayo2nifti1.m | 40 +- @nifti/private/mayostruc.m | 14 +- @nifti/private/nifti1struc.m | 4 +- @nifti/private/nifti2struc.m | 4 +- @nifti/private/nifti_stats.m | 6 +- @nifti/private/nifti_stats_mex.c | 4 +- @nifti/private/niftistruc.m | 6 +- @nifti/private/read_extras.m | 4 +- @nifti/private/read_hdr.m | 6 +- @nifti/private/read_hdr_raw.m | 38 +- @nifti/private/write_extras.m | 4 +- @nifti/private/write_hdr_raw.m | 4 +- @nifti/structn.m | 17 +- @nifti/subsasgn.m | 287 ++-- @nifti/subsref.m | 172 +-- @xmltree/private/xml_findstr.mexmaci64 | Bin 9144 -> 9048 bytes @xmltree/private/xml_findstr.mexw32 | Bin 7680 -> 7680 bytes @xmltree/private/xml_findstr.mexw64 | Bin 8704 -> 8704 bytes Contents.m | 6 +- EEGtemplates/fiducials.sfp | 3 +- LICENCE.txt | 4 +- README.txt | 4 +- bin/spm12-matlab | 80 ++ bin/spm12-mcr | 44 + bin/spm12-octave | 41 + config/spm_cfg.m | 60 +- config/spm_cfg_bms_map.m | 8 +- config/spm_cfg_cat.m | 5 +- config/spm_cfg_checkreg.m | 22 +- config/spm_cfg_con.m | 8 +- config/spm_cfg_coreg.m | 89 +- config/spm_cfg_dcm_bms.m | 4 +- config/spm_cfg_dcm_est.m | 90 +- config/spm_cfg_dcm_fmri.m | 19 +- config/spm_cfg_dcm_peb.m | 56 +- config/spm_cfg_deface.m | 10 +- config/spm_cfg_deformations.m | 27 +- config/spm_cfg_dicom.m | 93 +- config/spm_cfg_disp.m | 54 +- config/spm_cfg_ecat.m | 7 +- config/spm_cfg_eeg.m | 7 +- config/spm_cfg_eeg_artefact.m | 15 +- config/spm_cfg_eeg_average.m | 16 +- config/spm_cfg_eeg_cfc.m | 10 +- config/spm_cfg_eeg_channel_selector.m | 11 +- config/spm_cfg_eeg_convert.m | 33 +- config/spm_cfg_eeg_convert2images.m | 20 +- config/spm_cfg_eeg_dipfit.m | 352 +++++ config/spm_cfg_eeg_epochs.m | 12 +- config/spm_cfg_eeg_firstlevel.m | 38 +- config/spm_cfg_eeg_inv_extract.m | 4 +- config/spm_cfg_eeg_inv_headmodel.m | 49 +- config/spm_cfg_eeg_inv_headmodelhelmet.m | 10 +- config/spm_cfg_eeg_inv_invert.m | 15 +- config/spm_cfg_eeg_inv_invertiter.m | 43 +- config/spm_cfg_eeg_inv_priors.m | 168 ++- config/spm_cfg_eeg_inv_simulate.m | 18 +- config/spm_cfg_eeg_montage.m | 4 +- config/spm_cfg_eeg_opmsetup.m | 436 +++++++ config/spm_cfg_eeg_prepare.m | 130 +- config/spm_cfg_eeg_reduce.m | 6 +- config/spm_cfg_eeg_regressors.m | 6 +- config/spm_cfg_eeg_spatial_confounds.m | 13 +- config/spm_cfg_eeg_tf.m | 6 +- config/spm_cfg_exp_frames.m | 6 +- config/spm_cfg_factorial_design.m | 23 +- config/spm_cfg_fmri_data.m | 20 +- config/spm_cfg_fmri_design.m | 68 +- config/spm_cfg_fmri_est.m | 24 +- config/spm_cfg_fmri_spec.m | 254 ++-- config/spm_cfg_imcalc.m | 45 +- config/spm_cfg_minc.m | 7 +- config/spm_cfg_model_review.m | 6 +- config/spm_cfg_norm.m | 42 +- config/spm_cfg_preproc8.m | 174 ++- config/spm_cfg_print.m | 3 +- config/spm_cfg_realign.m | 135 +- config/spm_cfg_realignunwarp.m | 258 ++-- config/spm_cfg_render.m | 8 +- config/spm_cfg_reorient.m | 7 +- config/spm_cfg_results.m | 4 +- config/spm_cfg_sendmail.m | 4 +- config/spm_cfg_smooth.m | 38 +- config/spm_cfg_split.m | 4 +- config/spm_cfg_st.m | 109 +- config/spm_cfg_tissue_volumes.m | 21 +- config/spm_cfg_voi.m | 4 +- config/spm_make_manual.m | 6 +- config/spm_make_standalone.m | 81 +- config/spm_rewrite_job.m | 17 +- config/spm_run_con.m | 21 +- config/spm_run_dcm_bms.m | 11 +- config/spm_run_dicom.m | 11 +- config/spm_run_fmri_est.m | 41 +- config/spm_run_realign.m | 7 +- config/spm_run_voi.m | 42 +- external/Makefile.fieldtrip | 23 +- external/bemcp/bem_Cii_cog.c | 13 +- external/bemcp/bem_Cii_cog.mexa64 | Bin 13069 -> 13027 bytes external/bemcp/bem_Cii_cog.mexmaci64 | Bin 13400 -> 9128 bytes external/bemcp/bem_Cii_cog.mexw32 | Bin 8704 -> 8704 bytes external/bemcp/bem_Cii_cog.mexw64 | Bin 10240 -> 10240 bytes external/bemcp/bem_Cii_cst.c | 16 +- external/bemcp/bem_Cii_cst.mexa64 | Bin 17269 -> 17227 bytes external/bemcp/bem_Cii_cst.mexmaci64 | Bin 13504 -> 13460 bytes external/bemcp/bem_Cii_cst.mexw32 | Bin 11776 -> 10752 bytes external/bemcp/bem_Cii_cst.mexw64 | Bin 13312 -> 13312 bytes external/bemcp/bem_Cii_lin.c | 16 +- external/bemcp/bem_Cii_lin.mexa64 | Bin 17316 -> 17274 bytes external/bemcp/bem_Cii_lin.mexmaci64 | Bin 17640 -> 17588 bytes external/bemcp/bem_Cii_lin.mexw32 | Bin 13312 -> 13312 bytes external/bemcp/bem_Cii_lin.mexw64 | Bin 15872 -> 15872 bytes external/bemcp/bem_Cij_cog.c | 18 +- external/bemcp/bem_Cij_cog.mexa64 | Bin 13099 -> 13057 bytes external/bemcp/bem_Cij_cog.mexmaci64 | Bin 13416 -> 13256 bytes external/bemcp/bem_Cij_cog.mexw32 | Bin 9216 -> 9216 bytes external/bemcp/bem_Cij_cog.mexw64 | Bin 10752 -> 10752 bytes external/bemcp/bem_Cij_cst.c | 21 +- external/bemcp/bem_Cij_cst.mexa64 | Bin 13069 -> 13027 bytes external/bemcp/bem_Cij_cst.mexmaci64 | Bin 13400 -> 9128 bytes external/bemcp/bem_Cij_cst.mexw32 | Bin 8704 -> 8704 bytes external/bemcp/bem_Cij_cst.mexw64 | Bin 10240 -> 10240 bytes external/bemcp/bem_Cij_lin.c | 21 +- external/bemcp/bem_Cij_lin.mexa64 | Bin 13118 -> 13076 bytes external/bemcp/bem_Cij_lin.mexmaci64 | Bin 13440 -> 13272 bytes external/bemcp/bem_Cij_lin.mexw32 | Bin 10240 -> 10240 bytes external/bemcp/bem_Cij_lin.mexw64 | Bin 12288 -> 12288 bytes external/bemcp/bem_Gi_cog.c | 15 +- external/bemcp/bem_Gi_cog.mexa64 | Bin 13016 -> 12974 bytes external/bemcp/bem_Gi_cog.mexmaci64 | Bin 9248 -> 9088 bytes external/bemcp/bem_Gi_cog.mexw32 | Bin 8192 -> 8192 bytes external/bemcp/bem_Gi_cog.mexw64 | Bin 10240 -> 10240 bytes external/bemcp/bem_Gi_vert.c | 15 +- external/bemcp/bem_Gi_vert.mexa64 | Bin 13017 -> 12975 bytes external/bemcp/bem_Gi_vert.mexmaci64 | Bin 9248 -> 9088 bytes external/bemcp/bem_Gi_vert.mexw32 | Bin 7680 -> 7680 bytes external/bemcp/bem_Gi_vert.mexw64 | Bin 9728 -> 9728 bytes external/eeprobe/read_eep_avr.mexa64 | Bin 152092 -> 167200 bytes external/eeprobe/read_eep_cnt.mexa64 | Bin 152177 -> 167000 bytes external/eeprobe/read_eep_trg.mexa64 | Bin 152008 -> 39838 bytes external/eeprobe/write_eep_avr.mexa64 | Bin 151846 -> 166669 bytes external/eeprobe/write_eep_cnt.mexa64 | Bin 151846 -> 162573 bytes external/fieldtrip/Contents.m | 8 +- external/fieldtrip/README | 14 +- external/fieldtrip/besa2fieldtrip.m | 24 +- external/fieldtrip/bis2fieldtrip.m | 51 + .../connectivity/ft_connectivity_corr.m | 6 +- .../ft_connectivity_csd2transfer.m | 323 ++++- .../connectivity/ft_connectivity_dtf.m | 110 +- .../connectivity/ft_connectivity_granger.m | 80 +- .../ft_connectivity_laggedcoherence.m | 26 +- .../ft_connectivity_mutualinformation.m | 4 +- .../connectivity/ft_connectivity_pdc.m | 47 +- .../ft_connectivity_powcorr_ortho.m | 6 +- .../connectivity/ft_connectivity_ppc.m | 2 +- .../connectivity/ft_connectivity_psi.m | 2 +- .../connectivity/ft_connectivity_wpli.m | 2 +- .../connectivity/private/coeffs2iis.m | 63 + .../connectivity/private/ctranspose2x2.m | 7 + .../connectivity/private/ctranspose3x3.m | 11 + .../connectivity/private/defaultId.m | 57 + .../fieldtrip/connectivity/private/det2x2.m | 2 +- .../fieldtrip/connectivity/private/det3x3.m | 37 + .../fieldtrip/connectivity/private/fixname.m | 68 +- .../connectivity/private/ft_getopt.m | 30 +- .../connectivity/private/ft_getopt.mexmaci64 | Bin 9832 -> 9680 bytes .../connectivity/private/ft_getopt.mexw32 | Bin 8704 -> 8704 bytes .../connectivity/private/ft_getopt.mexw64 | Bin 9216 -> 9216 bytes .../connectivity/private/ft_notification.m | 482 +++++++ .../private/ft_platform_supports.m | 195 +-- .../connectivity/private/ft_progress.m | 2 + .../connectivity/private/ft_warning.m | 264 +--- .../fieldtrip/connectivity/private/inv2x2.m | 4 +- .../fieldtrip/connectivity/private/inv3x3.m | 36 + .../fieldtrip/connectivity/private/istrue.m | 42 + .../fieldtrip/connectivity/private/keyval.m | 6 +- .../connectivity/private/mtimes3x3.m | 36 + .../connectivity/private/sandwich3x3.m | 95 ++ .../private/sfactorization_wilson.m | 22 +- .../private/sfactorization_wilson2x2.m | 97 +- .../private/sfactorization_wilson3x3.m | 267 ++++ .../connectivity/private/standardise.m | 4 +- .../connectivity/private/transfer2coeffs.m | 160 +++ .../private/triplet_conditionalgranger.m | 119 ++ .../fieldtrip/connectivity/transfer2coeffs.m | 160 +++ external/fieldtrip/external/stats/lgamma.m | 3 - .../external/stats/nanmean.mexmaci64 | Bin 13864 -> 13720 bytes .../fieldtrip/external/stats/nanmean.mexw32 | Bin 10240 -> 10240 bytes .../fieldtrip/external/stats/nanmean.mexw64 | Bin 10752 -> 10752 bytes .../fieldtrip/external/stats/nanstd.mexmaci64 | Bin 13864 -> 13720 bytes .../fieldtrip/external/stats/nanstd.mexw32 | Bin 10752 -> 10752 bytes .../fieldtrip/external/stats/nanstd.mexw64 | Bin 13312 -> 13312 bytes .../fieldtrip/external/stats/nansum.mexmaci64 | Bin 13864 -> 9624 bytes .../fieldtrip/external/stats/nansum.mexw32 | Bin 9216 -> 9216 bytes .../fieldtrip/external/stats/nansum.mexw64 | Bin 9728 -> 9728 bytes .../fieldtrip/external/stats/nanvar.mexmaci64 | Bin 13864 -> 13720 bytes .../fieldtrip/external/stats/nanvar.mexw32 | Bin 11264 -> 11264 bytes .../fieldtrip/external/stats/nanvar.mexw64 | Bin 12288 -> 12288 bytes .../external/stats/{ => private}/iscomplex.m | 0 external/fieldtrip/fieldtrip2besa.m | 4 +- external/fieldtrip/fieldtrip2bis.m | 47 + external/fieldtrip/fieldtrip2ctf.m | 6 +- external/fieldtrip/fieldtrip2fiff.m | 8 +- external/fieldtrip/fieldtrip2spss.m | 8 +- external/fieldtrip/fileio/ft_chantype.m | 96 +- external/fieldtrip/fileio/ft_chanunit.m | 12 +- external/fieldtrip/fileio/ft_create_buffer.m | 2 +- external/fieldtrip/fileio/ft_filetype.m | 34 +- external/fieldtrip/fileio/ft_filter_event.m | 2 +- external/fieldtrip/fileio/ft_flush_data.m | 4 +- external/fieldtrip/fileio/ft_flush_event.m | 4 +- external/fieldtrip/fileio/ft_flush_header.m | 4 +- external/fieldtrip/fileio/ft_read_atlas.m | 376 ++---- external/fieldtrip/fileio/ft_read_cifti.m | 34 +- external/fieldtrip/fileio/ft_read_data.m | 142 +- external/fieldtrip/fileio/ft_read_event.m | 171 ++- external/fieldtrip/fileio/ft_read_header.m | 298 +++-- external/fieldtrip/fileio/ft_read_headshape.m | 168 +-- external/fieldtrip/fileio/ft_read_mri.m | 48 +- external/fieldtrip/fileio/ft_read_sens.m | 83 +- external/fieldtrip/fileio/ft_read_spike.m | 8 +- external/fieldtrip/fileio/ft_read_vol.m | 4 +- external/fieldtrip/fileio/ft_write_cifti.m | 12 +- external/fieldtrip/fileio/ft_write_data.m | 42 +- external/fieldtrip/fileio/ft_write_event.m | 12 +- .../fieldtrip/fileio/ft_write_headshape.m | 12 +- external/fieldtrip/fileio/ft_write_mri.m | 13 +- external/fieldtrip/fileio/ft_write_sens.m | 54 + external/fieldtrip/fileio/ft_write_spike.m | 8 +- .../fieldtrip/fileio/private/ReadHeader.m | 2 +- .../fieldtrip/fileio/private/avw_hdr_read.m | 13 +- .../fieldtrip/fileio/private/avw_img_read.m | 16 +- .../fieldtrip/fileio/private/bounding_mesh.m | 3 +- external/fieldtrip/fileio/private/bti2grad.m | 10 +- .../fileio/private/channelposition.m | 4 +- .../fieldtrip/fileio/private/cstructdecode.m | 4 +- external/fieldtrip/fileio/private/ctf2grad.m | 68 +- .../fieldtrip/fileio/private/dataset2files.m | 2 +- external/fieldtrip/fileio/private/db_insert.m | 2 +- external/fieldtrip/fileio/private/db_open.m | 4 +- external/fieldtrip/fileio/private/db_select.m | 2 +- .../fieldtrip/fileio/private/decode_nifti1.m | 2 +- external/fieldtrip/fileio/private/defaultId.m | 57 + external/fieldtrip/fileio/private/dimlength.m | 8 +- external/fieldtrip/fileio/private/elproj.m | 8 +- external/fieldtrip/fileio/private/fif2grad.m | 4 +- .../fieldtrip/fileio/private/fiff_open_le.m | 10 +- .../fileio/private/filetype_check_header.m | 4 +- .../fileio/private/filetype_check_uri.m | 2 +- external/fieldtrip/fileio/private/fixdimord.m | 24 +- external/fieldtrip/fileio/private/fixname.m | 68 +- external/fieldtrip/fileio/private/fixoldorg.m | 36 + external/fieldtrip/fileio/private/fixpos.m | 4 +- .../fileio/private/ft_apply_montage.m | 124 +- .../fieldtrip/fileio/private/ft_checkdata.m | 550 +++++--- .../fileio/private/ft_convert_units.m | 152 +-- .../fieldtrip/fileio/private/ft_datatype.m | 32 +- .../fileio/private/ft_datatype_comp.m | 48 +- .../fileio/private/ft_datatype_freq.m | 16 +- .../fileio/private/ft_datatype_headmodel.m | 14 +- .../fileio/private/ft_datatype_mvar.m | 2 +- .../fileio/private/ft_datatype_raw.m | 14 +- .../fileio/private/ft_datatype_sens.m | 70 +- .../fileio/private/ft_datatype_source.m | 4 +- .../fileio/private/ft_datatype_spike.m | 16 +- .../fileio/private/ft_datatype_timelock.m | 45 +- .../fileio/private/ft_datatype_vol.m | 2 +- .../fileio/private/ft_determine_units.m | 171 +++ .../fileio/private/ft_estimate_units.m | 6 +- .../fieldtrip/fileio/private/ft_fetch_data.m | 30 +- .../fieldtrip/fileio/private/ft_findcfg.m | 4 +- external/fieldtrip/fileio/private/ft_getopt.m | 30 +- .../fileio/private/ft_getopt.mexmaci64 | Bin 9832 -> 9680 bytes .../fieldtrip/fileio/private/ft_getopt.mexw32 | Bin 8704 -> 8704 bytes .../fieldtrip/fileio/private/ft_getopt.mexw64 | Bin 9216 -> 9216 bytes .../fieldtrip/fileio/private/ft_hastoolbox.m | 207 +-- .../fileio/private/ft_headcoordinates.m | 35 +- .../fileio/private/ft_notification.m | 482 +++++++ .../fileio/private/ft_platform_supports.m | 195 +-- .../fieldtrip/fileio/private/ft_progress.m | 2 + .../fileio/private/ft_scalingfactor.m | 4 +- .../fieldtrip/fileio/private/ft_senslabel.m | 6 +- .../fieldtrip/fileio/private/ft_senstype.m | 98 +- .../fieldtrip/fileio/private/ft_warning.m | 264 +--- .../fieldtrip/fileio/private/ft_warp_apply.m | 18 +- external/fieldtrip/fileio/private/getdimord.m | 93 +- external/fieldtrip/fileio/private/getdimsiz.m | 2 +- .../fieldtrip/fileio/private/hasyokogawa.m | 2 +- .../fieldtrip/fileio/private/homer2opto.m | 99 ++ .../fileio/private/in_fopen_manscan.m | 4 +- .../fileio/private/in_fread_manscan.m | 2 +- .../fieldtrip/fileio/private/inflate_file.m | 2 +- external/fieldtrip/fileio/private/inifile.m | 76 +- external/fieldtrip/fileio/private/istrue.m | 4 +- .../fieldtrip/fileio/private/jaga16_packet.m | 2 +- external/fieldtrip/fileio/private/keyval.m | 6 +- .../fieldtrip/fileio/private/labelcmb2indx.m | 30 +- external/fieldtrip/fileio/private/loadama.m | 4 +- external/fieldtrip/fileio/private/loadvar.m | 6 +- external/fieldtrip/fileio/private/match_str.m | 7 +- external/fieldtrip/fileio/private/mne2grad.m | 26 +- .../fieldtrip/fileio/private/mxDeserialize.m | 2 +- .../fieldtrip/fileio/private/mxSerialize.m | 2 +- external/fieldtrip/fileio/private/ndgrid.m | 4 +- .../private/np_read_splitted_fileinfo.m | 50 +- .../fieldtrip/fileio/private/np_readdata.m | 8 +- .../fieldtrip/fileio/private/np_readmarker.m | 8 +- external/fieldtrip/fileio/private/pos2dim.m | 3 +- external/fieldtrip/fileio/private/pos2dim3d.m | 17 +- .../fieldtrip/fileio/private/pos2transform.m | 4 +- .../fieldtrip/fileio/private/quaternion.m | 2 +- .../fileio/private/read_16bit.mexmaci64 | Bin 9312 -> 9184 bytes .../fileio/private/read_16bit.mexw32 | Bin 7680 -> 7680 bytes .../fileio/private/read_16bit.mexw64 | Bin 8192 -> 8192 bytes .../fileio/private/read_24bit.mexmaci64 | Bin 9320 -> 9184 bytes .../fileio/private/read_24bit.mexw32 | Bin 7680 -> 7680 bytes .../fileio/private/read_24bit.mexw64 | Bin 8704 -> 8704 bytes .../fieldtrip/fileio/private/read_4d_hdr.m | 8 +- .../fieldtrip/fileio/private/read_ahdf5_hdr.m | 4 +- external/fieldtrip/fileio/private/read_asa.m | 2 +- .../fieldtrip/fileio/private/read_asa_bnd.m | 2 +- .../fieldtrip/fileio/private/read_asa_dip.m | 2 +- .../fieldtrip/fileio/private/read_asa_elc.m | 2 +- .../fieldtrip/fileio/private/read_asa_mri.m | 2 +- .../fieldtrip/fileio/private/read_asa_msr.m | 4 +- .../fieldtrip/fileio/private/read_asa_vol.m | 10 +- .../fieldtrip/fileio/private/read_besa_avr.m | 4 +- .../fieldtrip/fileio/private/read_besa_besa.m | 269 ++-- .../fieldtrip/fileio/private/read_besa_sfp.m | 2 +- external/fieldtrip/fileio/private/read_biff.m | 137 +- .../fileio/private/read_bioimage_mgrid.m | 112 ++ .../fileio/private/read_biosemi_bdf.m | 36 +- .../fileio/private/read_biosig_header.m | 4 +- .../fileio/private/read_brainvision_eeg.m | 2 +- .../fileio/private/read_brainvision_vhdr.m | 6 +- .../fileio/private/read_brainvision_vmrk.m | 2 +- .../fieldtrip/fileio/private/read_bti_ascii.m | 8 +- .../fieldtrip/fileio/private/read_bti_hs.m | 2 +- .../fieldtrip/fileio/private/read_bti_m4d.m | 6 +- .../fileio/private/read_bucn_nirshdr.m | 7 + .../private/read_buffer_offline_events.m | 2 +- .../private/read_buffer_offline_header.m | 22 +- .../fieldtrip/fileio/private/read_ced_son.m | 18 +- .../fileio/private/read_combined_ds.m | 18 +- .../fieldtrip/fileio/private/read_ctf_ascii.m | 6 +- .../fieldtrip/fileio/private/read_ctf_cls.m | 4 +- .../fieldtrip/fileio/private/read_ctf_coef.m | 2 +- .../fieldtrip/fileio/private/read_ctf_dat.m | 4 +- .../fieldtrip/fileio/private/read_ctf_hc.m | 22 +- .../fieldtrip/fileio/private/read_ctf_hdm.m | 2 +- .../fieldtrip/fileio/private/read_ctf_meg4.m | 12 +- .../fieldtrip/fileio/private/read_ctf_mri.m | 6 +- .../fieldtrip/fileio/private/read_ctf_mri4.m | 14 +- .../fieldtrip/fileio/private/read_ctf_res4.m | 4 +- .../fieldtrip/fileio/private/read_ctf_sens.m | 4 +- .../fieldtrip/fileio/private/read_ctf_shape.m | 2 +- .../fieldtrip/fileio/private/read_ctf_shm.m | 6 +- .../fieldtrip/fileio/private/read_ctf_svl.m | 4 +- .../fieldtrip/fileio/private/read_curry.m | 8 +- .../fileio/private/read_deymed_ini.m | 2 +- external/fieldtrip/fileio/private/read_edf.m | 267 ++-- .../fileio/private/read_eeglabdata.m | 2 +- .../fileio/private/read_eeglabheader.m | 2 +- .../fieldtrip/fileio/private/read_egis_data.m | 6 +- .../fileio/private/read_egis_header.m | 6 +- external/fieldtrip/fileio/private/read_elec.m | 2 +- .../fileio/private/read_erplabheader.m | 2 +- .../fieldtrip/fileio/private/read_fcdc_trl.m | 2 +- .../fieldtrip/fileio/private/read_mclust_t.m | 2 +- .../fieldtrip/fileio/private/read_mff_bin.m | 2 +- .../fileio/private/read_micromed_event.m | 4 +- .../fileio/private/read_micromed_trc.m | 6 +- .../fieldtrip/fileio/private/read_mpi_dap.m | 4 +- .../fileio/private/read_nervus_data.m | 4 +- .../fileio/private/read_nervus_header.m | 138 +- .../fileio/private/read_neuralynx_bin.m | 14 +- .../fileio/private/read_neuralynx_dma.m | 12 +- .../fileio/private/read_neuralynx_ds.m | 16 +- .../fileio/private/read_neuralynx_ncs.m | 22 +- .../fileio/private/read_neuralynx_nev.m | 6 +- .../fileio/private/read_neuralynx_nse.m | 4 +- .../fileio/private/read_neuralynx_nst.m | 6 +- .../fileio/private/read_neuralynx_nts.m | 4 +- .../fileio/private/read_neuralynx_ntt.m | 6 +- .../fileio/private/read_neuralynx_sdma.m | 8 +- .../fileio/private/read_neuralynx_ttl.m | 2 +- .../fileio/private/read_neuromag_hc.m | 14 +- .../fileio/private/read_neuroshare.m | 10 +- .../fieldtrip/fileio/private/read_nex_data.m | 8 +- .../fieldtrip/fileio/private/read_nex_event.m | 38 +- .../fileio/private/read_nifti2_hdr.m | 6 +- .../fileio/private/read_nihonkohden_hdr.m | 2 +- .../fileio/private/read_nmc_archive_k_data.m | 2 +- .../fileio/private/read_nmc_archive_k_event.m | 4 +- .../fileio/private/read_nmc_archive_k_hdr.m | 10 +- .../fieldtrip/fileio/private/read_ns_avg.m | 2 +- .../fieldtrip/fileio/private/read_ns_eeg.m | 8 +- .../fieldtrip/fileio/private/read_ns_hdr.m | 4 +- external/fieldtrip/fileio/private/read_off.m | 4 +- .../fileio/private/read_plexon_ddt.m | 2 +- .../fieldtrip/fileio/private/read_plexon_ds.m | 30 +- .../fileio/private/read_plexon_nex.m | 8 +- .../fileio/private/read_plexon_plx.m | 10 +- external/fieldtrip/fileio/private/read_ply.m | 14 +- .../fileio/private/read_polhemus_fil.m | 4 +- .../fieldtrip/fileio/private/read_sbin_data.m | 24 +- .../fileio/private/read_sbin_events.m | 20 +- .../fileio/private/read_sbin_header.m | 8 +- .../fieldtrip/fileio/private/read_shm_data.m | 2 +- .../fileio/private/read_shm_header.m | 6 +- .../fileio/private/read_spike6mat_data.m | 2 +- .../fileio/private/read_spike6mat_header.m | 4 +- .../fileio/private/read_spmeeg_event.m | 2 +- .../fileio/private/read_spmeeg_header.m | 4 +- .../fieldtrip/fileio/private/read_tdt_sev.m | 4 +- .../fieldtrip/fileio/private/read_tdt_tev.m | 8 +- .../fileio/private/read_tmsi_poly5.m | 2 +- .../fieldtrip/fileio/private/read_trigger.m | 17 +- external/fieldtrip/fileio/private/read_vtk.m | 2 +- .../fileio/private/read_yokogawa_data.m | 14 +- .../fileio/private/read_yokogawa_data_new.m | 14 +- .../fileio/private/read_yokogawa_event.m | 4 +- .../fileio/private/read_yokogawa_header.m | 12 +- .../fileio/private/read_yokogawa_header_new.m | 22 +- external/fieldtrip/fileio/private/readbdf.m | 2 +- .../fieldtrip/fileio/private/readmarkerfile.m | 4 +- external/fieldtrip/fileio/private/refine.m | 2 +- external/fieldtrip/fileio/private/rotate.m | 2 +- .../fieldtrip/fileio/private/solid_angle.m | 9 +- .../fileio/private/solid_angle.mexa64 | Bin 13195 -> 13195 bytes .../fileio/private/solid_angle.mexmaci64 | Bin 13296 -> 13380 bytes .../fileio/private/solid_angle.mexw32 | Bin 8192 -> 8192 bytes .../fileio/private/solid_angle.mexw64 | Bin 9216 -> 9216 bytes .../fieldtrip/fileio/private/surf_to_tetgen.m | 2 +- .../fileio/private/timestamp_neuralynx.m | 4 +- .../fileio/private/timestamp_plexon.m | 4 +- external/fieldtrip/fileio/private/translate.m | 2 +- .../fieldtrip/fileio/private/undobalancing.m | 4 +- .../fileio/private/volumewrite_spm.m | 143 +- .../fileio/private/write_bioimage_mgrid.m | 298 +++++ .../fileio/private/write_brainvision_eeg.m | 4 +- .../fieldtrip/fileio/private/write_ctf_shm.m | 6 +- external/fieldtrip/fileio/private/write_edf.m | 29 +- .../fileio/private/write_neuralynx_ncs.m | 4 +- .../fileio/private/write_neuralynx_nts.m | 4 +- .../fileio/private/write_plexon_nex.m | 8 +- external/fieldtrip/fileio/private/write_ply.m | 8 +- .../fileio/private/write_serial_event.m | 4 +- external/fieldtrip/fileio/private/write_vtk.m | 2 +- .../fieldtrip/fileio/private/xml2struct.m | 4 +- .../fieldtrip/fileio/private/yokogawa2grad.m | 2 +- .../fileio/private/yokogawa2grad_new.m | 2 +- .../fieldtrip/fileio/private/yokogawa2vol.m | 2 +- external/fieldtrip/forward/ft_apply_montage.m | 124 +- external/fieldtrip/forward/ft_average_sens.m | 10 +- .../fieldtrip/forward/ft_compute_leadfield.m | 26 +- external/fieldtrip/forward/ft_convert_units.m | 152 +-- .../fieldtrip/forward/ft_determine_units.m | 171 +++ .../fieldtrip/forward/ft_estimate_units.m | 6 +- .../fieldtrip/forward/ft_headmodel_bemcp.m | 10 +- .../forward/ft_headmodel_concentricspheres.m | 8 +- .../fieldtrip/forward/ft_headmodel_dipoli.m | 20 +- external/fieldtrip/forward/ft_headmodel_fns.m | 6 +- .../forward/ft_headmodel_halfspace.m | 6 +- .../forward/ft_headmodel_interpolate.m | 20 +- .../forward/ft_headmodel_localspheres.m | 56 +- .../fieldtrip/forward/ft_headmodel_openmeeg.m | 41 +- .../fieldtrip/forward/ft_headmodel_simbio.m | 10 +- .../forward/ft_headmodel_singleshell.m | 6 +- .../forward/ft_headmodel_singlesphere.m | 10 +- .../fieldtrip/forward/ft_headmodel_slab.m | 6 +- external/fieldtrip/forward/ft_inside_vol.m | 123 +- .../fieldtrip/forward/ft_prepare_vol_sens.m | 34 +- external/fieldtrip/forward/ft_senslabel.m | 6 +- external/fieldtrip/forward/ft_senstype.m | 98 +- external/fieldtrip/forward/ft_sourcedepth.m | 2 +- .../forward/ft_transform_headshape.m | 2 +- .../fieldtrip/forward/ft_transform_sens.m | 2 +- external/fieldtrip/forward/ft_transform_vol.m | 2 +- .../fieldtrip/forward/private/bounding_mesh.m | 3 +- .../forward/private/channelposition.m | 4 +- .../fieldtrip/forward/private/defaultId.m | 57 + .../private/eeg_halfspace_medium_leadfield.m | 8 +- .../forward/private/eeg_halfspace_monopole.m | 8 +- .../forward/private/eeg_infinite_monopole.m | 4 +- .../forward/private/eeg_leadfield1.m | 4 +- .../forward/private/eeg_leadfield4.m | 14 +- .../forward/private/eeg_leadfieldb.m | 10 +- .../forward/private/eeg_slab_monopole.m | 8 +- external/fieldtrip/forward/private/elproj.m | 8 +- .../private/find_triangle_neighbours.m | 2 +- .../fieldtrip/forward/private/fitsphere.m | 2 +- external/fieldtrip/forward/private/fixname.m | 68 +- .../fieldtrip/forward/private/fixoldorg.m | 36 + external/fieldtrip/forward/private/fixpos.m | 4 +- .../forward/private/ft_datatype_headmodel.m | 14 +- .../forward/private/ft_datatype_sens.m | 70 +- .../fieldtrip/forward/private/ft_getopt.m | 30 +- .../forward/private/ft_getopt.mexmaci64 | Bin 9832 -> 9680 bytes .../forward/private/ft_getopt.mexw32 | Bin 8704 -> 8704 bytes .../forward/private/ft_getopt.mexw64 | Bin 9216 -> 9216 bytes .../fieldtrip/forward/private/ft_hastoolbox.m | 207 +-- .../forward/private/ft_headcoordinates.m | 35 +- .../forward/private/ft_notification.m | 482 +++++++ .../private/ft_platform_supports.m | 195 +-- .../forward/private/ft_scalingfactor.m | 4 +- .../fieldtrip/forward/private/ft_warning.m | 264 +--- .../fieldtrip/forward/private/ft_warp_apply.m | 18 +- .../private/halfspace_medium_leadfield.m | 6 +- .../fieldtrip/forward/private/hasyokogawa.m | 2 +- .../fieldtrip/forward/private/headsurface.m | 10 +- .../fieldtrip/forward/private/icosahedron.m | 1 - .../forward/private/icosahedron162.m | 1 - .../forward/private/icosahedron2562.m | 2 +- .../fieldtrip/forward/private/icosahedron42.m | 1 - .../forward/private/icosahedron642.m | 1 - .../forward/private/inf_medium_leadfield.m | 4 +- external/fieldtrip/forward/private/istrue.m | 4 +- external/fieldtrip/forward/private/keyval.m | 6 +- .../forward/private/leadfield_openmeeg.m | 30 +- .../forward/private/leadfield_simbio.m | 4 +- .../forward/private/leadsphere_all.m | 4 +- external/fieldtrip/forward/private/lmoutr.m | 6 +- .../fieldtrip/forward/private/lmoutr.mexa64 | Bin 13190 -> 13190 bytes .../forward/private/lmoutr.mexmaci64 | Bin 13296 -> 13240 bytes .../fieldtrip/forward/private/lmoutr.mexw32 | Bin 8192 -> 8192 bytes .../fieldtrip/forward/private/lmoutr.mexw64 | Bin 9216 -> 9216 bytes external/fieldtrip/forward/private/loadama.m | 4 +- .../fieldtrip/forward/private/match_str.m | 7 +- external/fieldtrip/forward/private/meg_ini.m | 6 +- .../forward/private/meg_leadfield1.mexmaci64 | Bin 8856 -> 8792 bytes .../forward/private/meg_leadfield1.mexw32 | Bin 7680 -> 7680 bytes .../forward/private/meg_leadfield1.mexw64 | Bin 9216 -> 9216 bytes .../fieldtrip/forward/private/mesh2edge.m | 2 +- external/fieldtrip/forward/private/normals.m | 6 +- external/fieldtrip/forward/private/plgndr.c | 123 ++ external/fieldtrip/forward/private/plgndr.m | 35 +- .../forward/private/plgndr.mexmaci64 | Bin 8800 -> 8768 bytes .../fieldtrip/forward/private/plgndr.mexw32 | Bin 8192 -> 8192 bytes .../fieldtrip/forward/private/plgndr.mexw64 | Bin 8704 -> 8704 bytes .../fieldtrip/forward/private/project_elec.m | 2 +- .../fieldtrip/forward/private/projecttri.m | 2 +- external/fieldtrip/forward/private/ptriproj.m | 6 +- .../fieldtrip/forward/private/ptriproj.mexa64 | Bin 13236 -> 13236 bytes .../forward/private/ptriproj.mexmaci64 | Bin 13360 -> 13304 bytes .../fieldtrip/forward/private/ptriproj.mexw32 | Bin 9216 -> 9216 bytes .../fieldtrip/forward/private/ptriproj.mexw64 | Bin 10752 -> 10752 bytes .../fieldtrip/forward/private/routlm.mexa64 | Bin 13234 -> 13234 bytes .../forward/private/routlm.mexmaci64 | Bin 13360 -> 13304 bytes .../fieldtrip/forward/private/routlm.mexw32 | Bin 7168 -> 7168 bytes .../fieldtrip/forward/private/routlm.mexw64 | Bin 8192 -> 8192 bytes .../fieldtrip/forward/private/solid_angle.m | 9 +- .../forward/private/solid_angle.mexa64 | Bin 13195 -> 13195 bytes .../forward/private/solid_angle.mexmaci64 | Bin 13296 -> 13380 bytes .../forward/private/solid_angle.mexw32 | Bin 8192 -> 8192 bytes .../forward/private/solid_angle.mexw64 | Bin 9216 -> 9216 bytes .../forward/private/surface_nesting.m | 4 +- .../fieldtrip/forward/private/undobalancing.m | 4 +- external/fieldtrip/ft_analysispipeline.m | 12 +- external/fieldtrip/ft_anonimizedata.m | 61 +- external/fieldtrip/ft_appenddata.m | 394 ++---- external/fieldtrip/ft_appendfreq.m | 425 +----- external/fieldtrip/ft_appendsens.m | 279 ++++ external/fieldtrip/ft_appendsource.m | 34 +- external/fieldtrip/ft_appendspike.m | 8 +- external/fieldtrip/ft_appendtimelock.m | 235 +--- external/fieldtrip/ft_artifact_clip.m | 26 +- external/fieldtrip/ft_artifact_ecg.m | 62 +- external/fieldtrip/ft_artifact_eog.m | 85 +- external/fieldtrip/ft_artifact_jump.m | 83 +- external/fieldtrip/ft_artifact_muscle.m | 87 +- external/fieldtrip/ft_artifact_nan.m | 83 ++ external/fieldtrip/ft_artifact_threshold.m | 18 +- external/fieldtrip/ft_artifact_tms.m | 32 +- external/fieldtrip/ft_artifact_zvalue.m | 46 +- external/fieldtrip/ft_audiovideobrowser.m | 8 +- external/fieldtrip/ft_channelnormalise.m | 58 +- external/fieldtrip/ft_channelrepair.m | 192 +-- external/fieldtrip/ft_channelselection.m | 492 ------- external/fieldtrip/ft_clusterplot.m | 175 +-- external/fieldtrip/ft_combineplanar.m | 87 +- external/fieldtrip/ft_componentanalysis.m | 303 +++-- external/fieldtrip/ft_conjunctionanalysis.m | 12 +- external/fieldtrip/ft_connectivityanalysis.m | 329 +++-- external/fieldtrip/ft_connectivityplot.m | 166 ++- .../fieldtrip/ft_connectivitysimulation.m | 375 +++++- .../fieldtrip/ft_crossfrequencyanalysis.m | 259 ++-- external/fieldtrip/ft_databrowser.m | 419 +++--- external/fieldtrip/ft_defacemesh.m | 11 +- external/fieldtrip/ft_defacevolume.m | 23 +- external/fieldtrip/ft_defaults.m | 67 +- external/fieldtrip/ft_definetrial.m | 23 +- external/fieldtrip/ft_denoise_pca.m | 201 +-- external/fieldtrip/ft_denoise_synthetic.m | 27 +- external/fieldtrip/ft_detect_movement.m | 12 +- external/fieldtrip/ft_dipolefitting.m | 78 +- external/fieldtrip/ft_dipolesimulation.m | 26 +- external/fieldtrip/ft_electrodeplacement.m | 1153 ++++++++++------- external/fieldtrip/ft_electroderealign.m | 444 +++---- external/fieldtrip/ft_freqanalysis.m | 378 +++--- external/fieldtrip/ft_freqanalysis_mvar.m | 18 +- external/fieldtrip/ft_freqbaseline.m | 54 +- external/fieldtrip/ft_freqcomparison.m | 137 -- external/fieldtrip/ft_freqdescriptives.m | 32 +- external/fieldtrip/ft_freqgrandaverage.m | 18 +- external/fieldtrip/ft_freqinterpolate.m | 13 +- external/fieldtrip/ft_freqsimulation.m | 140 +- external/fieldtrip/ft_freqstatistics.m | 6 +- external/fieldtrip/ft_globalmeanfield.m | 27 +- external/fieldtrip/ft_headmovement.m | 81 +- external/fieldtrip/ft_interactiverealign.m | 304 ++--- external/fieldtrip/ft_interpolatenan.m | 92 +- external/fieldtrip/ft_lateralizedpotential.m | 8 +- external/fieldtrip/ft_layoutplot.m | 34 +- external/fieldtrip/ft_math.m | 114 +- external/fieldtrip/ft_megplanar.m | 51 +- external/fieldtrip/ft_megrealign.m | 28 +- external/fieldtrip/ft_meshrealign.m | 961 ++++++++++++++ external/fieldtrip/ft_movieplotER.m | 4 +- external/fieldtrip/ft_movieplotTFR.m | 36 +- external/fieldtrip/ft_multiplotCC.m | 25 +- external/fieldtrip/ft_multiplotER.m | 894 +++++-------- external/fieldtrip/ft_multiplotTFR.m | 707 +++++----- external/fieldtrip/ft_mvaranalysis.m | 76 +- external/fieldtrip/ft_neighbourplot.m | 21 +- external/fieldtrip/ft_networkanalysis.m | 54 +- external/fieldtrip/ft_prepare_bemmodel.m | 303 ----- .../fieldtrip/ft_prepare_concentricspheres.m | 152 --- external/fieldtrip/ft_prepare_headmodel.m | 74 +- external/fieldtrip/ft_prepare_layout.m | 1141 +++++++++++----- external/fieldtrip/ft_prepare_leadfield.m | 8 +- external/fieldtrip/ft_prepare_localspheres.m | 195 --- external/fieldtrip/ft_prepare_mesh.m | 88 +- external/fieldtrip/ft_prepare_montage.m | 111 ++ external/fieldtrip/ft_prepare_neighbours.m | 38 +- external/fieldtrip/ft_prepare_singleshell.m | 79 -- external/fieldtrip/ft_prepare_sourcemodel.m | 95 +- external/fieldtrip/ft_preprocessing.m | 170 ++- external/fieldtrip/ft_qualitycheck.m | 11 +- external/fieldtrip/ft_recodeevent.m | 16 +- external/fieldtrip/ft_redefinetrial.m | 33 +- external/fieldtrip/ft_regressconfound.m | 340 +---- external/fieldtrip/ft_rejectartifact.m | 113 +- external/fieldtrip/ft_rejectcomponent.m | 137 +- external/fieldtrip/ft_rejectvisual.m | 6 +- .../fieldtrip/ft_removetemplateartifact.m | 8 +- external/fieldtrip/ft_removetmsartifact.m | 282 ---- external/fieldtrip/ft_resampledata.m | 80 +- external/fieldtrip/ft_scalpcurrentdensity.m | 41 +- external/fieldtrip/ft_sensorrealign.m | 761 ----------- external/fieldtrip/ft_singleplotER.m | 841 +++++------- external/fieldtrip/ft_singleplotTFR.m | 726 +++++------ external/fieldtrip/ft_sliceinterp.m | 20 +- external/fieldtrip/ft_sourceanalysis.m | 118 +- external/fieldtrip/ft_sourcedescriptives.m | 91 +- external/fieldtrip/ft_sourcegrandaverage.m | 6 +- external/fieldtrip/ft_sourceinterpolate.m | 46 +- external/fieldtrip/ft_sourcemovie.m | 152 ++- external/fieldtrip/ft_sourceparcellate.m | 115 +- external/fieldtrip/ft_sourceplot.m | 694 ++++++---- external/fieldtrip/ft_sourcestatistics.m | 30 +- external/fieldtrip/ft_sourcewrite.m | 6 +- external/fieldtrip/ft_statistics_analytic.m | 6 +- .../fieldtrip/ft_statistics_crossvalidate.m | 13 +- external/fieldtrip/ft_statistics_montecarlo.m | 38 +- external/fieldtrip/ft_statistics_stats.m | 77 +- external/fieldtrip/ft_steadystatesimulation.m | 397 ++++++ external/fieldtrip/ft_stratify.m | 224 ++-- external/fieldtrip/ft_surfacerealign.m | 73 -- external/fieldtrip/ft_timelockanalysis.m | 20 +- external/fieldtrip/ft_timelockbaseline.m | 7 +- external/fieldtrip/ft_timelockgrandaverage.m | 38 +- external/fieldtrip/ft_timelockstatistics.m | 6 +- external/fieldtrip/ft_topoplotCC.m | 6 +- external/fieldtrip/ft_topoplotER.m | 61 +- external/fieldtrip/ft_topoplotIC.m | 15 +- external/fieldtrip/ft_topoplotTFR.m | 61 +- external/fieldtrip/ft_volumebiascorrect.m | 174 +++ external/fieldtrip/ft_volumedownsample.m | 29 +- external/fieldtrip/ft_volumelookup.m | 200 +-- external/fieldtrip/ft_volumenormalise.m | 81 +- external/fieldtrip/ft_volumerealign.m | 136 +- external/fieldtrip/ft_volumereslice.m | 249 ++-- external/fieldtrip/ft_volumesegment.m | 564 ++++---- external/fieldtrip/ft_volumewrite.m | 42 +- external/fieldtrip/inverse/beamformer_dics.m | 59 +- external/fieldtrip/inverse/beamformer_lcmv.m | 17 +- external/fieldtrip/inverse/beamformer_pcc.m | 15 +- external/fieldtrip/inverse/beamformer_sam.m | 11 +- external/fieldtrip/inverse/dipole_fit.m | 24 +- external/fieldtrip/inverse/ft_eloreta.m | 4 +- external/fieldtrip/inverse/ft_sloreta.m | 33 +- external/fieldtrip/inverse/harmony.m | 10 +- .../fieldtrip/inverse/minimumnormestimate.m | 10 +- external/fieldtrip/inverse/music.m | 2 +- .../fieldtrip/inverse/private/SAM_costfun.m | 2 +- .../fieldtrip/inverse/private/bounding_mesh.m | 3 +- .../fieldtrip/inverse/private/calctangent.m | 6 +- .../fieldtrip/inverse/private/defaultId.m | 57 + .../fieldtrip/inverse/private/fixdipole.m | 6 +- external/fieldtrip/inverse/private/fixname.m | 68 +- .../fieldtrip/inverse/private/ft_getopt.m | 30 +- .../inverse/private/ft_getopt.mexmaci64 | Bin 9832 -> 9680 bytes .../inverse/private/ft_getopt.mexw32 | Bin 8704 -> 8704 bytes .../inverse/private/ft_getopt.mexw64 | Bin 9216 -> 9216 bytes .../fieldtrip/inverse/private/ft_hastoolbox.m | 207 +-- .../fieldtrip/inverse/private/ft_inside_vol.m | 123 +- .../inverse/private/ft_notification.m | 482 +++++++ .../inverse/private/ft_platform_supports.m | 336 +++++ .../fieldtrip/inverse/private/ft_progress.m | 2 + .../inverse/private/ft_scalingfactor.m | 4 +- .../fieldtrip/inverse/private/ft_senslabel.m | 6 +- .../fieldtrip/inverse/private/ft_senstype.m | 98 +- .../fieldtrip/inverse/private/ft_warning.m | 65 + .../fieldtrip/inverse/private/hasyokogawa.m | 2 +- external/fieldtrip/inverse/private/keyval.m | 6 +- .../fieldtrip/inverse/private/quaternion.m | 2 +- .../fieldtrip/inverse/private/rigidbody.m | 2 +- external/fieldtrip/inverse/private/rotate.m | 2 +- .../fieldtrip/inverse/private/solid_angle.m | 9 +- .../inverse/private/solid_angle.mexa64 | Bin 13195 -> 13195 bytes .../inverse/private/solid_angle.mexmaci64 | Bin 13296 -> 13380 bytes .../inverse/private/solid_angle.mexw32 | Bin 8192 -> 8192 bytes .../inverse/private/solid_angle.mexw64 | Bin 9216 -> 9216 bytes .../fieldtrip/inverse/private/translate.m | 2 +- external/fieldtrip/inverse/residualvariance.m | 21 +- external/fieldtrip/loreta2fieldtrip.m | 6 +- external/fieldtrip/nutmeg2fieldtrip.m | 8 +- external/fieldtrip/plotting/ft_plot_axes.m | 108 +- external/fieldtrip/plotting/ft_plot_box.m | 28 +- external/fieldtrip/plotting/ft_plot_cloud.m | 718 ++++++++++ .../fieldtrip/plotting/ft_plot_crosshair.m | 136 +- external/fieldtrip/plotting/ft_plot_dipole.m | 26 +- .../fieldtrip/plotting/ft_plot_headshape.m | 16 +- external/fieldtrip/plotting/ft_plot_lay.m | 58 +- external/fieldtrip/plotting/ft_plot_line.m | 25 +- external/fieldtrip/plotting/ft_plot_matrix.m | 110 +- external/fieldtrip/plotting/ft_plot_mesh.m | 176 ++- external/fieldtrip/plotting/ft_plot_montage.m | 41 +- external/fieldtrip/plotting/ft_plot_ortho.m | 34 +- external/fieldtrip/plotting/ft_plot_patch.m | 30 +- external/fieldtrip/plotting/ft_plot_sens.m | 272 ++-- external/fieldtrip/plotting/ft_plot_slice.m | 135 +- external/fieldtrip/plotting/ft_plot_text.m | 87 +- external/fieldtrip/plotting/ft_plot_topo.m | 77 +- external/fieldtrip/plotting/ft_plot_topo3d.m | 8 +- external/fieldtrip/plotting/ft_plot_vector.m | 80 +- external/fieldtrip/plotting/ft_plot_vol.m | 8 +- external/fieldtrip/plotting/ft_select_box.m | 4 +- .../fieldtrip/plotting/ft_select_channel.m | 84 +- external/fieldtrip/plotting/ft_select_point.m | 2 + .../fieldtrip/plotting/ft_select_point3d.m | 4 +- external/fieldtrip/plotting/ft_select_range.m | 45 +- external/fieldtrip/plotting/ft_select_voxel.m | 2 + .../fieldtrip/plotting/private/bg_rgba2rgb.m | 162 +++ external/fieldtrip/plotting/private/black.m | 6 +- external/fieldtrip/plotting/private/blue.m | 6 +- external/fieldtrip/plotting/private/brain.m | 6 +- .../fieldtrip/plotting/private/cdat2rgb.m | 28 + .../plotting/private/channelposition.m | 4 +- .../plotting/private/coordsys2label.m | 169 +++ external/fieldtrip/plotting/private/cortex.m | 6 +- .../fieldtrip/plotting/private/cortex_dark.m | 19 + .../fieldtrip/plotting/private/cortex_light.m | 19 + .../fieldtrip/plotting/private/defaultId.m | 57 + external/fieldtrip/plotting/private/elproj.m | 8 +- external/fieldtrip/plotting/private/fixname.m | 68 +- .../fieldtrip/plotting/private/fixoldorg.m | 36 + external/fieldtrip/plotting/private/fixpos.m | 4 +- .../plotting/private/ft_apply_montage.m | 124 +- .../plotting/private/ft_convert_units.m | 152 +-- .../plotting/private/ft_datatype_sens.m | 70 +- .../plotting/private/ft_datatype_volume.m | 4 +- .../plotting/private/ft_determine_units.m | 171 +++ .../plotting/private/ft_estimate_units.m | 6 +- .../fieldtrip/plotting/private/ft_getopt.m | 30 +- .../plotting/private/ft_notification.m | 482 +++++++ .../plotting/private/ft_platform_supports.m | 195 +-- .../fieldtrip/plotting/private/ft_progress.m | 2 + .../plotting/private/ft_scalingfactor.m | 4 +- .../fieldtrip/plotting/private/ft_senslabel.m | 6 +- .../fieldtrip/plotting/private/ft_senstype.m | 98 +- .../fieldtrip/plotting/private/ft_warning.m | 264 +--- .../plotting/private/ft_warp_apply.m | 18 +- external/fieldtrip/plotting/private/green.m | 6 +- .../fieldtrip/plotting/private/icosahedron.m | 1 - .../plotting/private/icosahedron162.m | 1 - .../plotting/private/icosahedron2562.m | 2 +- .../plotting/private/icosahedron42.m | 1 - .../plotting/private/icosahedron642.m | 1 - external/fieldtrip/plotting/private/istrue.m | 4 +- external/fieldtrip/plotting/private/keyval.m | 6 +- .../fieldtrip/plotting/private/keyvalcheck.m | 8 +- external/fieldtrip/plotting/private/lmoutrn.m | 61 + .../fieldtrip/plotting/private/ltrisect.m | 6 +- .../fieldtrip/plotting/private/match_str.m | 7 +- .../fieldtrip/plotting/private/mesh2edge.m | 2 +- external/fieldtrip/plotting/private/ndgrid.m | 4 +- external/fieldtrip/plotting/private/pinvNx2.m | 36 + .../fieldtrip/plotting/private/projecttri.m | 2 +- .../fieldtrip/plotting/private/ptriside.m | 4 +- .../fieldtrip/plotting/private/quaternion.m | 2 +- external/fieldtrip/plotting/private/red.m | 6 +- external/fieldtrip/plotting/private/refine.m | 3 +- external/fieldtrip/plotting/private/rotate.m | 2 +- external/fieldtrip/plotting/private/scale.m | 2 +- .../fieldtrip/plotting/private/select3d.m | 24 +- .../fieldtrip/plotting/private/select3dtool.m | 4 +- external/fieldtrip/plotting/private/skin.m | 2 +- external/fieldtrip/plotting/private/skull.m | 2 +- .../fieldtrip/plotting/private/translate.m | 2 +- .../plotting/private/undobalancing.m | 4 +- external/fieldtrip/plotting/private/white.m | 6 +- external/fieldtrip/plotting/private/yellow.m | 6 +- .../preproc/ft_preproc_bandpassfilter.m | 41 +- .../preproc/ft_preproc_bandstopfilter.m | 41 +- .../fieldtrip/preproc/ft_preproc_denoise.m | 9 +- .../fieldtrip/preproc/ft_preproc_derivative.m | 7 +- .../fieldtrip/preproc/ft_preproc_dftfilter.m | 178 ++- .../preproc/ft_preproc_highpassfilter.m | 41 +- .../fieldtrip/preproc/ft_preproc_hilbert.m | 7 +- .../preproc/ft_preproc_lowpassfilter.m | 40 +- .../preproc/ft_preproc_medianfilter.m | 28 +- .../preproc/ft_preproc_online_filter_apply.m | 30 +- .../preproc/ft_preproc_online_filter_init.m | 25 +- .../fieldtrip/preproc/ft_preproc_padding.m | 23 +- .../preproc/ft_preproc_polyremoval.m | 50 +- .../preproc/ft_preproc_rereference.m | 47 +- .../fieldtrip/preproc/ft_preproc_resample.m | 55 +- .../preproc/ft_preproc_slidingrange.m | 7 +- .../fieldtrip/preproc/ft_preproc_smooth.m | 6 +- .../preproc/ft_preproc_standardize.m | 17 +- .../fieldtrip/preproc/private/defaultId.m | 57 + .../preproc/private/filter_with_correction.m | 24 +- external/fieldtrip/preproc/private/fir_df.m | 2 +- .../preproc/private/fir_filterdcpadded.m | 8 +- external/fieldtrip/preproc/private/firws.m | 6 +- external/fieldtrip/preproc/private/firwsord.m | 6 +- external/fieldtrip/preproc/private/fixname.m | 68 +- .../preproc/private/ft_notification.m | 482 +++++++ .../preproc/private/ft_platform_supports.m | 336 +++++ .../fieldtrip/preproc/private/ft_warning.m | 264 +--- .../fieldtrip/preproc/private/invfirwsord.m | 6 +- external/fieldtrip/preproc/private/istrue.m | 4 +- external/fieldtrip/preproc/private/keyval.m | 6 +- .../fieldtrip/preproc/private/plotfresp.m | 8 +- .../fieldtrip/preproc/private/print_once.m | 8 +- external/fieldtrip/preproc/private/windows.m | 8 +- external/fieldtrip/private/align_ijk2xyz.m | 2 +- external/fieldtrip/private/append_common.m | 348 +++++ external/fieldtrip/private/atlas_lookup.m | 117 +- external/fieldtrip/private/avw_img_write.m | 103 +- external/fieldtrip/private/bandpassfilter.m | 3 +- external/fieldtrip/private/bandstopfilter.m | 3 +- external/fieldtrip/private/binomialprob.m | 2 +- external/fieldtrip/private/bivariate_common.m | 169 +++ external/fieldtrip/private/bounding_mesh.m | 3 +- external/fieldtrip/private/bsscca.m | 373 ++---- external/fieldtrip/private/cancorr.m | 2 +- .../fieldtrip/private/cellStruct2StructCell.m | 2 +- .../fieldtrip/private/channelconnectivity.m | 4 +- external/fieldtrip/private/channelposition.m | 4 +- external/fieldtrip/private/chanscale_common.m | 152 +++ external/fieldtrip/private/checktime.m | 3 +- external/fieldtrip/private/clusterstat.m | 75 +- external/fieldtrip/private/convert_event.m | 22 +- external/fieldtrip/private/coordsys2label.m | 169 +++ external/fieldtrip/private/crosshair.m | 106 -- external/fieldtrip/private/ctf2grad.m | 68 +- external/fieldtrip/private/dataset2files.m | 2 +- external/fieldtrip/private/defaultId.m | 57 + external/fieldtrip/private/dftfilter.m | 4 +- external/fieldtrip/private/dimassign.m | 24 +- external/fieldtrip/private/dimindex.m | 8 +- external/fieldtrip/private/dimlength.m | 8 +- external/fieldtrip/private/elec1020_follow.m | 224 ++++ .../fieldtrip/private/elec1020_fraction.m | 50 + .../fieldtrip/private/elec1020_intersect.m | 122 ++ external/fieldtrip/private/elec1020_locate.m | 878 +++++++++++++ external/fieldtrip/private/elproj.m | 8 +- external/fieldtrip/private/estimate_fwhm1.m | 4 +- external/fieldtrip/private/estimate_fwhm2.m | 4 +- .../fieldtrip/private/expand_orthogonal.m | 26 +- .../private/find_triangle_neighbours.m | 2 +- external/fieldtrip/private/findcluster.m | 20 +- external/fieldtrip/private/fitsphere.m | 2 +- external/fieldtrip/private/fixcoordsys.m | 37 + external/fieldtrip/private/fixdimord.m | 24 +- external/fieldtrip/private/fixdipole.m | 6 +- external/fieldtrip/private/fixname.m | 68 +- external/fieldtrip/private/fixpos.m | 4 +- .../fieldtrip/private/fourier2crsspctrm.m | 10 +- external/fieldtrip/private/freq2cumtapcnt.m | 2 +- external/fieldtrip/private/freq2timelock.m | 2 +- external/fieldtrip/private/ft_fetch_sens.m | 120 +- external/fieldtrip/private/ft_fetch_vol.m | 4 +- external/fieldtrip/private/ft_getuserfun.m | 4 +- external/fieldtrip/private/getdimord.m | 93 +- external/fieldtrip/private/getdimsiz.m | 2 +- external/fieldtrip/private/grid2transform.m | 10 +- external/fieldtrip/private/headsurface.m | 10 +- external/fieldtrip/private/highpassfilter.m | 3 +- external/fieldtrip/private/icosahedron.m | 1 - external/fieldtrip/private/icosahedron162.m | 1 - external/fieldtrip/private/icosahedron2562.m | 2 +- external/fieldtrip/private/icosahedron42.m | 1 - external/fieldtrip/private/icosahedron642.m | 1 - external/fieldtrip/private/ignorefields.m | 44 +- .../private/inputlabel2outputlabel.m | 4 +- external/fieldtrip/private/interp_gridded.m | 10 +- external/fieldtrip/private/interp_ungridded.m | 12 +- external/fieldtrip/private/labelcmb2indx.m | 30 +- external/fieldtrip/private/lmoutr.m | 6 +- external/fieldtrip/private/lmoutr.mexa64 | Bin 13190 -> 13190 bytes external/fieldtrip/private/lmoutr.mexmaci64 | Bin 13296 -> 13240 bytes external/fieldtrip/private/lmoutr.mexw32 | Bin 8192 -> 8192 bytes external/fieldtrip/private/lmoutr.mexw64 | Bin 9216 -> 9216 bytes external/fieldtrip/private/loadvar.m | 6 +- external/fieldtrip/private/lowpassfilter.m | 3 +- .../fieldtrip/private/megplanar_fitplane.m | 4 +- external/fieldtrip/private/megplanar_orig.m | 2 +- external/fieldtrip/private/mergeconfig.m | 72 +- external/fieldtrip/private/mesh2edge.m | 2 +- external/fieldtrip/private/mesh_spectrum.m | 2 +- external/fieldtrip/private/mesh_spherify.m | 4 +- external/fieldtrip/private/mni2tal.m | 9 +- external/fieldtrip/private/mollify.m | 2 +- external/fieldtrip/private/moveinward.m | 18 + external/fieldtrip/private/moviefunction.m | 20 +- external/fieldtrip/private/mutexlock.m | 4 +- external/fieldtrip/private/mxDeserialize.m | 2 +- external/fieldtrip/private/mxSerialize.m | 2 +- external/fieldtrip/private/ndgrid.m | 4 +- external/fieldtrip/private/nimh2grad.m | 4 +- external/fieldtrip/private/normals.m | 6 +- external/fieldtrip/private/peakdetect2.m | 2 +- external/fieldtrip/private/plgndr.c | 123 ++ external/fieldtrip/private/plgndr.m | 35 +- external/fieldtrip/private/plgndr.mexmaci64 | Bin 8800 -> 8768 bytes external/fieldtrip/private/plgndr.mexw32 | Bin 8192 -> 8192 bytes external/fieldtrip/private/plgndr.mexw64 | Bin 8704 -> 8704 bytes external/fieldtrip/private/pntdist.m | 24 + external/fieldtrip/private/poly2tri.m | 4 +- external/fieldtrip/private/pos2dim.m | 3 +- external/fieldtrip/private/pos2dim3d.m | 17 +- external/fieldtrip/private/pos2transform.m | 4 +- external/fieldtrip/private/prepare_design.m | 44 +- .../fieldtrip/private/prepare_freq_matrices.m | 9 +- .../fieldtrip/private/prepare_headmodel.m | 27 +- ...cortexhull.m => prepare_mesh_cortexhull.m} | 45 +- .../private/prepare_mesh_headshape.m | 20 +- .../private/prepare_mesh_hexahedral.m | 92 +- .../fieldtrip/private/prepare_mesh_manual.m | 4 +- .../private/prepare_mesh_segmentation.m | 65 +- .../private/prepare_mesh_tetrahedral.m | 77 ++ .../private/prepare_resampled_data.m | 38 +- external/fieldtrip/private/preproc.m | 38 +- external/fieldtrip/private/procrustes_trans.m | 4 +- external/fieldtrip/private/project_elec.m | 2 +- external/fieldtrip/private/projecttri.m | 2 +- external/fieldtrip/private/ptriproj.m | 6 +- external/fieldtrip/private/ptriproj.mexa64 | Bin 13236 -> 13236 bytes external/fieldtrip/private/ptriproj.mexmaci64 | Bin 13360 -> 13304 bytes external/fieldtrip/private/ptriproj.mexw32 | Bin 9216 -> 9216 bytes external/fieldtrip/private/ptriproj.mexw64 | Bin 10752 -> 10752 bytes external/fieldtrip/private/ptriside.m | 55 + external/fieldtrip/private/quaternion.m | 2 +- external/fieldtrip/private/randstatprob.m | 6 +- external/fieldtrip/private/raw2data.m | 2 +- external/fieldtrip/private/read_besa_avr.m | 4 +- external/fieldtrip/private/read_besa_src.m | 4 +- external/fieldtrip/private/read_ctf_hc.m | 22 +- .../fieldtrip/private/read_labview_dtlg.m | 8 +- .../fieldtrip/private/read_neuralynx_dma.m | 12 +- external/fieldtrip/private/refine.m | 3 +- .../fieldtrip/private/rejectvisual_summary.m | 39 +- external/fieldtrip/private/resampledesign.m | 30 +- external/fieldtrip/private/rigidbody.m | 2 +- external/fieldtrip/private/rotate.m | 2 +- external/fieldtrip/private/routlm.m | 6 +- external/fieldtrip/private/routlm.mexa64 | Bin 13234 -> 13234 bytes external/fieldtrip/private/routlm.mexmaci64 | Bin 13360 -> 13304 bytes external/fieldtrip/private/routlm.mexw32 | Bin 7168 -> 7168 bytes external/fieldtrip/private/routlm.mexw64 | Bin 8192 -> 8192 bytes external/fieldtrip/private/scale.m | 2 +- external/fieldtrip/private/select3d.m | 24 +- .../fieldtrip/private/select_channel_list.m | 4 +- external/fieldtrip/private/setviewpoint.m | 91 ++ external/fieldtrip/private/shiftpredict.m | 10 +- external/fieldtrip/private/sine_taper.m | 4 +- external/fieldtrip/private/smooth_source.m | 2 +- external/fieldtrip/private/solid_angle.m | 9 +- external/fieldtrip/private/solid_angle.mexa64 | Bin 13195 -> 13195 bytes .../fieldtrip/private/solid_angle.mexmaci64 | Bin 13296 -> 13380 bytes external/fieldtrip/private/solid_angle.mexw32 | Bin 8192 -> 8192 bytes external/fieldtrip/private/solid_angle.mexw64 | Bin 9216 -> 9216 bytes external/fieldtrip/private/specest_nanfft.m | 2 +- .../private/sphericalSplineInterpolate.m | 14 +- external/fieldtrip/private/spikesort.m | 2 +- external/fieldtrip/private/splint.m | 2 +- external/fieldtrip/private/splitstruct.m | 4 +- external/fieldtrip/private/standardise.m | 4 +- .../fieldtrip/private/statistics_wrapper.m | 22 +- external/fieldtrip/private/swapmemfile.m | 4 +- external/fieldtrip/private/tal2mni.m | 13 +- external/fieldtrip/private/topoplot_common.m | 1128 +++++++--------- external/fieldtrip/private/transform2grid.m | 2 +- external/fieldtrip/private/translate.m | 2 +- external/fieldtrip/private/triangulate_seg.m | 10 +- external/fieldtrip/private/tritrisect.m | 108 ++ external/fieldtrip/private/undobalancing.m | 4 +- .../fieldtrip/private/univariate2bivariate.m | 55 +- external/fieldtrip/private/validate_seg.m | 28 +- external/fieldtrip/private/volplot.m | 42 +- external/fieldtrip/private/volumeedit.m | 12 +- external/fieldtrip/private/volumefillholes.m | 11 +- external/fieldtrip/private/volumeflip.m | 19 +- external/fieldtrip/private/volumepermute.m | 18 +- external/fieldtrip/private/volumesmooth.m | 10 +- external/fieldtrip/private/volumethreshold.m | 14 +- external/fieldtrip/private/warp_dykstra2012.m | 339 +++++ external/fieldtrip/private/wizard_base.m | 2 +- .../fieldtrip/private/write_neuralynx_nse.m | 4 +- external/fieldtrip/spass2fieldtrip.m | 14 +- .../fieldtrip/specest/ft_specest_hilbert.m | 17 +- .../fieldtrip/specest/ft_specest_mtmconvol.m | 17 +- .../fieldtrip/specest/ft_specest_mtmfft.m | 58 +- .../fieldtrip/specest/ft_specest_neuvar.m | 94 ++ external/fieldtrip/specest/ft_specest_tfr.m | 9 +- .../fieldtrip/specest/ft_specest_wavelet.m | 9 +- .../fieldtrip/specest/private/defaultId.m | 57 + .../specest/private/filter_with_correction.m | 24 +- external/fieldtrip/specest/private/fixname.m | 68 +- .../fieldtrip/specest/private/ft_getopt.m | 30 +- .../specest/private/ft_notification.m | 482 +++++++ .../specest/private/ft_platform_supports.m | 336 +++++ .../private/ft_preproc_bandpassfilter.m | 41 +- .../specest/private/ft_preproc_polyremoval.m | 50 +- .../fieldtrip/specest/private/ft_warning.m | 264 +--- external/fieldtrip/specest/private/istrue.m | 42 + external/fieldtrip/specest/private/keyval.m | 6 +- .../fieldtrip/specest/private/keyvalcheck.m | 8 +- .../fieldtrip/specest/private/sine_taper.m | 4 +- .../specest/private/sine_taper_scaled.m | 4 +- external/fieldtrip/spm2fieldtrip.m | 8 +- external/fieldtrip/src/det2x2.c | 1 - external/fieldtrip/src/det2x2.m | 2 +- external/fieldtrip/src/det3x3.c | 94 ++ external/fieldtrip/src/det3x3.m | 37 + external/fieldtrip/src/ft_spike_sub_crossx.c | 1 - external/fieldtrip/src/geometry.c | 1 - external/fieldtrip/src/inv2x2.c | 1 - external/fieldtrip/src/inv2x2.m | 4 +- external/fieldtrip/src/inv3x3.c | 146 +++ external/fieldtrip/src/inv3x3.m | 36 + external/fieldtrip/src/lmoutr.c | 1 - external/fieldtrip/src/lmoutr.m | 2 +- external/fieldtrip/src/ltrisect.c | 1 - external/fieldtrip/src/ltrisect.m | 2 +- external/fieldtrip/src/meg_leadfield1.c | 1 - external/fieldtrip/src/meg_leadfield1.m | 2 +- external/fieldtrip/src/mtimes2x2.c | 1 - external/fieldtrip/src/mtimes3x3.c | 170 +++ external/fieldtrip/src/mtimes3x3.m | 36 + external/fieldtrip/src/mxDeserialize.m | 2 +- external/fieldtrip/src/mxSerialize.m | 2 +- external/fieldtrip/src/nanaccum.h | 1 - external/fieldtrip/src/nanmean.c | 1 - external/fieldtrip/src/nannumel.c | 25 - external/fieldtrip/src/nanstd.c | 1 - external/fieldtrip/src/nansum.c | 1 - external/fieldtrip/src/nanvar.c | 1 - external/fieldtrip/src/platform.h | 83 +- external/fieldtrip/src/plgndr.c | 1 - external/fieldtrip/src/plgndr.m | 35 +- external/fieldtrip/src/plinproj.c | 1 - external/fieldtrip/src/plinproj.m | 2 +- external/fieldtrip/src/ptriproj.c | 1 - external/fieldtrip/src/ptriproj.m | 2 +- external/fieldtrip/src/read_16bit.c | 3 +- external/fieldtrip/src/read_16bit.m | 2 +- external/fieldtrip/src/read_24bit.c | 3 +- external/fieldtrip/src/read_24bit.m | 2 +- external/fieldtrip/src/read_ctf_shm.c | 2 +- external/fieldtrip/src/read_ctf_shm.m | 2 +- external/fieldtrip/src/rename.c | 1 - external/fieldtrip/src/rfbevent.c | 1 - external/fieldtrip/src/rfbevent.m | 2 +- external/fieldtrip/src/routlm.c | 1 - external/fieldtrip/src/routlm.m | 2 +- external/fieldtrip/src/sandwich2x2.c | 1 - external/fieldtrip/src/sandwich3x3.c | 204 +++ external/fieldtrip/src/sandwich3x3.m | 95 ++ external/fieldtrip/src/solid_angle.c | 1 - external/fieldtrip/src/solid_angle.m | 9 +- external/fieldtrip/src/splint_gh.c | 1 - external/fieldtrip/src/splint_gh.m | 2 +- external/fieldtrip/src/write_ctf_shm.c | 2 +- external/fieldtrip/src/write_ctf_shm.m | 2 +- .../fieldtrip/statfun/ft_statfun_actvsblT.m | 103 +- .../statfun/ft_statfun_correlationT.m | 21 +- .../ft_statfun_depsamplesFmultivariate.m | 69 +- .../ft_statfun_depsamplesFunivariate.m | 63 +- .../statfun/ft_statfun_depsamplesT.m | 13 +- .../statfun/ft_statfun_depsamplesregrT.m | 39 +- external/fieldtrip/statfun/ft_statfun_diff.m | 4 +- .../fieldtrip/statfun/ft_statfun_diff_itc.m | 6 +- .../statfun/ft_statfun_indepsamplesF.m | 50 +- .../statfun/ft_statfun_indepsamplesT.m | 37 +- .../statfun/ft_statfun_indepsamplesZcoh.m | 38 +- .../statfun/ft_statfun_indepsamplesregrT.m | 37 +- .../fieldtrip/statfun/ft_statfun_pooledT.m | 2 +- external/fieldtrip/statfun/ft_statfun_roc.m | 2 +- .../fieldtrip/statfun/private/defaultId.m | 57 + external/fieldtrip/statfun/private/fixname.m | 68 +- .../statfun/private/ft_notification.m | 490 +++++++ .../fieldtrip/statfun/private/ft_warning.m | 264 +--- external/fieldtrip/statfun/private/istrue.m | 42 + .../ft_trialfun_brainvision_segmented.m | 63 +- external/fieldtrip/trialfun/ft_trialfun_edf.m | 2 +- .../fieldtrip/trialfun/ft_trialfun_example1.m | 13 +- .../fieldtrip/trialfun/ft_trialfun_example2.m | 8 +- .../fieldtrip/trialfun/ft_trialfun_general.m | 34 +- .../fieldtrip/trialfun/ft_trialfun_realtime.m | 5 +- .../fieldtrip/trialfun/ft_trialfun_trial.m | 7 + .../ft_trialfun_twoclass_classification.m | 8 +- .../fieldtrip/trialfun/private/defaultId.m | 57 + .../trialfun/private/select_channel_list.m | 4 +- external/fieldtrip/utilities/appendstruct.m | 40 +- external/fieldtrip/utilities/copyfields.m | 2 +- .../utilities/ft_channelcombination.m | 6 +- .../fieldtrip/utilities/ft_channelselection.m | 90 +- external/fieldtrip/utilities/ft_checkconfig.m | 166 +-- external/fieldtrip/utilities/ft_checkdata.m | 550 +++++--- external/fieldtrip/utilities/ft_checkopt.m | 2 +- external/fieldtrip/utilities/ft_compile_mex.m | 14 +- .../fieldtrip/utilities/ft_convert_coordsys.m | 42 +- .../fieldtrip/utilities/ft_convert_grad.m | 11 - external/fieldtrip/utilities/ft_datatype.m | 32 +- .../fieldtrip/utilities/ft_datatype_comp.m | 48 +- .../fieldtrip/utilities/ft_datatype_freq.m | 16 +- .../utilities/ft_datatype_headmodel.m | 14 +- .../fieldtrip/utilities/ft_datatype_mvar.m | 2 +- .../utilities/ft_datatype_parcellation.m | 2 +- .../fieldtrip/utilities/ft_datatype_raw.m | 14 +- .../utilities/ft_datatype_segmentation.m | 10 +- .../fieldtrip/utilities/ft_datatype_sens.m | 70 +- .../fieldtrip/utilities/ft_datatype_source.m | 4 +- .../fieldtrip/utilities/ft_datatype_spike.m | 16 +- .../utilities/ft_datatype_timelock.m | 45 +- .../fieldtrip/utilities/ft_datatype_volume.m | 4 +- external/fieldtrip/utilities/ft_debug.m | 64 + .../utilities/ft_determine_coordsys.m | 77 +- .../utilities/ft_documentationindex.m | 2 +- .../utilities/ft_documentationreference.m | 2 +- external/fieldtrip/utilities/ft_error.m | 40 + external/fieldtrip/utilities/ft_fetch_data.m | 30 +- external/fieldtrip/utilities/ft_findcfg.m | 4 +- external/fieldtrip/utilities/ft_getopt.m | 30 +- .../fieldtrip/utilities/ft_getopt.mexmaci64 | Bin 9832 -> 9680 bytes external/fieldtrip/utilities/ft_getopt.mexw32 | Bin 8704 -> 8704 bytes external/fieldtrip/utilities/ft_getopt.mexw64 | Bin 9216 -> 9216 bytes external/fieldtrip/utilities/ft_hash.m | 2 +- external/fieldtrip/utilities/ft_hastoolbox.m | 207 +-- .../fieldtrip/utilities/ft_headcoordinates.m | 35 +- external/fieldtrip/utilities/ft_info.m | 64 + external/fieldtrip/utilities/ft_notice.m | 64 + .../utilities/ft_platform_supports.m | 336 +++++ external/fieldtrip/utilities/ft_postamble.m | 34 +- external/fieldtrip/utilities/ft_preamble.m | 45 +- external/fieldtrip/utilities/ft_progress.m | 2 + .../fieldtrip/utilities/ft_scalingfactor.m | 4 +- external/fieldtrip/utilities/ft_selectdata.m | 200 +-- .../fieldtrip/utilities/ft_selectdata_new.m | 72 +- .../fieldtrip/utilities/ft_selectdata_old.m | 44 +- external/fieldtrip/utilities/ft_source2full.m | 54 +- external/fieldtrip/utilities/ft_source2grid.m | 2 +- .../fieldtrip/utilities/ft_source2sparse.m | 6 +- .../fieldtrip/utilities/ft_struct2double.m | 2 +- .../fieldtrip/utilities/ft_struct2single.m | 2 +- external/fieldtrip/utilities/ft_test.m | 111 ++ external/fieldtrip/utilities/ft_test_result.m | 197 --- external/fieldtrip/utilities/ft_trackusage.m | 236 ++-- .../utilities/ft_transform_geometry.m | 68 +- external/fieldtrip/utilities/ft_version.m | 38 +- external/fieldtrip/utilities/ft_warning.m | 264 +--- external/fieldtrip/utilities/ft_warp_apply.m | 18 +- .../fieldtrip/utilities/ft_warp_dykstra2012.m | 158 --- external/fieldtrip/utilities/ft_warp_optim.m | 10 +- external/fieldtrip/utilities/hasyokogawa.m | 2 +- external/fieldtrip/utilities/istrue.m | 4 +- external/fieldtrip/utilities/keepfields.m | 2 +- external/fieldtrip/utilities/keyval.m | 6 +- external/fieldtrip/utilities/keyvalcheck.m | 8 +- external/fieldtrip/utilities/match_str.m | 7 +- external/fieldtrip/utilities/match_val.m | 35 + external/fieldtrip/utilities/memtic.m | 8 +- external/fieldtrip/utilities/nearest.m | 24 +- external/fieldtrip/utilities/printstruct.m | 8 +- .../utilities/private/align_ctf2acpc.m | 191 +++ .../utilities/private/align_ctf2spm.m | 167 --- .../utilities/private/align_fsaverage2mni.m | 24 + .../utilities/private/align_itab2spm.m | 142 -- .../utilities/private/align_neuromag2acpc.m | 191 +++ .../fieldtrip/utilities/private/avgoverdim.m | 10 +- .../utilities/private/base64encode.m | 14 +- .../utilities/private/channelposition.m | 4 +- .../private/convert_segmentationstyle.m | 4 +- .../utilities/private/coordsys2label.m | 169 +++ .../utilities/private/dataset2files.m | 2 +- .../fieldtrip/utilities/private/defaultId.m | 57 + .../fieldtrip/utilities/private/dimindex.m | 70 + .../fieldtrip/utilities/private/dimlength.m | 8 +- .../fieldtrip/utilities/private/fixdimord.m | 24 +- .../fieldtrip/utilities/private/fixdipole.m | 6 +- .../fieldtrip/utilities/private/fixname.m | 68 +- .../fieldtrip/utilities/private/fixoldorg.m | 36 + external/fieldtrip/utilities/private/fixpos.m | 4 +- .../utilities/private/fixsegmentation.m | 40 +- .../fieldtrip/utilities/private/fixsource.m | 2 +- .../fieldtrip/utilities/private/fixvolume.m | 4 +- .../fieldtrip/utilities/private/ft_findcfg.m | 4 +- .../utilities/private/ft_notification.m | 482 +++++++ .../utilities/private/ft_postamble_debug.m | 12 +- .../utilities/private/ft_postamble_history.m | 8 +- .../private/ft_postamble_provenance.m | 2 +- .../utilities/private/ft_preamble_debug.m | 39 +- .../utilities/private/ft_preamble_init.m | 12 +- .../utilities/private/ft_preamble_loadvar.m | 2 +- .../private/ft_preamble_provenance.m | 2 +- .../utilities/private/ft_struct2json.m | 2 +- .../utilities/private/ft_test_compare.m | 105 ++ .../utilities/private/ft_test_moxunit_run.m | 64 + .../utilities/private/ft_test_report.m | 86 ++ .../utilities/{ => private}/ft_test_run.m | 116 +- .../fieldtrip/utilities/private/ft_urlread.m | 2 +- .../fieldtrip/utilities/private/funargname.m | 2 +- .../fieldtrip/utilities/private/getaddress.m | 15 +- .../fieldtrip/utilities/private/getdimord.m | 93 +- .../fieldtrip/utilities/private/getdimsiz.m | 2 +- .../fieldtrip/utilities/private/icosahedron.m | 1 - .../utilities/private/icosahedron42.m | 1 - .../utilities/private/ignorefields.m | 44 +- .../utilities/private/individual2sn.m | 6 +- .../utilities/private/labelcmb2indx.m | 30 +- .../fieldtrip/utilities/private/leaveoneout.m | 8 +- external/fieldtrip/utilities/private/lmoutr.m | 6 +- .../fieldtrip/utilities/private/lmoutr.mexa64 | Bin 13190 -> 13190 bytes .../utilities/private/lmoutr.mexmaci64 | Bin 13296 -> 13240 bytes .../fieldtrip/utilities/private/lmoutr.mexw32 | Bin 8192 -> 8192 bytes .../fieldtrip/utilities/private/lmoutr.mexw64 | Bin 9216 -> 9216 bytes .../fieldtrip/utilities/private/loadvar.m | 6 +- .../utilities/private/mergecellstruct.m | 11 + .../fieldtrip/utilities/private/mergeconfig.m | 72 +- .../fieldtrip/utilities/private/mxSerialize.m | 2 +- .../fieldtrip/utilities/private/pos2dim.m | 3 +- .../utilities/private/pos2transform.m | 4 +- .../fieldtrip/utilities/private/printand.m | 28 + .../fieldtrip/utilities/private/printor.m | 28 + .../utilities/private/project_elec.m | 2 +- .../fieldtrip/utilities/private/ptriproj.m | 6 +- .../utilities/private/ptriproj.mexa64 | Bin 13236 -> 13236 bytes .../utilities/private/ptriproj.mexmaci64 | Bin 13360 -> 13304 bytes .../utilities/private/ptriproj.mexw32 | Bin 9216 -> 9216 bytes .../utilities/private/ptriproj.mexw64 | Bin 10752 -> 10752 bytes .../fieldtrip/utilities/private/quaternion.m | 2 +- external/fieldtrip/utilities/private/refine.m | 3 +- .../fieldtrip/utilities/private/rigidbody.m | 2 +- external/fieldtrip/utilities/private/rotate.m | 2 +- external/fieldtrip/utilities/private/scale.m | 2 +- .../fieldtrip/utilities/private/selfromraw.m | 6 +- .../fieldtrip/utilities/private/seloverdim.m | 10 +- .../fieldtrip/utilities/private/selparam.m | 2 +- .../utilities/private/sn2individual.m | 7 +- .../utilities/private/struct2table.m | 89 ++ .../fieldtrip/utilities/private/translate.m | 2 +- .../utilities/private/undobalancing.m | 4 +- .../utilities/private/volumefillholes.m | 11 +- .../fieldtrip/utilities/private/volumeflip.m | 19 +- .../utilities/private/volumepermute.m | 18 +- .../utilities/private/volumesmooth.m | 10 +- .../utilities/private/volumethreshold.m | 14 +- external/fieldtrip/utilities/removefields.m | 2 +- external/fieldtrip/utilities/renamefields.m | 10 +- external/mne/fiff_define_constants.m | 18 +- external/mne/fiff_read_bad_channels.m | 2 +- external/mne/fiff_read_epochs.m | 2 +- external/mne/fiff_read_events.m | 2 +- external/mne/fiff_read_hpi_result.m | 69 + external/mne/fiff_read_meas_info.m | 7 +- external/mne/fiff_read_raw_segment.m | 10 +- external/mne/fiff_setup_read_raw.m | 32 +- external/mne/fiff_write_int_matrix.m | 2 +- external/mne/mne_babyMEG_dig_trig.m | 251 ++++ external/mne/mne_load_coil_def.m | 4 +- help/index.html | 2 +- man/Makefile | 29 +- man/auditory/auditory.tex | 2 +- man/dartelguide/dartelguide.tex | 9 +- man/example_scripts/DCM_example_MMC_BGC.m | 80 ++ man/manual.pdf | Bin 13846775 -> 13847441 bytes man/meeg/eeg_imaging.tex | 2 +- man/meeg/eeg_preprocessing.tex | 4 +- man/meeg_artefact/meeg_artefact.tex | 2 +- man/multi/figures/figure7.png | Bin 4422 -> 1725 bytes matlabbatch/@cfg_dep/ctranspose.m | 18 + matlabbatch/cfg_basicio/cfg_cfg_basicio.m | 57 +- matlabbatch/cfg_basicio/cfg_run_dir_move.m | 50 + matlabbatch/cfg_basicio/cfg_run_file_fplist.m | 8 +- matlabbatch/cfg_basicio/cfg_run_save_vars.m | 10 +- matlabbatch/cfg_basicio/cfg_vout_dir_move.m | 24 + matlabbatch/cfg_callbuiltin.m | 38 + matlabbatch/cfg_getfile.m | 40 +- matlabbatch/cfg_load_jobs.m | 30 +- matlabbatch/cfg_util.m | 6 +- spm.m | 15 +- spm_ADEM.m | 18 +- spm_BIDS.m | 811 +++++++++--- spm_Ce.m | 114 +- spm_Menu.fig | Bin 105552 -> 105552 bytes spm_Welcome.m | 5 +- spm_add.mexmaci64 | Bin 203816 -> 186336 bytes spm_add.mexw32 | Bin 94208 -> 94208 bytes spm_add.mexw64 | Bin 111616 -> 111616 bytes spm_ancova.m | 18 +- spm_bilinear_condition.m | 12 +- spm_bsplinc.mexmaci64 | Bin 212232 -> 194688 bytes spm_bsplinc.mexw32 | Bin 69632 -> 69632 bytes spm_bsplinc.mexw64 | Bin 80896 -> 80896 bytes spm_bsplins.mexmaci64 | Bin 22064 -> 22164 bytes spm_bsplins.mexw32 | Bin 14848 -> 14848 bytes spm_bsplins.mexw64 | Bin 17408 -> 17408 bytes spm_bwlabel.mexmaci64 | Bin 13808 -> 13820 bytes spm_bwlabel.mexw32 | Bin 9216 -> 9216 bytes spm_bwlabel.mexw64 | Bin 11776 -> 11776 bytes spm_cat.mexmaci64 | Bin 19016 -> 18916 bytes spm_cat.mexw32 | Bin 15360 -> 15360 bytes spm_cat.mexw64 | Bin 17920 -> 17920 bytes spm_cat_struct.m | 22 +- spm_changepath.m | 30 +- spm_check_installation.m | 94 +- spm_cli.m | 276 ++++ spm_contrasts.m | 17 +- spm_conv_vol.mexmaci64 | Bin 207856 -> 186280 bytes spm_conv_vol.mexw32 | Bin 98304 -> 98304 bytes spm_conv_vol.mexw64 | Bin 115200 -> 115200 bytes spm_copy.m | 77 ++ spm_create_vol.m | 62 +- spm_cva_ui.m | 4 +- spm_dcm_bma.m | 4 +- spm_dcm_bmr.m | 4 +- spm_dcm_bmr_all.m | 116 +- spm_dcm_bpa.m | 4 +- spm_dcm_delay.m | 11 +- spm_dcm_fmri_check.m | 7 +- spm_dcm_fmri_csd.m | 42 +- spm_dcm_fmri_nmm.m | 43 +- spm_dcm_loo.m | 22 +- spm_dcm_mdp.m | 18 +- spm_dcm_peb.m | 153 ++- spm_dcm_peb_bmc.m | 46 +- spm_dcm_peb_bmc_fam.m | 291 +++++ spm_dcm_peb_fit.m | 10 +- spm_dcm_peb_review.m | 122 +- spm_dcm_review.m | 23 +- spm_dcm_simulate.m | 39 +- spm_dcm_sparse.m | 237 ++++ spm_dcm_specify.m | 11 +- spm_ddiff.m | 189 +++ spm_defaults.m | 6 +- spm_dicom_convert.m | 118 +- spm_dicom_metadata.m | 275 ++++ spm_diff.m | 18 +- spm_diff_dx.m | 73 ++ spm_diffeo.mexa64 | Bin 183994 -> 188397 bytes spm_diffeo.mexmaci64 | Bin 194232 -> 189660 bytes spm_diffeo.mexw32 | Bin 143360 -> 143360 bytes spm_diffeo.mexw64 | Bin 195072 -> 195584 bytes spm_dilate_erode.mexmaci64 | Bin 13720 -> 13708 bytes spm_dilate_erode.mexw32 | Bin 8704 -> 8704 bytes spm_dilate_erode.mexw64 | Bin 10240 -> 10240 bytes spm_dx.m | 353 +++-- spm_eeg_artefact.m | 78 +- spm_eeg_artefact_events.m | 62 +- spm_eeg_artefact_eyeblink.m | 134 +- spm_eeg_artefact_flat.m | 73 +- spm_eeg_artefact_heartbeat.m | 67 +- spm_eeg_artefact_jump.m | 70 +- spm_eeg_artefact_nans.m | 46 +- spm_eeg_artefact_peak2peak.m | 52 +- spm_eeg_artefact_saccade.m | 142 +- spm_eeg_artefact_threshchan.m | 98 +- spm_eeg_artefact_zscore.m | 69 +- spm_eeg_artefact_zscorediff.m | 65 +- spm_eeg_assemble_priors.m | 182 ++- spm_eeg_average.m | 20 +- spm_eeg_average_TF.m | 21 +- spm_eeg_avgfreq.m | 28 +- spm_eeg_avgtime.m | 19 +- spm_eeg_bc.m | 18 +- spm_eeg_collapse_timefreq.m | 27 +- spm_eeg_combineplanar.m | 24 +- spm_eeg_contrast.m | 31 +- spm_eeg_convert.m | 7 +- spm_eeg_convert2images.m | 9 +- spm_eeg_copy.m | 14 +- spm_eeg_correct_sensor_data.m | 37 +- spm_eeg_crop.m | 36 +- spm_eeg_definetrial.m | 19 +- spm_eeg_dipoles_ui.m | 88 +- spm_eeg_downsample.m | 28 +- spm_eeg_epochs.m | 32 +- spm_eeg_filter.m | 33 +- spm_eeg_ft2spm.m | 14 +- spm_eeg_grandmean.m | 57 +- spm_eeg_inv_Mesh2Voxels.m | 21 +- spm_eeg_inv_checkdatareg.m | 9 +- spm_eeg_inv_checkforward.m | 12 +- spm_eeg_inv_datareg.m | 41 +- spm_eeg_inv_datareg_ui.m | 49 +- spm_eeg_inv_extract.m | 6 +- spm_eeg_inv_forward.m | 31 +- spm_eeg_inv_prep_modes_xval.m | 254 ++-- spm_eeg_inv_results.m | 17 +- spm_eeg_inv_vb_ecd_gui.m | 33 +- spm_eeg_inv_visu3D_api.m | 26 +- spm_eeg_invert.m | 121 +- spm_eeg_invert_prepro.m | 170 +-- spm_eeg_invert_setuppatches.m | 4 +- spm_eeg_invert_ui.m | 3 +- spm_eeg_lgainmat.m | 73 +- spm_eeg_merge.m | 53 +- spm_eeg_montage.m | 94 +- spm_eeg_montage_ui.m | 33 +- spm_eeg_morlet.m | 32 +- spm_eeg_planarchannelset.m | 8 +- spm_eeg_prep.m | 66 +- spm_eeg_prep_ui.m | 65 +- spm_eeg_review_callbacks.m | 115 +- spm_eeg_review_switchDisplay.m | 4 +- spm_eeg_simulate.m | 4 +- spm_eeg_spatial_confounds.m | 10 +- spm_eeg_specest_morlet.m | 91 +- spm_eeg_tf.m | 7 +- spm_est_V.m | 4 +- spm_est_non_sphericity.m | 9 +- spm_existfile.mexmaci64 | Bin 8856 -> 8816 bytes spm_existfile.mexw32 | Bin 6656 -> 6656 bytes spm_existfile.mexw64 | Bin 7680 -> 7680 bytes spm_fMRI_design.m | 6 +- spm_field.mexa64 | Bin 34824 -> 34824 bytes spm_field.mexmaci64 | Bin 34824 -> 34900 bytes spm_field.mexw32 | Bin 23552 -> 23552 bytes spm_field.mexw64 | Bin 31744 -> 32256 bytes spm_fieldindices.m | 26 +- spm_figure.m | 5 +- spm_file.m | 30 +- spm_find_pC.m | 7 +- spm_fmri_concatenate.m | 8 +- spm_fmri_spm_ui.m | 28 +- spm_gamrnd.mexmaci64 | Bin 9112 -> 9048 bytes spm_gamrnd.mexw32 | Bin 8192 -> 8192 bytes spm_gamrnd.mexw64 | Bin 9728 -> 9728 bytes spm_gen_fmri.m | 6 +- spm_getSPM.m | 18 +- spm_get_dataset.m | 143 ++ spm_get_lm.mexmaci64 | Bin 13832 -> 13828 bytes spm_get_lm.mexw32 | Bin 10752 -> 10752 bytes spm_get_lm.mexw64 | Bin 12288 -> 12288 bytes spm_global.mexmaci64 | Bin 199704 -> 182012 bytes spm_global.mexw32 | Bin 94208 -> 94208 bytes spm_global.mexw64 | Bin 109056 -> 109056 bytes spm_graph.m | 85 +- spm_graph_ui.m | 25 +- spm_hist.mexmaci64 | Bin 9000 -> 8928 bytes spm_hist.mexw32 | Bin 6656 -> 6656 bytes spm_hist.mexw64 | Bin 7680 -> 7680 bytes spm_hist2.mexmaci64 | Bin 13552 -> 13572 bytes spm_hist2.mexw32 | Bin 9216 -> 9216 bytes spm_hist2.mexw64 | Bin 10240 -> 10240 bytes spm_imcalc.m | 47 +- spm_int_L.m | 28 +- spm_inv.m | 4 +- spm_jobman.m | 21 +- spm_jsonread.m | 12 +- spm_jsonread.mexa64 | Bin 18362 -> 22943 bytes spm_jsonread.mexmaci64 | Bin 14996 -> 19748 bytes spm_jsonread.mexw32 | Bin 11776 -> 13824 bytes spm_jsonread.mexw64 | Bin 13824 -> 16896 bytes spm_jsonwrite.m | 195 ++- spm_kernels.m | 30 +- spm_krutil.mexmaci64 | Bin 17528 -> 17636 bytes spm_krutil.mexw32 | Bin 13824 -> 13824 bytes spm_krutil.mexw64 | Bin 16896 -> 16896 bytes spm_list.m | 15 +- spm_load.m | 26 +- spm_maff8.m | 4 +- spm_mesh_contour.m | 319 +++++ spm_mesh_join.m | 35 + spm_mesh_normals.m | 86 +- spm_mesh_project.m | 5 +- spm_mesh_render.m | 86 +- spm_mesh_split.m | 14 +- spm_mesh_utils.mexa64 | Bin 13731 -> 13731 bytes spm_mesh_utils.mexmaci64 | Bin 14424 -> 14248 bytes spm_mesh_utils.mexw32 | Bin 10752 -> 10752 bytes spm_mesh_utils.mexw64 | Bin 13824 -> 13824 bytes spm_mkdir.m | 33 + spm_mrf.mexa64 | Bin 13020 -> 13020 bytes spm_mrf.mexmaci64 | Bin 13400 -> 13612 bytes spm_mrf.mexw32 | Bin 12800 -> 12800 bytes spm_mrf.mexw64 | Bin 13824 -> 14848 bytes spm_mvb.m | 4 +- spm_mvb_display.m | 34 +- spm_mvb_ui.m | 27 +- spm_nlsi_N.m | 40 +- spm_orthviews.m | 825 ++++++------ spm_orthviews/spm_ov_mesh.m | 261 ++++ spm_orthviews/spm_ov_movie.m | 27 +- spm_orthviews/spm_ov_roi.m | 25 +- spm_platform.m | 17 +- spm_plot_convergence.m | 9 +- spm_powell.m | 15 +- spm_preproc8.m | 8 +- spm_preproc_write8.m | 47 +- spm_print.m | 25 +- spm_progress_bar.m | 13 +- spm_project.mexmaci64 | Bin 13272 -> 13176 bytes spm_project.mexw32 | Bin 9728 -> 9728 bytes spm_project.mexw64 | Bin 10752 -> 10752 bytes spm_provenance.m | 28 +- spm_read_vols.m | 43 +- spm_realign.m | 36 +- spm_regions.m | 6 +- spm_reml.m | 178 +-- spm_reml_A.m | 12 +- spm_reml_sc.m | 33 +- spm_render_vol.mexmaci64 | Bin 203600 -> 186104 bytes spm_render_vol.mexw32 | Bin 122880 -> 122880 bytes spm_render_vol.mexw64 | Bin 162816 -> 162816 bytes spm_resels_vol.mexmaci64 | Bin 203624 -> 185956 bytes spm_resels_vol.mexw32 | Bin 94208 -> 94208 bytes spm_resels_vol.mexw64 | Bin 110592 -> 110592 bytes spm_reslice.m | 28 +- spm_results_nidm.m | 85 +- spm_results_ui.m | 8 +- spm_sample_vol.mexmaci64 | Bin 203528 -> 181764 bytes spm_sample_vol.mexw32 | Bin 98304 -> 98304 bytes spm_sample_vol.mexw64 | Bin 131072 -> 131072 bytes spm_slice_vol.mexmaci64 | Bin 199432 -> 181764 bytes spm_slice_vol.mexw32 | Bin 94208 -> 94208 bytes spm_slice_vol.mexw64 | Bin 109568 -> 109568 bytes spm_sp_reml.m | 16 +- spm_spm.m | 8 +- spm_standalone.m | 145 ++- spm_tests.m | 37 +- spm_unlink.mexmaci64 | Bin 8824 -> 8768 bytes spm_unlink.mexw32 | Bin 6656 -> 6656 bytes spm_unlink.mexw64 | Bin 7680 -> 7680 bytes spm_update.m | 6 +- spm_voronoi.mexmaci64 | Bin 14016 -> 13980 bytes spm_voronoi.mexw32 | Bin 12800 -> 12800 bytes spm_voronoi.mexw64 | Bin 14336 -> 14336 bytes spm_wft.m | 19 +- src/shoot_diffeo3d.c | 8 +- src/shoot_optimN.c | 95 +- src/shoot_regularisers.c | 10 +- src/spm_field.c | 6 +- src/spm_jsonread.c | 239 +++- src/spm_mrf.c | 40 +- tests/ROBOT_DCM_EEG.m | 138 +- tests/test_checkcode.m | 42 + tests/test_spm_Ce.m | 47 + tests/test_spm_cat_struct.m | 66 + tests/test_spm_create_vol.m | 59 + tests/test_spm_dcm_bmr.m | 40 + tests/test_spm_dcm_bmr_all.m | 37 + tests/test_spm_dcm_loo.m | 14 +- tests/test_spm_dcm_peb.m | 97 ++ tests/test_spm_dcm_peb_bmc_fam.m | 66 + tests/test_spm_dcm_simulate.m | 48 +- tests/test_spm_jsonread.m | 31 +- tests/test_spm_jsonwrite.m | 23 +- tests/test_spm_mesh_contour.m | 21 + tests/test_spm_mesh_normals.m | 17 + tests/test_spm_run_dcm_bms.m | 248 ++++ toolbox/DARTEL/spm_dartel_norm_fun.m | 78 +- toolbox/DARTEL/spm_dartel_template.m | 49 +- toolbox/DARTEL/spm_dartel_warp.m | 42 +- toolbox/DARTEL/tbx_cfg_dartel.m | 6 +- toolbox/DEM/ADEM_sample_image.m | 3 +- toolbox/DEM/DEMO_MDP_maze.m | 429 ++++++ toolbox/DEM/DEM_I3_and_TS.m | 283 ++++ toolbox/DEM/DEM_birdsong.m | 50 +- toolbox/DEM/DEM_cells.m | 213 +++ toolbox/DEM/DEM_cells_cells.m | 345 +++++ toolbox/DEM/DEM_demo.fig | Bin 28768 -> 30544 bytes toolbox/DEM/DEM_demo.m | 251 ++-- toolbox/DEM/DEM_demo_MDP_DEM.m | 300 +++-- toolbox/DEM/DEM_demo_MDP_fit_fields.m | 315 +++++ toolbox/DEM/DEM_demo_MDP_maze.m | 4 +- toolbox/DEM/DEM_demo_MDP_search.m | 6 +- toolbox/DEM/DEM_evidence_accumulation.m | 165 +-- toolbox/DEM/DEM_morphogenesis.m | 4 +- toolbox/DEM/DEM_self_MI_a.m | 337 +++++ toolbox/DEM/DEM_self_MI_b.m | 221 ++++ toolbox/DEM/DEM_self_MI_c.m | 221 ++++ toolbox/DEM/DEM_spatial_deconvolution.m | 4 +- toolbox/DEM/FEP_MB_demo.m | 492 +++++++ toolbox/DEM/FEP_Manifold.m | 4 +- toolbox/DEM/FEP_fluctuations.m | 406 ++++++ toolbox/DEM/FEP_physics.m | 792 +++++++++++ toolbox/DEM/FEP_self_entropy.m | 485 +++++++ toolbox/DEM/MDP_search_graphics.mat | Bin 484840 -> 486693 bytes toolbox/DEM/spm_DEM_ButtonDownFcn.m | 29 +- toolbox/DEM/spm_MDP_DEM.m | 8 +- toolbox/DEM/spm_MDP_L.m | 42 + toolbox/DEM/spm_MDP_VB.m | 62 +- toolbox/DEM/spm_MDP_VB_ERP.m | 4 +- toolbox/DEM/spm_MDP_VB_LFP.m | 9 +- toolbox/DEM/spm_MDP_VB_X.m | 43 +- toolbox/DEM/spm_MDP_VB_game.m | 4 +- toolbox/DEM/spm_MDP_check.m | 41 +- toolbox/DEM/spm_MDP_plot.m | 281 ++++ toolbox/DEM/spm_Manifold_solve.m | 104 +- toolbox/DEM/spm_find_internal.m | 19 + toolbox/DEM/spm_soup.m | 264 ++++ toolbox/FieldMap/FIL/pm_defaults_Prisma.m | 65 + .../FieldMap/FIL/pm_defaults_Trio_al_128.m | 9 +- toolbox/FieldMap/FIL/pm_defaults_Trio_al_64.m | 9 +- toolbox/FieldMap/FIL/pm_defaults_Trio_al_96.m | 9 +- toolbox/FieldMap/FieldMap.m | 51 +- .../pm_create_connectogram_dtj.mexmaci64 | Bin 13464 -> 13484 bytes .../pm_create_connectogram_dtj.mexw32 | Bin 9216 -> 9216 bytes .../pm_create_connectogram_dtj.mexw64 | Bin 10240 -> 10240 bytes toolbox/FieldMap/pm_diff.m | 4 +- toolbox/FieldMap/pm_estimate_ramp.mexmaci64 | Bin 13432 -> 13484 bytes toolbox/FieldMap/pm_estimate_ramp.mexw32 | Bin 8192 -> 8192 bytes toolbox/FieldMap/pm_estimate_ramp.mexw64 | Bin 9728 -> 9728 bytes toolbox/FieldMap/pm_ff_unwrap.mexmaci64 | Bin 13568 -> 13588 bytes toolbox/FieldMap/pm_ff_unwrap.mexw32 | Bin 10752 -> 10752 bytes toolbox/FieldMap/pm_ff_unwrap.mexw64 | Bin 12800 -> 12800 bytes .../FieldMap/pm_invert_phasemap_dtj.mexmaci64 | Bin 17640 -> 13684 bytes .../FieldMap/pm_invert_phasemap_dtj.mexw32 | Bin 11776 -> 11776 bytes .../FieldMap/pm_invert_phasemap_dtj.mexw64 | Bin 13312 -> 13312 bytes toolbox/FieldMap/pm_merge_regions.mexmaci64 | Bin 17912 -> 17916 bytes toolbox/FieldMap/pm_merge_regions.mexw32 | Bin 14336 -> 14336 bytes toolbox/FieldMap/pm_merge_regions.mexw64 | Bin 17408 -> 17408 bytes toolbox/FieldMap/pm_pad.mexmaci64 | Bin 13256 -> 13308 bytes toolbox/FieldMap/pm_pad.mexw32 | Bin 9728 -> 9728 bytes toolbox/FieldMap/pm_pad.mexw64 | Bin 9728 -> 9728 bytes toolbox/FieldMap/pm_restore_ramp.mexmaci64 | Bin 9304 -> 9332 bytes toolbox/FieldMap/pm_restore_ramp.mexw32 | Bin 8704 -> 8704 bytes toolbox/FieldMap/pm_restore_ramp.mexw64 | Bin 9216 -> 9216 bytes toolbox/FieldMap/tbx_cfg_fieldmap.m | 19 +- toolbox/Longitudinal/tbx_cfg_longitudinal.m | 8 +- toolbox/MEEGtools/eb_read_lvm.m | 9 + toolbox/MEEGtools/spm_eeg_cont_power.m | 6 +- toolbox/MEEGtools/spm_eeg_erp_correction.m | 6 +- toolbox/MEEGtools/spm_eeg_fix_ctf_headloc.m | 4 +- .../MEEGtools/spm_eeg_interpolate_artefact.m | 6 +- toolbox/MEEGtools/spm_eeg_plot_interactive.m | 10 +- toolbox/MEEGtools/spm_eeg_tms_correct.m | 9 +- toolbox/MEEGtools/spm_opm_convert.m | 65 + toolbox/MEEGtools/spm_opm_denoise.m | 78 ++ toolbox/Neural_Models/DEMO_dcm_fmri_nnm.m | 88 +- .../Neural_Models/spm_dcm_prior_responses.m | 4 +- toolbox/Neural_Models/spm_induced_optimise.m | 10 +- toolbox/Neural_Models/spm_lfp_demo.m | 2 +- toolbox/Neural_Models/spm_seizure_demo.m | 6 +- toolbox/Neural_Models/spm_sigmoid_demo.m | 4 +- toolbox/OldNorm/spm_brainwarp.mexmaci64 | Bin 211936 -> 198472 bytes toolbox/OldNorm/spm_brainwarp.mexw32 | Bin 110592 -> 110592 bytes toolbox/OldNorm/spm_brainwarp.mexw64 | Bin 151552 -> 151552 bytes toolbox/OldNorm/spm_cfg_normalise.m | 4 +- toolbox/OldSeg/spm_cfg_preproc.m | 6 +- toolbox/SRender/spm_sextract.m | 62 +- toolbox/SRender/spm_srender.m | 18 +- toolbox/SRender/tbx_cfg_render.m | 607 +++------ toolbox/Shoot/spm_shoot_greens.m | 51 +- toolbox/Shoot/tbx_cfg_shoot.m | 11 +- toolbox/dcm_fnirs/spm_dcm_fnirs_estimate.m | 24 +- toolbox/dcm_fnirs/spm_dcm_fnirs_priors.m | 6 +- toolbox/dcm_fnirs/spm_dcm_fnirs_specify.m | 18 +- toolbox/dcm_fnirs/spm_fx_fnirs.m | 5 +- toolbox/dcm_meeg/spm_L_priors.m | 25 +- toolbox/dcm_meeg/spm_bgc_priors.m | 25 + toolbox/dcm_meeg/spm_dcm_csd.m | 8 +- toolbox/dcm_meeg/spm_dcm_erp.m | 16 +- toolbox/dcm_meeg/spm_dcm_ind.m | 4 +- toolbox/dcm_meeg/spm_dcm_neural_priors.m | 126 +- toolbox/dcm_meeg/spm_dcm_tfm.m | 12 +- toolbox/dcm_meeg/spm_dcm_x_neural.m | 29 +- toolbox/dcm_meeg/spm_epileptor_demo.m | 20 +- toolbox/dcm_meeg/spm_erp_L.m | 4 +- toolbox/dcm_meeg/spm_fs_csd.m | 14 +- toolbox/dcm_meeg/spm_fx_bgc.m | 161 +++ toolbox/dcm_meeg/spm_fx_cmc_tfm.m | 45 +- toolbox/dcm_meeg/spm_fx_gen.m | 36 +- toolbox/dcm_meeg/spm_fx_mmc.m | 249 ++++ toolbox/dcm_meeg/spm_int_U.m | 6 +- toolbox/dcm_meeg/spm_mmc_priors.m | 137 ++ 1775 files changed, 57726 insertions(+), 28932 deletions(-) create mode 100644 @gifti/private/obj_read.m create mode 100644 @gifti/private/zstream.mexw32 create mode 100755 bin/spm12-matlab create mode 100755 bin/spm12-mcr create mode 100755 bin/spm12-octave create mode 100644 config/spm_cfg_eeg_dipfit.m create mode 100644 config/spm_cfg_eeg_opmsetup.m create mode 100644 external/fieldtrip/bis2fieldtrip.m create mode 100644 external/fieldtrip/connectivity/private/coeffs2iis.m create mode 100644 external/fieldtrip/connectivity/private/ctranspose2x2.m create mode 100644 external/fieldtrip/connectivity/private/ctranspose3x3.m create mode 100644 external/fieldtrip/connectivity/private/defaultId.m create mode 100644 external/fieldtrip/connectivity/private/det3x3.m create mode 100644 external/fieldtrip/connectivity/private/ft_notification.m rename external/fieldtrip/{ => connectivity}/private/ft_platform_supports.m (56%) create mode 100644 external/fieldtrip/connectivity/private/inv3x3.m create mode 100644 external/fieldtrip/connectivity/private/istrue.m create mode 100644 external/fieldtrip/connectivity/private/mtimes3x3.m create mode 100644 external/fieldtrip/connectivity/private/sandwich3x3.m create mode 100644 external/fieldtrip/connectivity/private/sfactorization_wilson3x3.m create mode 100644 external/fieldtrip/connectivity/private/transfer2coeffs.m create mode 100644 external/fieldtrip/connectivity/private/triplet_conditionalgranger.m create mode 100644 external/fieldtrip/connectivity/transfer2coeffs.m delete mode 100644 external/fieldtrip/external/stats/lgamma.m rename external/fieldtrip/external/stats/{ => private}/iscomplex.m (100%) create mode 100644 external/fieldtrip/fieldtrip2bis.m create mode 100644 external/fieldtrip/fileio/ft_write_sens.m create mode 100644 external/fieldtrip/fileio/private/defaultId.m create mode 100644 external/fieldtrip/fileio/private/fixoldorg.m create mode 100644 external/fieldtrip/fileio/private/ft_determine_units.m create mode 100644 external/fieldtrip/fileio/private/ft_notification.m create mode 100644 external/fieldtrip/fileio/private/homer2opto.m create mode 100644 external/fieldtrip/fileio/private/read_bioimage_mgrid.m create mode 100644 external/fieldtrip/fileio/private/write_bioimage_mgrid.m create mode 100644 external/fieldtrip/forward/ft_determine_units.m create mode 100644 external/fieldtrip/forward/private/defaultId.m create mode 100644 external/fieldtrip/forward/private/fixoldorg.m create mode 100644 external/fieldtrip/forward/private/ft_notification.m rename external/fieldtrip/{utilities => forward}/private/ft_platform_supports.m (56%) create mode 100644 external/fieldtrip/forward/private/plgndr.c create mode 100644 external/fieldtrip/ft_appendsens.m create mode 100644 external/fieldtrip/ft_artifact_nan.m delete mode 100644 external/fieldtrip/ft_channelselection.m delete mode 100644 external/fieldtrip/ft_freqcomparison.m create mode 100644 external/fieldtrip/ft_meshrealign.m delete mode 100644 external/fieldtrip/ft_prepare_bemmodel.m delete mode 100644 external/fieldtrip/ft_prepare_concentricspheres.m delete mode 100644 external/fieldtrip/ft_prepare_localspheres.m create mode 100644 external/fieldtrip/ft_prepare_montage.m delete mode 100644 external/fieldtrip/ft_prepare_singleshell.m delete mode 100644 external/fieldtrip/ft_removetmsartifact.m delete mode 100644 external/fieldtrip/ft_sensorrealign.m create mode 100644 external/fieldtrip/ft_steadystatesimulation.m delete mode 100644 external/fieldtrip/ft_surfacerealign.m create mode 100644 external/fieldtrip/ft_volumebiascorrect.m create mode 100644 external/fieldtrip/inverse/private/defaultId.m create mode 100644 external/fieldtrip/inverse/private/ft_notification.m create mode 100644 external/fieldtrip/inverse/private/ft_platform_supports.m create mode 100644 external/fieldtrip/inverse/private/ft_warning.m create mode 100644 external/fieldtrip/plotting/ft_plot_cloud.m create mode 100644 external/fieldtrip/plotting/private/bg_rgba2rgb.m create mode 100644 external/fieldtrip/plotting/private/cdat2rgb.m create mode 100644 external/fieldtrip/plotting/private/coordsys2label.m create mode 100644 external/fieldtrip/plotting/private/cortex_dark.m create mode 100644 external/fieldtrip/plotting/private/cortex_light.m create mode 100644 external/fieldtrip/plotting/private/defaultId.m create mode 100644 external/fieldtrip/plotting/private/fixoldorg.m create mode 100644 external/fieldtrip/plotting/private/ft_determine_units.m create mode 100644 external/fieldtrip/plotting/private/ft_notification.m create mode 100644 external/fieldtrip/plotting/private/lmoutrn.m create mode 100644 external/fieldtrip/plotting/private/pinvNx2.m create mode 100644 external/fieldtrip/preproc/private/defaultId.m create mode 100644 external/fieldtrip/preproc/private/ft_notification.m create mode 100644 external/fieldtrip/preproc/private/ft_platform_supports.m create mode 100644 external/fieldtrip/private/append_common.m create mode 100644 external/fieldtrip/private/bivariate_common.m create mode 100644 external/fieldtrip/private/chanscale_common.m create mode 100644 external/fieldtrip/private/coordsys2label.m delete mode 100644 external/fieldtrip/private/crosshair.m create mode 100644 external/fieldtrip/private/defaultId.m create mode 100644 external/fieldtrip/private/elec1020_follow.m create mode 100644 external/fieldtrip/private/elec1020_fraction.m create mode 100644 external/fieldtrip/private/elec1020_intersect.m create mode 100644 external/fieldtrip/private/elec1020_locate.m create mode 100644 external/fieldtrip/private/fixcoordsys.m create mode 100644 external/fieldtrip/private/moveinward.m create mode 100644 external/fieldtrip/private/plgndr.c create mode 100644 external/fieldtrip/private/pntdist.m rename external/fieldtrip/private/{prepare_cortexhull.m => prepare_mesh_cortexhull.m} (55%) create mode 100644 external/fieldtrip/private/prepare_mesh_tetrahedral.m create mode 100644 external/fieldtrip/private/ptriside.m create mode 100644 external/fieldtrip/private/setviewpoint.m create mode 100644 external/fieldtrip/private/tritrisect.m create mode 100644 external/fieldtrip/private/warp_dykstra2012.m create mode 100644 external/fieldtrip/specest/ft_specest_neuvar.m create mode 100644 external/fieldtrip/specest/private/defaultId.m create mode 100644 external/fieldtrip/specest/private/ft_notification.m create mode 100644 external/fieldtrip/specest/private/ft_platform_supports.m create mode 100644 external/fieldtrip/specest/private/istrue.m create mode 100644 external/fieldtrip/src/det3x3.c create mode 100644 external/fieldtrip/src/det3x3.m create mode 100644 external/fieldtrip/src/inv3x3.c create mode 100644 external/fieldtrip/src/inv3x3.m create mode 100644 external/fieldtrip/src/mtimes3x3.c create mode 100644 external/fieldtrip/src/mtimes3x3.m delete mode 100644 external/fieldtrip/src/nannumel.c create mode 100644 external/fieldtrip/src/sandwich3x3.c create mode 100644 external/fieldtrip/src/sandwich3x3.m create mode 100644 external/fieldtrip/statfun/private/defaultId.m create mode 100644 external/fieldtrip/statfun/private/ft_notification.m create mode 100644 external/fieldtrip/statfun/private/istrue.m create mode 100644 external/fieldtrip/trialfun/private/defaultId.m delete mode 100644 external/fieldtrip/utilities/ft_convert_grad.m create mode 100644 external/fieldtrip/utilities/ft_debug.m create mode 100644 external/fieldtrip/utilities/ft_error.m create mode 100644 external/fieldtrip/utilities/ft_info.m create mode 100644 external/fieldtrip/utilities/ft_notice.m create mode 100644 external/fieldtrip/utilities/ft_platform_supports.m create mode 100644 external/fieldtrip/utilities/ft_test.m delete mode 100644 external/fieldtrip/utilities/ft_test_result.m delete mode 100644 external/fieldtrip/utilities/ft_warp_dykstra2012.m create mode 100644 external/fieldtrip/utilities/match_val.m create mode 100644 external/fieldtrip/utilities/private/align_ctf2acpc.m delete mode 100644 external/fieldtrip/utilities/private/align_ctf2spm.m create mode 100644 external/fieldtrip/utilities/private/align_fsaverage2mni.m delete mode 100644 external/fieldtrip/utilities/private/align_itab2spm.m create mode 100644 external/fieldtrip/utilities/private/align_neuromag2acpc.m create mode 100644 external/fieldtrip/utilities/private/coordsys2label.m create mode 100644 external/fieldtrip/utilities/private/defaultId.m create mode 100644 external/fieldtrip/utilities/private/dimindex.m create mode 100644 external/fieldtrip/utilities/private/fixoldorg.m create mode 100644 external/fieldtrip/utilities/private/ft_notification.m create mode 100644 external/fieldtrip/utilities/private/ft_test_compare.m create mode 100644 external/fieldtrip/utilities/private/ft_test_moxunit_run.m create mode 100644 external/fieldtrip/utilities/private/ft_test_report.m rename external/fieldtrip/utilities/{ => private}/ft_test_run.m (61%) create mode 100644 external/fieldtrip/utilities/private/mergecellstruct.m create mode 100644 external/fieldtrip/utilities/private/printand.m create mode 100644 external/fieldtrip/utilities/private/printor.m create mode 100644 external/fieldtrip/utilities/private/struct2table.m create mode 100644 external/mne/fiff_read_hpi_result.m create mode 100644 external/mne/mne_babyMEG_dig_trig.m create mode 100644 man/example_scripts/DCM_example_MMC_BGC.m create mode 100644 matlabbatch/@cfg_dep/ctranspose.m create mode 100644 matlabbatch/cfg_basicio/cfg_run_dir_move.m create mode 100644 matlabbatch/cfg_basicio/cfg_vout_dir_move.m create mode 100644 spm_cli.m create mode 100644 spm_copy.m create mode 100644 spm_dcm_peb_bmc_fam.m create mode 100644 spm_dcm_sparse.m create mode 100644 spm_ddiff.m create mode 100644 spm_dicom_metadata.m create mode 100644 spm_diff_dx.m create mode 100644 spm_get_dataset.m create mode 100644 spm_mesh_contour.m create mode 100644 spm_mesh_join.m create mode 100644 spm_mkdir.m create mode 100644 spm_orthviews/spm_ov_mesh.m create mode 100644 tests/test_checkcode.m create mode 100644 tests/test_spm_Ce.m create mode 100644 tests/test_spm_cat_struct.m create mode 100644 tests/test_spm_create_vol.m create mode 100644 tests/test_spm_dcm_bmr.m create mode 100644 tests/test_spm_dcm_bmr_all.m create mode 100644 tests/test_spm_dcm_peb.m create mode 100644 tests/test_spm_dcm_peb_bmc_fam.m create mode 100644 tests/test_spm_mesh_contour.m create mode 100644 tests/test_spm_mesh_normals.m create mode 100644 tests/test_spm_run_dcm_bms.m create mode 100644 toolbox/DEM/DEMO_MDP_maze.m create mode 100644 toolbox/DEM/DEM_I3_and_TS.m create mode 100644 toolbox/DEM/DEM_cells.m create mode 100644 toolbox/DEM/DEM_cells_cells.m create mode 100644 toolbox/DEM/DEM_demo_MDP_fit_fields.m create mode 100644 toolbox/DEM/DEM_self_MI_a.m create mode 100644 toolbox/DEM/DEM_self_MI_b.m create mode 100644 toolbox/DEM/DEM_self_MI_c.m create mode 100644 toolbox/DEM/FEP_MB_demo.m create mode 100644 toolbox/DEM/FEP_fluctuations.m create mode 100644 toolbox/DEM/FEP_physics.m create mode 100644 toolbox/DEM/FEP_self_entropy.m create mode 100644 toolbox/DEM/spm_MDP_L.m create mode 100644 toolbox/DEM/spm_MDP_plot.m create mode 100644 toolbox/DEM/spm_find_internal.m create mode 100644 toolbox/DEM/spm_soup.m create mode 100644 toolbox/FieldMap/FIL/pm_defaults_Prisma.m create mode 100644 toolbox/MEEGtools/eb_read_lvm.m create mode 100644 toolbox/MEEGtools/spm_opm_convert.m create mode 100644 toolbox/MEEGtools/spm_opm_denoise.m create mode 100644 toolbox/dcm_meeg/spm_bgc_priors.m create mode 100644 toolbox/dcm_meeg/spm_fx_bgc.m create mode 100644 toolbox/dcm_meeg/spm_fx_mmc.m create mode 100644 toolbox/dcm_meeg/spm_mmc_priors.m diff --git a/@file_array/Contents.m b/@file_array/Contents.m index 841f8aab..a4b1db51 100644 --- a/@file_array/Contents.m +++ b/@file_array/Contents.m @@ -41,10 +41,8 @@ % size(fa4) % size(fa2) % length(fa0) -% _________________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: Contents.m 2696 2009-02-05 20:29:48Z guillaume $ - - +% $Id: Contents.m 7147 2017-08-03 14:07:01Z spm $ diff --git a/@file_array/cat.m b/@file_array/cat.m index df738eff..b6cf9b83 100644 --- a/@file_array/cat.m +++ b/@file_array/cat.m @@ -1,40 +1,40 @@ function o = cat(dr,varargin) % Concatenate file_array objects. The result is a non-simple object % that can no longer be reshaped. -% _______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: cat.m 4136 2010-12-09 22:22:28Z guillaume $ +% $Id: cat.m 7147 2017-08-03 14:07:01Z spm $ -if dr>32 || dr<0, error('Unknown command option.'); end; +if dr>32 || dr<0, error('Unknown command option.'); end dr = max(round(dr),1); d = ones(nargin-1,16); tmp = {}; dpos = 0; -for i=1:nargin-1, +for i=1:nargin-1 vi = varargin{i}; if strcmp(class(vi),'file_array') sz = size(vi); d(i,1:length(sz)) = sz; svi = struct(vi); svi = svi(:); - for j=1:length(svi(:)), + for j=1:length(svi(:)) if length(svi(j).pos)1, +if numel(struct(obj))>1 fprintf(' %s object: ', class(obj)); sz = size(obj); - if length(sz)>4, + if length(sz)>4 fprintf('%d-D\n',length(sz)); else - for i=1:(length(sz)-1), + for i=1:(length(sz)-1) fprintf('%d-by-',sz(i)); - end; + end fprintf('%d\n',sz(end)); - end; + end else disp(mystruct(obj)) -end; -return; -%======================================================================= +end -%======================================================================= + +%========================================================================== +% function t = mystruct(obj) +%========================================================================== function t = mystruct(obj) fn = fieldnames(obj); for i=1:length(fn) t.(fn{i}) = subsref(obj,struct('type','.','subs',fn{i})); -end; -return; -%======================================================================= +end diff --git a/@file_array/display.m b/@file_array/display.m index 21d83827..fe39869b 100644 --- a/@file_array/display.m +++ b/@file_array/display.m @@ -1,10 +1,10 @@ function display(obj) % Display a file_array object -% _______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: display.m 1143 2008-02-07 19:33:33Z spm $ +% $Id: display.m 7147 2017-08-03 14:07:01Z spm $ disp(' '); diff --git a/@file_array/double.m b/@file_array/double.m index f86ac7b6..3c001938 100644 --- a/@file_array/double.m +++ b/@file_array/double.m @@ -2,11 +2,11 @@ % Convert to double precision % FORMAT double(fa) % fa - a file_array -% _______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: double.m 1143 2008-02-07 19:33:33Z spm $ +% $Id: double.m 7147 2017-08-03 14:07:01Z spm $ -out = double(numeric(fa)); +out = double(numeric(fa)); diff --git a/@file_array/end.m b/@file_array/end.m index 5ac6efb6..1e76b192 100644 --- a/@file_array/end.m +++ b/@file_array/end.m @@ -1,17 +1,18 @@ function en = end(a,k,n) % Overloaded end function for file_array objects. -% _______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: end.m 1143 2008-02-07 19:33:33Z spm $ +% $Id: end.m 7147 2017-08-03 14:07:01Z spm $ + dim = size(a); if k>length(dim) en = 1; else - if n=1, a = fname(a,varargin{1}); end; -if nargin>=2, a = dim(a,varargin{2}); end; -if nargin>=3, a = dtype(a,varargin{3}); end; -if nargin>=4, a = offset(a,varargin{4}); end; -if nargin>=5, a = scl_slope(a,varargin{5}); end; -if nargin>=6, a = scl_inter(a,varargin{6}); end; -if nargin>=7, a = permission(a,varargin{7}); end; +if nargin>=1, a = fname(a,varargin{1}); end +if nargin>=2, a = dim(a,varargin{2}); end +if nargin>=3, a = dtype(a,varargin{3}); end +if nargin>=4, a = offset(a,varargin{4}); end +if nargin>=5, a = scl_slope(a,varargin{5}); end +if nargin>=6, a = scl_inter(a,varargin{6}); end +if nargin>=7, a = permission(a,varargin{7}); end a.pos = ones(size(a.dim)); a = file_array(a); - diff --git a/@file_array/horzcat.m b/@file_array/horzcat.m index 070c5174..ae497515 100644 --- a/@file_array/horzcat.m +++ b/@file_array/horzcat.m @@ -1,11 +1,10 @@ function o = horzcat(varargin) % Horizontal concatenation of file_array objects -% _______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: horzcat.m 1143 2008-02-07 19:33:33Z spm $ +% $Id: horzcat.m 7147 2017-08-03 14:07:01Z spm $ -o = cat(2,varargin{:}); -return; +o = cat(2,varargin{:}); diff --git a/@file_array/initialise.m b/@file_array/initialise.m index 189a77db..377989be 100644 --- a/@file_array/initialise.m +++ b/@file_array/initialise.m @@ -4,10 +4,10 @@ function initialise(fa) % This creates a file on disk with the appropriate size by explicitly % writing data to prevent a sparse file. %__________________________________________________________________________ -% Copyright (C) 2013 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2013-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: initialise.m 5458 2013-05-01 14:32:23Z guillaume $ +% $Id: initialise.m 7147 2017-08-03 14:07:01Z spm $ % first approach diff --git a/@file_array/isnan.m b/@file_array/isnan.m index e5d2738e..6fde9ef7 100644 --- a/@file_array/isnan.m +++ b/@file_array/isnan.m @@ -2,20 +2,20 @@ % Convert to numeric form % FORMAT isnan(fa) % fa - a file_array -% _______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: isnan.m 1301 2008-04-03 13:21:44Z john $ +% $Id: isnan.m 7147 2017-08-03 14:07:01Z spm $ + bs = 10240; m = size(fa); fa = reshape(fa,prod(m),1); n = prod(m); out = false(m); -for i=1:ceil(n/bs), +for i=1:ceil(n/bs) ii = ((((i-1)*bs)+1):min((i*bs),n))'; tmp = subsref(fa,struct('type','()','subs',{{ii}})); out(ii) = isnan(tmp); end - diff --git a/@file_array/length.m b/@file_array/length.m index 8299c09f..88bbe71a 100644 --- a/@file_array/length.m +++ b/@file_array/length.m @@ -1,11 +1,10 @@ function l = length(x) % Overloaded length function for file_array objects -% _______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: length.m 1143 2008-02-07 19:33:33Z spm $ +% $Id: length.m 7147 2017-08-03 14:07:01Z spm $ l = max(size(x)); - diff --git a/@file_array/loadobj.m b/@file_array/loadobj.m index aeb24aed..9d2e8e82 100644 --- a/@file_array/loadobj.m +++ b/@file_array/loadobj.m @@ -1,14 +1,15 @@ function b = loadobj(a) % loadobj for file_array class -% _______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: loadobj.m 1544 2008-05-06 10:34:36Z guillaume $ +% $Id: loadobj.m 7147 2017-08-03 14:07:01Z spm $ + if isa(a,'file_array') b = a; else a = permission(a, 'rw'); b = file_array(a); -end \ No newline at end of file +end diff --git a/@file_array/ndims.m b/@file_array/ndims.m index 2ce31fdd..674ea6ba 100644 --- a/@file_array/ndims.m +++ b/@file_array/ndims.m @@ -1,12 +1,11 @@ function out = ndims(fa) % Number of dimensions -%_______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: ndims.m 1143 2008-02-07 19:33:33Z spm $ +% $Id: ndims.m 7147 2017-08-03 14:07:01Z spm $ out = size(fa); out = length(out); - diff --git a/@file_array/numel.m b/@file_array/numel.m index 24aa5d79..8b6c1d10 100644 --- a/@file_array/numel.m +++ b/@file_array/numel.m @@ -1,10 +1,10 @@ function t = numel(obj) % Number of simple file arrays involved. -% _______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: numel.m 1143 2008-02-07 19:33:33Z spm $ +% $Id: numel.m 7147 2017-08-03 14:07:01Z spm $ % Should be this, but it causes problems when accessing diff --git a/@file_array/numeric.m b/@file_array/numeric.m index 74235abb..01b7bd60 100644 --- a/@file_array/numeric.m +++ b/@file_array/numeric.m @@ -2,13 +2,12 @@ % Convert to numeric form % FORMAT numeric(fa) % fa - a file_array -% _______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: numeric.m 1143 2008-02-07 19:33:33Z spm $ +% $Id: numeric.m 7147 2017-08-03 14:07:01Z spm $ [vo{1:ndims(fa)}] = deal(':'); out = subsref(fa,struct('type','()','subs',{vo})); - diff --git a/@file_array/permute.m b/@file_array/permute.m index f849057d..2a34b064 100644 --- a/@file_array/permute.m +++ b/@file_array/permute.m @@ -1,10 +1,10 @@ function varargout = permute(varargin) -% Can not be permuted. -% _______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +% file_array objects can not be permuted +%__________________________________________________________________________ +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: permute.m 1143 2008-02-07 19:33:33Z spm $ +% $Id: permute.m 7147 2017-08-03 14:07:01Z spm $ error('file_array objects can not be permuted.'); diff --git a/@file_array/private/datatypes.m b/@file_array/private/datatypes.m index 0e2ea0b6..0a755410 100644 --- a/@file_array/private/datatypes.m +++ b/@file_array/private/datatypes.m @@ -1,14 +1,14 @@ function dt = datatypes -% Datatype -% _______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +% Dictionary of datatypes +%__________________________________________________________________________ +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: datatypes.m 4136 2010-12-09 22:22:28Z guillaume $ +% $Id: datatypes.m 7147 2017-08-03 14:07:01Z spm $ persistent dtype -if isempty(dtype), +if isempty(dtype) t = true; f = false; table = {... @@ -40,7 +40,7 @@ 'unsigned' ,table(:,8),... 'min',-Inf,'max',Inf',... 'supported',table(:,9)); - for i=1:length(dtype), + for i=1:length(dtype) if dtype(i).isint if dtype(i).unsigned dtype(i).min = 0; @@ -48,9 +48,9 @@ else dtype(i).min = -2^(8*dtype(i).size-1); dtype(i).max = 2^(8*dtype(i).size-1)-1; - end; - end; - end; -end; + end + end + end +end dt = dtype; diff --git a/@file_array/private/dim.m b/@file_array/private/dim.m index 1749205e..94f22030 100644 --- a/@file_array/private/dim.m +++ b/@file_array/private/dim.m @@ -1,37 +1,42 @@ function varargout = dim(varargin) -% Format +% file_array's dimension property % For getting the value % dat = dim(obj) % % For setting the value % obj = dim(obj,dat) -% _______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: dim.m 1143 2008-02-07 19:33:33Z spm $ +% $Id: dim.m 7147 2017-08-03 14:07:01Z spm $ -if nargin==2, +if nargin==2 varargout{1} = asgn(varargin{:}); -elseif nargin==1, +elseif nargin==1 varargout{1} = ref(varargin{:}); else error('Wrong number of arguments.'); -end; -return; +end + +%========================================================================== +% function dat = ref(obj) +%========================================================================== function dat = ref(obj) dat = obj.dim; -return; + +%========================================================================== +% function obj = asgn(obj,dat) +%========================================================================== function obj = asgn(obj,dat) -if isnumeric(dat) && all(dat>=0) && all(rem(dat,1)==0), +if isnumeric(dat) && all(dat>=0) && all(rem(dat,1)==0) dat = [double(dat(:)') 1 1]; lim = max([2 find(dat~=1)]); dat = dat(1:lim); obj.dim = dat; else error('"dim" must be a vector of positive integers.'); -end; -return; +end diff --git a/@file_array/private/dtype.m b/@file_array/private/dtype.m index a1be7519..7cd9a17c 100644 --- a/@file_array/private/dtype.m +++ b/@file_array/private/dtype.m @@ -1,4 +1,5 @@ function varargout = dtype(varargin) +% file_array's dtype property % FORMAT varargout = dtype(varargin) % For getting the value % dat = dtype(obj) @@ -6,15 +7,15 @@ % For setting the value % obj = dtype(obj,dat) %__________________________________________________________________________ -% Copyright (C) 2005-2013 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: dtype.m 6157 2014-09-05 18:17:54Z guillaume $ +% $Id: dtype.m 7147 2017-08-03 14:07:01Z spm $ -if nargin==2, +if nargin==2 varargout{1} = asgn(varargin{:}); -elseif nargin==1, +elseif nargin==1 varargout{1} = ref(varargin{:}); else error('Wrong number of arguments.'); diff --git a/@file_array/private/file2mat.c b/@file_array/private/file2mat.c index 7b3c6035..f964859d 100644 --- a/@file_array/private/file2mat.c +++ b/@file_array/private/file2mat.c @@ -1,5 +1,5 @@ /* - * $Id: file2mat.c 6618 2015-12-01 16:25:38Z spm $ + * $Id: file2mat.c 6988 2017-01-16 12:38:29Z guillaume $ * John Ashburner */ @@ -67,8 +67,8 @@ return size; static long long icumprod[MXDIMS], ocumprod[MXDIMS]; -static void get_1_sat(mwSize ndim, mwSize idim[], int *iptr[], unsigned char idat[], - mwSize odim[], unsigned char odat[], int indi, int indo) +static void get_1_sat(mwSize ndim, mwSize idim[], unsigned long long *iptr[], unsigned char idat[], + mwSize odim[], unsigned char odat[], unsigned long long indi, unsigned long long indo) { mwIndex i; if (ndim == 0) @@ -87,13 +87,13 @@ static void get_1_sat(mwSize ndim, mwSize idim[], int *iptr[], unsigned char ida } } -void get_1(mwSize ndim, mwSize idim[], int *iptr[], unsigned char idat[], +void get_1(mwSize ndim, mwSize idim[], unsigned long long *iptr[], unsigned char idat[], mwSize odim[], unsigned char odat[]) { get_1_sat(ndim, idim, iptr, idat, odim, odat, 0, 0); } -void get_8(mwSize ndim, mwSize idim[], int *iptr[], unsigned char idat[], +void get_8(mwSize ndim, mwSize idim[], unsigned long long *iptr[], unsigned char idat[], mwSize odim[], unsigned char odat[]) { mwIndex i; @@ -110,7 +110,7 @@ void get_8(mwSize ndim, mwSize idim[], int *iptr[], unsigned char idat[], } } -void get_16(mwSize ndim, mwSize idim[], int *iptr[], unsigned short idat[], +void get_16(mwSize ndim, mwSize idim[], unsigned long long *iptr[], unsigned short idat[], mwSize odim[], unsigned short odat[]) { mwIndex i; @@ -127,7 +127,7 @@ void get_16(mwSize ndim, mwSize idim[], int *iptr[], unsigned short idat[], } } -void get_32(mwSize ndim, mwSize idim[], int *iptr[], unsigned int idat[], +void get_32(mwSize ndim, mwSize idim[], unsigned long long *iptr[], unsigned int idat[], mwSize odim[], unsigned int odat[]) { mwIndex i; @@ -144,7 +144,7 @@ void get_32(mwSize ndim, mwSize idim[], int *iptr[], unsigned int idat[], } } -void get_64(mwSize ndim, mwSize idim[], int *iptr[], unsigned long long idat[], +void get_64(mwSize ndim, mwSize idim[], unsigned long long *iptr[], unsigned long long idat[], mwSize odim[], unsigned long long odat[]) { mwSize i; @@ -161,7 +161,7 @@ void get_64(mwSize ndim, mwSize idim[], int *iptr[], unsigned long long idat[], } } -void get_w8(mwSize ndim, mwSize idim[], int *iptr[], unsigned char idat[], +void get_w8(mwSize ndim, mwSize idim[], unsigned long long *iptr[], unsigned char idat[], mwSize odim[], unsigned char odat_r[], unsigned char odat_i[]) { mwIndex i; @@ -183,7 +183,7 @@ void get_w8(mwSize ndim, mwSize idim[], int *iptr[], unsigned char idat[], } } -void get_w16(mwSize ndim, mwSize idim[], int *iptr[], unsigned short idat[], +void get_w16(mwSize ndim, mwSize idim[], unsigned long long *iptr[], unsigned short idat[], mwSize odim[], unsigned short odat_r[], unsigned short odat_i[]) { mwIndex i; @@ -205,7 +205,7 @@ void get_w16(mwSize ndim, mwSize idim[], int *iptr[], unsigned short idat[], } } -void get_w32(mwSize ndim, mwSize idim[], int *iptr[], unsigned int idat[], +void get_w32(mwSize ndim, mwSize idim[], unsigned long long *iptr[], unsigned int idat[], mwSize odim[], unsigned int odat_r[], unsigned int odat_i[]) { mwIndex i; @@ -227,7 +227,7 @@ void get_w32(mwSize ndim, mwSize idim[], int *iptr[], unsigned int idat[], } } -void get_w64(mwSize ndim, mwSize idim[], int *iptr[], unsigned long long idat[], +void get_w64(mwSize ndim, mwSize idim[], unsigned long long *iptr[], unsigned long long idat[], mwSize odim[], unsigned long long odat_r[], unsigned long long odat_i[]) { mwIndex i; @@ -563,8 +563,8 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) void *idat; int i; mwSize odim[MXDIMS], *idim, ndim; - int *iptr[MXDIMS]; - int one[1]; + unsigned long long *iptr[MXDIMS]; + unsigned long long one[1]; one[0] = 1; if (nrhs<2 || nlhs>1) mexErrMsgTxt("Incorrect usage."); @@ -582,13 +582,13 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) for(i=0;i((iLE08*=SHix7YAv( zp%2}%woar@FQLw3q@pNv{n@S`QTGfV70Vl`JESMmCR9oW zxx%!!mFml5saTd4hJj~swU8E ztVd6oo8noDqLTR-=29K)vu`zrDzhje>#uj!YBOl2VpXFQjhc<=3@jlg8HCDNep-R%k%W+_S5X_t9j39F_XWq)x9zF) z4ph(UU1k@}GyMF%>{|L1epk~~ew28F6wO~yw_|iKIC_%?aZEy5l%DZrL{PdcJA+&zQ$ns)?rt@ z5>X+U)A%A}XQC7Im%G-m?&zqjjK!E*epwGWQdZa<9uIW zb!Du7ht0AsO6OZUxb$}q8Tw|7P5)OdbX#g5G|xxh(Efb<{+Yg^b%R1XEuR>ke1#2I zW1X2<+1cEW#k)hY@Wv+TFLwQyCm`)XvdSXJz<5*JYL~2iqmLL6{XI;4VU^?SX5C$l zt+C{+>40%AHkfgS=|J^d-Lk+=8@B%QuAg#386A9sONM*u-s+PTb#EPu?MrH4HFn`C zWoDb=%;P3K;EVp9dygT+7Kez7bP3e zl5(kg%BSqVao?&lDX>pyy?5PMhx_nsWWga~c}&`f7qLV1sm_XkLPze_oSuYqdDmt0 z0NH9gxu5m7Rcl$$3=e9Cwf7an0C<8DD;31K`*YB8DFIzxe{Dk*_dgY#3bBnh|H;03 zCS^STJaC8)Rc21bl!8qN8ny@EZ^m%TX`8ci3`xl z*Y5Fb+>mP^?T0ziz-HPuW|U#mG&FCU|uF(Kgwq+^8IFhj@?bof$|EEvm1D z`5FcOkp{mHAD}du=O>24rQICMOQ#p)zp*7r<+;;sSZ23Hlj&@}EpyluKG4Co*ovtO zo?YIxu~eEYFSxC=jl7+uww0{>x6OMFPmYdJBlR|wXxLOkC6j15mtBokO>a&8`# z498G`wH9TeR2AKM2_GcCzTNN;(4u2&6qhqpm*3z-{?4`~?+H5?VZ#ST$Omj{N+S6c zTa*$@HnNve@<|!noid5+XB{b4UCk}loN8fFsX1ZhTbxw%d#p0GkeH#3vi>ZLif!`c zn|uu%r&9d_gQAWKWd>4DWSTDp0@1wC413i%2A?xsNI0V_jTGDgsYGj|!jBtW|RK)Zxx{qx+W&!7glN)#?` zD11l|&oj6kxO@~CPXaZA?8VF|62~@YCXqz83-?^sg8K`sBQt67OdunN@T_|hAR;JC zQ2HD!nXki~f23~*K87tGmrkZK5%;BR-?$v|G3ywYlXx3%JLOd9ukm++YeHY(nK1tQ zI-Ecw*pBRG(%`XAXw!xJkA^N5nU@sqKMJ~75qkb(6pni6`HxLaOzhX&ho1i^*TgQN z=Rdl&GcvKS&rI}!KIfnp^tll||Iw@6vuomC3?zfCF31UQP);UT4(yKw1>wzFubFkC z7d(1r78Zni(|K_O!RuLGc+@}|n0-pL-Xt_bT8NRYMlTY|)l<@SgtE7$<&au-a@s6B zW2`0f7yE-ND*|4^P(K|`)!QtJQ$Y(Xn6&X(R&`vd8=72lyg!A?Ucz{SHr~$8lmt(v z%Ep0qyrLb2*%7e6Bsj*Ptr>rl?A8HtX(v>ZP@s--R zzrZ%O&psay^6=7}z{%Us{ZAU!z~+?ZkY#LhsU=XF$81+=I@#|zS!yBV2W;PT3t6Sy r>y`VP{O&0!%OH53FE7st5Bxjf*;U@83#nMS7Jo=oQio?JO(y>X*Us0z delta 4281 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 literal 18928 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 Ku7l8rgZ>9YS=m_t diff --git a/@file_array/private/file2mat.mexw32 b/@file_array/private/file2mat.mexw32 index acaa89e2a172cb7aad6a9b2f462aeddcfc85577c..1ea74fbcefd58d4a70b9dff28df0eb6e00eb8527 100755 GIT binary patch delta 5372 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 IrI$kgzm-UU_y7O^ diff --git a/@file_array/private/file2mat.mexw64 b/@file_array/private/file2mat.mexw64 index 61a0e7becf7bde404afd12aa6a01f35c9e6937d6..de4f6fbf014df5f720a4559932f0c6b3646a75ea 100755 GIT binary patch delta 4842 zcma)A4OCQB9)E9!Cj-nl!^ay01{mNWAczx#$cG#uM}4!6rW>}JsB~;yx6Di#we16R zz?kzGqb{x1x`kWE+>?8xrFPS8H^>kCO35sBX!>21ABRIpo>?0rw7SHVOe$C znOcL?0!S@64q7)pLwO;~9hWuD7n-kOrM^1sTd&f3bzly4WIin`4a|vb-Sxg~Y-Nt+ zKp!s$tE6JDa>8rf)qHgT`N+m*JqqPrIp~vIa?m4X`!G3uO6~!#azs7M$S&;JQF#qG-sdEjl_J$V``p;Sd`XO=7T1; zOiykhk`wCTNG@}Hvg&!VX;dOIo4(J@9sRd<!scAV>^j${A{SWPsyQKntFwGXzNgiRu6Zm9b^8dvPh; z;O!^Q(GF|VO}yvH9ivMP)@<_R=q&s8tRZ!eavWBIwUSd4)5yNjKj$}-d}~n_2Ony{ zN{_uys*pqC1sJP*lSeOkm7{6|%|0Y-Ac}Re#Sf9{WV*t=?M)5T)W12V*6Mcz_19h*;4I?b~y)RpoA4C%vfI; zIZ6^@bL~eNPuw=biY6-Lp4e3TW?kgDNpv@PDmFjuE?v}C zBKO1<%$*G@>VimG99cQ8i8W4+3k+(?fIkkj8V!jYvLsTii44cxs~porm#*h`P$CHg z)xHqHv`>mt%7=6P~%cDje=%A9UN)c@-3p}Pg6r-kB!RB;WA3SDtTtvH>)GTj-xNCet}(zav7dUFWoxhRR~qjxF(T| zPspvy1>@E!Z)4es&x}Y?6DL#k;glyK?hz@g=p8kKrHYvGNRk8HCV9zTxeQSwRqF;j zu10U58;`sLCYcTIa!KZ`jc2cGng>s$3R$U@*7-2a>o;Pjy-Rvz<*>Kxlx*N>YC~ZACgdQZ7NtOBND7^bGM$Jb_i{BY&M;%Vhv$L*|g2O3zf zjBJ)^=ovIi5d*``a+U}wWI;8oXqmIvT*2l7HcM=#KD0~|o3FvVmU)TIAG5iK&F`@J zbvAEj^AjlC$wxl&+3;RNY*KJIzBkfvkZ z)QS34=I##)1PpiQfY18cco!6FQ}kNzR@r^_Wz2Wd7)br9A{a`^*0cnNRzi=$`dI3v z6HQ+0#qD;UF_)9~(z2w<5NTpQRR{{NKmf1y1%GTG)%OLb$=r>j>Un;^_5RIL+=G{1CoVpbEME?{Nd^7bCveW~3g5!B8sUFCX zX5%_^9yAu}8nXb@42ZggQ^g#IZRZ-lD)xsXl#`(4K>0-gt~L$UdV#6G#6gC`XuMDM zP;Gq7HL(j44?q4IF=oumc{&{$C;YJ`;%4-mKML7ZOU}NdP!3$*(t3a9lDLyDjx3_sIDX9GiTs)?a$1u3!{x3YG4n0 zInZfB4WEWCv_7FAC@gSMO8+YbWHq?mLIIc&VO(dokOzz%6-78h?{r+L%dq%^A$+AK z{&+N=3Bp$Bu@{4S7W?i#q=~nKFV}@EM$}9b%RvRo*FcN&N9u}ivIfb6U=Q_$zSG39 zbkX{KO;FpbW$vI<$dWLTml`4wbwPQt`i`eIS4C6^{X4b-EY_PTpDF*E`XQWZRDi-(2v zquxHrKHE1XgRA``BE>=IoB-aTj>f&f9*U zXEX3^9ntxR4Thq^j=#Ak@q7&t3sMCeOu9%(L6YDC79jHrk`fpXRQ+_0OK^s9&cZ8P zB>x##LqY|UL@rP7oZ@VbTZ>UM4v?HF$Q7u>L?Ya&L)dut18F}(pV9+z=LC)`M3>ZH zQ0N6+3fMw+yWP=Li*_SDDpxRUQ94C3W*@FHJ+nfSWLCfVTj?7{hVPfFmmI zb)2Dk;IPA;jN`a1z~PmZm~VYlcZ)k zSH}f_Om}iz1-6mGcQQE60lWurE;g+VINiLB7_Gnu0O#hy0p$aBW2nH{wqk1wXJC5) zt1xW9DQv|UfKD5rFdhkmZv%8ps6)gcoY?2Z*ynoSbngQg>wvca{uW~;@OHp2F*<>B zw{aZZ_mfl~Fx<^?7lGRVb1*&v?gErC!esaWBp7DkZGaar9KctWpjlqUC>**?%~ delta 4736 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 diff --git a/@file_array/private/init.mexw32 b/@file_array/private/init.mexw32 index 92ef6d97963d5472223a78966e4b1028ae26fdf1..abde5e911d507f27f1315a1400cdb45744be4832 100755 GIT binary patch delta 32 lcmZqhXz-ZugXM|zv&e~me3&+sZ1!TTk^=KLpOCiT008zA4h8@K delta 32 lcmZqhXz-ZugXQDjPoWe4_%J;)*zCnvB?abhJ|S(v0RR+8599y< diff --git a/@file_array/private/init.mexw64 b/@file_array/private/init.mexw64 index a7f1b272bfda595ef618d9f92b3bd8597682dbf5..17301452f415831e282b31580c700963c0594523 100755 GIT binary patch delta 33 mcmZn&Xb70_fhGU>)5wWme3%o&7&kjJGRlGlHhakJ-~<5nLk)`n delta 33 mcmZn&Xb70_frW2hOz6ZfKFmG47&bdIGRlGlHhakJ-~<5Rm<%ic diff --git a/@file_array/private/mat2file.c b/@file_array/private/mat2file.c index ab316d27..3465d6bd 100644 --- a/@file_array/private/mat2file.c +++ b/@file_array/private/mat2file.c @@ -1,5 +1,5 @@ /* - * $Id: mat2file.c 5446 2013-04-24 16:56:51Z guillaume $ + * $Id: mat2file.c 7038 2017-03-15 12:43:51Z guillaume $ * John Ashburner */ @@ -269,18 +269,15 @@ void open_file(const mxArray *ptr, FTYPE *map) /* if (map->off < 0) map->off = 0; Unsigned, so not necessary */ arr = mxGetField(ptr,0,"fname"); - if (arr == (mxArray *)0) mexErrMsgTxt("Cant find 'fname' field."); + if (arr == (mxArray *)0) mexErrMsgTxt("Cannot find 'fname' field."); if (mxIsChar(arr)) { - int buflen; - char *buf; - buflen = mxGetNumberOfElements(arr)+1; - buf = mxCalloc(buflen+1,sizeof(char)); - if (mxGetString(arr,buf,buflen)) + char *buf = NULL; + if ((buf = mxArrayToString(arr)) == NULL) { mxFree(buf); - mexErrMsgTxt("Cant get 'fname'."); + mexErrMsgTxt("Cannot get 'fname'."); } map->fp = fopen(buf,"rb+"); if (map->fp == (FILE *)0) diff --git a/@file_array/private/mat2file.m b/@file_array/private/mat2file.m index 6a117349..903ed213 100644 --- a/@file_array/private/mat2file.m +++ b/@file_array/private/mat2file.m @@ -1,16 +1,16 @@ function mat2file(a,val,varargin) -% Function for writing to file_array objects. +% Function for writing to file_array objects % FORMAT mat2file(a,val,ind1,ind2,ind3,...) % a - file_array object % val - values to write % indx - indices for dimension x (int32) % -% This function is normally called by file_array/subsasgn -% _______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +% This function is normally called by file_array/subsasgn. +%__________________________________________________________________________ +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % John Ashburner -% $Id: mat2file.m 1530 2008-04-30 19:28:22Z guillaume $ +% $Id: mat2file.m 7147 2017-08-03 14:07:01Z spm $ %-This is merely the help file for the compiled routine error('mat2file.c not compiled - see Makefile'); diff --git a/@file_array/private/mat2file.mexa64 b/@file_array/private/mat2file.mexa64 index 1dff21b8d2cd193dfdcd8b828d0555e7c5582018..08dd23c8549b1ef2f23b2af0788da7af714498bb 100755 GIT binary patch delta 3989 zcmZu!3viUx75?wPdF;lJ-8?p%jU@YTgqR3q6Eukt0$D}!Vn}h>$-NC&qZFX9c+#MGftRDW6t4glp%hYw@X%b{ zxLFyracJl$xhUBvIVc$^LBozxjN(KYkCG9GYS@66(>C3c&GS{z-}Hd!C5LUM_?Q}O z9=gX?FRE#s?QW4pBenotn`MduaE~}E?M7A^y`NPtK9tOrT_%QPt1a7XSuc3yBdN@s z89aeT5hB09X@Jyl5RfMLvwi~Y$o?od*wxkX==`O$KIe0a=aycUcFJN$O5`>yS_f|y z1|9Wl^E8cD%)&FX2>b=n<~$lG#m{q|vb5h`VqdH5FlasHi;)5`z61Lxz2o0^6Q!NHY5imzm7R?NU~q@sm#NC3X^fExQZ2gB9kj5uVT(S zkX$BtIdcv_d5`2p%=u&{=SrT(Jdb&sisS6S z+n3ZN|Cl*%O!Cy%P)r@&1bY+@Dwb4slik@bqABhO-nn<@15V#6jRi9dR$_()n6kSZ?teGnj@Sy!SnI2aN@t0{ zg}&PLgQ-vPT$4no#p)@6-wjMxUdva{xjKQ7LebWM49C4J9o2Gr*EKQBe%8YOAnK_5 zBxW+F>D_KK`uL!A^ebLU>k#(ax)BarWjv98O5;ZtQ>nglsh+g!=Ctccb}fhNoclhS z<9y?WdPwEjIQvq#64@MW3 z#BR@BeZXmcxZ{G&j8?>8F!$Kfy(`|PyNWyozhYhFYV*DWaCn~jiv0Fo?jIf3L9Z7D z_1p?NS#)Lb?(wW^%#}lrV#4eSsx9`Fe{lipoM!7T2}OpjwM=5IE*yI61l?O43~x9O zO=Kr>-cuclZR2wniX1m%jd83t6iL0qu~-RsfmlE1{*ixKR|8iK_V~ZkqbJ?NTBDr5 zr<|+7|HpYf?jc63vTjq}et6%w`dIJHJpLb`oDV|3A>Q1nMfLeYn;P_*Y%DEj!hy*v5z1sCAR zn=3yn(=}~QIWNrP{(AQfgq~XtOSkDHYh+hp% zbVe>~*!msqb{pay8g@^1ysUH!Xnd&=PN!$snvByqYC0$5!1NiI(2ThsgyVMJL=N@% z8P4l2-fa$JK5W*(vz(`4s}i_s(7Ebahv^Ed4WCugnl?vPjJ^)Wy*Qr*jxR$ z-ez?5vXczgT2tu*&y<`;*R+O5;HsO)-ig!;?;wMP)U zwc$(YutJS>;R|G~W%o~g=#MhWj* zVh1fQuWORaiDfrnIeT|zUT1}DyH&m9_F@B1=($w47mxBq+E;#scq8$7`PaI>WGQ`C z;bq9Ke47R<>*sZzN~IpdE0r)oXUEnF;Vc?A;snl1%*{4&f$vEM^$3o@<%aMRp zz-}DM*MVz*9{>j^=(|!Jqs2a-uqcB1G;Q$t^!!t_&sQmel=KDkqERY0s>Ll7Gy=8H zV8q+8Xd#R!Pk6G>xfKDqqM z=!aA4!~A24MS*tH7|sD-YQJj?mp?Bq>Ho+WJO3DC;eYBZy{f_g(;>Qs-==i|T)~z) zpV&;dp&3E;puV3rH2BzQpL9w}gJUWTiQ1`7UF@QkYrqw7ju7&r%F|-qhISsKHTUsiBd^=5ID8 zvq3e~(iCuH_O+LmH#HZ=RgyEfg0?gT3SDZ&8SJF<+>^hTAidPk+?*FzEM87s%}tJP zzsBB#@la*j^-yJEw0VsX`xB40goQBa{B_Na{#j{b2enLl$(vbpT9>YE_?TKkBhx%M zMkCYQHoIm?bYNxv>26z|Hkam2_uzABC0M=|2YS4jXumsB0pfiVzH!uUn@j7aqhNjMQeG-I|NH>hf6ooJ(ZGw;R@zd192{X9C;*@f^*&A%KUO+aJjKu&hsU?LCWUMSi-e{ZNNi)2VQl$LqlR r`u{%o+-wzoSvSeLP1f@h>u0Ufsjj_aocap9wYzKak{{EH?Q8xE#Bjom delta 4110 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 diff --git a/@file_array/private/mat2file.mexmaci64 b/@file_array/private/mat2file.mexmaci64 index b0f2e69fde2c4a29f79a57a7567afb26568450a0..ef8a18a38612c2439669234ca2a1da5c80a6722f 100755 GIT binary patch literal 14444 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 BN>%^> literal 14560 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 diff --git a/@file_array/private/mat2file.mexw32 b/@file_array/private/mat2file.mexw32 index 1817c1f74dedd0fdec766f5d22522baebdd4e935..48b129f691e3f843aefe2ee5f2c736955c158734 100755 GIT binary patch delta 2324 zcmds&|5H>|6u|FY7Tl1v1$JRU&|N^ZAbq>^KFzFE2ckj_|)g3dTtre&p=pj0m-Bef*Mw)5U%<4pfSJM+2co^#JR z_sqHH&2H$y8+vdHhou0YSG=z_?bMaz{MLJPc3WD10KKz2t+fZF*$}J9&Tf0__ljRZ z>(|P;x%Gx3b6T$|l2K&Q%B5a8SD?qJ?j8NZ(}AHBj7bunqhEZhtXhW;1OuuHZGh4o)Oj#&BE_+#1#SxI z{2e-H-aR(1_DwRw2(*?vPLw}1(1^GHj>o5uDB8(ZOdJyQO#vl^V^-I5(t?*utyf#RtVQ|HT% znE@tG=o~yHl(jhqs;GX{Yx=M85s$aD-KsPWYW5-(Lh!`JkisK%gVMZn2<$}?QnEus zPl8eD<~(RCeOk(r>-m1caqk|;B7F;|_qSU+eA?AT9x-M#yc!Pn*K5#vt+$bZh%I50 zSg#i!Y;NlLD-?1UN_k30H5-r0I>HFm!Jziv8`L#&oLh<0h||?>$)()d2W2^@Xylpx z*VQe%j=Sed&KRwZ?;u_H*%QTS{V?Im@H=G3&y^#MI7?k9eH3On}BOS~yQ`P#0-SUZ(2m3JxWY zz|qT~!{WeGA;V&#O)-x;Wrh^>FtjJt8COk&OL-V?AS+VJq6X#1>?apeOi_}&?c1KZ z6IYU5shM~UIhvZH@q+c~kYP=*H}%m7ILR>2!i$5I<}8ellD4#i@jh?}jjK`CI%RDn zCFvP(x;fp8_2k#|x8k=b_Lr2kMOk+Q-_G!iB<(6w!)6wtN?hv#}RdWi?Z(s!E=lQ!(3DwX%Fgu*oh&Jlq3+gmUMuKri6C{FiS)?*@7R zoe`lMZ16f87YSplJ2+Ww!ZjpvaiC$9y~bW|-)`S;KVrXb&vpooD#x>q*BpBtHywkH zCvxZHzLWbw?lQK9UC%bMFS0G{F1C%`%kF0nu!qwJ z9p@-6nX_>`_ZU~mE$1q@7r5QrA?`5uDR+Up%>B&W;SfK9H}RPbd@k?eXYq6S3ci|e znbGB4X= zw>)7fwNzQ&wj8jWww$%Bv({Rht?ybtwRT!3(hSYglj#C_E?r7*qCcb0(Ld7BOd^xc oWHB@&FiV-$%sQry*~DyNwlO;x1aq1Jmkm(2f;UUFqXLxr9~W@ga{vGU delta 2434 zcmc(gjdK&n6~K3;v!nV0WLvW3uOL}A4%ooSI$6^BPG=xM66B0*5z9bg0^|6Q(vYcEBn-nWE5Gqezjlr)oU`$@+?Bgjg!z5gBi=v#1lg*Q!3UV zWCTTZLTMryc%JFlZiG~dLW>amltz(>;UH-a$IDW?>(B zCu?_MBGRK1k#ydPl|AyxL!?&ce5gDbA<@=AdUfU$7xZCYKItC$NM}mPnjD@Zw{)gl zDM^_XTeab@d>!S|%P{tdqf!Sk>&>{1EYX+FY=E6cBIDo2Gx1iEkz)u()Ud~~&`^0e4qM@5_XD7UxIU>n(dinT-t}v! z0iU!$Rt)0qu>20t*?>J#qwF9eD{95RdVSJk$|6H}Fp%YyY%uUYB0FtX)EbdrB_DS& zsJ!vdLPJ3f?0jb$Y_xTO-#DrLpK^}ZKUe{&-8T*a{Blu3#XJozywc||h=gUmN1_rz zz0z+$spNYlB;I;SngtW$&1cU0-vTevFw9OpkW{r?1Tam~4aLE?6Kg};HR#23e-{G_ zb|+NgcAYpq5{`WXv1%o={PIJZ9cSb*!U%OhC67#2@lu&b*1 z8oB7dGxf-(Ws|0)-%#PW0q(#O>LN#6Gy+#Zxg8GK@XyMWMqEnOO215)RgL|~AbP1f z>1~piYfDvZ(`4J9kQKR}#8{HE|1kMQ?$M%W$Dm?rMkcP&j-f{&?M;m< zl5KfwqOm+RPVvJ?9IcP**N{8;rfIiL;AJ}$?FFh>Z6XB)vvC($QqYn-E+6M8IaOdx z9+A5ei52X_0kW-dCf-6078YnWf_iyeza@IMaDf_TDAQ8BCh9SjVLVJaicVy;fkC{a zLuoseb{Cm%E{554WOb>KKK;6On%1f4$u zUjX-k6mT>bke{#Z2^j-<1sDL{0`>qqfp)+TGy-nG1<=4upa7tNvC4#xsqHuUNc)vh z{xV0urRS)00poLP1IE&Io0?nJmd*vsh0UADd}~g$-g-*Ta)xbQdiIROm;8%|VJ)e# z5{yTHQGhnU|7}(D?`&q$iE7FSmn3ObZ}1iS8}^^sPuefq|7O=Z+>R#4 z9>;5rGmdkPET_S_*%@$NbY6CLv9Gf~Wsk7O*?x9_JJi%RR+C!>!|<=XP?ha_@2l+%@iNF3zR$dAyM?<*S4I zVtzT_$p4UU=U?Ub@kjX6{8c{2-{f!e_xK0=G*_9+;qtf+yZ+!Z2yUTHXb>8OHNpnr zd7(`R3Oj{}uvd6fI4ry;M1_xqPlQXtpM+uIOW|L_0|7E&L?{44MQ74EbRlh~opd$* zI6Y2NmP|{brO9luTih0(WwRx0*<<;w7YDJF}2k%6OS3Cd7!$e&zskh&jf5z?@_d)NL^Yy-$xt|Jj^A F?Y{#&)|&tT diff --git a/@file_array/private/mat2file.mexw64 b/@file_array/private/mat2file.mexw64 index 33c1634894c772d37cc5c3a7da4eed0783283397..787f6557146e5e13fc58b0b82590198658ef93b7 100755 GIT binary patch delta 4490 zcmeHK{Z~}S8J@eauzaj6!Ucf^0e3+nB8Wj0P*BiIvQ`qU#l#b}5+sS=?i$jVtR5g{ zd)*eCG}Y52HEEJ#sX5i)X`{^#i;@r`Nlff9AKFHnM;yIQ%{Q?s!7{j_a2_=C>g(Q@qQw%#7-$BwQQ_}S;{rM|xR z3Bk+meL?uQ_WoL6YwtdREduYnZ(SSp)sr`=sHuUmmd9e)=D&ZolF8pSmY+H*G09E~7Rny-w)n~{Uv@gwN%y>JIv4--H zrk@k8hvDiNF@0g8FHAf)8N?U*ierARC?E4zW1aqCC-vZQl^Xwuhorw_^a49WzR6lp z^@A>)9{qJweKtZpC8-aMQH#Gv-4UVg2c_%07C7u`#(dkS(FoPy=9+F8$~4|=o2*!Q zyUm>v8);P}2N>i>Y_k;~H*5=&_r!^~5;5P`X&S%a)o~9h+5A{se%4K_y{7N6MPttG zlN2wJdNF0=l8yf>E?wEj(_2bZU*K1^=|Ml2^w&Q#=v-CTVx^2jZPs*%ABv zuw4rrb79Arah^XHUz~C-W3<1KSQ`Jd@g%<#?@>1Ll7!rp6%lW{^v>dI6P&4q5qqPw zn=!m6AuDGDCnp?UrgXd+Bf8b}YsPW@X2LBgM!Y*SAk4?-|w(+9Gss3dVuTOf* zfY{3^o}kqt7FRV#=VYp`2z`;He`Af%&t_3D>Y*|E*Xg6-rAzuC=$JKy_XmjlOk!cm zOA*#PVXv`~$J?ELuh7EFr|E}Xk7F6Nu8^jG;G@lo#c;-Bvc+A%&QMZk4-$k{wVv!@ zZc6!(F@w~g{Z)i!EEBSNn8MUgn`$8q4{Bh~B%B4GhAHeN-`(U)_`b6ktKt})pGQA^ zf*~eT{Y#qY%NRlj;qCY*Nr>Z*z$+B(32dS9p|HN{YUX(p((Mft$nJqQba85!*H2jD ze}JZR7f4;^qtvL1^xL2}>PcE~xvPni!bn9koT`gJW93cL)Yf@jO}oEiNETYAHt=^M zh2JvOvnotM`vsbIl;~!u&G;&ccza#VFjUn!=vn~v5U6qB_7L|2o{_Y=Yy*fm31R|83GN`}-7L(B4k-jpd&wEww)!wtR)NWBiUUa$HLL z;Yk~ zLUKh_{Fj)tuC6OXFZP-;#1OQu0GRK4)>)@R!1#;EtiN@FZcI~cp9teRHMxv0ndtH_ zBrRy4MGLrH92hJ>2^q0`VtIEDjKF!ybl0Y!xqGIlU7}7CwN2DF(Z+ON74=_5eMZzL zMSV=vFN%7}uIOT(sn zZt^IZTGTGnIRZrxS19RcAxySz z+G_#pG8oE3*E~r_r&ogL&1r4z#@}%R8)~XnN5q>6ug}n}@w53;sTs~#sHVCSevw=w z-bPKge_lbxdj4)|p(_=;vty@c=bcMW$$8m!*qZJp)mHG70&=^5`8=yWgJq{$J9zIO7 ztKG!;2&xTXMg_o_0@tAR<6AA1u&nDpmA+Vnasj&5QF9f*ym{#D6G+CB$V&{E?9pF4 zLF`6-*i?t$saK|-;8AJKMRf?J>pfq}9Q8+#dC>$qqZ8nj-8grh+Xdguxd)Vtas z2c^8lRDYbnSirgp-5e*PaS{7oK4hwQ!mjy)_9&bqQ(XeBqox8Z=8F##Ul9kS8jce* z7S5fiR#2ne0~GD4@PWokeuxuxxf|@U^Q!3|;)SACI$mj0y%M$@<4Wch+i4srEtoyP zAIj8hdRXb?Lz(?}-Sw=MeJ)o14O}xMCGWno4@3&n0o-1 zV&nC*o1pj4n2JlM8lMiPd!DFkMZG}OPoNLey-3uRJUjaneniQgb7&rd!*8F& zof0=lyi;O@#C(Z1UY3&{cM>0m^m~!tk&~XcLuz3gV;iL2A~B!$7pD6cREPZ@iOmw% zNZcXuafwe#d`{vKi6Mz^Nc>2mA(6>ZCrX?eMnCgN!wQL`;l_+Ml!mKSVd0|0lM)Y0 zd`99viMu53kk}$|g+xuDld*ZyFiWCSqN9pGs}w|cPiBsuywsO-t1L4%ZT9A_zt@{v z*t%)$#(N7(L_`bMZX$c@eVbZF9Z>Gw&{EQOf4;@yznH^VDKayU;rjR9&e*Ib#_$3= zQH%;{Z}A8_*_NZ6A-m1OY_OBQA0H*JkgYG8^`X6O;5N~Ij2q2t=sSA(9pCFa!)eK3 z@yZfLLDb>`%%eMV`O}tCy!~}32l*vedfb?%xU;55wAsWD^X6tDcG4-RPxo7>t+4S% z_mpw%eeMVH{#?k!%{)J!G1nBvnotPmK)(gJiz@}?$;6`jY7ef6PwATA4F&VnQR{km zpFlZC$PW}`HFnPxt1YT;utiN}=xLlS4d@?Ow=)Q_z(c^7tf(9CjoC9r}&9 zHP%2T>_TaROxT#sSn+J;7lH>Fmk0;pPf$kCDP`eed}SPh9rp_R8s!zpEEim4M+mY5 zxD;7(4KiiUb`%5hF5m%_i;xcjKSL?41P?eD`BM+M33%PT85s_R6)={8;(?qCtVHob zt_60W?1bD6Jd3gy@*1StuTY+cOljAT@)YEYz^JK=4M27P&!G&HT*TNtC`b6#GXHOE NGcAhI7dPv=@?Q{bP7(kB delta 4535 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 diff --git a/@file_array/private/mystruct.m b/@file_array/private/mystruct.m index d5d16825..54fee96a 100644 --- a/@file_array/private/mystruct.m +++ b/@file_array/private/mystruct.m @@ -1,16 +1,15 @@ function t = mystruct(obj) -% _______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: mystruct.m 1143 2008-02-07 19:33:33Z spm $ +% $Id: mystruct.m 7147 2017-08-03 14:07:01Z spm $ -if numel(obj)~=1, - error('Too many elements to convert'); -end; +if numel(obj)~=1 + error('Too many elements to convert.'); +end fn = fieldnames(obj); for i=1:length(fn) t.(fn{i}) = subsref(obj,struct('type','.','subs',fn{i})); -end; -return; +end diff --git a/@file_array/private/offset.m b/@file_array/private/offset.m index bad3673d..cffebdfe 100644 --- a/@file_array/private/offset.m +++ b/@file_array/private/offset.m @@ -1,35 +1,40 @@ function varargout = offset(varargin) -% Format +% file_array's offset property % For getting the value % dat = offset(obj) % % For setting the value % obj = offset(obj,dat) -% _______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: offset.m 1143 2008-02-07 19:33:33Z spm $ +% $Id: offset.m 7147 2017-08-03 14:07:01Z spm $ -if nargin==2, +if nargin==2 varargout{1} = asgn(varargin{:}); -elseif nargin==1, +elseif nargin==1 varargout{1} = ref(varargin{:}); else error('Wrong number of arguments.'); -end; -return; +end + +%========================================================================== +% function dat = ref(obj) +%========================================================================== function dat = ref(obj) dat = obj.offset; -return; + +%========================================================================== +% function obj = asgn(obj,dat) +%========================================================================== function obj = asgn(obj,dat) -if isnumeric(dat) && numel(dat)==1 && dat>=0 && rem(dat,1)==0, +if isnumeric(dat) && numel(dat)==1 && dat>=0 && rem(dat,1)==0 obj.offset = double(dat); else error('"offset" must be a positive integer.'); -end; -return; +end diff --git a/@file_array/private/permission.m b/@file_array/private/permission.m index b8e84cd7..d3bcbf3b 100644 --- a/@file_array/private/permission.m +++ b/@file_array/private/permission.m @@ -1,43 +1,46 @@ function varargout = permission(varargin) -% Format +% file_array's permission property % For getting the value % dat = permission(obj) % % For setting the value % obj = permission(obj,dat) -% _______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: permission.m 1340 2008-04-09 17:11:23Z john $ +% $Id: permission.m 7147 2017-08-03 14:07:01Z spm $ - -if nargin==2, +if nargin==2 varargout{1} = asgn(varargin{:}); -elseif nargin==1, +elseif nargin==1 varargout{1} = ref(varargin{:}); else error('Wrong number of arguments.'); -end; -return; +end + +%========================================================================== +% function dat = ref(obj) +%========================================================================== function dat = ref(obj) dat = obj.permission; -return; + +%========================================================================== +% function obj = asgn(obj,dat) +%========================================================================== function obj = asgn(obj,dat) if ischar(dat) tmp = lower(deblank(dat(:)')); - switch tmp, - case 'ro', - case 'rw', - otherwise, - error('Permission must be either "ro" or "rw"'); + switch tmp + case 'ro' + case 'rw' + otherwise + error('Permission must be either "ro" or "rw".'); end obj.permission = tmp; else error('"permission" must be a character string.'); -end; -return; - +end diff --git a/@file_array/private/resize_scales.m b/@file_array/private/resize_scales.m index 44e47685..153f0d0c 100644 --- a/@file_array/private/resize_scales.m +++ b/@file_array/private/resize_scales.m @@ -1,10 +1,11 @@ function s1 = resize_scales(s0,dim,args) % Resize scalefactors %__________________________________________________________________________ -% Copyright (C) 2005-2013 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: resize_scales.m 5456 2013-04-29 15:49:22Z guillaume $ +% $Id: resize_scales.m 7147 2017-08-03 14:07:01Z spm $ + dim = [dim ones(1,max(numel(args)-numel(dim),0))]; args1 = cell(1,numel(args)); diff --git a/@file_array/private/scl_inter.m b/@file_array/private/scl_inter.m index 39c62a9b..9490fd94 100644 --- a/@file_array/private/scl_inter.m +++ b/@file_array/private/scl_inter.m @@ -1,36 +1,39 @@ function varargout = scl_inter(varargin) -% Format +% file_array's scl_inter property % For getting the value % dat = scl_inter(obj) % % For setting the value % obj = scl_inter(obj,dat) -% _______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: scl_inter.m 1143 2008-02-07 19:33:33Z spm $ +% $Id: scl_inter.m 7147 2017-08-03 14:07:01Z spm $ - -if nargin==2, +if nargin==2 varargout{1} = asgn(varargin{:}); -elseif nargin==1, +elseif nargin==1 varargout{1} = ref(varargin{:}); else error('Wrong number of arguments.'); -end; -return; +end + +%========================================================================== +% function dat = ref(obj) +%========================================================================== function dat = ref(obj) dat = obj.scl_inter; -return; + +%========================================================================== +% function obj = asgn(obj,dat) +%========================================================================== function obj = asgn(obj,dat) -if isnumeric(dat), % && numel(dat)<=1, +if isnumeric(dat) % && numel(dat)<=1, obj.scl_inter = double(dat); else error('"scl_inter" must be numeric.'); -end; -return; - +end \ No newline at end of file diff --git a/@file_array/private/scl_slope.m b/@file_array/private/scl_slope.m index 47858a07..a9bfcae9 100644 --- a/@file_array/private/scl_slope.m +++ b/@file_array/private/scl_slope.m @@ -1,35 +1,40 @@ function varargout = scl_slope(varargin) -% Format +% file_array's scl_slope property % For getting the value % dat = scl_slope(obj) % % For setting the value % obj = scl_slope(obj,dat) -% _______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: scl_slope.m 1143 2008-02-07 19:33:33Z spm $ +% $Id: scl_slope.m 7147 2017-08-03 14:07:01Z spm $ -if nargin==2, +if nargin==2 varargout{1} = asgn(varargin{:}); -elseif nargin==1, +elseif nargin==1 varargout{1} = ref(varargin{:}); else error('Wrong number of arguments.'); -end; -return; +end + +%========================================================================== +% function dat = ref(obj) +%========================================================================== function dat = ref(obj) dat = obj.scl_slope; -return; + +%========================================================================== +% function obj = asgn(obj,dat) +%========================================================================== function obj = asgn(obj,dat) -if isnumeric(dat), % && numel(dat)<=1, +if isnumeric(dat) % && numel(dat)<=1, obj.scl_slope = double(dat); else error('"scl_slope" must be numeric.'); -end; -return; +end diff --git a/@file_array/reshape.m b/@file_array/reshape.m index 166ce500..0b0db837 100644 --- a/@file_array/reshape.m +++ b/@file_array/reshape.m @@ -1,21 +1,20 @@ function a = reshape(b,varargin) % Overloaded reshape function for file_array objects -% _______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: reshape.m 1143 2008-02-07 19:33:33Z spm $ +% $Id: reshape.m 7147 2017-08-03 14:07:01Z spm $ -if length(struct(b))~=1, error('Can only reshape simple file_array objects.'); end; +if length(struct(b))~=1, error('Can only reshape simple file_array objects.'); end args = []; -for i=1:length(varargin), +for i=1:length(varargin) args = [args varargin{i}(:)']; -end; -if prod(args)~=prod(b.dim), +end +if prod(args)~=prod(b.dim) error('To RESHAPE the number of elements must not change.'); -end; +end a = b; a.dim = args; - diff --git a/@file_array/size.m b/@file_array/size.m index 790c5188..5b1c7473 100644 --- a/@file_array/size.m +++ b/@file_array/size.m @@ -1,10 +1,10 @@ function d = size(a,varargin) % Method 'size' for file_array objects %__________________________________________________________________________ -% Copyright (C) 2008-2012 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2017-2012 Wellcome Trust Centre for Neuroimaging % -% $Id: size.m 5160 2012-12-21 16:58:38Z guillaume $ +% $Id: size.m 7147 2017-08-03 14:07:01Z spm $ sa = struct(a); diff --git a/@file_array/subsasgn.m b/@file_array/subsasgn.m index 452f9962..35befb83 100644 --- a/@file_array/subsasgn.m +++ b/@file_array/subsasgn.m @@ -1,10 +1,10 @@ function obj = subsasgn(obj,subs,dat) % Overloaded subsasgn function for file_array objects %__________________________________________________________________________ -% Copyright (C) 2005-2013 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: subsasgn.m 6522 2015-08-14 18:55:42Z john $ +% $Id: subsasgn.m 7147 2017-08-03 14:07:01Z spm $ if isempty(subs), return; end diff --git a/@file_array/subsref.m b/@file_array/subsref.m index 4640a48d..46a39245 100644 --- a/@file_array/subsref.m +++ b/@file_array/subsref.m @@ -2,10 +2,10 @@ % SUBSREF Subscripted reference % An overloaded function... %__________________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: subsref.m 6804 2016-06-08 16:58:48Z john $ +% $Id: subsref.m 7209 2017-11-10 15:33:10Z guillaume $ if isempty(subs), return; end @@ -18,7 +18,7 @@ return; end -if numel(subs)~=1, error('Expression too complicated'); end; +if numel(subs)~=1, error('Expression too complicated'); end dim = [size(obj) ones(1,16)]; nd = find(dim>1,1,'last')-1; @@ -45,7 +45,7 @@ if ischar(subs.subs{i}) if ~strcmp(subs.subs{i},':'), error('This shouldn''t happen....'); end if length(subs.subs) == 1 - args{i} = 1:prod(dim); % possible overflow when int32() + args{i} = 1:prod(dim); k = 0; for j=1:length(sobj) sobj(j).dim = [prod(sobj(j).dim) 1]; @@ -92,7 +92,7 @@ try args = cell(size(varargin)); for i=1:length(varargin) - args{i} = int32(varargin{i}); + args{i} = int64(varargin{i}); end t = file2mat(sobj,args{:}); catch @@ -111,7 +111,7 @@ end if numel(inter)>1 inter = resize_scales(inter,sobj.dim,varargin); - end; + end t = t + inter; end @@ -151,6 +151,7 @@ % Convert subscripts into linear index [indx2{1:length(varargin)}] = ndgrid(varargin{:},1); +if numel(sobj.dim) == 1, sobj.dim = [sobj.dim 1]; end ind = sub2ind(sobj.dim,indx2{:}); % Work out the partition @@ -175,7 +176,7 @@ for i=reshape(find(c),1,[]) obj.offset = sobj.offset + mem*(i-1); obj.dim = [1 min(mem/sz, prod(sobj.dim)-(i-1)*mem/sz)]; - val(cc(i)+1:cc(i+1)) = file2mat(obj,int32(1),int32(x(y==i))); + val(cc(i)+1:cc(i+1)) = file2mat(obj,int64(1),int64(x(y==i))); end r = cellfun('length',varargin); if numel(r) == 1, r = [r 1]; end diff --git a/@file_array/transpose.m b/@file_array/transpose.m index 09751854..893197f2 100644 --- a/@file_array/transpose.m +++ b/@file_array/transpose.m @@ -1,10 +1,10 @@ function varargout = transpose(varargin) -% Transposing is not allowed. -% _______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +% file_array objects can not be transposed +%__________________________________________________________________________ +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: transpose.m 1143 2008-02-07 19:33:33Z spm $ +% $Id: transpose.m 7147 2017-08-03 14:07:01Z spm $ error('file_array objects can not be transposed.'); diff --git a/@file_array/vertcat.m b/@file_array/vertcat.m index f7e14850..ff2824db 100644 --- a/@file_array/vertcat.m +++ b/@file_array/vertcat.m @@ -1,11 +1,10 @@ function o = vertcat(varargin) % Vertical concatenation of file_array objects. -% _______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: vertcat.m 1143 2008-02-07 19:33:33Z spm $ +% $Id: vertcat.m 7147 2017-08-03 14:07:01Z spm $ o = cat(1,varargin{:}); -return; diff --git a/@gifti/gifti.m b/@gifti/gifti.m index b1b8bf0a..2dcf6135 100644 --- a/@gifti/gifti.m +++ b/@gifti/gifti.m @@ -8,7 +8,7 @@ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Guillaume Flandin -% $Id: gifti.m 6601 2015-11-19 13:55:32Z guillaume $ +% $Id: gifti.m 7037 2017-03-15 11:45:13Z guillaume $ switch nargin @@ -52,6 +52,18 @@ struct('type','.','subs','cdata'),... varargin{1}); + elseif iscell(varargin{1}) && numel(varargin{1}) == 1 && ... + isnumeric(varargin{1}{1}) + this = gifti; + for i=1:size(varargin{1}{1},2) + this.data{i}.metadata = struct([]); + this.data{i}.space = []; + this.data{i}.attributes.Intent = 'NIFTI_INTENT_NONE'; + this.data{i}.attributes.DataType = 'NIFTI_TYPE_FLOAT32'; + this.data{i}.attributes.Dim = size(varargin{1}{1},1); + this.data{i}.data = single(varargin{1}{1}(:,i)); + end + elseif ischar(varargin{1}) if size(varargin{1},1)>1 this = gifti(cellstr(varargin{1})); @@ -70,6 +82,9 @@ elseif strcmpi(e,'.vtk') this = mvtk_read(varargin{1}); this = gifti(this); + elseif strcmpi(e,'.obj') + this = obj_read(varargin{1}); + this = gifti(this); else this = read_gifti_file(varargin{1},giftistruct); this = class(this,'gifti'); diff --git a/@gifti/private/obj_read.m b/@gifti/private/obj_read.m new file mode 100644 index 00000000..5d303321 --- /dev/null +++ b/@gifti/private/obj_read.m @@ -0,0 +1,85 @@ +function M = obj_read(filename) +% Read Wavefront OBJ-formatted data from disk +% FORMAT M = obj_read(filename) +% +% filename - OBJ-formatted file name +% M - data structure +%__________________________________________________________________________ +% +% Wavefront OBJ Format Specification: +% https://en.wikipedia.org/wiki/Wavefront_.obj_file +%__________________________________________________________________________ +% Copyright (C) 2017 Wellcome Trust Centre for Neuroimaging + +% Guillaume Flandin +% $Id: obj_read.m 7004 2017-02-03 10:57:17Z guillaume $ + + +fid = fopen(filename,'rt'); +if fid == -1 + error('Cannot open %s.',filename); +end + +M = struct('vertices',[],'faces',[]); + +while true + l = fgetl(fid); + if ~ischar(l), break; end + if numel(l) < 1 || isempty(strtrim(l)) || l(1) == '#', continue; end + switch l(1) + case 'v' + switch l(2) + case 't' + % texture coordinates, in (u, v [,w]) coordinates + t = sscanf(l(2:end),'%f %f %f'); + case 'n' + % vertex normals in (x,y,z) form + n = sscanf(l(2:end),'%f %f %f'); + case 'p' + % Parameter space vertices in (u [,v] [,w]) form + p = sscanf(l(2:end),'%f %f %f'); + otherwise + v = sscanf(l(2:end),'%f %f %f'); + if numel(v) > 3, v = v(1:3); end + M.vertices(size(M.vertices,1)+1,:) = v; + end + case 'f' + f = sscanf(l(2:end),'%d %d %d'); + if numel(f) ~= 3 + f = sscanf(l(2:end),'%d/%d %d/d %d/%d'); + if numel(f) ~= 6 + f = sscanf(l(2:end),'%d//%d %d//d %d//%d'); + if numel(f) ~= 6 + f = sscanf(l(2:end),'%d/%d/%d %d/%d/%d %d/%d/%d'); + if numel(f) == 9 + f = f([1 4 7]); + else + fprintf('Not a triangle.\n'); + continue; + end + else + f = f([1 3 5]); + end + else + f = f([1 3 5]); + end + end + i = find(f<0); + if isempty(i), f(i) = size(M.vertices,1) + f(i); end + M.faces(size(M.faces,1)+1,:) = f; + case 'o' + fprintf('Ignoring named objects.\n'); + case 'g' + fprintf('Ignoring polygon groups.\n'); + case 's' + fprintf('Ignoring smooth shading.\n'); + otherwise + if ~isempty(strmatch('mtllib',l)) || ~isempty(strmatch('usemtl',l)) + fprintf('Ignoring materials.\n'); + else + fprintf('Ignoring line starting with %c.\n',l(1)); + end + end +end + +fclose(fid); diff --git a/@gifti/private/zstream.mexmaci64 b/@gifti/private/zstream.mexmaci64 index 5cb0138def4975b5d8d4b19113a01c3a85956979..9324133a71d7aa0600b40e8639bfbe4f85e8a354 100755 GIT binary patch literal 39860 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 literal 39608 zcmeHw3w%`7x$o?mfea7X0TJ;@TEi(3N)yGJX|!gO8Q3EeMUzxp@q`c(;mFHmh5(8t z>>0@FW@D;Exwm-BIj!f?*Da^zB?!#~OafX6!7A0ZMtm?seBh%YptA4(TYK%vB!GCX z_xC%$-@UA`XYKX+*0;X(t#5tnTWf6&o__yKn!_Qv91e#E&n0-&feuF$KDjIKEO9y< zrKQFGdy9Eg-=EsPL5Bzfregpe^2wE!hANhXtamHi7v4U%@0}%9_G|&q z4kv+}MZfTZnz;*Rm(E>Kx$qqDGL~5-*9ia=?$aMhz}8D?X~mq<%Br&Y6?V99|85uX zas|;SoZ4QHb!I9^;=6jZrL@$i6e}qywcx&S<9vEHIk)miY;QJ$O)kHV>aN&F^QowA|)ys|HYmr={JIYjq5D4Yt9 z+B@9J!hg};vQSxXME~|~sI}5A6!>a5Z_0Vy3ZpWs}9F9O%yBh75BY#0c zVRWAy*^if;j+~}|)|0mQ+OE6hF|~+6J(jn1pxLaNEmDlNO9unqrkeMa9S_x})%sZb z$v5#6J1)=d_{elPvJRa*MuBD?Xf4c&g{qY8yh`@5B5!p{ZTP)iGDhZFZ%(P%dU4q= zZu@0`{W8#gNegJr9;w+F>M?E^>|-5S9~+a?2%TqHdyu`7m}Q!#JSN`}JC<&^<$ZhP zF%fEoqa>#Z%?+@25Fu0?F!D`y>f|9+>oG%bf+qvP+7DG0o|V-(1*w3 z&VX@Cy4ESN=-a%&E(f(Y^3MdMHR?ftTu!$d-9iDmu{oIcTLLOS(d22CqnYS=MY|>Q zCPnvUW+-}b=D2_!%*^-ek7T+F@s`V?Cy?EbHgG!*9yz(05Tj z-JmRfMx_}_`x(k92xce;NWaSoY_1r1qCux0iYXnB1q#Q0`a$St%vvN%m)uHL2sH zL`l_fJ5^&kdaDKfMpRC$L9{(i1ivY|J5x0-8wA!<%iSwfsom@xiiPR(SXLSE|KWBx z_Mn)CMddI&_u`@O9>lN1Li}5Jco=cTSPRqp{{S=%3)DY|FvTrFn0y0^%fev}$FnfJ zZNsAMDG_hOAU{XcDZ@Vw$jWly8>@Lw*=Y%kBP1}6qza68dj&>IFzcWk`7Y2^o+F`A z$o2r1i%W=U5E|Lmn=Le^*+OHQEi|UtLSvdOG^Rml>=8m^5`@NUzN}_0HDWctVC{wM zNaB9X|Ry-PKt zJcGGMG20XfnDBFnx#*EXc08EZNZ0yve1J|+ zG&4KfW20C)I@!O!wDtpVBKjMm*(#Q4ZV@n{phjFuy_fF#-@M}inrW}6%t z18xbj!@R{k0P!9qV8D1jvmU0x9T~tsryDcsCiHQTJ+lE`JW_-bx)r7KC=~W%a+oBq zc$v2duYl^HiD)#szy6ny*q8u}jS%$RC6o4#m+;tg(|Q1f1E)Q7r&s-rcUFWz#X7v${2% z$-y>XuM%2Xvs=|p$>BHa&X64r16ngB`Dv0x(Hp-Yji5Mlw5YQ+nvEjlTBBFvm+HaH ziRmx{Az&B*hH~WRh(;4BPTrapX_B}0gdSq2bGr4_jf9k;NG!tNa-cy;-DWd1n?s2~ zE#A}N4>fbJys8I6ke!Yl9aK4_kt(V?Lqe!#g2k5*Xorsq8nP2U=@l!vlC7OeBwqYB z$Jyj4LMjs;z*65ukd(YfA`|2lB={BWv{R1!41-HCCYzki5>9lVr5=cBK@3G%`xzPq znKqC_D&>VZwxr#PMPNt_Cm}H!5K4|9KDue3(BMeKy17E9wE8lU3E=QTY{g%$rV&Rm z>GT4E5GDVE4_hwU!=n`AcF*C?TOG9!+N)MUw5o?c;QF~7 zSxSO-P!ncD5_yq#KZAPpWK!@@3&x=ZwyXi(rjSna{$Wph$qu<0M73!V+Dm2siCX^+ zz_g}!iW*B%Kk6fF`GiO$w*{3gPWnutG=<44Ct<_}*@3!ui819ruC5`@!*Z(r3y_{2 zh@BZ!_a@Cz%pi4{eWYZaghbZ(+%3zivVo$!wUN?%tVuDOCfBdcn2-e;pa&+fcE#n( z%vQWj@`{xh3Ub5?HIcA}ly@Y4(MP;;tiJ#{HrD;Ig=~BhNU6qv$L^u=+U#TdXo7&8 zC3y=m;&yTjR%ejxOdLO(DEpwjo)f&!Yt5po{yTE$Tc|zS2kG)wzC6HO{LBv>4&L>? z@m9v&BS+KZsu^E_Hot@a5d?gBExH}TFdQt}hr{JH^Szq47|A8E$WvNXPjgk16M3YqZ zhR_(tTdJbBRb_lRR6R^LX!!;ezV^#$BdkG)Ph=Nf7-&)p-{yB#Q0KpWlM=1bqkxMXO#864q;A#-BZy|LJYFxD2TB^#C zClHZT<7Od{lmN?7OR9!59*NZXU~g1tX=SL})>p=Tl*$ggwI@O3FK34~U0O zVkYrhK(SPOu@;cEcR}ue@gvD!?@XzN6s0v8kTHlOrcqI~)+5PlXep|)R;bs|TgFj} z_MtQJ1V~{i-X{p}tb=2r2|(RG0X~U7{wYvDdl?|t{}4pxivZT1TB`mADz%s7dHvmz zKnm6yC$*m=76B)z=!NkXZooiwS;!c^G$*G~8M1(Q*VK$ubXrD$Ms5%%19ak)Nv=xl z^@Ggv(3}IC-8N)=XO3hflY%ZPye52hog z;Y3*?#Jk1bT0|J#P^{X?+WuZbW2fM2JL8=5Kdp3uZ=OR7wP0HRiwO`gJF=?F>>68`4 zX8;GvbNxDXMIo=80z#sqNM;sb`{{)$LCo6B>+u45VJ7Dp##_Nb&2=A>wy1cqz#W3Y zMq}|?=&Hnc2x5z)ySjRDA1eg2w+)uQ9VpmMK5Zfevc9KLgAF7bdG;DlqPmujR$X@L` z83kG6Mn0agb~_?wB-Pul%2S(F?;dz0VB+ah!HV{z#0&J*>jTp30qHd*>j+8X=)ZzM zN;j4~k{n6ko$D`L2RsaVB}O1h%#`w4ZZlZRHT3JD3Ru%FruSSdAZYg8?H-6VA>(?X ztS#hoozPW(j`Jg_g7G^@Bm#^e0vyG}Z%dpM5gxHbcoXAdTCNWR25W&3=ZpW7V)D73 zYYoBxu$9CIi8xyMCtd-P1edgn6u7-Q(@l^{TxaS7aVOVS1;i`S!@Uq6L=t$S;I1T3 z&>~nng-JCz2XsJ$@TStlYTSA`@(LAwJF-!up=dY~?*lo`Hi_jB=&qi7AjusYO2{1p&FSrgkJQLHiVY#gVwGU)DF?x3bl@&Q6yESan>=1VYAd;topZqicdjjs_CuYx&*g5MJ1qT7+! z1`yi2J*qJ>N0*pOSFiw&c~}9wJs#D&zXpaI*gv4D$*aB%Mko0Y8G{B`+L{x(U9<%8 zi2#0flju6xND37D2s58r&fhWpnJw1b2g}_(WM6>gjwdZS1eGgMkFxMdL6KL@dyhE3 zkCNg-6r}G3m6Sv_GAh_snJjPJ%vUgp+lcTJbnbl^tRqnJs9u-4m;=p4hkKjl^5vj3keJp9Xu9WO-n} zuSBxM3hG7M>YCXH$bjR$!d%@kKsa@0@@;qW?K%4m2CYn$hQS1DTw@KI0rm>8^<3Lm z**&9kI#gEUQQ4j8mYKwCZgF^2v#IWM19FB>Px6NLf z+KK;a$rtFn*hIlj0t^F|4wtA+&DJQgSrhDD2>fIlp6-)07fB=-Y4OZD`s*>=2#VEd z9O6UOw~!Yw9?4YWMc;=6gZ?`q8EY;0$UKp)N-gmlkb(1jQpMpmPod%@ennl%yX)97 z!OUGFXn)91EYi0lnw=t5y~Du9HEHXxxeHxADHIMRjv^m={-hCB(3U;p(hWrxMAD@J{0OnKPn!3Hz{2)8g zf7i4GbJrIt>ru2eH=R4EdoP3NWbAVMnbWBUSOyJ)Je9qo8jUCTn?arrD5)%lR<%Yc zJJl55*-1@NTbqE18SPMIUz7^lyY8aDexQ^n#eTN8XeVVut#hp2;oZWv5N%+k=9FRv zk?xODlsroZiMm2_FwrM2o zPmR4f5XU6e@z}_a{dLgo4T6Ocy`~g13HTD@vl!!P^TXNhqrt4BGcCi(FrKugiiNUc$_A0ps*bR4!$x@n)n6}g`F zR&X}N80s*lIN9p!X|snmP!w;=^1mmctf@sgwLEIIq>);ZgSNPvRG7_!#@h7TA4j?b zM%$eJ<9bwxeVhn%o2_l3Tp!zyO_EK3Yi*Ly8}_K8`yRbArvvjKwo5uNDL_(Uzogj@ z6a4$Ey^;+yTQO0oT8q=Wi?{99=wYIMN{=Nm;>|m(_i>h=`BR#bgjg8+Q@0LlbZgg`JYONuU+z?UuK;$KoC{ z(nzHTkY0c)=-vBC&0qXEujf6p2?~ACcy<#e`vChwksJ45V^lHsfUBtjY%jp5KpSyG zSI~ijl=B(r;7yqDTqEnCWT>}trK1bDgl?T;4E;0pAO-{oCvQuG*;~IHClgey)qS`J z&t|N5g2J;Tq>BF$( zQ{-*#OusSJtR#~?Y*al`rGk+wuR+gZd!|EqjwXdaqL8EO%0PK@z!({kw>c}NfvBUB zea~!Fygi|RMvC8iiV~L(50u9Mc4(y1J6P62D6SGSqvRxBk_|*LWM2Lsl+k-SU<{2c zms3FJNmU!2uAgEwR6?(d^w4^_2lnA5-(<1fXpyOw$IN}0Tq3HxEgiLv zTx&LaKdNNu;dd0{u`{~~Z|pcl%_YNug&!Fre(!!c@*xs(I=U_ilsB0NaG0Ue&xS_4 zA3yS;F=+%Uj&?ux5~%g)RY7(%2RoJ9Xr~e*Mer8R41|w!BCh!e6)46Xl6ETNv46tA zCwUMk$BKQDrjHU~LNewWscEOa!A6CTgJoz;bU*sdoP9o8E;Lf1tTuHW%)>Cp#}sLg z;yn<43#UzXQUiRLI1j%C+l(ApfuJa$7>lVUESrpxE7bB99Hk2y?kF+BeTsi-4?pkA!Yk%)!9p14SQ>gF->JFWM14%sw{vdryb{f@KWh zMQepvC(d-me0r8Y`hMumu1!edQcaI?>Cnyht5xIbeQNBj0jlvlACU2val8ZdQWg{- z*@uB;JU^I(#tt%%#ea_+AcVYTDil}f5mwe+R4p0FxLqS?40Y)>ZlHNpPKUVAg~o*+lB^?f3ZsJaT#R_Gk_}53u!rPy7*io3*r}{T-uBQX z07J|lQM}EeciF*&i7a3;+G9tgsH4(+Na6@}wH8sQ#P|dp_yE zo`9UPmlUdYdQteJ${h|M(c<{BMTKf;|AOU6pm$-j-Cp9Te@wn57eGO#Q}*X%^n8%z zV|BA6U1f_#Tl6Dg_C|ap^n9MdirkTbynJv_;z_bD6wF}JAZUO+0rEKQ4|fhKn5pq- zr_MbbvSbA_d)x2u8`ZB#>X8l0DXa)&PR-Mlp2}10_nI7%8^ybkyNbOV_ zn>M57rJ!D&9W;LWE12yA>{FjUZKl49vK4y&F0Z@>fR$au^@-v5#pH51OoM;E0gNJV zyGJTCN?qU#_Ui5EyCp#^h6{+DV8rD-XH3dP?lesQfy14JgXqMjJ1uD3+K34n5>wvV zq+B=harTkV7&;JAc`V=JY+_i~<8)CwEU)i@Bjv4=((zh$GriuDj(i9eApx_1f}=b@ zi#5qxhf=2Jze}0i>5JX0l^wutJ|k(dxnTc~L7&6#%3D{DroLf4{_94r3Jz*fjG=UF z5c>eqL3L0|&|9v`D^H-ctOvUU*u;ptv^RSKY*Hp`!mfmNEG;1IRSvyh=>0_2BqE6R zg;dDikR#WEP(DUWbJCPv2FGF@m*!`2kmpbwbi&?Dv-YvX(MhEd&@yhx4Gua$^u|F6 z>{*5(Nm2S93HEaK0?Il80tF*QR1nAlRgm~f;<E)Y@D6W~=m6r(GI*vfI}7=@-yf zYE=il!rQwlodkE?UK&U_O(|16F$OV}V2(bV0Zx%uy#+3bLL)5C53+Y#IYWYUj@E)1 zmN%0;IdVDZgihap4%E!yJJKoA;%a&FtJs{@-K(&D%b8o^teVQ(i}S6KZ~dn7_p~H` zb9PSU@077o^AbCRp38bQtl5=r(|!zgkhea0J6Pd-)qXd%s&fn_F@_Qz8b%xe8ch3f z{s2P|$7BUTQ^<*}jq!!X!;(_>C(Q zYf&iv`lqJJrG=fGlo~OlV56Yxnm+V0_uoovDo1_*v#G*bYIi(0JbhHe^)jBK&*$!7&?A@@kEDXnsLjw z5X;46`JeqcZ^vgM*3XWst=jD?Q3D)a?-s9q>0^X`)SEC%ytZopBHk)nwFUfDjy#M8 zKxv?P+AM%H@G9FuC^J9O9bVv%z8;#aXrIBjIR&c!)&cH!4sg;wk59m={YjU@1V16yCEd7I(j31H|;9*pQI>}4=A0FW9-sur_-$IhZSL(N+1Jq`h~`p zRru2^HF@y`2kg0l8p{SKh95vJh-Mn&lOKC{#)TpBoY+dm z)@-s=&3@ImoD{`8p52Y0vW6ru`IL&AZBMm!m5YMN>?9|+o!s(DrU`A zs8&92Yq*hC{gHo%DGYZ_KEaL)#x4$Hipu@QT@n_j*66@q2DW)QGNd{THf;9cNEx>{ zQz_fGKhA-crM8^aAE2(h_+iZQMCcfZVAaiA4|1QFj2+I=n1cJ%)rSP<5dY_%e8GW}a0}F^V%K0du%9^$V&Z z$E=TBMglQW)CZ;1yg;acXNJ7AbMGbVFl$Nt9{Q}pUP#bU-QEUWsPxT!+LM}lgfaCW zeev3fnl1p@MrsVGsjQ8mrwF}Qzyu) zu0mWuTTV08HS}skfAxe50vR@5y|68ym*gs~{zU{Deu#V=`3kVYd_^yut`2xUC_%~h zlQ1~kQ}3kX-OHzYV9^a^`LmU7|M2wC)qcI?5!`)|BZZJo{qO~p8GgNDW$|*FnK}ot(dv^hK4}i{c80HU;TAdP&N1Pvh4nRl{0K2eFa{?8RT`EZzbWMi~r8WFMM>g-^4rk z0J@<#yq;+IIhu!?Y7KN0*njU>+D5<*dt_W2+CY`#h*clP$`$ndPuGwA&AgK0s;3h_ zCW30qi@yU!6t9U~PT;~B%JWN5r*imh|B#BA#$8;++uLkP5J!MoU&Z?wg9iD6jk+(GCA;`X*jLv1o@ahUCZ= zgu6CSIJz%1B31CntB6OrP?sYkIQdJsjM(i)JfRLdczpD^x*xpPkH5bv|HY1a%md+n zPy8Fv4*i&z1Eq%#3R{w%JyO6FVk$s42>R3bXSlEHmJ34a!q{0c_(F|AhRV1&}@vBH)aq$$%+`vc`pjMp3k(z%xeK-vztU+yZ{&}(u~YSN*2llT`a|C=Telm*8_8! zy|ZjhQzbedl;|buzI;cCJ~cxGY6%|oUyxOF2HE^Ljs^r79cft(10+m4_v5_tdoaj- zFIe8K>Ob;e=lA;o@81^Z>yvT2EHsDU*&Fco?mNl&qLN2<`uH`xOMhgt@5xUjT+ac^psuJf~gM)AvwkfwcJXq%pf|lQg z+xww3wRIqJ;Cls4I0?~8ujp`MA;>C|c45gJNj*|egwrLPf*v>|rUJzndB`_nu z;l>J}UsuWxBWc)(|4%lfH;YXHQb59JKIl| zaS~FMKDL^_V9PMzJzY7OMGAiPgyaaXqjsxo`F4IR!l#!+fT!Z!9GzhY@l6A6wKX3cVDD{KGG04FR*E9cKIr0Sv z%nfc+@S^kNvG^n$DY4NTDayas#7zUDDJ&$gdk`(R*p{cx%b)rH@{+)?2bS zbXgLb6VO5n~}J4o4NF@&L!+|%`Kc_kL4 zj0@ldjHS@Ud>8}#SFkvk4yTkqMBD0?uQkV@39C#55`V*wPxr6ocOHHZlGiQY>j0DL zC40A%ucDv8_V!pKuC#^#-f}Sv&Kd#_VZ5Ao2oMk2tOLP-aR-6rumnS*8G1O-9J75S z;%WwLPlu=bT<)Op>o$5V1Y_;>dBI5jdI$oXjU9mL&cDI%4M+bMZt!87(nUGtZG$RV z;Tl;Zg%`2Ah(~?;{p;DQ$pPPhd{`6bV+_`tZF&9%e1Hej7V9A^DiIo|k>zc;9Yf#T zz!8ngtad^Fwd;?=Y2FA6p}9$YmJ75qAT8?&7=+|D|C-9Yf#Fw(WD4I1vlvC_@A5Xq8N{Jb z6$|&uyeZCbIbzTUI23REz>OGp_%6f@M9e_M3`ESp@NINp9;cl=IAcV>Z&F|z*`m~a z?n3`svl=U0tH_i0GXMI-B49%kF`tGL8+y1h6J#;WBO%!=*?_Z8>Y>x$8;H3c zd)$V5I_4T#yA~}|yfDJ-@yk>G>i7N?CceR(StlF5D@|;uqlF-W54B-RTA#QUbkhCn zEGfGVLNr^SHXFj$SZdP!yrhV=CGJ-cwW}Z`&&}WvwU1s#48X-K$yW$glD}Z+{_?d~ zuxiWKITv54m#l-x{o@Ga6jC-hPB4c~%cPMb1h=^#yQLrmD_NgdgTbypd^N6oUt9OA zHJeJfnMrTa?(kr1s`+nRtaG_66%`W^Xu5HJjp^nsbnAI(unf&Tiw5st>+8#CupXD9 zX_u1E9Rs!v$D7sY{^YRQo@j)bTxezgLPv({KIdA;s{3ivME7qGVlse)xziYlPc#v= zu-i<`BX7+O;Cz+Yq!=TI;)^C2!K@uq4yw+tf8NrZh8ZhphO)!lAU)Y|U&)Hb;SR{+ zA7Q5lpp2073-*yQMG`vHKB3R8y@Jai>=2P3J31JL40D?E<*ltb&7#7Nq`Jj6TWS}J zOe3LFNcZt>2QJjzcAHizs4d9QCMctcM`-s0$KOKmsS6S-F`D=beW(O-Q7>GJ37P<~ zX|rLW;%Hd&G%J{g>DiXL1#=R2(%2&)L^eTiLEuSt()AcZJkRebkAJUFmcC~zUm6fG z{p)>s73)JX(p~=bA}tgL|2ZLY(ICt>OVMQsx+l{|-k^k-a(3|f2H0TEX$Rt0a;aaE z#J6Y;$A2v=n4NeExX@w-3lT6kUx@Hkha8FEI)PY`B$nWv2$9%L;jlMn(R9k}(~Bkq_4~3};bs;Mp>4WUgYRqZlN)ak5ar(-$}LLkQY?%cCyN^ZLZrzDYTxE zpW?R=C!$V`N4n&dt3iHP8i<-fV<%U&82{Ku*EIU3lXP0zMa`6!1IJoGwv;rVT+lA< zqBdr6Ky}a3JKBr5n=(F7<|L3UrZkMZxiuxXiCcVV{NsPnQ6B9wt03Z}6w%TjLq zzPI}j=>d#aeHw^V0A=4I5(f)SZlg8Cc*g`;LU}#|-PAP@ngPB+*Q=K-gI+S(8P4m~ zOO`<|nd}Z{_39r=)oxt&B32GqF5tmZ-G6ss_J1Xf_u}1`K{T z#Fuqk@xH9cQ(k5raUY6{0-|_=aM4cTWYL`%V~I{+c@oC?F|?#}AjvXdB`UD-U}=XH z>l4Rt0!N5jV(&&8a2AsjSCb6DniaD?n3{Oo;(06{iLb%s)*3SL4z^T#?F}Ug!#S%a zoUz7b8|^*hEy2ywlAic=@6jch25uj>?R!4~M5H>3!Uu0XHeeqtd2)wbjp8q4MvzQ4PTj zs1OENKd}HTCfrJ?nYYPz^k}VKwH$NL@{RG=abgLkPK?V<_^u^Hn`-zs1dZh{wfbMm zqVkO2N)X~%Y%rVgM{q|^_rJtVBL0`co!VzZHVp=wzYWz^p1emjZu${&U=N5j=|fkD z(zSm|k85!hf+Tv{nc9Q5gFsI-O4ch(XmDK@<&S_SWpmS{D+sV!W3UeXe!^P+?0ts~R*D3P=! zx){G#wnT{+2e)v!4?s&1a>RN(EzxE4))IXf-X-<^75IjrRqPQ&1X`lY;i)arN8$Ne zqL0D5yTxDYXz|xM>iwG4$`*eF5mACy?_UWBG;r(vt6++4@z;A)Y%JB6u=>Ka_5PnA zZUTKrEdE&g@I@w#7u zQ2SVOAN>nESVuinm+y*eaMwiDPPxNfFsI;1JSQA(>X)GE-Oygp{;vTCqtI-c{~0f`jwQfA$&x0#>IxyCiIw|jwRz*x`hyb_m?!W zuvldSplraUxJ_(-?D%MW?5e&v8@5ecTRGznza=^y{Ge(MZ~O*sYw&NPlcGQ`#n!Ap zL)65M7G_x?g3K4WJtSwJ^(j4ehPdjE&xu>HPJ0*V&Os4G0$KkjIs0%JP?3MvZN8{t zv%s~5MrV8svirQx672BSKI}OFDP&A8gH$HKPlIn^2i_E4LoXJ7eU1j({A&%`t{17$ zEab)2+HV6C`Y3`XVLwB8j!f-BnuzOu@vRVVV*i6uu(Lt?9V$EAyWequc0nM4^6Bfs zuvgIr!typubpc!-WG}$3UaVqY>`pFV;_uS{k0Nbv=vE&~U@rsP9k@{xe~(Y!A(d{U z9g8<18!n(>@50){NZq}#*b4c?eh1|XpRn@Lu7{OQn~h>np9VyJ9VFh0rHk1X{%O}w z8*qjPS0OvB_GS>)MqwvpRVNVxeq8t`gx^DcC<_wC`7Q<>TYf@iVN6A@;(~Ad4G0Y~ z?SZK}#aCp-W}nZtkBR-h!>ZwL2ermwRe@UC1@t4r?-V|-Jv;32}N>zwH?U_&cDk<#gU0V9BsnFQ7|ka1P1oa=Ql%7zmdJ=Mip@aD)4~A^qIY3%E-z;D&uoCx1oPse_aYx^PLKsWq|0=BH4Q!9)hKu3}yJm7FA;&1bgXkKN7+UV!~BnEZdr zm;aZ_aoWsI-*!z~#)7=xWdG%#8kD~-{`9T~AH28h_l37SG+=s$w*7tIlk$o9&tG|E z^&iS!+|)e#r!RLLUb*Dx;0;%QylWR3mhdn6e;eVWz4F` zD9f<^Z(A%Htn@%?T2)2ayo~VN1)*FZP*t{cqQi&PQ&rW%s*IXB6$>(ESClWDzo@FB zx*GpIZU+5#r4vEclniGlmn?X2!NQsa83K>c(nS@tV1Y|5hKfT3QZ!_7S=HRKS@V!n z)o#6xm_8)qg4{RpM*kVp2>5hlH1WfyOmhywLgFQeO#BIpo`yN&te8tFW+#uqRd>oW zh+<%XLY~{L7!$phc$&wQSuy{hm?)2-ZbGRpiXkgv!<+^y=1qzz<1zng#k@)}ck&pz z35!yHqL^EG%mFKA55hKiWbjE`!DBwLVtz+4X*`BbQ~=Ji6!QI;}cFgbngJl0#+qS0qeYYKEm8Yj>2GH z$fn`=|5#&C!Z$cx%+hg2JMxbq7guFgA<@lJ%x9gYp<4ypYChvUQp4yg&f zlRekr+BDZ8;s0@V4#y}H%SVT_>~4p&1Z%;eX`TjvC)^0%jcd_-xY4{yM7VL(!Z9p; zrPB=~uj3N5l{?BG#Ivr^%0JtRMt&;D^OK0}lON~J97jZck|Esn=BMT+^HckOgJ-+Q zzme9}_bXI`>hNj$B3-PALHLPBkg z+f8!57Z}w6U~trKABv`Lw&48>MUv~qYZyYwcHDwM2>GXr{7cSTKS|fs1C0T^Ey)V0 z{AQGC*kaXprQHF&^$Gl`!MrR1($WYNUMAuB6y+DuP=t#OMFhFC%2SK2Vg!ZgKLI51 zv{~gCZ~eK-3A#}_A@8Q1B{=ZlsDApC&-8;9oNYW7KWEiXa8_eY2~Tr#I{yYyM?^V( zxPi)^RgMU%xu{?Miu~#!s~)?VDf#)-ZIh4k4+Z7MiTsqvT`zpfn(RlS$1TY35&56D za-RbqBEK;}aNy%EP(-jIFG2K(08Xudv-MH|sJC9xpMCp-@O_@@hxL;j&9U6|mg_U# zsGj$bzXx_@a^E7llIzWX-g+{T_XM^R$X#ufN-fuijzpJY_OXK87 z(#7TzY9D>kU=BXvLvHrjaQf6s`CmeQ`tlFC#b@Ui^;-Nvfr}KlNP&wK zxJZHjpD8f>8yPcc?_*T{?4|Q&msW?uvr1>pT`;?%%5m32=?#vDGDhW>R#sJ1IPg9W z@AJ#%&0APbp==6O%r9TGltQ^ysJbFVq5Kh)wglGs!s-W#m+&}sIO3Klv?Wlyuqado zQ$1y!&Z7&+cwcb`wkxXUmKT;GbxG;XH)d0YdwGT_0*9GAG_@k+!^Qz6&#@y=cveN# zot6H16@1f!5*P8rKy|^KvMLHMvBTJbm{+lcqG}}(S3+AB6jLvuEwqav8rnc%?0A&V zUxZ}gBx>K3@PhKt+=UAq>2AlS!(^e!zyp8aIN`&@&BM9E&lkQb{OQ8KSNJo9KS%hB zgug`iwZg9#KH)?4ks0V(LO?if?M9e)F5+mrWEjFB>TEa#4~5AVPp%LTg*T-0pyM79 zPNz*VxS4n;9d>)}szkV*0K*X;lukB%a=*pH;fpZY(@uKQ22z; z3Xc+D>o&>jNZ0ujc30(U;S+W^WTl@G;f$~q9tB(opKKAHD8e&ESP|h)5iYXRg+X$T zoi4(Ui13UW3x2%_*NX772ww}s{X4|CaDSk5Savtm@}PsR>&u`Y_H?*AhA{S!k|s(z zV4NEMN53$A`XMzPTc8w1t1Wk_6-Et~BU>=ili}O?g{Srl-`y`fw_murU%0kkShvE- z_N?s}CL1x3Nv4w>_}h4BIDH2X4VxT1G+b`PLw4|+@O&4~&3I_oc=3D>4_rPyUk65p zqqKDXoYGn01+(W>l+LLrqZy#@lmK~+gn5gQP+H29Dk1(#=Pg|LV0e+EbpEo^GL)^l z@do~0UR5sM`0P=No!QEHrM-Kg8Ng#n9-*FcZOR@PL>IG~gXBW4_{pzo&nj5Mp zojbqmfeNDCBJ@$^T=d}F1w^ogRZB}T%L!aBnAgsjtV{HW)$;SDT0O$)-M^sKmDQsD zc@?0^QgmN30tXZ-N@vfl4)u+%CMDw>@$-7~S1butmGweODIrq8j5=9g7Jh#p8* z2n>=XIfqWX;k!3`DZ_kFjB`h6H5jIP;tefy!r2uZc_Lt^B(9*rw^cLi^(>_f(Lx=w-h?8?1C|DsRK0AStFIWs5P|#OCuZ># diff --git a/@gifti/private/zstream.mexw32 b/@gifti/private/zstream.mexw32 new file mode 100644 index 0000000000000000000000000000000000000000..8153a1d404d31a0786f5cd0d2747458e6c42de75 GIT binary patch literal 27136 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 literal 0 HcmV?d00001 diff --git a/@gifti/private/zstream.mexw64 b/@gifti/private/zstream.mexw64 index 82b535a7286b63a7d280389354f8718a32e5e195..cd58fb3b914e8c95da2143d94f6c8b6edbf764bf 100644 GIT binary patch delta 35 ocmZo@U}|V!n(%?8@cGloiC=t}_4YArc4k~y3>Mh@qC|ol02;y%wg3PC delta 35 ocmZo@U}|V!n(%>T-|W?46TkQ{2P-gcc4k~y3>Mh@qC|ol01QkH#sB~S diff --git a/@gifti/saveas.m b/@gifti/saveas.m index aed49ddf..3f81a381 100644 --- a/@gifti/saveas.m +++ b/@gifti/saveas.m @@ -9,7 +9,7 @@ function saveas(this,filename,format) % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Guillaume Flandin -% $Id: saveas.m 6618 2015-12-01 16:25:38Z spm $ +% $Id: saveas.m 7004 2017-02-03 10:57:17Z guillaume $ % Check filename and file format @@ -28,6 +28,10 @@ function saveas(this,filename,format) format = lower(format(5:end)); ext = '.vtk'; end + if nargin == 3 && strncmpi(format,'obj',3) + format = lower(format(5:end)); + ext = '.obj'; + end [p,f,e] = fileparts(filename); if strcmpi(e,'.gii') warning('Use save instead of saveas.'); @@ -53,6 +57,8 @@ function saveas(this,filename,format) case {'.vtk','.vtp'} if nargin < 3, format = 'legacy-ascii'; end mvtk_write(s,filename,format); + case '.obj' + save_obj(s,filename); otherwise error('Unknown file format.'); end @@ -363,3 +369,26 @@ function save_idtf(s,filename) % Close file %-------------------------------------------------------------------------- fclose(fid); + + +%========================================================================== +% function save_obj(s,filename) +%========================================================================== +function save_obj(s,filename) + +% Open file for writing +%-------------------------------------------------------------------------- +fid = fopen(filename,'wt'); +if fid == -1 + error('Unable to write file %s: permission denied.',filename); +end + +% Vertices & faces +%-------------------------------------------------------------------------- +fprintf(fid,'# Wavefront OBJ file saved by %s\n',spm('Version')); +fprintf(fid,'v %f %f %f\n',s.vertices'); +fprintf(fid,'f %d %d %d\n',s.faces'); + +% Close file +%-------------------------------------------------------------------------- +fclose(fid); diff --git a/@meeg/badsamples.m b/@meeg/badsamples.m index e13f424e..e913fc7b 100644 --- a/@meeg/badsamples.m +++ b/@meeg/badsamples.m @@ -5,7 +5,7 @@ % Copyright (C) 2013 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: badsamples.m 6311 2015-01-21 15:44:23Z vladimir $ +% $Id: badsamples.m 7199 2017-11-01 16:42:12Z vladimir $ if ischar(chanind) && isequal(chanind, ':') chanind = 1:nchannels(this); @@ -19,9 +19,14 @@ trialind = 1:ntrials(this); end +if ~isequal(type(this), 'continuous') && ~any(trialonset(this)) + error('Trial onset information is not available. Cannot map artefact events to samples.'); +end + res = false(length(chanind), nsamples(this), length(trialind)); for i = 1:length(trialind) - ev = events(this, trialind(i), 'samples'); + + ev = events(this, trialind(i)); if iscell(ev) ev = ev{1}; end @@ -31,7 +36,9 @@ find(cellfun(@ischar, {ev.value})))); for k = 1:numel(ev) [dum, chan] = intersect(chanind, selectchannels(this, ev(k).value)); - res(chan, ev(k).sample+(0:(ev(k).duration-1)), i) = true; + samples = find((trialonset(this, trialind(i))+time(this))>=ev(k).time & ... + (trialonset(this, trialind(i))+time(this))<=(ev(k).time+ev(k).duration)); + res(chan, samples, i) = true; end end end diff --git a/@meeg/indtrial.m b/@meeg/indtrial.m index 1b37c0f0..e4971842 100644 --- a/@meeg/indtrial.m +++ b/@meeg/indtrial.m @@ -13,7 +13,7 @@ % Copyright (C) 2008-2012 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: indtrial.m 5596 2013-08-01 14:36:18Z vladimir $ +% $Id: indtrial.m 6998 2017-01-31 16:48:27Z vladimir $ if ischar(label) label = {label}; @@ -23,10 +23,11 @@ if nargin > 2 if strcmpi(flag, 'GOOD') - res = setdiff(res, badtrials(this)); + [dum, ind] = setdiff(res, badtrials(this)); elseif strcmpi(flag, 'BAD') - res = intersect(res, badtrials(this)); - end + [dum, ind] = intersect(res, badtrials(this)); + end + res = res(sort(ind)); end res = res(:)'; \ No newline at end of file diff --git a/@meeg/montage.m b/@meeg/montage.m index 2b66d941..cb529b1a 100644 --- a/@meeg/montage.m +++ b/@meeg/montage.m @@ -1,5 +1,4 @@ function [res] = montage(this,action,varargin) - % Method for specifying an online montage, or setting one to use % FORMAT % res = montage(this, 'add', montage) @@ -21,11 +20,11 @@ % depending on list provided (current one by default if % no list passed). % _______________________________________________________________________ -% Copyright (C) 2011 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2011-2017 Wellcome Trust Centre for Neuroimaging % Remy Lehembre & Christophe Phillips -% Cyclotron Research Centre, University of Liège, Belgium -% $Id: montage.m 6264 2014-11-18 13:46:51Z vladimir $ +% Cyclotron Research Centre, University of Liege, Belgium +% $Id: montage.m 7111 2017-06-16 09:01:09Z guillaume $ % Montage definition in the object structure by simply adding a 'montage' % field in the object structure: @@ -59,7 +58,7 @@ %check that all info are consistent if size(mont.tra,1)~=length(mont.labelnew) || ... size(mont.tra,2)~=length(mont.labelorg) - error('Montage Matrix inconsistent with original or new number of electrodes') + error('Montage Matrix inconsistent with original or new number of electrodes.') end if size(mont.labelorg,1)~=size(mont.tra,2) mont.labelorg = mont.labelorg'; @@ -103,7 +102,7 @@ this.montage.M(ind).channels = mont.channels; else % try to derive it from object channel info - display('No new channels information : setting channels info automatically.') + disp('No new channels information : setting channels info automatically.') this = set_channels(this,mont); end res = meeg(this); @@ -207,11 +206,18 @@ error('Wrong use of the ''montage'' method.') end -end - -%% Subfunction(s) +%========================================================================== function S = set_channels(S,mont) + +% provided montage does not necessarily apply to all channels +% this adjusts it to include also the unused channels +mont_orig = []; +mont_orig.labelorg = {S.channels(:).label}; +mont_orig.labelnew = mont_orig.labelorg; +mont_orig.tra = eye(numel(mont_orig.labelnew)); +mont = ft_apply_montage(mont_orig, mont); + % set channels "default" value, try to guess values from main channels % definition in the object. @@ -276,5 +282,3 @@ S.montage.M(idx).channels(ii).Y_plot2D = []; end end - -end \ No newline at end of file diff --git a/@meeg/rmdata.m b/@meeg/rmdata.m index 5c23c233..d705fb79 100644 --- a/@meeg/rmdata.m +++ b/@meeg/rmdata.m @@ -5,11 +5,11 @@ % Copyright (C) 2011-2012 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: rmdata.m 5025 2012-10-31 14:44:13Z vladimir $ +% $Id: rmdata.m 6976 2016-12-22 11:04:45Z vladimir $ if islinked(this) try - delete(fullfile(path(this), fnamedat(this))); + delete(fnamedat(this)); end end diff --git a/@nifti/Contents.m b/@nifti/Contents.m index 6d3c0109..f237c265 100644 --- a/@nifti/Contents.m +++ b/@nifti/Contents.m @@ -74,8 +74,8 @@ % imagesc(M.dat(:,:,12)); % % _______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: Contents.m 2696 2009-02-05 20:29:48Z guillaume $ +% $Id: Contents.m 7147 2017-08-03 14:07:01Z spm $ diff --git a/@nifti/create.m b/@nifti/create.m index ece30c24..7c5242d9 100644 --- a/@nifti/create.m +++ b/@nifti/create.m @@ -6,10 +6,10 @@ function create(obj,wrt) % FORMAT create(obj,wrt) % Also write out an empty image volume if wrt==1 %__________________________________________________________________________ -% Copyright (C) 2005-2013 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: create.m 5451 2013-04-26 14:03:05Z guillaume $ +% $Id: create.m 7147 2017-08-03 14:07:01Z spm $ for i=1:numel(obj) diff --git a/@nifti/disp.m b/@nifti/disp.m index 68e0efb2..1bc73f06 100644 --- a/@nifti/disp.m +++ b/@nifti/disp.m @@ -1,23 +1,22 @@ function disp(obj) % Disp a NIFTI-1 object -% _______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: disp.m 4136 2010-12-09 22:22:28Z guillaume $ +% $Id: disp.m 7147 2017-08-03 14:07:01Z spm $ sz = size(obj); fprintf('NIFTI object: '); -if length(sz)>4, +if length(sz)>4 fprintf('%d-D\n',length(sz)); else - for i=1:(length(sz)-1), + for i=1:(length(sz)-1) fprintf('%d-by-',sz(i)); - end; + end fprintf('%d\n',sz(end)); -end; -if prod(sz)==1, +end +if prod(sz)==1 disp(structn(obj)) -end; -return; +end diff --git a/@nifti/display.m b/@nifti/display.m index 35e4f6ab..3eb160eb 100644 --- a/@nifti/display.m +++ b/@nifti/display.m @@ -1,10 +1,10 @@ function display(obj) % Display a NIFTI-1 object -% _______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: display.m 1143 2008-02-07 19:33:33Z spm $ +% $Id: display.m 7147 2017-08-03 14:07:01Z spm $ disp(' '); diff --git a/@nifti/fieldnames.m b/@nifti/fieldnames.m index 6f4cd6ec..0c0d7aa3 100644 --- a/@nifti/fieldnames.m +++ b/@nifti/fieldnames.m @@ -1,10 +1,10 @@ function t = fieldnames(obj) % Fieldnames of a NIFTI-1 object -% _______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: fieldnames.m 1143 2008-02-07 19:33:33Z spm $ +% $Id: fieldnames.m 7147 2017-08-03 14:07:01Z spm $ if isfield(obj.hdr,'magic') @@ -23,4 +23,4 @@ }; else error('This should not happen.'); -end; +end diff --git a/@nifti/nifti.m b/@nifti/nifti.m index 08eec5fb..5df72a01 100644 --- a/@nifti/nifti.m +++ b/@nifti/nifti.m @@ -1,10 +1,10 @@ function h = nifti(varargin) % Create a NIFTI-1 object %__________________________________________________________________________ -% Copyright (C) 2005-2012 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: nifti.m 4986 2012-10-05 17:35:09Z guillaume $ +% $Id: nifti.m 7147 2017-08-03 14:07:01Z spm $ switch nargin @@ -62,7 +62,7 @@ if ~vol.hdr.scl_slope && ~vol.hdr.scl_inter vol.hdr.scl_slope = 1; - end; + end slope = double(vol.hdr.scl_slope); inter = double(vol.hdr.scl_inter); diff --git a/@nifti/private/M2Q.m b/@nifti/private/M2Q.m index 1591754e..17df5689 100644 --- a/@nifti/private/M2Q.m +++ b/@nifti/private/M2Q.m @@ -1,33 +1,31 @@ function Q = M2Q(M) % Convert from rotation matrix to quaternion form % See: http://skal.planet-d.net/demo/matrixfaq.htm -% _______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: M2Q.m 1143 2008-02-07 19:33:33Z spm $ +% $Id: M2Q.m 7147 2017-08-03 14:07:01Z spm $ d = diag(M(1:3,1:3)); t = sum(d) + 1; -if t>0.5, +if t>0.5 s = sqrt(t)*2; Q = [(M(3,2)-M(2,3))/s (M(1,3)-M(3,1))/s (M(2,1)-M(1,2))/s 0.25*s]'; else t = find(d==max(d)); t = t(1); - switch(t), - case 1, + switch(t) + case 1 s = 2*sqrt(1 + M(1,1) - M(2,2) - M(3,3)); Q = [0.25*s (M(1,2)+M(2,1))/s (M(3,1)+M(1,3))/s (M(3,2)-M(2,3))/s]'; - case 2, + case 2 s = 2*sqrt(1 + M(2,2) - M(1,1) - M(3,3)); Q = [(M(1,2)+M(2,1))/s 0.25*s (M(2,3)+M(3,2))/s (M(1,3)-M(3,1))/s ]'; - case 3, + case 3 s = 2*sqrt(1 + M(3,3) - M(1,1) - M(2,2)); Q = [(M(3,1)+M(1,3))/s (M(2,3)+M(3,2))/s 0.25*s (M(2,1)-M(1,2))/s]'; - end; -end; -if Q(4)<0, Q = -Q; end; % w must be +ve -return; - + end +end +if Q(4)<0, Q = -Q; end % w must be +ve diff --git a/@nifti/private/Q2M.m b/@nifti/private/Q2M.m index a3176c95..679663bb 100644 --- a/@nifti/private/Q2M.m +++ b/@nifti/private/Q2M.m @@ -2,23 +2,23 @@ % Generate a rotation matrix from a quaternion xi+yj+zk+w, % where Q = [x y z], and w = 1-x^2-y^2-z^2. % See: http://skal.planet-d.net/demo/matrixfaq.htm -% _______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: Q2M.m 1143 2008-02-07 19:33:33Z spm $ +% $Id: Q2M.m 7147 2017-08-03 14:07:01Z spm $ Q = Q(1:3); % Assume rigid body w = sqrt(1 - sum(Q.^2)); x = Q(1); y = Q(2); z = Q(3); -if w<1e-7, +if w<1e-7 w = 1/sqrt(x*x+y*y+z*z); x = x*w; y = y*w; z = z*w; w = 0; -end; +end xx = x*x; yy = y*y; zz = z*z; ww = w*w; xy = x*y; xz = x*z; xw = x*w; yz = y*z; yw = y*w; zw = z*w; @@ -27,5 +27,3 @@ 2*(xy+zw) (-xx+yy-zz+ww) 2*(yz-xw) 0 2*(xz-yw) 2*(yz+xw) (-xx-yy+zz+ww) 0 0 0 0 1]; -return; - diff --git a/@nifti/private/decode_qform0.m b/@nifti/private/decode_qform0.m index b0d85fb0..dc65ce72 100644 --- a/@nifti/private/decode_qform0.m +++ b/@nifti/private/decode_qform0.m @@ -1,15 +1,15 @@ function M = decode_qform0(hdr) % Decode qform info from NIFTI-1 headers. -% _______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: decode_qform0.m 3131 2009-05-18 15:54:10Z guillaume $ +% $Id: decode_qform0.m 7147 2017-08-03 14:07:01Z spm $ dim = double(hdr.dim); pixdim = double(hdr.pixdim); -if ~isfield(hdr,'magic') || hdr.qform_code <= 0, +if ~isfield(hdr,'magic') || hdr.qform_code <= 0 flp = spm_flip_analyze_images; %disp('------------------------------------------------------'); %disp('The images are in a form whereby it is not possible to'); @@ -25,16 +25,16 @@ n = min(dim(1),3); vox = [pixdim(2:(n+1)) ones(1,3-n)]; - if ~isfield(hdr,'origin') || ~any(hdr.origin(1:3)), + if ~isfield(hdr,'origin') || ~any(hdr.origin(1:3)) origin = (dim(2:4)+1)/2; else origin = double(hdr.origin(1:3)); - end; + end off = -vox.*origin; M = [vox(1) 0 0 off(1) ; 0 vox(2) 0 off(2) ; 0 0 vox(3) off(3) ; 0 0 0 1]; % Stuff for default orientations - if flp, M = diag([-1 1 1 1])*M; end; + if flp, M = diag([-1 1 1 1])*M; end else % Rotations from quaternions @@ -48,7 +48,7 @@ n = min(dim(1),3); Z = [pixdim(2:(n+1)) ones(1,4-n)]; Z(Z<0) = 1; - if pixdim(1)<0, Z(3) = -Z(3); end; + if pixdim(1)<0, Z(3) = -Z(3); end Z = diag(Z); M = T*R*Z; @@ -56,6 +56,4 @@ % Convert from first voxel at [1,1,1] % to first voxel at [0,0,0] M = M * [eye(4,3) [-1 -1 -1 1]']; -end; -return; - +end diff --git a/@nifti/private/empty_hdr.m b/@nifti/private/empty_hdr.m index 23234017..1e6103ef 100644 --- a/@nifti/private/empty_hdr.m +++ b/@nifti/private/empty_hdr.m @@ -2,10 +2,10 @@ % Create an empty NIFTI header % FORMAT hdr = empty_hdr %__________________________________________________________________________ -% Copyright (C) 2005-2013 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: empty_hdr.m 5451 2013-04-26 14:03:05Z guillaume $ +% $Id: empty_hdr.m 7147 2017-08-03 14:07:01Z spm $ if ~nargin, fmt = 'nifti1'; end diff --git a/@nifti/private/encode_qform0.m b/@nifti/private/encode_qform0.m index fad97c14..ccc7daa8 100644 --- a/@nifti/private/encode_qform0.m +++ b/@nifti/private/encode_qform0.m @@ -1,10 +1,10 @@ function hdr = encode_qform0(M,hdr) % Encode an affine transform into qform -% _______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: encode_qform0.m 1143 2008-02-07 19:33:33Z spm $ +% $Id: encode_qform0.m 7147 2017-08-03 14:07:01Z spm $ % Convert from first voxel at [1,1,1] to first voxel at [0,0,0] @@ -24,7 +24,7 @@ % Ensure that R is O(3) [U,S,V] = svd(R); R = U*V'; -if any(abs(diag(S)-1)>1e-3), warning('QFORM0 representation has been rounded.'); end; +if any(abs(diag(S)-1)>1e-3), warning('QFORM0 representation has been rounded.'); end % Ensure that R is SO(3) if det(R)>0 @@ -32,7 +32,7 @@ else R = R*diag([1 1 -1]); hdr.pixdim(1:4) = [-1 vx]; -end; +end % Convert to quaternions Q = M2Q(R); @@ -40,6 +40,4 @@ hdr.quatern_c = Q(2); hdr.quatern_d = Q(3); -if hdr.qform_code == 0, hdr.qform_code = 2; end; -return; - +if hdr.qform_code == 0, hdr.qform_code = 2; end diff --git a/@nifti/private/findindict.m b/@nifti/private/findindict.m index 5d674c0d..3d0d3a09 100644 --- a/@nifti/private/findindict.m +++ b/@nifti/private/findindict.m @@ -1,18 +1,18 @@ function entry = findindict(c,dcode) % Look up an entry in the dictionary %__________________________________________________________________________ -% Copyright (C) 2005-2012 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: findindict.m 4986 2012-10-05 17:35:09Z guillaume $ +% $Id: findindict.m 7147 2017-08-03 14:07:01Z spm $ entry = []; d = getdict; d = d.(dcode); if ischar(c) - for i=1:length(d), - if strcmpi(d(i).label,c), + for i=1:length(d) + if strcmpi(d(i).label,c) entry = d(i); break; end diff --git a/@nifti/private/getdict.m b/@nifti/private/getdict.m index 5bd397eb..2a689650 100644 --- a/@nifti/private/getdict.m +++ b/@nifti/private/getdict.m @@ -1,10 +1,10 @@ function d = getdict % Dictionary of NIFTI stuff -% _________________________________________________________________________ -% Copyright (C) 2005-2013 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: getdict.m 5759 2013-11-21 14:01:14Z guillaume $ +% $Id: getdict.m 7147 2017-08-03 14:07:01Z spm $ persistent dict; diff --git a/@nifti/private/mayo2nifti1.m b/@nifti/private/mayo2nifti1.m index 59c07250..929f7c54 100644 --- a/@nifti/private/mayo2nifti1.m +++ b/@nifti/private/mayo2nifti1.m @@ -1,19 +1,19 @@ function hdr = mayo2nifti1(ohdr,mat) % Convert from an ANALYZE to a NIFTI-1 header -% _______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: mayo2nifti1.m 5070 2012-11-19 16:00:40Z john $ +% $Id: mayo2nifti1.m 7147 2017-08-03 14:07:01Z spm $ -if isfield(ohdr,'magic'), +if isfield(ohdr,'magic') hdr = ohdr; return; -end; +end hdr = empty_hdr; hdr.dim = ohdr.dim; -if hdr.dim(1)<1, +if hdr.dim(1)<1 tmp = [find(~hdr.dim(2:end))-1, 7]; hdr.dim(1) = tmp(1); end @@ -31,34 +31,34 @@ hdr.cal_min = ohdr.cal_min; hdr.magic = 'ni1'; -switch hdr.datatype, -case 130, hdr.datatype = 256; % int8 -case 132, hdr.datatype = 512; % uint16 -case 136, hdr.datatype = 768; % uint32 -end; +switch hdr.datatype + case 130, hdr.datatype = 256; % int8 + case 132, hdr.datatype = 512; % uint16 + case 136, hdr.datatype = 768; % uint32 +end -if nargin<2, +if nargin<2 % No mat, so create the equivalent from the hdr... if any(ohdr.origin(1:3)), origin = double(ohdr.origin(1:3)); - else origin = (double(ohdr.dim(2:4))+1)/2; end; + else origin = (double(ohdr.dim(2:4))+1)/2; end vox = double(ohdr.pixdim(2:4)); - if vox(1)<0, + if vox(1)<0 % Assume FSL orientation flp = 0; else % Assume SPM or proper Analyze flp = spm_flip_analyze_images; - end; - if all(vox == 0), vox = [1 1 1]; end; + end + if all(vox == 0), vox = [1 1 1]; end off = -vox.*origin; mat = [vox(1) 0 0 off(1) ; 0 vox(2) 0 off(2) ; 0 0 vox(3) off(3) ; 0 0 0 1]; - if flp, + if flp %disp(['Assuming that image is stored left-handed']); mat = diag([-1 1 1 1])*mat; else %disp(['Assuming that image is stored right-handed']); - end; -end; + end +end hdr = encode_qform0(mat,hdr); mat = mat*[eye(4,3) [1 1 1 1]']; @@ -67,5 +67,3 @@ hdr.srow_z = mat(3,:); hdr.qform_code = 2; hdr.sform_code = 2; -return; - diff --git a/@nifti/private/mayostruc.m b/@nifti/private/mayostruc.m index 52a8536f..68adc7ed 100644 --- a/@nifti/private/mayostruc.m +++ b/@nifti/private/mayostruc.m @@ -1,17 +1,17 @@ function o = mayostruc % Create a data structure describing Analyze headers -% _______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: mayostruc.m 1143 2008-02-07 19:33:33Z spm $ +% $Id: mayostruc.m 7147 2017-08-03 14:07:01Z spm $ persistent org; -if ~isempty(org), +if ~isempty(org) o = org; return; -end; +end t = struct('conv',{ @char, @int16, @int32, @single },... 'prec',{'uint8','int16','int32','single'},... 'size',{ 1, 2, 4, 4}); @@ -74,7 +74,5 @@ org(j).def = feval(fun,def); org(j).offset = os; os = os + org(j).len*org(j).dtype.size; -end; +end o = org; -return; - diff --git a/@nifti/private/nifti1struc.m b/@nifti/private/nifti1struc.m index 6c3ea8e3..3ff0184b 100644 --- a/@nifti/private/nifti1struc.m +++ b/@nifti/private/nifti1struc.m @@ -1,10 +1,10 @@ function o = nifti1struc % Create a data structure describing NIFTI-1 headers %__________________________________________________________________________ -% Copyright (C) 2005-2012 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: nifti1struc.m 6289 2014-12-18 15:55:02Z guillaume $ +% $Id: nifti1struc.m 7147 2017-08-03 14:07:01Z spm $ persistent org; diff --git a/@nifti/private/nifti2struc.m b/@nifti/private/nifti2struc.m index c2b1694b..9a6aa417 100644 --- a/@nifti/private/nifti2struc.m +++ b/@nifti/private/nifti2struc.m @@ -1,10 +1,10 @@ function o = nifti2struc % Create a data structure describing NIFTI-2 headers %__________________________________________________________________________ -% Copyright (C) 2005-2012 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: nifti2struc.m 6314 2015-01-23 17:00:51Z guillaume $ +% $Id: nifti2struc.m 7147 2017-08-03 14:07:01Z spm $ persistent org; diff --git a/@nifti/private/nifti_stats.m b/@nifti/private/nifti_stats.m index 12136ad1..47d54377 100644 --- a/@nifti/private/nifti_stats.m +++ b/@nifti/private/nifti_stats.m @@ -24,13 +24,13 @@ % % P is an array with the same dimensions as VAL. % -%_______________________________________________________________________ +%__________________________________________________________________________ % 99.99% of the work by RW Cox - SSCC/NIMH/NIH/DHHS/USA/EARTH - March 2004 % 0.01% of the work (the mex wrapper) by John Ashburner - FIL/ION/UCL -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: nifti_stats.m 1143 2008-02-07 19:33:33Z spm $ +% $Id: nifti_stats.m 7147 2017-08-03 14:07:01Z spm $ fprintf('******************************************\n'); diff --git a/@nifti/private/nifti_stats_mex.c b/@nifti/private/nifti_stats_mex.c index 76d7be7b..412b4316 100644 --- a/@nifti/private/nifti_stats_mex.c +++ b/@nifti/private/nifti_stats_mex.c @@ -1,8 +1,8 @@ #ifndef lint -static char svnid[] = "$Id: nifti_stats_mex.c 253 2005-10-13 15:31:34Z guillaume $"; +static char svnid[] = "$Id: nifti_stats_mex.c 7147 2017-08-03 14:07:01Z spm $"; #endif /* - * This is a Matlab mex interface for Bob Cox's extensive nifti_stats.c + * This is a MATLAB MEX interface for Bob Cox's extensive nifti_stats.c * functionality. See nifti_stats.m for documentation. */ diff --git a/@nifti/private/niftistruc.m b/@nifti/private/niftistruc.m index ae2408e4..09314300 100644 --- a/@nifti/private/niftistruc.m +++ b/@nifti/private/niftistruc.m @@ -1,10 +1,10 @@ function o = niftistruc(fmt) % Create a data structure describing NIFTI headers %__________________________________________________________________________ -% Copyright (C) 2005-2012 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: niftistruc.m 4967 2012-09-26 18:19:23Z guillaume $ +% $Id: niftistruc.m 7147 2017-08-03 14:07:01Z spm $ if ~nargin, fmt = 'nifti1'; end @@ -15,4 +15,4 @@ o = nifti2struc; otherwise error('Unknown format.'); -end \ No newline at end of file +end diff --git a/@nifti/private/read_extras.m b/@nifti/private/read_extras.m index e875e4ca..dfeb94a9 100644 --- a/@nifti/private/read_extras.m +++ b/@nifti/private/read_extras.m @@ -1,10 +1,10 @@ function extras = read_extras(fname) % Read extra bits of information %__________________________________________________________________________ -% Copyright (C) 2005-2011 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: read_extras.m 4492 2011-09-16 12:11:09Z guillaume $ +% $Id: read_extras.m 7147 2017-08-03 14:07:01Z spm $ extras = struct; diff --git a/@nifti/private/read_hdr.m b/@nifti/private/read_hdr.m index 687f2e82..1f252adc 100644 --- a/@nifti/private/read_hdr.m +++ b/@nifti/private/read_hdr.m @@ -4,14 +4,14 @@ % fname - filename of image % vol - various bits of information %__________________________________________________________________________ -% Copyright (C) 2005-2012 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: read_hdr.m 4967 2012-09-26 18:19:23Z guillaume $ +% $Id: read_hdr.m 7147 2017-08-03 14:07:01Z spm $ persistent d -if isempty(d), d = getdict; end; +if isempty(d), d = getdict; end [pth,nam,ext] = spm_fileparts(fname); switch ext diff --git a/@nifti/private/read_hdr_raw.m b/@nifti/private/read_hdr_raw.m index 959f35b7..c507b0d7 100644 --- a/@nifti/private/read_hdr_raw.m +++ b/@nifti/private/read_hdr_raw.m @@ -5,17 +5,17 @@ % hdr - a structure containing header info % be - whether big-endian or not %__________________________________________________________________________ -% Copyright (C) 2005-2015 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: read_hdr_raw.m 6336 2015-02-11 18:06:41Z guillaume $ +% $Id: read_hdr_raw.m 6995 2017-01-27 15:57:40Z guillaume $ hdr = []; be = []; sts = true; -% Open header file +%-Open header file %-------------------------------------------------------------------------- fp = fopen(hname,'r','native'); if fp==-1 @@ -104,6 +104,15 @@ hdr.(org(i).label) = feval(org(i).dtype.conv,field); end +%-Read header extensions +%-------------------------------------------------------------------------- +try + ext = read_extensions(fp,hdr); + if ~isempty(ext) + hdr.ext = ext; + end +end + %-Close header file %-------------------------------------------------------------------------- try, fclose(fp); catch, sts = false; end @@ -114,3 +123,26 @@ fprintf('There was a problem reading the header of\n'); fprintf('"%s".\n', hname); end + + +%========================================================================== +function ext = read_extensions(fp,hdr) + +%-Read first header extension (if any) +%-------------------------------------------------------------------------- +ext = []; n = 0; +exts = fread(fp,4,'*uint8'); +if numel(exts) ~= 4, exts = uint8([0 0 0 0]); end +if exts(1) ~= 0 + n = n + 1; + ext(n).esize = fread(fp,1,'*int32'); + ext(n).ecode = fread(fp,1,'*int32'); + ext(n).edata = fread(fp,ext(n).esize-8,'*uint8'); + if numel(ext(n).edata) ~= ext(n).esize-8 + fprintf('Cannot read header extension.'); + ext(n) = []; + n = n - 1; + else + while ext(n).edata(end) == 0, ext(n).edata(end) = []; end + end +end diff --git a/@nifti/private/write_extras.m b/@nifti/private/write_extras.m index 447b69fe..93856707 100644 --- a/@nifti/private/write_extras.m +++ b/@nifti/private/write_extras.m @@ -1,10 +1,10 @@ function extras = write_extras(fname,extras) % Write extra bits of information %__________________________________________________________________________ -% Copyright (C) 2005-2013 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: write_extras.m 5451 2013-04-26 14:03:05Z guillaume $ +% $Id: write_extras.m 7147 2017-08-03 14:07:01Z spm $ if ~isstruct(extras) || isempty(fieldnames(extras)) diff --git a/@nifti/private/write_hdr_raw.m b/@nifti/private/write_hdr_raw.m index 113e5f89..57477fc8 100644 --- a/@nifti/private/write_hdr_raw.m +++ b/@nifti/private/write_hdr_raw.m @@ -7,10 +7,10 @@ % % sts - status (1=good, 0=bad) %__________________________________________________________________________ -% Copyright (C) 2005-2014 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: write_hdr_raw.m 6289 2014-12-18 15:55:02Z guillaume $ +% $Id: write_hdr_raw.m 7147 2017-08-03 14:07:01Z spm $ [pth,nam] = fileparts(fname); diff --git a/@nifti/structn.m b/@nifti/structn.m index 1ccd212a..5b080fce 100644 --- a/@nifti/structn.m +++ b/@nifti/structn.m @@ -1,20 +1,19 @@ function t = structn(obj) % Convert a NIFTI-1 object into a form of struct -% _______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: structn.m 1143 2008-02-07 19:33:33Z spm $ +% $Id: structn.m 7147 2017-08-03 14:07:01Z spm $ -if numel(obj)~=1, - error('Too many elements to convert'); -end; +if numel(obj)~=1 + error('Too many elements to convert.'); +end fn = fieldnames(obj); for i=1:length(fn) tmp = subsref(obj,struct('type','.','subs',fn{i})); if ~isempty(tmp) t.(fn{i}) = tmp; - end; -end; -return; + end +end diff --git a/@nifti/subsasgn.m b/@nifti/subsasgn.m index ba227681..8fcf2aeb 100644 --- a/@nifti/subsasgn.m +++ b/@nifti/subsasgn.m @@ -1,153 +1,153 @@ function obj = subsasgn(obj,subs,varargin) % Subscript assignment % See subsref for meaning of fields. -% _______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: subsasgn.m 5985 2014-05-14 18:32:51Z john $ +% $Id: subsasgn.m 7147 2017-08-03 14:07:01Z spm $ -switch subs(1).type, -case {'.'}, - if numel(obj)~=nargin-2, +switch subs(1).type +case {'.'} + if numel(obj)~=nargin-2 error('The number of outputs should match the number of inputs.'); - end; + end objs = struct(obj); - for i=1:length(varargin), + for i=1:length(varargin) val = varargin{i}; obji = nifti(objs(i)); obji = fun(obji,subs,val); objs(i) = struct(obji); - end; + end obj = nifti(objs); -case {'()'}, +case {'()'} objs = struct(obj); - if length(subs)>1, + if length(subs)>1 t = subsref(objs,subs(1)); % A lot of this stuff is a little flakey, and may cause Matlab to bomb. % %if numel(t) ~= nargin-2, % error('The number of outputs should match the number of inputs.'); %end; - for i=1:numel(t), + for i=1:numel(t) val = varargin{1}; obji = nifti(t(i)); obji = subsasgn(obji,subs(2:end),val); t(i) = struct(obji); - end; + end objs = subsasgn(objs,subs(1),t); else - if numel(varargin)>1, + if numel(varargin)>1 error('Illegal right hand side in assignment. Too many elements.'); - end; + end val = varargin{1}; - if isa(val,'nifti'), + if isa(val,'nifti') objs = subsasgn(objs,subs,struct(val)); - elseif isempty(val), + elseif isempty(val) objs = subsasgn(objs,subs,[]); else error('Assignment between unlike types is not allowed.'); - end; - end; + end + end obj = nifti(objs); otherwise error('Cell contents reference from a non-cell array object.'); -end; -return; -%======================================================================= +end -%======================================================================= +%========================================================================== + +%========================================================================== function obj = fun(obj,subs,val) % Subscript referencing -switch subs(1).type, -case {'.'}, +switch subs(1).type +case {'.'} objs = struct(obj); for ii=1:numel(objs) obj = objs(ii); - if any(strcmpi(subs(1).subs,{'dat'})), - if length(subs)>1, + if any(strcmpi(subs(1).subs,{'dat'})) + if length(subs)>1 val = subsasgn(obj.dat,subs(2:end),val); - end; + end obj = assigndat(obj,val); objs(ii) = obj; continue; - end; + end - if isempty(obj.hdr), obj.hdr = empty_hdr; end; - if ~isfield(obj.hdr,'magic'), error('Not a NIFTI-1 header'); end; + if isempty(obj.hdr), obj.hdr = empty_hdr; end + if ~isfield(obj.hdr,'magic'), error('Not a NIFTI-1 header.'); end - if length(subs)>1, % && ~strcmpi(subs(1).subs,{'raw','dat'}), + if length(subs)>1 % && ~strcmpi(subs(1).subs,{'raw','dat'}), val0 = subsref(nifti(obj),subs(1)); val1 = subsasgn(val0,subs(2:end),val); else val1 = val; - end; + end switch(subs(1).subs) case {'extras'} - if length(subs)>1, + if length(subs)>1 obj.extras = subsasgn(obj.extras,subs(2:end),val); else obj.extras = val; - end; + end case {'mat0'} if ~isnumeric(val1) || ndims(val1)~=2 || any(size(val1)~=[4 4]) || sum((val1(4,:)-[0 0 0 1]).^2)>1e-8, error('"mat0" should be a 4x4 matrix, with a last row of 0,0,0,1.'); - end; - if obj.hdr.qform_code==0, obj.hdr.qform_code=2; end; + end + if obj.hdr.qform_code==0, obj.hdr.qform_code=2; end s = double(bitand(obj.hdr.xyzt_units,7)); if s d = findindict(s,'units'); val1 = diag([[1 1 1]/d.rescale 1])*val1; - end; + end obj.hdr = encode_qform0(double(single(val1-1)+1), obj.hdr); case {'mat0_intent'} - if isempty(val1), + if isempty(val1) obj.hdr.qform_code = 0; else - if ~ischar(val1) && ~(isnumeric(val1) && numel(val1)==1), + if ~ischar(val1) && ~(isnumeric(val1) && numel(val1)==1) error('"mat0_intent" should be a string or a scalar.'); - end; + end d = findindict(val1,'xform'); if ~isempty(d) obj.hdr.qform_code = d.code; - end; - end; + end + end case {'mat'} if ~isnumeric(val1) || ndims(val1)~=2 || any(size(val1)~=[4 4]) || sum((val1(4,:)-[0 0 0 1]).^2)>1e-8 error('"mat" should be a 4x4 matrix, with a last row of 0,0,0,1.'); - end; - if obj.hdr.sform_code==0, obj.hdr.sform_code=2; end; + end + if obj.hdr.sform_code==0, obj.hdr.sform_code=2; end s = double(bitand(obj.hdr.xyzt_units,7)); if s d = findindict(s,'units'); val1 = diag([[1 1 1]/d.rescale 1])*val1; - end; + end val1 = val1 * [eye(4,3) [1 1 1 1]']; obj.hdr.srow_x = single(val1(1,:)-1)+1; obj.hdr.srow_y = single(val1(2,:)-1)+1; obj.hdr.srow_z = single(val1(3,:)-1)+1; case {'mat_intent'} - if isempty(val1), + if isempty(val1) obj.hdr.sform_code = 0; else - if ~ischar(val1) && ~(isnumeric(val1) && numel(val1)==1), + if ~ischar(val1) && ~(isnumeric(val1) && numel(val1)==1) error('"mat_intent" should be a string or a scalar.'); - end; + end d = findindict(val1,'xform'); - if ~isempty(d), + if ~isempty(d) obj.hdr.sform_code = d.code; - end; - end; + end + end case {'intent'} if ~valid_fields(val1,{'code','param','name'}) @@ -157,67 +157,67 @@ obj.hdr.intent_p3 = 0; obj.hdr.intent_name = ''; else - if ~isfield(val1,'code'), + if ~isfield(val1,'code') val1.code = obj.hdr.intent_code; - end; + end d = findindict(val1.code,'intent'); - if ~isempty(d), + if ~isempty(d) obj.hdr.intent_code = d.code; - if isfield(val1,'param'), + if isfield(val1,'param') prm = [double(val1.param(:)) ; 0 ; 0; 0]; prm = [prm(1:length(d.param)) ; 0 ; 0; 0]; obj.hdr.intent_p1 = prm(1); obj.hdr.intent_p2 = prm(2); obj.hdr.intent_p3 = prm(3); - end; - if isfield(val1,'name'), + end + if isfield(val1,'name') obj.hdr.intent_name = val1.name; - end; - end; - end; + end + end + end case {'diminfo'} if ~valid_fields(val1,{'frequency','phase','slice','slice_time'}) tmp = obj.hdr.dim_info; - for bit=1:6, + for bit=1:6 tmp = bitset(tmp,bit,0); - end; + end obj.hdr.dim_info = tmp; obj.hdr.slice_start = 0; obj.hdr.slice_end = 0; obj.hdr.slice_duration = 0; obj.hdr.slice_code = 0; else - if isfield(val1,'frequency'), + if isfield(val1,'frequency') tmp = val1.frequency; - if ~isnumeric(tmp) || numel(tmp)~=1 || tmp<0 || tmp>3, - error('Invalid frequency direction'); - end; + if ~isnumeric(tmp) || numel(tmp)~=1 || tmp<0 || tmp>3 + error('Invalid frequency direction.'); + end obj.hdr.dim_info = bitset(obj.hdr.dim_info,1,bitget(tmp,1)); obj.hdr.dim_info = bitset(obj.hdr.dim_info,2,bitget(tmp,2)); - end; + end - if isfield(val1,'phase'), + if isfield(val1,'phase') tmp = val1.phase; - if ~isnumeric(tmp) || numel(tmp)~=1 || tmp<0 || tmp>3, - error('Invalid phase direction'); - end; + if ~isnumeric(tmp) || numel(tmp)~=1 || tmp<0 || tmp>3 + error('Invalid phase direction.'); + end obj.hdr.dim_info = bitset(obj.hdr.dim_info,3,bitget(tmp,1)); obj.hdr.dim_info = bitset(obj.hdr.dim_info,4,bitget(tmp,2)); - end; + end - if isfield(val1,'slice'), + if isfield(val1,'slice') tmp = val1.slice; - if ~isnumeric(tmp) || numel(tmp)~=1 || tmp<0 || tmp>3, - error('Invalid slice direction'); - end; + if ~isnumeric(tmp) || numel(tmp)~=1 || tmp<0 || tmp>3 + error('Invalid slice direction.'); + end obj.hdr.dim_info = bitset(obj.hdr.dim_info,5,bitget(tmp,1)); obj.hdr.dim_info = bitset(obj.hdr.dim_info,6,bitget(tmp,2)); - end; + end if isfield(val1,'slice_time') tim = val1.slice_time; - if ~valid_fields(tim,{'start','end','duration','code'}), + if ~valid_fields(tim,{'start','end','duration','code'}) obj.hdr.slice_code = 0; obj.hdr.slice_start = 0; obj.hdr.end_slice = 0; @@ -225,103 +225,103 @@ else % sld = double(bitget(obj.hdr.dim_info,5)) + 2*double(bitget(obj.hdr.dim_info,6)); - if isfield(tim,'start'), + if isfield(tim,'start') ss = double(tim.start); - if isnumeric(ss) && numel(ss)==1 && ~rem(ss,1), % && ss>=1 && ss<=obj.hdr.dim(sld+1) + if isnumeric(ss) && numel(ss)==1 && ~rem(ss,1) % && ss>=1 && ss<=obj.hdr.dim(sld+1) obj.hdr.slice_start = ss-1; else error('Inappropriate "slice_time.start".'); - end; - end; + end + end - if isfield(tim,'end'), + if isfield(tim,'end') ss = double(tim.end); - if isnumeric(ss) && numel(ss)==1 && ~rem(ss,1), % && ss>=1 && ss<=obj.hdr.dim(sld+1) + if isnumeric(ss) && numel(ss)==1 && ~rem(ss,1) % && ss>=1 && ss<=obj.hdr.dim(sld+1) obj.hdr.slice_end = ss-1; else error('Inappropriate "slice_time.end".'); - end; - end; + end + end if isfield(tim,'duration') sd = double(tim.duration); - if isnumeric(sd) && numel(sd)==1, + if isnumeric(sd) && numel(sd)==1 s = double(bitand(obj.hdr.xyzt_units,24)); d = findindict(s,'units'); - if ~isempty(d) && d.rescale, sd = sd/d.rescale; end; + if ~isempty(d) && d.rescale, sd = sd/d.rescale; end obj.hdr.slice_duration = sd; else error('Inappropriate "slice_time.duration".'); - end; - end; + end + end - if isfield(tim,'code'), + if isfield(tim,'code') d = findindict(tim.code,'sliceorder'); - if ~isempty(d), + if ~isempty(d) obj.hdr.slice_code = d.code; - end; - end; - end; - end; - end; + end + end + end + end + end case {'timing'} - if ~valid_fields(val1,{'toffset','tspace'}), + if ~valid_fields(val1,{'toffset','tspace'}) obj.hdr.pixdim(5) = 0; obj.hdr.toffset = 0; else s = double(bitand(obj.hdr.xyzt_units,24)); d = findindict(s,'units'); - if isfield(val1,'toffset'), - if isnumeric(val1.toffset) && numel(val1.toffset)==1, - if d.rescale, + if isfield(val1,'toffset') + if isnumeric(val1.toffset) && numel(val1.toffset)==1 + if d.rescale val1.toffset = val1.toffset/d.rescale; - end; + end obj.hdr.toffset = val1.toffset; else - error('"timing.toffset" needs to be numeric with 1 element'); - end; - end; - if isfield(val1,'tspace'), - if isnumeric(val1.tspace) && numel(val1.tspace)==1, - if d.rescale, + error('"timing.toffset" needs to be numeric with 1 element.'); + end + end + if isfield(val1,'tspace') + if isnumeric(val1.tspace) && numel(val1.tspace)==1 + if d.rescale val1.tspace = val1.tspace/d.rescale; - end; + end obj.hdr.pixdim(5) = val1.tspace; else - error('"timing.tspace" needs to be numeric with 1 element'); - end; - end; - end; + error('"timing.tspace" needs to be numeric with 1 element.'); + end + end + end case {'descrip'} - if isempty(val1), val1 = char(val1); end; - if ischar(val1), + if isempty(val1), val1 = char(val1); end + if ischar(val1) obj.hdr.descrip = val1; else error('"descrip" must be a string.'); - end; + end case {'cal'} - if isempty(val1), + if isempty(val1) obj.hdr.cal_min = 0; obj.hdr.cal_max = 0; else - if isnumeric(val1) && numel(val1)==2, + if isnumeric(val1) && numel(val1)==2 obj.hdr.cal_min = val1(1); obj.hdr.cal_max = val1(2); else error('"cal" should contain two elements.'); - end; - end; + end + end case {'aux_file'} - if isempty(val1), val1 = char(val1); end; - if ischar(val1), + if isempty(val1), val1 = char(val1); end + if ischar(val1) obj.hdr.aux_file = val1; else error('"aux_file" must be a string.'); - end; + end case {'hdr'} error('hdr is a read-only field.'); @@ -329,7 +329,7 @@ otherwise error(['Reference to non-existent field ''' subs(1).subs '''.']); - end; + end objs(ii) = obj; end @@ -337,11 +337,11 @@ otherwise error('This should not happen.'); -end; -return; -%======================================================================= +end + +%========================================================================== -%======================================================================= +%========================================================================== function obj = assigndat(obj,val) if isa(val,'file_array') sz = size(val); @@ -392,32 +392,31 @@ obj.hdr.dim(2:(numel(sz)+1)) = sz; nd = max(find(obj.hdr.dim(2:end)>1)); - if isempty(nd), nd = 3; end; + if isempty(nd), nd = 3; end obj.hdr.dim(1) = nd; obj.hdr.datatype = sval.dtype; obj.hdr.bitpix = d.size*8; - if ~isempty(sval.scl_slope), obj.hdr.scl_slope = sval.scl_slope; end; - if ~isempty(sval.scl_inter), obj.hdr.scl_inter = sval.scl_inter; end; + if ~isempty(sval.scl_slope), obj.hdr.scl_slope = sval.scl_slope; end + if ~isempty(sval.scl_inter), obj.hdr.scl_inter = sval.scl_inter; end obj.dat = val; else - error('"raw" must be of class "file_array"'); -end; -return; -%======================================================================= + error('"raw" must be of class "file_array".'); +end + +%========================================================================== -%======================================================================= +%========================================================================== function ok = valid_fields(val,allowed) -if isempty(val), ok = false; return; end; -if ~isstruct(val), +if isempty(val), ok = false; return; end +if ~isstruct(val) error(['Expecting a structure, not a ' class(val) '.']); -end; +end fn = fieldnames(val); -for ii=1:length(fn), - if ~any(strcmpi(fn{ii},allowed)), +for ii=1:length(fn) + if ~any(strcmpi(fn{ii},allowed)) fprintf('Allowed fieldnames are:\n'); - for i=1:length(allowed), fprintf(' %s\n', allowed{i}); end; + for i=1:length(allowed), fprintf(' %s\n', allowed{i}); end error(['"' fn{ii} '" is not a valid fieldname.']); end end ok = true; -return; diff --git a/@nifti/subsref.m b/@nifti/subsref.m index af270ced..4f38a154 100644 --- a/@nifti/subsref.m +++ b/@nifti/subsref.m @@ -35,19 +35,19 @@ % descrip - a brief description of the image % cal - a two-element vector containing cal_min and cal_max % aux_file - name of an auxiliary file -% _________________________________________________________________________ -% Copyright (C) 2005-2013 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: subsref.m 5759 2013-11-21 14:01:14Z guillaume $ +% $Id: subsref.m 7147 2017-08-03 14:07:01Z spm $ varargout = rec(opt,subs); return; function c = rec(opt,subs) -switch subs(1).type, -case {'.'}, +switch subs(1).type +case {'.'} c = {}; opts = struct(opt); for ii=1:numel(opts) @@ -57,48 +57,48 @@ %end; h = opt.hdr; - if isempty(h), + if isempty(h) %error('No header.'); h = empty_hdr; - end; + end % NIFTI-1 FORMAT switch(subs(1).subs) - case 'extras', + case 'extras' t = opt.extras; - case 'raw', % A hidden field - if isa(opt.dat,'file_array'), + case 'raw' % A hidden field + if isa(opt.dat,'file_array') tmp = struct(opt.dat); tmp.scl_slope = []; tmp.scl_inter = []; t = file_array(tmp); else t = opt.dat; - end; + end - case 'dat', + case 'dat' t = opt.dat; - case 'mat0', + case 'mat0' t = decode_qform0(h); s = double(bitand(h.xyzt_units,7)); if s d = findindict(s,'units'); if ~isempty(d) t = diag([d.rescale*[1 1 1] 1])*t; - end; - end; + end + end - case 'mat0_intent', + case 'mat0_intent' d = findindict(h.qform_code,'xform'); - if isempty(d) || d.code==0, + if isempty(d) || d.code==0 t = ''; else t = d.label; - end; + end - case 'mat', + case 'mat' if h.sform_code > 0 t = double([h.srow_x ; h.srow_y ; h.srow_z ; 0 0 0 1]); t = t * [eye(4,3) [-1 -1 -1 1]']; @@ -113,22 +113,22 @@ end end - case 'mat_intent', - if h.sform_code>0, + case 'mat_intent' + if h.sform_code>0 t = h.sform_code; else t = h.qform_code; - end; + end d = findindict(t,'xform'); - if isempty(d) || d.code==0, + if isempty(d) || d.code==0 t = ''; else t = d.label; - end; + end - case 'intent', + case 'intent' d = findindict(h.intent_code,'intent'); - if isempty(d) || d.code == 0, + if isempty(d) || d.code == 0 %t = struct('code','UNKNOWN','param',[]); t = []; else @@ -137,7 +137,7 @@ t.param = t.param(1:length(d.param)); end - case 'diminfo', + case 'diminfo' t = []; tmp = bitand( h.dim_info ,3); if tmp, t.frequency = double(tmp); end; tmp = bitand(bitshift(h.dim_info,-2),3); if tmp, t.phase = double(tmp); end; @@ -146,98 +146,98 @@ % 'phase',bitand(bitshift(h.dim_info,-2),3),... % 'slice',bitand(bitshift(h.dim_info,-4),3)) if isfield(t,'slice') - sc = double(h.slice_code); - ss = double(h.slice_start)+1; - se = double(h.slice_end)+1; - ss = max(ss,1); - se = min(se,double(h.dim(t.slice+1))); - - sd = double(h.slice_duration); - s = double(bitand(h.xyzt_units,24)); - d = findindict(s,'units'); - if d.rescale, sd = sd*d.rescale; end; - - ns = (se-ss+1); - d = findindict(sc,'sliceorder'); - if isempty(d) - label = 'UNKNOWN'; - else - label = d.label; - end; - t.slice_time = struct('code',label,'start',ss,'end',se,'duration',sd); - if 0, % Never - t.times = zeros(1,double(h.dim(t.slice+1)))+NaN; - switch sc, - case 0, % Unknown - t.times(ss:se) = zeros(1,ns); - case 1, % sequential increasing - t.times(ss:se) = (0:(ns-1))*sd; - case 2, % sequential decreasing - t.times(ss:se) = ((ns-1):-1:0)*sd; - case 3, % alternating increasing - t.times(ss:2:se) = (0:floor((ns+1)/2-1))*sd; - t.times((ss+1):2:se) = (floor((ns+1)/2):(ns-1))*sd; - case 4, % alternating decreasing - t.times(se:-2:ss) = (0:floor((ns+1)/2-1))*sd; - t.times(se:-2:(ss+1)) = (floor((ns+1)/2):(ns-1))*sd; - end; - end; - end; - - case 'timing', + sc = double(h.slice_code); + ss = double(h.slice_start)+1; + se = double(h.slice_end)+1; + ss = max(ss,1); + se = min(se,double(h.dim(t.slice+1))); + + sd = double(h.slice_duration); + s = double(bitand(h.xyzt_units,24)); + d = findindict(s,'units'); + if d.rescale, sd = sd*d.rescale; end + + ns = (se-ss+1); + d = findindict(sc,'sliceorder'); + if isempty(d) + label = 'UNKNOWN'; + else + label = d.label; + end + t.slice_time = struct('code',label,'start',ss,'end',se,'duration',sd); + if 0 % Never + t.times = zeros(1,double(h.dim(t.slice+1)))+NaN; + switch sc + case 0 % Unknown + t.times(ss:se) = zeros(1,ns); + case 1 % sequential increasing + t.times(ss:se) = (0:(ns-1))*sd; + case 2 % sequential decreasing + t.times(ss:se) = ((ns-1):-1:0)*sd; + case 3 % alternating increasing + t.times(ss:2:se) = (0:floor((ns+1)/2-1))*sd; + t.times((ss+1):2:se) = (floor((ns+1)/2):(ns-1))*sd; + case 4 % alternating decreasing + t.times(se:-2:ss) = (0:floor((ns+1)/2-1))*sd; + t.times(se:-2:(ss+1)) = (floor((ns+1)/2):(ns-1))*sd; + end + end + end + + case 'timing' to = double(h.toffset); dt = double(h.pixdim(5)); - if to==0 && dt==0, + if to==0 && dt==0 t = []; else s = double(bitand(h.xyzt_units,24)); d = findindict(s,'units'); - if d.rescale, + if d.rescale to = to*d.rescale; dt = dt*d.rescale; - end; + end t = struct('toffset',to,'tspace',dt); - end; + end - case 'descrip', + case 'descrip' t = deblank(h.descrip); msk = find(t==0); - if any(msk), t=t(1:(msk(1)-1)); end; + if any(msk), t=t(1:(msk(1)-1)); end - case 'cal', + case 'cal' t = [double(h.cal_min) double(h.cal_max)]; - if all(t==0), t = []; end; + if all(t==0), t = []; end - case 'aux_file', + case 'aux_file' t = deblank(h.aux_file); - case 'hdr', % Hidden field + case 'hdr' % Hidden field t = h; otherwise error(['Reference to non-existent field ''' subs(1).subs '''.']); - end; - if numel(subs)>1, + end + if numel(subs)>1 t = subsref(t,subs(2:end)); - end; + end c{ii} = t; - end; -case {'{}'}, + end +case {'{}'} error('Cell contents reference from a non-cell array object.'); -case {'()'}, +case {'()'} opt = struct(opt); t = subsref(opt,subs(1)); if length(subs)>1 c = {}; - for i=1:numel(t), + for i=1:numel(t) ti = nifti(t(i)); ti = rec(ti,subs(2:end)); c = {c{:}, ti{:}}; - end; + end else c = {nifti(t)}; - end; + end otherwise error('This should not happen.'); -end; +end diff --git a/@xmltree/private/xml_findstr.mexmaci64 b/@xmltree/private/xml_findstr.mexmaci64 index 4ceeec1de3f5cdc6b0746ee5d8ba2c4ad1ea257d..2b438ae269d0732466495c303b634fc483c71e35 100755 GIT binary patch literal 9048 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 M06&HsSAwPe2TVr5&;S4c diff --git a/@xmltree/private/xml_findstr.mexw32 b/@xmltree/private/xml_findstr.mexw32 index 724484ef99909f80cf2dcd04a1f9ba0b57a8efd6..536ae5602b6c318131ae024991763788b22f3aed 100755 GIT binary patch delta 32 lcmZp$X|S2_f#rkrv&e~Ge3&{uY<6Ny5(V=&uMmr12LSd$4jljh delta 32 lcmZp$X|S2_f#vhxPoWdP_%N+lv)PF;NfgZAyh1F39RLx}57Phu diff --git a/@xmltree/private/xml_findstr.mexw64 b/@xmltree/private/xml_findstr.mexw64 index b2baa9e01950872c772ffb7c03ce4d237c685fac..9f3950dab151a6bb62c7ff4689af0de6d3505b73 100755 GIT binary patch delta 32 lcmZp0X>ghFfu->I)5wWme3(ARZFXX85(D!$pAfg;0ssJk4#NNd delta 32 lcmZp0X>ghFfyIRRbLhk`K1`GQHajskiGlf>Pl#J^0RY*o3}pZS diff --git a/Contents.m b/Contents.m index 13b7c78f..3e69b70c 100644 --- a/Contents.m +++ b/Contents.m @@ -1,5 +1,5 @@ % Statistical Parametric Mapping -% Version 6906 (SPM12) 20-Oct-16 +% Version 7219 (SPM12) 16-Nov-17 %__________________________________________________________________________ % ___ ____ __ __ % / __)( _ \( \/ ) @@ -35,9 +35,9 @@ % % See README.txt for details of this release. %__________________________________________________________________________ -% Copyright (C) 1991,1994-2016 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 1991,1994-2017 Wellcome Trust Centre for Neuroimaging -% $Id: Contents.m 6905 2016-10-20 15:00:48Z guillaume $ +% $Id: Contents.m 7218 2017-11-16 10:03:14Z guillaume $ %========================================================================== % PROGRAMMERS NOTE: diff --git a/EEGtemplates/fiducials.sfp b/EEGtemplates/fiducials.sfp index 1d98d6f0..7273e262 100644 --- a/EEGtemplates/fiducials.sfp +++ b/EEGtemplates/fiducials.sfp @@ -2,5 +2,4 @@ nas 1 85 -41 lpa -83 -20 -65 rpa 83 -20 -65 FIL_CTF_L -87 -11 -62 -FIL_CTF_R 87 -11 -62 - \ No newline at end of file +FIL_CTF_R 87 -11 -62 \ No newline at end of file diff --git a/LICENCE.txt b/LICENCE.txt index 06942a17..95a6b4e8 100644 --- a/LICENCE.txt +++ b/LICENCE.txt @@ -359,7 +359,7 @@ % library. If this is what you want to do, use the GNU Library General % Public License instead of this License. %__________________________________________________________________________ -% Copyright (C) 1991,1994-2016 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 1991,1994-2017 Wellcome Trust Centre for Neuroimaging % The FIL Methods Group -% $Id: LICENCE.txt 6660 2016-01-06 17:49:19Z guillaume $ +% $Id: LICENCE.txt 6980 2017-01-04 10:10:29Z guillaume $ diff --git a/README.txt b/README.txt index 20e47efe..6566b5e4 100644 --- a/README.txt +++ b/README.txt @@ -140,6 +140,6 @@ % as is. No formal support or maintenance is provided or implied. % %__________________________________________________________________________ -% % Copyright (C) 1991,1994-2016 Wellcome Trust Centre for Neuroimaging +% % Copyright (C) 1991,1994-2017 Wellcome Trust Centre for Neuroimaging % -% $Id: README.txt 6660 2016-01-06 17:49:19Z guillaume $ +% $Id: README.txt 6980 2017-01-04 10:10:29Z guillaume $ diff --git a/bin/spm12-matlab b/bin/spm12-matlab new file mode 100755 index 00000000..605b6e70 --- /dev/null +++ b/bin/spm12-matlab @@ -0,0 +1,80 @@ +#!/bin/sh +# +# Command Line Interface for SPM +# SPM: http://www.fil.ion.ucl.ac.uk/spm/ +# +# Copyright (C) 2017 Wellcome Trust Centre for Neuroimaging +# +# Guillaume Flandin +# $Id: spm12-matlab 7014 2017-02-13 12:31:33Z guillaume $ + +PLATFORM=$(uname) + +if [ "${MATLAB_EXEC}" = "" ]; then + MATLAB_EXEC="matlab" +fi +if [ "$(command -v ${MATLAB_EXEC})" = "" ]; then + echo "MATLAB executable not found." >&2 + exit 1 +fi + +if [ "${SPM_HOME}" = "" ]; then + if [ "${PLATFORM}" = "Darwin" ]; then + RL_FLAG="" # alternative needed + else + RL_FLAG="-f" + fi + SPM_HOME=$(readlink ${RL_FLAG} "$0") + SPM_HOME=$(dirname "$(dirname "${SPM_HOME}")") +fi +if [ ! -d "${SPM_HOME}" ]; then + echo "SPM directory not found." >&2 + exit 1 +fi + +INPUTS="" +for arg in "$@" +do + INPUTS=${INPUTS}"'${arg//\'/''}'," +done +if [ "${INPUTS}" != "" ]; then + INPUTS=${INPUTS:0:$((${#INPUTS}-1))} +fi + +if [ "${PLATFORM}" = "Darwin" ]; then + TMPFILE=$(mktemp -u -t spm) + TMPFILE=${TMPFILE//./_}.m +else + TMPFILE=$(mktemp --tmpdir -u spm_XXXXXX).m +fi +cat << EOF > ${TMPFILE} +warning('off','backtrace'); +cd(getenv('PWD')); +spm_dir = '${SPM_HOME}'; +try, spm_dir = cd(cd(spm_dir)); end % canonical path +addpath(spm_dir); +try + spm('Ver'); +catch + fprintf(['Error: Cannot find the SPM directory. ' ... + 'Set SPM_HOME environment variable.\n']); + exit(1); +end +warning('on','backtrace'); +spm_standalone(${INPUTS}); +while ~isempty(get(0,'CurrentFigure')) + waitfor(get(0,'CurrentFigure')); +end +exit(0); +EOF + +${MATLAB_EXEC} -nosplash -nodesktop ${MATLAB_FLAGS} -r "run('${TMPFILE}');" | tail -n +11 +ERR=${PIPESTATUS[0]} + +rm -f ${TMPFILE} + +if [[ ${ERR} -eq 0 ]]; then + exit 0 +else + exit 1 +fi diff --git a/bin/spm12-mcr b/bin/spm12-mcr new file mode 100755 index 00000000..4e8b5294 --- /dev/null +++ b/bin/spm12-mcr @@ -0,0 +1,44 @@ +#!/bin/sh +# +# Command Line Interface for SPM +# SPM: http://www.fil.ion.ucl.ac.uk/spm/ +# +# Copyright (C) 2017 Wellcome Trust Centre for Neuroimaging +# +# Guillaume Flandin +# $Id: spm12-mcr 7014 2017-02-13 12:31:33Z guillaume $ + +if [ "${MCR_HOME}" = "" ]; then + echo "Set MCR_HOME environment variable." >&2 + exit 1 +fi +if [ ! -d "${MCR_HOME}" ]; then + echo "MCR directory not found." >&2 + exit 1 +fi + +if [ "${SPM_HOME}" = "" ]; then + if [ "${PLATFORM}" = "Darwin" ]; then + RL_FLAG="" # alternative needed + else + RL_FLAG="-f" + fi + SPM_HOME=$(readlink ${RL_FLAG} "$0") + while [ ! -x "${SPM_HOME}/run_spm12.sh" ]; do + if [ "${SPM_HOME}" = "$(dirname "${SPM_HOME}")" ]; then + echo "Set SPM_HOME environment variable." >&2 + exit 1 + fi + SPM_HOME=$(dirname "${SPM_HOME}") + done +fi +if [ ! -d "${SPM_HOME}" ]; then + echo "SPM MCR directory not found." >&2 + exit 1 +fi +if [ ! -x "${SPM_HOME}/run_spm12.sh" ]; then + echo "SPM MCR executable not found." >&2 + exit 1 +fi + +${SPM_HOME}/run_spm12.sh ${MCR_HOME} $@ diff --git a/bin/spm12-octave b/bin/spm12-octave new file mode 100755 index 00000000..b8b2f5b3 --- /dev/null +++ b/bin/spm12-octave @@ -0,0 +1,41 @@ +#!/usr/bin/octave -fqH +# +# Command Line Interface for SPM +# SPM: http://www.fil.ion.ucl.ac.uk/spm/ +# +# Copyright (C) 2017 Wellcome Trust Centre for Neuroimaging +# +# Guillaume Flandin +# $Id: spm12-octave 7053 2017-04-03 11:04:13Z guillaume $ + + +spm_dir = getenv ("SPM_HOME"); +if (isempty (spm_dir)) + spm_dir = mfilename ("fullpath"); + sts = false; + while ! (sts) + [out, sts] = readlink (spm_dir); + if ! (sts) + if ! (is_absolute_filename (out)) + spm_dir = fullfile (fileparts (spm_dir), out); + else + spm_dir = out; + endif + endif + endwhile + spm_dir = fullfile (fileparts (spm_dir), ".."); +endif +addpath (canonicalize_file_name (spm_dir)); + +try + spm ("Ver"); +catch + printf (["error: Cannot find the SPM directory. " ... + "Set SPM_HOME environment variable.\n"]); + exit (1); +end + +spm_standalone (argv (){:}); + +H = get (0, "CurrentFigure"); +if ! (isempty (H)), waitfor (H); endif diff --git a/config/spm_cfg.m b/config/spm_cfg.m index 760a197f..c1b7c325 100644 --- a/config/spm_cfg.m +++ b/config/spm_cfg.m @@ -1,36 +1,36 @@ function spmjobs = spm_cfg % SPM Configuration file for MATLABBATCH %__________________________________________________________________________ -% Copyright (C) 2008-2015 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2008-2016 Wellcome Trust Centre for Neuroimaging -% $Id: spm_cfg.m 6711 2016-02-03 15:25:43Z peter $ +% $Id: spm_cfg.m 6952 2016-11-25 16:03:13Z guillaume $ %-------------------------------------------------------------------------- % Temporal %-------------------------------------------------------------------------- -temporal = cfg_choice; -temporal.tag = 'temporal'; -temporal.name = 'Temporal'; -temporal.help = {'Temporal pre-processing functions.'}; -temporal.values = { spm_cfg_st }; +temporal = cfg_choice; +temporal.tag = 'temporal'; +temporal.name = 'Temporal'; +temporal.help = {'Temporal pre-processing functions.'}; +temporal.values = { spm_cfg_st }; %-------------------------------------------------------------------------- % Spatial %-------------------------------------------------------------------------- -spatial = cfg_choice; -spatial.tag = 'spatial'; -spatial.name = 'Spatial'; -spatial.help = {'Various spatial and other pre-processing functions.'}; -spatial.values = { spm_cfg_realign spm_cfg_realignunwarp spm_cfg_coreg spm_cfg_preproc8 spm_cfg_norm spm_cfg_smooth }; +spatial = cfg_choice; +spatial.tag = 'spatial'; +spatial.name = 'Spatial'; +spatial.help = {'Spatial pre-processing functions.'}; +spatial.values = { spm_cfg_realign spm_cfg_realignunwarp spm_cfg_coreg spm_cfg_preproc8 spm_cfg_norm spm_cfg_smooth }; %-------------------------------------------------------------------------- % Stats %-------------------------------------------------------------------------- -stats = cfg_choice; -stats.tag = 'stats'; -stats.name = 'Stats'; -stats.help = {'Various analysis utilities.'}; -stats.values = { spm_cfg_fmri_spec spm_cfg_fmri_design spm_cfg_fmri_data spm_cfg_factorial_design spm_cfg_model_review spm_cfg_fmri_est spm_cfg_con spm_cfg_results spm_cfg_mfx spm_cfg_bms_map spm_cfg_ppi spm_cfg_setlevel }; +stats = cfg_choice; +stats.tag = 'stats'; +stats.name = 'Stats'; +stats.help = {'Statistical modelling and inference functions.'}; +stats.values = { spm_cfg_fmri_spec spm_cfg_fmri_design spm_cfg_fmri_data spm_cfg_factorial_design spm_cfg_model_review spm_cfg_fmri_est spm_cfg_con spm_cfg_results spm_cfg_mfx spm_cfg_bms_map spm_cfg_ppi spm_cfg_setlevel }; %-------------------------------------------------------------------------- % Dynamic Causal Modelling @@ -38,13 +38,13 @@ spm_cfg_dcm_spec = cfg_choice; spm_cfg_dcm_spec.tag = 'spec'; spm_cfg_dcm_spec.name = 'DCM specification'; -spm_cfg_dcm_spec.values = {spm_cfg_dcm_fmri spm_cfg_dcm_meeg}; +spm_cfg_dcm_spec.values = { spm_cfg_dcm_fmri spm_cfg_dcm_meeg }; -dcm = cfg_choice; -dcm.tag = 'dcm'; -dcm.name = 'DCM'; -dcm.help = {'Dynamic Causal Modelling.'}; -dcm.values = { spm_cfg_dcm_spec spm_cfg_dcm_est spm_cfg_dcm_bms spm_cfg_dcm_peb}; +dcm = cfg_choice; +dcm.tag = 'dcm'; +dcm.name = 'DCM'; +dcm.help = {'Dynamic Causal Modelling.'}; +dcm.values = { spm_cfg_dcm_spec spm_cfg_dcm_est spm_cfg_dcm_bms spm_cfg_dcm_peb }; %-------------------------------------------------------------------------- % Util @@ -53,13 +53,13 @@ spm_cfg_import.tag = 'import'; spm_cfg_import.name = 'Import'; spm_cfg_import.help = {'Import.'}; -spm_cfg_import.values = { spm_cfg_dicom spm_cfg_minc spm_cfg_ecat spm_cfg_parrec}; +spm_cfg_import.values = { spm_cfg_dicom spm_cfg_minc spm_cfg_ecat spm_cfg_parrec }; -util = cfg_choice; -util.tag = 'util'; -util.name = 'Util'; -util.help = {'Various useful tools.'}; -util.values = { spm_cfg_disp spm_cfg_checkreg spm_cfg_render spm_cfg_import spm_cfg_imcalc spm_cfg_reorient spm_cfg_voi spm_cfg_cdir spm_cfg_md spm_cfg_bbox spm_cfg_deface spm_cfg_deformations spm_cfg_tissue_volumes spm_cfg_print spm_cfg_cat spm_cfg_split spm_cfg_exp_frames spm_cfg_sendmail }; +util = cfg_choice; +util.tag = 'util'; +util.name = 'Util'; +util.help = {'Utility tools.'}; +util.values = { spm_cfg_disp spm_cfg_checkreg spm_cfg_render spm_cfg_import spm_cfg_imcalc spm_cfg_reorient spm_cfg_voi spm_cfg_cdir spm_cfg_md spm_cfg_bbox spm_cfg_deface spm_cfg_deformations spm_cfg_tissue_volumes spm_cfg_print spm_cfg_cat spm_cfg_split spm_cfg_exp_frames spm_cfg_sendmail }; %-------------------------------------------------------------------------- % Tools @@ -67,7 +67,7 @@ tools = cfg_choice; tools.tag = 'tools'; tools.name = 'Tools'; -tools.help = {'Other tools', ... +tools.help = {'Other tools.', ... ['Toolbox configuration files should be placed in the ' ... 'toolbox directory, with their own *_cfg_*.m files. ' ... 'If you write a toolbox, then you can include it in ' ... diff --git a/config/spm_cfg_bms_map.m b/config/spm_cfg_bms_map.m index 9b1371f3..96a48b13 100644 --- a/config/spm_cfg_bms_map.m +++ b/config/spm_cfg_bms_map.m @@ -1,10 +1,10 @@ function bms = spm_cfg_bms_map % Configuration file for BMS interface %__________________________________________________________________________ -% Copyright (C) 2008-2014 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2008-2016 Wellcome Trust Centre for Neuroimaging % Maria Joao Rosa -% $Id: spm_cfg_bms_map.m 6004 2014-05-21 14:24:14Z guillaume $ +% $Id: spm_cfg_bms_map.m 6952 2016-11-25 16:03:13Z guillaume $ %-------------------------------------------------------------------------- % dir Directory @@ -269,7 +269,7 @@ bms_map_inf.tag = 'inference'; bms_map_inf.name = 'BMS: Maps (Inference)'; bms_map_inf.val = {dir map name_mod method_maps out_file mask nsamp }; -bms_map_inf.help = {'Bayesian Model Selection for Log-Evidence Maps. '... +bms_map_inf.help = {'Bayesian Model Selection for Log-Evidence Maps.'... ''... ['Input: log-evidence maps for each model, session and '... 'subject. Note that there must be identical numbers of models for '... @@ -295,7 +295,7 @@ bms_map_vis.tag = 'results'; bms_map_vis.name = 'BMS: Maps (Results)'; bms_map_vis.val = {file img thres k scale}; -bms_map_vis.help = {['Bayesian Model Selection Maps (Results). '... +bms_map_vis.help = {['Bayesian Model Selection Maps (Results).'... 'Show results from BMS Maps (Inference).']}; bms_map_vis.prog = @spm_run_bms_vis; diff --git a/config/spm_cfg_cat.m b/config/spm_cfg_cat.m index d14d40f4..b1be91cc 100644 --- a/config/spm_cfg_cat.m +++ b/config/spm_cfg_cat.m @@ -1,10 +1,10 @@ function cat = spm_cfg_cat % SPM Configuration file for 3D to 4D volumes conversion %__________________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2008-2016 Wellcome Trust Centre for Neuroimaging % John Ashburner -% $Id: spm_cfg_cat.m 5828 2014-01-03 18:38:35Z guillaume $ +% $Id: spm_cfg_cat.m 6918 2016-11-02 14:33:11Z guillaume $ %-------------------------------------------------------------------------- % vols 3D Volumes @@ -40,6 +40,7 @@ name.tag = 'name'; name.name = 'Output Filename'; name.help = {'Specify the name of the output 4D volume file.' + 'Unless explicit, the output folder is the one containing the first image.' 'A ''.nii'' extension will be added if not specified.'}'; name.strtype = 's'; name.num = [1 Inf]; diff --git a/config/spm_cfg_checkreg.m b/config/spm_cfg_checkreg.m index a4025759..426f22d5 100644 --- a/config/spm_cfg_checkreg.m +++ b/config/spm_cfg_checkreg.m @@ -1,9 +1,10 @@ function checkreg = spm_cfg_checkreg % SPM Configuration file for Check Reg %__________________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2008-2016 Wellcome Trust Centre for Neuroimaging + +% $Id: spm_cfg_checkreg.m 6952 2016-11-25 16:03:13Z guillaume $ -% $Id: spm_cfg_checkreg.m 4905 2012-09-06 15:34:26Z guillaume $ %-------------------------------------------------------------------------- % data Images to Display @@ -24,15 +25,18 @@ checkreg.name = 'Check Registration'; checkreg.val = {data}; checkreg.help = { - 'Orthogonal views of one or more images are displayed. Clicking in any image moves the centre of the orthogonal views. Images are shown in orientations relative to that of the first selected image. The first specified image is shown at the top-left, and the last at the bottom right. The fastest increment is in the left-to-right direction (the same as you are reading this).' - '' - 'If you have put your images in the correct file format, then (possibly after specifying some rigid-body rotations):' - ' The top-left image is coronal with the top (superior) of the head displayed at the top and the left shown on the left. This is as if the subject is viewed from behind.' - ' The bottom-left image is axial with the front (anterior) of the head at the top and the left shown on the left. This is as if the subject is viewed from above.' - ' The top-right image is sagittal with the front (anterior) of the head at the left and the top of the head shown at the top. This is as if the subject is viewed from the left.' -}'; + 'Display of orthogonal views of one or more images.' + '' + 'Clicking in any image moves the centre of the orthogonal views. Images are shown in orientations relative to that of the first selected image. The first specified image is shown at the top-left, and the last at the bottom right. The fastest increment is in the left-to-right direction (the same as you are reading this).' + '' + 'If you have put your images in the correct file format, then (possibly after specifying some rigid-body rotations):' + ' The top-left image is coronal with the top (superior) of the head displayed at the top and the left shown on the left. This is as if the subject is viewed from behind.' + ' The bottom-left image is axial with the front (anterior) of the head at the top and the left shown on the left. This is as if the subject is viewed from above.' + ' The top-right image is sagittal with the front (anterior) of the head at the left and the top of the head shown at the top. This is as if the subject is viewed from the left.' + }'; checkreg.prog = @check_reg; + %========================================================================== function check_reg(job) spm_check_registration(char(job.data)); \ No newline at end of file diff --git a/config/spm_cfg_con.m b/config/spm_cfg_con.m index 5eec5af1..cc335dc0 100644 --- a/config/spm_cfg_con.m +++ b/config/spm_cfg_con.m @@ -1,9 +1,9 @@ function con = spm_cfg_con % SPM Configuration file for contrast specification %__________________________________________________________________________ -% Copyright (C) 2005-2013 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2016 Wellcome Trust Centre for Neuroimaging -% $Id: spm_cfg_con.m 5652 2013-09-25 09:36:22Z volkmar $ +% $Id: spm_cfg_con.m 6952 2016-11-25 16:03:13Z guillaume $ %-------------------------------------------------------------------------- @@ -422,7 +422,7 @@ delete = cfg_menu; delete.tag = 'delete'; delete.name = 'Delete existing contrasts'; -delete.help = {''}; +delete.help = {'Delete existing contrasts.'}; delete.labels = {'Yes', 'No'}; delete.values = {1 0}; delete.val = {0}; @@ -434,7 +434,7 @@ con.tag = 'con'; con.name = 'Contrast Manager'; con.val = {spmmat consess delete}; -con.help = {'Set up T and F contrasts.'}; +con.help = {'Specify T and F contrasts.'}; con.prog = @spm_run_con; con.vout = @vout_stats; diff --git a/config/spm_cfg_coreg.m b/config/spm_cfg_coreg.m index 8195a8c5..8be26a79 100644 --- a/config/spm_cfg_coreg.m +++ b/config/spm_cfg_coreg.m @@ -1,9 +1,9 @@ function coreg = spm_cfg_coreg % SPM Configuration file for Coregister %__________________________________________________________________________ -% Copyright (C) 2005-2014 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2016 Wellcome Trust Centre for Neuroimaging -% $Id: spm_cfg_coreg.m 6148 2014-09-03 15:49:04Z guillaume $ +% $Id: spm_cfg_coreg.m 6952 2016-11-25 16:03:13Z guillaume $ %-------------------------------------------------------------------------- @@ -49,7 +49,11 @@ cost_fun = cfg_menu; cost_fun.tag = 'cost_fun'; cost_fun.name = 'Objective Function'; -cost_fun.help = {'Registration involves finding parameters that either maximise or minimise some objective function. For inter-modal registration, use Mutual Information/* \cite{collignon95,wells96}*/, Normalised Mutual Information/* \cite{studholme99}*/, or Entropy Correlation Coefficient/* \cite{maes97}*/.For within modality, you could also use Normalised Cross Correlation.'}; +cost_fun.help = { + 'Registration involves finding parameters that either maximise or minimise some objective function.' + 'For inter-modal registration, use Mutual Information/* \cite{collignon95,wells96}*/, Normalised Mutual Information/* \cite{studholme99}*/, or Entropy Correlation Coefficient/* \cite{maes97}*/.' + 'For within modality, you could also use Normalised Cross Correlation.' + }'; cost_fun.labels = { 'Mutual Information' 'Normalised Mutual Information' @@ -70,7 +74,10 @@ sep = cfg_entry; sep.tag = 'sep'; sep.name = 'Separation'; -sep.help = {'The average distance between sampled points (in mm). Can be a vector to allow a coarse registration followed by increasingly fine ones.'}; +sep.help = { + 'The average distance between sampled points (in mm).' + 'Can be a vector to allow a coarse registration followed by increasingly fine ones.' + }'; sep.strtype = 'r'; sep.num = [1 Inf]; sep.def = @(val)spm_get_defaults('coreg.estimate.sep', val{:}); @@ -81,7 +88,10 @@ tol = cfg_entry; tol.tag = 'tol'; tol.name = 'Tolerances'; -tol.help = {'The accuracy for each parameter. Iterations stop when differences between successive estimates are less than the required tolerance.'}; +tol.help = { + 'The accuracy for each parameter.' + 'Iterations stop when differences between successive estimates are less than the required tolerance.' + }'; tol.strtype = 'r'; tol.num = [1 12]; tol.def = @(val)spm_get_defaults('coreg.estimate.tol', val{:}); @@ -92,7 +102,10 @@ fwhm = cfg_entry; fwhm.tag = 'fwhm'; fwhm.name = 'Histogram Smoothing'; -fwhm.help = {'Gaussian smoothing to apply to the 256x256 joint histogram. Other information theoretic coregistration methods use fewer bins, but Gaussian smoothing seems to be more elegant.'}; +fwhm.help = { + 'Gaussian smoothing to apply to the 256x256 joint histogram.' + 'Other information theoretic coregistration methods use fewer bins, but Gaussian smoothing seems to be more elegant.' + }'; fwhm.strtype = 'r'; fwhm.num = [1 2]; fwhm.def = @(val)spm_get_defaults('coreg.estimate.fwhm', val{:}); @@ -114,12 +127,14 @@ estimate.name = 'Coregister: Estimate'; estimate.val = {ref source other eoptions}; estimate.help = { - 'The registration method used here is based on work by Collignon et al/* \cite{collignon95}*/. The original interpolation method described in this paper has been changed in order to give a smoother cost function. The images are also smoothed slightly, as is the histogram. This is all in order to make the cost function as smooth as possible, to give faster convergence and less chance of local minima.' - '' - 'At the end of coregistration, the voxel-to-voxel affine transformation matrix is displayed, along with the histograms for the images in the original orientations, and the final orientations. The registered images are displayed at the bottom.' - '' - 'Registration parameters are stored in the headers of the "source" and the "other" images.' -}'; + 'Within-subject registration using a rigid-body model.' + '' + 'The registration method used here is based on work by Collignon et al/* \cite{collignon95}*/. The original interpolation method described in this paper has been changed in order to give a smoother cost function. The images are also smoothed slightly, as is the histogram. This is all in order to make the cost function as smooth as possible, to give faster convergence and less chance of local minima.' + '' + 'At the end of coregistration, the voxel-to-voxel affine transformation matrix is displayed, along with the histograms for the images in the original orientations, and the final orientations. The registered images are displayed at the bottom.' + '' + 'Registration parameters are stored in the headers of the "source" and the "other" images.' + }'; estimate.prog = @spm_run_coreg; estimate.vout = @vout_estimate; @@ -129,7 +144,7 @@ refwrite = cfg_files; refwrite.tag = 'ref'; refwrite.name = 'Image Defining Space'; -refwrite.help = {'This is analogous to the reference image. Images are resliced to match this image (providing they have been coregistered first).'}; +refwrite.help = {'This is analogous to the reference image. Images are resliced to match this image (providing they have been coregistered first).'}; refwrite.filter = 'image'; refwrite.ufilter = '.*'; refwrite.num = [1 1]; @@ -153,7 +168,10 @@ interp = cfg_menu; interp.tag = 'interp'; interp.name = 'Interpolation'; -interp.help = {'The method by which the images are sampled when being written in a different space. Nearest Neighbour is fastest, but not normally recommended. It can be useful for re-orienting images while preserving the original intensities (e.g. an image consisting of labels). Trilinear Interpolation is OK for PET, or realigned and re-sliced fMRI. If subject movement (from an fMRI time series) is included in the transformations then it may be better to use a higher degree approach. Note that higher degree B-spline interpolation/* \cite{thevenaz00a,unser93a,unser93b}*/ is slower because it uses more neighbours.'}; +interp.help = { + 'The method by which the images are sampled when being written in a different space.' + 'Nearest Neighbour is fastest, but not normally recommended. It can be useful for re-orienting images while preserving the original intensities (e.g. an image consisting of labels). Trilinear Interpolation is OK for PET, or realigned and re-sliced fMRI. If subject movement (from an fMRI time series) is included in the transformations then it may be better to use a higher degree approach. Note that higher degree B-spline interpolation/* \cite{thevenaz00a,unser93a,unser93b}*/ is slower because it uses more neighbours.' + }'; interp.labels = { 'Nearest neighbour' 'Trilinear' @@ -174,10 +192,11 @@ wrap.tag = 'wrap'; wrap.name = 'Wrapping'; wrap.help = { - 'These are typically:' - ' No wrapping - for PET or images that have already been spatially transformed.' - ' Wrap in Y - for (un-resliced) MRI where phase encoding is in the Y direction (voxel space).' -}'; + 'This indicates which directions in the volumes the values should wrap around in.' + 'These are typically:' + ' No wrapping - for PET or images that have already been spatially transformed.' + ' Wrap in Y - for (un-resliced) MRI where phase encoding is in the Y direction (voxel space).' + }'; wrap.labels = { 'No wrap' 'Wrap X' @@ -212,7 +231,7 @@ prefix = cfg_entry; prefix.tag = 'prefix'; prefix.name = 'Filename Prefix'; -prefix.help = {'Specify the string to be prepended to the filenames of the resliced image file(s). Default prefix is ''r''.'}; +prefix.help = {'String to be prepended to the filenames of the resliced image file(s). Default prefix is ''r''.'}; prefix.strtype = 's'; prefix.num = [1 Inf]; prefix.def = @(val)spm_get_defaults('coreg.write.prefix', val{:}); @@ -232,8 +251,11 @@ write = cfg_exbranch; write.tag = 'write'; write.name = 'Coregister: Reslice'; -write.val = {refwrite source roptions }; -write.help = {'Reslice images to match voxel-for-voxel with an image defining some space. The resliced images are named the same as the originals except that they are prefixed by ''r''.'}; +write.val = {refwrite source roptions}; +write.help = { + 'Reslice images to match voxel-for-voxel with an image defining some space.' + 'The resliced images are named the same as the originals except that they are prefixed by ''r''.' + }'; write.prog = @spm_run_coreg; write.vout = @vout_reslice; @@ -255,14 +277,16 @@ estwrite = cfg_exbranch; estwrite.tag = 'estwrite'; estwrite.name = 'Coregister: Estimate & Reslice'; -estwrite.val = {ref source other eoptions roptions }; +estwrite.val = {ref source other eoptions roptions}; estwrite.help = { - 'The registration method used here is based on work by Collignon et al/* \cite{collignon95}*/. The original interpolation method described in this paper has been changed in order to give a smoother cost function. The images are also smoothed slightly, as is the histogram. This is all in order to make the cost function as smooth as possible, to give faster convergence and less chance of local minima.' - '' - 'At the end of coregistration, the voxel-to-voxel affine transformation matrix is displayed, along with the histograms for the images in the original orientations, and the final orientations. The registered images are displayed at the bottom.' - '' - 'Registration parameters are stored in the headers of the "source" and the "other" images. These images are also resliced to match the source image voxel-for-voxel. The resliced images are named the same as the originals except that they are prefixed by ''r''.' -}'; + 'Within-subject registration using a rigid-body model and image reslicing.' + '' + 'The registration method used here is based on work by Collignon et al/* \cite{collignon95}*/. The original interpolation method described in this paper has been changed in order to give a smoother cost function. The images are also smoothed slightly, as is the histogram. This is all in order to make the cost function as smooth as possible, to give faster convergence and less chance of local minima.' + '' + 'At the end of coregistration, the voxel-to-voxel affine transformation matrix is displayed, along with the histograms for the images in the original orientations, and the final orientations. The registered images are displayed at the bottom.' + '' + 'Registration parameters are stored in the headers of the "source" and the "other" images. These images are also resliced to match the source image voxel-for-voxel. The resliced images are named the same as the originals except that they are prefixed by ''r''.' + }'; estwrite.prog = @spm_run_coreg; estwrite.vout = @vout_estwrite; @@ -273,10 +297,11 @@ coreg.tag = 'coreg'; coreg.name = 'Coregister'; coreg.help = { - 'Within-subject registration using a rigid-body model. A rigid-body transformation (in 3D) can be parameterised by three translations and three rotations about the different axes.' - '' - 'You get the options of estimating the transformation, reslicing images according to some rigid-body transformations, or estimating and applying rigid-body transformations.' -}'; + 'Within-subject registration using a rigid-body model.' + 'A rigid-body transformation (in 3D) can be parameterised by three translations and three rotations about the different axes.' + '' + 'You get the options of estimating the transformation, reslicing images according to some rigid-body transformations, or estimating and applying rigid-body transformations.' + }'; coreg.values = {estimate write estwrite}; %coreg.num = [1 Inf]; diff --git a/config/spm_cfg_dcm_bms.m b/config/spm_cfg_dcm_bms.m index 4d8dbd7e..a2234af5 100644 --- a/config/spm_cfg_dcm_bms.m +++ b/config/spm_cfg_dcm_bms.m @@ -4,7 +4,7 @@ % Copyright (C) 2008-2014 Wellcome Trust Centre for Neuroimaging % Maria Joao Rosa -% $Id: spm_cfg_dcm_bms.m 6642 2015-12-11 16:52:29Z peter $ +% $Id: spm_cfg_dcm_bms.m 6929 2016-11-14 13:07:31Z guillaume $ %-------------------------------------------------------------------------- % dir Directory @@ -161,7 +161,7 @@ '''F1'' and ''F2'' and assigns model 1, 4 and 5 to '... 'the first family and models 2 and 3 to the second '... 'family.']}; -family_file.val{1} = {''}; +family_file.val = {{''}}; family_file.filter = 'mat'; family_file.ufilter = '.*'; family_file.num = [0 1]; diff --git a/config/spm_cfg_dcm_est.m b/config/spm_cfg_dcm_est.m index 7871513d..b687051a 100644 --- a/config/spm_cfg_dcm_est.m +++ b/config/spm_cfg_dcm_est.m @@ -1,10 +1,10 @@ function estimate = spm_cfg_dcm_est % SPM Configuration file for DCM estimation %__________________________________________________________________________ -% Copyright (C) 2008-2014 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2008-2017 Wellcome Trust Centre for Neuroimaging % Guillaume Flandin & Peter Zeidman -% $Id: spm_cfg_dcm_est.m 6735 2016-03-02 15:40:47Z peter $ +% $Id: spm_cfg_dcm_est.m 7153 2017-08-10 10:18:14Z adeel $ % ------------------------------------------------------------------------- % dcmmat Select DCM_*.mat @@ -189,6 +189,7 @@ fmri.tag = 'fmri'; fmri.name = 'MRI specific options'; fmri.val = {fmri_analysis}; +fmri.help = {'MRI specific options'}; % ------------------------------------------------------------------------- % estimate Estimate @@ -210,7 +211,7 @@ est = cfg_choice; est.tag = 'est'; est.name = 'DCM estimation'; -est.help = {'Estimation of DCM models'}; +est.help = {'Estimation of Dynamic Causal Models.'}; est.values = { estimate }; %========================================================================== @@ -280,10 +281,7 @@ end P(:,m) = dcms.model(m).dcmmat; - end - - % Load all models into memory - GCM = spm_dcm_load(P); + end case INPUT_DCM_BY_SUBJECT ns = length(dcms.subj); @@ -299,25 +297,50 @@ P(s,:) = dcms.subj(s).dcmmat'; end - % Load all models into memory - GCM = spm_dcm_load(P); - case INPUT_GCM GCM = load(dcms.gcmmat{1}); GCM = GCM.GCM; ns = size(GCM,1); nm = size(GCM,2); + + if ischar(GCM{1}) + P = GCM; + else + P = ''; + end +end + +% Load all models into memory +if ~isempty(P) + GCM = spm_dcm_load(P); end % Set timeseries or CSD estimation (fMRI) for s = 1:ns for m = 1:nm if strcmpi(job.fmri.analysis,'CSD') - GCM{s,m}.options.analysis = 'CSD'; + GCM{s,m}.options = 'CSD'; + GCM{s,m}.options.induced = 1; + GCM{s,m}.options.stochastic = 0; else if isfield(GCM{s,m},'options') && isfield(GCM{s,m},'analysis') GCM{s,m}.options = rmfield(GCM{s,m}.options,'analysis'); end + GCM{s,m}.options.induced = 0; + end + end +end + +% Check that models 2-N are nested forms of the full model +if nm > 1 && (est_type == EST_FULL_BMR || est_type == EST_FULL_BMR_PEB) + idx1 = spm_find_pC(GCM{1}); + for m = 2:nm + idx = spm_find_pC(GCM{1,m}); + if any(setdiff(idx,idx1)) + error(['Model %d is not a nested model of model 1. This is ' ... + 'required for Bayesian Model Reduction (BMR). Please ' ... + 'introduce a full model as Model 1, or switch estimation ' ... + 'type to ''full'''],m); end end end @@ -338,36 +361,41 @@ % Do nothing end -% Save +% Save individual DCM .mat files if requested +if ~isempty(P) && (est_type == OUTPUT_DCM) + for s = 1:ns + for m = 1:nm + DCM = GCM{s,m}; + F = DCM.F; + Ep = DCM.Ep; + Cp = DCM.Cp; + save(P{s,m}, 'DCM', 'F', 'Ep', 'Cp', ... + spm_get_defaults('mat.format')); + end + end +end + +% If filenames were provided, set the GCM to contain the filenames +if ~isempty(P) + GCM = P; %#ok +end + +% Save GCM if output_type == OUTPUT_GCM_NEW - % Create single mat file + % Create single GCM mat file dir = job.output.single.dir{1}; - name = ['GCM_' job.output.single.name '.mat']; - + name = ['GCM_' job.output.single.name '.mat']; filename = fullfile(dir,name); - save(filename,'GCM'); + save(filename,'GCM', spm_get_defaults('mat.format')); out.gcmmat = {filename}; elseif output_type == OUTPUT_GCM_OVERWRITE % Update existing gcm file - filename = dcms.gcmmat{1}; - - save(filename,'GCM'); + filename = dcms.gcmmat{1}; + save(filename,'GCM', spm_get_defaults('mat.format')); out.gcmmat = {filename}; else - % Update existing mat files - if (est_type ~= EST_NONE) - for s = 1:ns - for m = 1:nm - DCM = GCM{s,m}; - F = DCM.F; - Ep = DCM.Ep; - Cp = DCM.Cp; - save(P{s,m}, 'DCM', 'F', 'Ep', 'Cp'); - end - end - end out.dcmmat = P; end diff --git a/config/spm_cfg_dcm_fmri.m b/config/spm_cfg_dcm_fmri.m index 02573c4f..f5ea242d 100644 --- a/config/spm_cfg_dcm_fmri.m +++ b/config/spm_cfg_dcm_fmri.m @@ -1,10 +1,11 @@ function fmri = spm_cfg_dcm_fmri % SPM Configuration file for DCM for fMRI %__________________________________________________________________________ -% Copyright (C) 2008-2014 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2008-2016 Wellcome Trust Centre for Neuroimaging % Guillaume Flandin & Peter Zeidman -% $Id: spm_cfg_dcm_fmri.m 6711 2016-02-03 15:25:43Z peter $ +% $Id: spm_cfg_dcm_fmri.m 6952 2016-11-25 16:03:13Z guillaume $ + % ------------------------------------------------------------------------- % dcmmat Select DCM_*.mat @@ -46,7 +47,7 @@ session.tag = 'session'; session.name = 'Which session'; session.help = {'Enter the session number.'}; -session.strtype = 'e'; +session.strtype = 'n'; session.num = [1 1]; %-------------------------------------------------------------------------- @@ -70,7 +71,7 @@ 'to include this condition (with no parameteric regressor). '... 'Entering [1 0 1] would include this condition and '... 'its second parametric regressor.'}; -val.strtype = 'e'; +val.strtype = 'w'; val.num = [1 Inf]; % ------------------------------------------------------------------------- @@ -93,7 +94,7 @@ model.tag = 'model'; model.name = 'Model'; model.val = {dcmmat}; -model.help = {'Corresponding model for each subject'}; +model.help = {'Corresponding model for each subject.'}; % ------------------------------------------------------------------------- % subjects Create set of models @@ -102,7 +103,7 @@ models.tag = 'models'; models.name = 'Per model'; models.values = {model}; -models.help = {'Select DCM.mat files per model'}; +models.help = {'Select DCM.mat files per model.'}; models.num = [1 Inf]; % ------------------------------------------------------------------------- @@ -112,7 +113,7 @@ regions.tag = 'regions'; regions.name = 'Region specification'; regions.val = { dcmmat voimat }; -regions.help = {'Insert new regions into a DCM model. '... +regions.help = {'Insert new regions into a DCM model.'... '' ... 'The RT is assumed to be the same as before. '... ''... @@ -129,7 +130,7 @@ inputs.tag = 'inputs'; inputs.name = 'Input specification'; inputs.val = { dcmmat spmmat session inp }; -inputs.help = {'Insert new inputs into a DCM model'... +inputs.help = {'Insert new inputs into a DCM model.'... ''... ['This functionality can be used, for example, to replace subject X''s '... 'inputs by subject Y''s. The model can then be re-estimated without '... @@ -169,4 +170,4 @@ dep(1) = cfg_dep; dep(1).sname = 'DCM mat File(s)'; dep(1).src_output = substruct('.','dcmmat'); -dep(1).tgt_spec = cfg_findspec({{'filter','mat','strtype','e'}}); \ No newline at end of file +dep(1).tgt_spec = cfg_findspec({{'filter','mat','strtype','e'}}); diff --git a/config/spm_cfg_dcm_peb.m b/config/spm_cfg_dcm_peb.m index 8aa8c44f..50a97977 100644 --- a/config/spm_cfg_dcm_peb.m +++ b/config/spm_cfg_dcm_peb.m @@ -1,10 +1,10 @@ function second_level = spm_cfg_dcm_peb % SPM Configuration file for second-level DCM (PEB) %__________________________________________________________________________ -% Copyright (C) 2016 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2016-2017 Wellcome Trust Centre for Neuroimaging % Peter Zeidman -% $Id: spm_cfg_dcm_peb.m 6784 2016-04-27 13:12:05Z peter $ +% $Id: spm_cfg_dcm_peb.m 7007 2017-02-07 10:15:24Z guillaume $ %========================================================================== @@ -145,7 +145,7 @@ regressor.tag = 'regressor'; regressor.name = 'Covariate'; regressor.val = {cov_name cov_val }; -regressor.help = {'regressor'}; +regressor.help = {'Regressor.'}; %-------------------------------------------------------------------------- % covariate Specify design matrix per covariate @@ -168,7 +168,7 @@ cov_none.name = 'None'; cov_none.val = {}; cov_none.help = {'Include no covariates (only the group mean for each '... - 'connection)'}; + 'connection).'}; %-------------------------------------------------------------------------- % covariates Covariates branch @@ -195,18 +195,20 @@ %-------------------------------------------------------------------------- % field_default Select fields A,B %-------------------------------------------------------------------------- -field_default = cfg_const; +field_default = cfg_const; field_default.tag = 'default'; field_default.name = 'A- and B-matrix'; -field_default.val = {{'A','B'}}; +field_default.val = {{'A','B'}}; +field_default.help = {'A- and B-matrix.'}; %-------------------------------------------------------------------------- % field_all Select all fields %-------------------------------------------------------------------------- -field_all = cfg_const; +field_all = cfg_const; field_all.tag = 'all'; field_all.name = 'All'; -field_all.val = {'All fields'}; +field_all.val = {'All fields'}; +field_all.help = {'All fields.'}; %-------------------------------------------------------------------------- % field_entry Custom field entry @@ -222,7 +224,7 @@ %-------------------------------------------------------------------------- % fields DCM fields to include %-------------------------------------------------------------------------- -fields = cfg_choice; +fields = cfg_choice; fields.tag = 'fields'; fields.name = 'Fields'; fields.values = {field_default field_all field_entry}; @@ -243,6 +245,7 @@ dcm_all.tag = 'all'; dcm_all.name = 'All'; dcm_all.val = {'All DCMs'}; +dcm_all.help = {'All DCMs.'}; %-------------------------------------------------------------------------- % dcm_idx Single DCM index selection @@ -262,7 +265,7 @@ dcm_idx_1 = dcm_sel_idx; dcm_idx_1.val = {1}; -dcm_idx = cfg_choice; +dcm_idx = cfg_choice; dcm_idx.tag = 'dcm'; dcm_idx.name = 'DCM index'; dcm_idx.values = {dcm_idx_1 dcm_all}; @@ -279,7 +282,7 @@ %-------------------------------------------------------------------------- % priors_log_precision_mu Priors on log precision expectation %-------------------------------------------------------------------------- -priors_log_precision_mu = cfg_entry; +priors_log_precision_mu = cfg_entry; priors_log_precision_mu.name = 'Expectation'; priors_log_precision_mu.tag = 'expectation'; priors_log_precision_mu.help = {['Prior expectation of the log precision ' ... @@ -292,7 +295,7 @@ %-------------------------------------------------------------------------- % priors_log_precision_var Priors on log precision variance %-------------------------------------------------------------------------- -priors_log_precision_var = cfg_entry; +priors_log_precision_var = cfg_entry; priors_log_precision_var.name = 'Uncertainty'; priors_log_precision_var.tag = 'var'; priors_log_precision_var.help = {['Uncertainty over the prior expectation ' ... @@ -305,7 +308,7 @@ %-------------------------------------------------------------------------- % group priors_parameters_ratio Priors on log precision variance %-------------------------------------------------------------------------- -group_priors_parameters_ratio = cfg_entry; +group_priors_parameters_ratio = cfg_entry; group_priors_parameters_ratio.name = 'Group ratio'; group_priors_parameters_ratio.tag = 'group_ratio'; group_priors_parameters_ratio.help = {['The group ratio (M.alpha) expresses ' ... @@ -341,13 +344,13 @@ %-------------------------------------------------------------------------- % priors_between Priors on log precision branch %-------------------------------------------------------------------------- -priors_between = cfg_branch; -priors_between.tag = 'priors_between'; -priors_between.name = 'Between-subjects variability'; -priors_between.val = { priors_parameters_ratio ... - priors_log_precision_mu ... - priors_log_precision_var}; -priors_between.help = {['Between-subjects variability over second-' ... +priors_between = cfg_branch; +priors_between.tag = 'priors_between'; +priors_between.name = 'Between-subjects variability'; +priors_between.val = { priors_parameters_ratio ... + priors_log_precision_mu ... + priors_log_precision_var}; +priors_between.help = {['Between-subjects variability over second-' ... 'level parameters.'], '' ... ['A multi-component model is used. Each component is a ' ... '[p x p] precision matrix given p DCM parameters, where elements on ' ... @@ -378,13 +381,14 @@ show_review.labels = {'Yes','No'}; show_review.values = {1,0}; show_review.val = {1}; +show_review.help = {'Review PEB parameters'}; %========================================================================== % PEB specification batch %========================================================================== % Set show review default to off -sr = show_review; -sr.val = {0}; +sr = show_review; +sr.val = {0}; specify = cfg_exbranch; specify.tag = 'specify'; @@ -543,7 +547,7 @@ % Write PEB peb_filename = fullfile(dir_out,['PEB_' name '.mat']); -save(peb_filename,'PEB'); +save(peb_filename,'PEB', spm_get_defaults('mat.format')); % Review PEB if job.show_review == 1 @@ -566,7 +570,7 @@ name = job.name; loo_filename = fullfile(dir_out,['LOO_' name '.mat']); -save(loo_filename,'qE','qC','Q'); +save(loo_filename,'qE','qC','Q', spm_get_defaults('mat.format')); out.loo_mat = {loo_filename}; @@ -703,7 +707,7 @@ % Write BMA [dir_out, name] = fileparts(job.peb_mat{1}); filename = fullfile(dir_out, ['BMA_' name '.mat']); -save(filename,'BMA'); +save(filename,'BMA', spm_get_defaults('mat.format')); out.bmamat = filename; @@ -728,7 +732,7 @@ %========================================================================== % Load and validate selected model space -gcm_file = job.model_space_mat{1}; +gcm_file = char(job.model_space_mat); GCM = load(gcm_file); if ~isfield(GCM,'GCM') error('Provided file is not a valid model space.'); diff --git a/config/spm_cfg_deface.m b/config/spm_cfg_deface.m index 2ef8bed7..62762824 100644 --- a/config/spm_cfg_deface.m +++ b/config/spm_cfg_deface.m @@ -1,10 +1,10 @@ function job = spm_cfg_deface % SPM Configuration file for toolbox 'De-Face' %__________________________________________________________________________ -% Copyright (C) 2013-2014 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2013-2016 Wellcome Trust Centre for Neuroimaging % John Ashburner -% $Id: spm_cfg_deface.m 6086 2014-07-03 16:08:44Z guillaume $ +% $Id: spm_cfg_deface.m 6952 2016-11-25 16:03:13Z guillaume $ %-------------------------------------------------------------------------- @@ -25,8 +25,10 @@ job.tag = 'deface'; job.name = 'De-face Images'; job.val = {images}; -job.help = {'This is a little routine for attempting to strip the face from images, so individuals are more difficult to identify from surface renderings.',... - 'De-faced images are prefixed by ''anon_''.'}; +job.help = { + 'Strip the face from images, so individuals are more difficult to identify from surface renderings.' + 'De-faced images are prefixed by ''anon_''.' + }'; job.prog = @spm_deface; job.vout = @vout; diff --git a/config/spm_cfg_deformations.m b/config/spm_cfg_deformations.m index 680fe3ec..e7ddf7b3 100644 --- a/config/spm_cfg_deformations.m +++ b/config/spm_cfg_deformations.m @@ -1,14 +1,14 @@ function conf = spm_cfg_deformations % Configuration file for deformation jobs %_______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2008-2016 Wellcome Trust Centre for Neuroimaging % John Ashburner -% $Id: spm_cfg_deformations.m 6578 2015-10-15 15:22:12Z volkmar $ +% $Id: spm_cfg_deformations.m 6952 2016-11-25 16:03:13Z guillaume $ -hsummary = {[... -'This is a utility for working with deformation fields. ',... -'They can be loaded, inverted, combined etc, and the results ',... +hsummary = { +'Utility for working with deformation fields.',... +['They can be loaded, inverted, combined etc, and the results ',... 'either saved to disk, or applied to some image or surface file. ',... 'This utility was intended for imaging experts and may therefore ',... 'be a bit difficult for naive users. ',... @@ -436,11 +436,9 @@ conf.prog = @spm_deformations; conf.vout = @vout; conf.help = hsummary; -return; -%_______________________________________________________________________ -%_______________________________________________________________________ +%========================================================================== function vo = vout(job) vo = []; savedef = false; @@ -449,28 +447,28 @@ savejac = false; for i=1:numel(job.out) out = job.out{i}; - if isfield(out,'savedef') && ~savedef, + if isfield(out,'savedef') && ~savedef savedef = true; if isempty(vo), vo = cfg_dep; else vo(end+1) = cfg_dep; end vo(end).sname = 'Deformation'; vo(end).src_output = substruct('.','def'); vo(end).tgt_spec = cfg_findspec({{'filter','nifti'}}); end - if (isfield(out,'pull') || isfield(out,'push')) && ~saveimage, + if (isfield(out,'pull') || isfield(out,'push')) && ~saveimage saveimage = true; if isempty(vo), vo = cfg_dep; else vo(end+1) = cfg_dep; end vo(end).sname = 'Warped Images'; vo(end).src_output = substruct('.','warped'); vo(end).tgt_spec = cfg_findspec({{'filter','image'}}); end - if isfield(out,'surf') && ~savesurf, + if isfield(out,'surf') && ~savesurf savesurf = true; if isempty(vo), vo = cfg_dep; else vo(end+1) = cfg_dep; end vo(end).sname = 'Warped Surfaces'; vo(end).src_output = substruct('.','surf'); vo(end).tgt_spec = cfg_findspec({{'filter','mesh'}}); end - if isfield(out,'savejac') && ~savejac, + if isfield(out,'savejac') && ~savejac savejac = true; if isempty(vo), vo = cfg_dep; else vo(end+1) = cfg_dep; end vo(end).sname = 'Jacobian'; @@ -478,10 +476,9 @@ vo(end).tgt_spec = cfg_findspec({{'filter','image'}}); end end -return; -%_______________________________________________________________________ -%_______________________________________________________________________ + +%========================================================================== function entry_item = entry(name, tag, strtype, num) entry_item = cfg_entry; entry_item.name = name; diff --git a/config/spm_cfg_dicom.m b/config/spm_cfg_dicom.m index ebca419e..a4f2a926 100644 --- a/config/spm_cfg_dicom.m +++ b/config/spm_cfg_dicom.m @@ -1,13 +1,13 @@ function dicom = spm_cfg_dicom % SPM Configuration file for DICOM Import -%_______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging -% $Id: spm_cfg_dicom.m 6376 2015-03-12 15:15:57Z john $ +% $Id: spm_cfg_dicom.m 7201 2017-11-08 11:13:25Z guillaume $ -% --------------------------------------------------------------------- +%------------------------------------------------------------------------- % data DICOM files -% --------------------------------------------------------------------- +%-------------------------------------------------------------------------- data = cfg_files; data.tag = 'data'; data.name = 'DICOM files'; @@ -15,19 +15,33 @@ data.filter = 'any'; data.ufilter = '.*'; data.num = [1 Inf]; -% --------------------------------------------------------------------- -% root Directory structure for converted files -% --------------------------------------------------------------------- + +%-------------------------------------------------------------------------- +% outdir Output directory +%-------------------------------------------------------------------------- +outdir = cfg_files; +outdir.tag = 'outdir'; +outdir.name = 'Output directory'; +outdir.val{1} = {''}; +outdir.help = {'Files produced by this function will be written into this output directory. If no directory is given, images will be written to current working directory.'}; +outdir.filter = 'dir'; +outdir.ufilter = '.*'; +outdir.num = [0 1]; + +%-------------------------------------------------------------------------- +% root Directory structure +%-------------------------------------------------------------------------- root = cfg_menu; root.tag = 'root'; -root.name = 'Directory structure for converted files'; +root.name = 'Directory structure'; root.help = {'Choose root directory of converted file tree. The options are:' '' '* Output directory: ./: Automatically determine the project name and try to convert into the output directory, starting with a StudyDate-StudyTime subdirectory. This option is useful if automatic project recognition fails and one wants to convert data into a project directory.' '' '* Output directory: ./: Convert into the output directory, starting with a PatientID subdirectory.' '' - '* Output directory: ./: Convert into the output directory, starting with a PatientName subdirectory.' + '* Output directory: ./: Convert into the output directory, starting with a ProtocolName subdirectory.' + '' '* No directory hierarchy: Convert all files into the output directory, without sequence/series subdirectories'}'; root.labels = {'Output directory: .//' 'Output directory: .//' @@ -41,19 +55,10 @@ 'series' 'flat'}'; root.def = @(val)spm_get_defaults('dicom.root', val{:}); -% --------------------------------------------------------------------- -% outdir Output directory -% --------------------------------------------------------------------- -outdir = cfg_files; -outdir.tag = 'outdir'; -outdir.name = 'Output directory'; -outdir.help = {'Select a directory where files are written.'}; -outdir.filter = 'dir'; -outdir.ufilter = '.*'; -outdir.num = [1 1]; -% --------------------------------------------------------------------- + +%-------------------------------------------------------------------------- % protfilter Protocol name filter -% --------------------------------------------------------------------- +%-------------------------------------------------------------------------- protfilter = cfg_entry; protfilter.tag = 'protfilter'; protfilter.name = 'Protocol name filter'; @@ -61,21 +66,34 @@ protfilter.strtype = 's'; protfilter.num = [0 Inf]; protfilter.val = {'.*'}; -% --------------------------------------------------------------------- + +%-------------------------------------------------------------------------- % format Output image format -% --------------------------------------------------------------------- +%-------------------------------------------------------------------------- format = cfg_menu; format.tag = 'format'; format.name = 'Output image format'; -format.help = {'DICOM conversion can create separate img and hdr files or combine them in one file. The single file option will help you save space on your hard disk, but may be incompatible with programs that are not NIfTI-aware.' +format.help = {'Output files can be written as .img + .hdr, or the two can be combined into a single .nii file.' 'In any case, only 3D image files will be produced.'}'; format.labels = {'Two file (img+hdr) NIfTI' 'Single file (nii) NIfTI'}'; format.values = {'img' 'nii'}; format.def = @(val)spm_get_defaults('images.format', val{:}); -% --------------------------------------------------------------------- + +%-------------------------------------------------------------------------- +% meta Export metadata +%-------------------------------------------------------------------------- +meta = cfg_menu; +meta.tag = 'meta'; +meta.name = 'Export metadata'; +meta.help = {'Save DICOM fields in a sidecar JSON file.'}; +meta.labels = {'No', 'Yes'}; +meta.values = {0 1}; +meta.val = {0}; + +%-------------------------------------------------------------------------- % icedims Use ICEDims in filename -% --------------------------------------------------------------------- +%-------------------------------------------------------------------------- icedims = cfg_menu; icedims.tag = 'icedims'; icedims.name = 'Use ICEDims in filename'; @@ -83,27 +101,32 @@ icedims.labels = {'No' 'Yes'}; icedims.values = {0 1}; icedims.val = {0}; -% --------------------------------------------------------------------- + +%-------------------------------------------------------------------------- % convopts Conversion options -% --------------------------------------------------------------------- +%-------------------------------------------------------------------------- convopts = cfg_branch; convopts.tag = 'convopts'; convopts.name = 'Conversion options'; -convopts.val = {format icedims}; +convopts.val = {format meta icedims}; convopts.help = {''}; -% --------------------------------------------------------------------- + +%-------------------------------------------------------------------------- % dicom DICOM Import -% --------------------------------------------------------------------- +%-------------------------------------------------------------------------- dicom = cfg_exbranch; dicom.tag = 'dicom'; dicom.name = 'DICOM Import'; dicom.val = {data root outdir protfilter convopts}; -dicom.help = {'DICOM Conversion. Most scanners produce data in DICOM format. This routine attempts to convert DICOM files into SPM compatible image volumes, which are written into the current directory by default. Note that not all flavours of DICOM can be handled, as DICOM is a very complicated format, and some scanner manufacturers use their own fields, which are not in the official documentation at http://medical.nema.org/'}; +dicom.help = { + 'DICOM Conversion.' + 'Most scanners produce data in DICOM format. This routine attempts to convert DICOM files into SPM compatible image volumes, which are written into the current directory by default. Note that not all flavours of DICOM can be handled, as DICOM is a very complicated format, and some scanner manufacturers use their own fields, which are not in the official documentation at http://medical.nema.org/' + }'; dicom.prog = @spm_run_dicom; dicom.vout = @vout; -% --------------------------------------------------------------------- -% --------------------------------------------------------------------- + +%========================================================================== function dep = vout(job) dep = cfg_dep; dep.sname = 'Converted Images'; diff --git a/config/spm_cfg_disp.m b/config/spm_cfg_disp.m index fc709dc9..72400d0a 100644 --- a/config/spm_cfg_disp.m +++ b/config/spm_cfg_disp.m @@ -1,9 +1,10 @@ function disp = spm_cfg_disp % SPM Configuration file for Image Display %__________________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2008-2016 Wellcome Trust Centre for Neuroimaging + +% $Id: spm_cfg_disp.m 6952 2016-11-25 16:03:13Z guillaume $ -% $Id: spm_cfg_disp.m 4205 2011-02-21 15:39:08Z guillaume $ %------------------------------------------------------------------------- % data Image to Display @@ -24,32 +25,33 @@ disp.name = 'Display Image'; disp.val = {data}; disp.help = { - 'This is an interactive facility that allows orthogonal sections from an image volume to be displayed. Clicking the cursor on either of the three images moves the point around which the orthogonal sections are viewed. The co-ordinates of the cursor are shown both in voxel co-ordinates and millimetres within some fixed framework. The intensity at that point in the image (sampled using the current interpolation scheme) is also given. The position of the cross-hairs can also be moved by specifying the co-ordinates in millimetres to which they should be moved. Clicking on the horizontal bar above these boxes will move the cursor back to the origin (analogous to setting the cross-hair position (in mm) to [0 0 0]).' - '' - 'The images can be re-oriented by entering appropriate translations, rotations and zooms into the panel on the left. The transformations can then be saved by hitting the "Reorient images..." button. The transformations that were applied to the image are saved to the header information of the selected images. The transformations are considered to be relative to any existing transformations that may be stored. Note that the order that the transformations are applied in is the same as in spm_matrix.m.' - '' - 'The "Reset..." button next to it is for setting the orientation of images back to transverse. It retains the current voxel sizes, but sets the origin of the images to be the centre of the volumes and all rotations back to zero.' - '' - 'The right panel shows miscellaneous information about the image. This includes:' - ' Dimensions - the x, y and z dimensions of the image.' - ' Datatype - the computer representation of each voxel.' - ' Intensity - scale-factors and possibly a DC offset.' - ' Miscellaneous other information about the image.' - ' Vox size - the distance (in mm) between the centres of neighbouring voxels.' - ' Origin - the voxel at the origin of the co-ordinate system' - ' DIr Cos - Direction cosines. This is a widely used representation of the orientation of an image.' - '' - 'There are also a few options for different resampling modes, zooms etc. You can also flip between voxel space (as would be displayed by Analyze) or world space (the orientation that SPM considers the image to be in). If you are re-orienting the images, make sure that world space is specified. Blobs (from activation studies) can be superimposed on the images and the intensity windowing can also be changed.' - '' - '' - 'If you have put your images in the correct file format, then (possibly after specifying some rigid-body rotations):' - ' The top-left image is coronal with the top (superior) of the head displayed at the top and the left shown on the left. This is as if the subject is viewed from behind.' - ' The bottom-left image is axial with the front (anterior) of the head at the top and the left shown on the left. This is as if the subject is viewed from above.' - ' The top-right image is sagittal with the front (anterior) of the head at the left and the top of the head shown at the top. This is as if the subject is viewed from the left.' - '/*\begin{figure} \begin{center} \includegraphics[width=150mm]{images/disp1} \end{center} \caption{The Display routine. \label{disp1}}\end{figure} */' -}'; + 'Interactive display of the orthogonal sections from an image volume.' + 'Clicking the cursor on either of the three images moves the point around which the orthogonal sections are viewed. The co-ordinates of the cursor are shown both in voxel co-ordinates and millimetres within some fixed framework. The intensity at that point in the image (sampled using the current interpolation scheme) is also given. The position of the cross-hairs can also be moved by specifying the co-ordinates in millimetres to which they should be moved. Clicking on the horizontal bar above these boxes will move the cursor back to the origin (analogous to setting the cross-hair position (in mm) to [0 0 0]).' + '' + 'The images can be re-oriented by entering appropriate translations, rotations and zooms into the panel on the left. The transformations can then be saved by hitting the "Reorient images..." button. The transformations that were applied to the image are saved to the header information of the selected images. The transformations are considered to be relative to any existing transformations that may be stored. Note that the order that the transformations are applied in is the same as in spm_matrix.m.' + '' + 'The "Reset..." button next to it is for setting the orientation of images back to transverse. It retains the current voxel sizes, but sets the origin of the images to be the centre of the volumes and all rotations back to zero.' + '' + 'The right panel shows miscellaneous information about the image. This includes:' + ' Dimensions - the x, y and z dimensions of the image.' + ' Datatype - the computer representation of each voxel.' + ' Intensity - scale-factors and possibly a DC offset.' + ' Miscellaneous other information about the image.' + ' Vox size - the distance (in mm) between the centres of neighbouring voxels.' + ' Origin - the voxel at the origin of the co-ordinate system' + ' DIr Cos - Direction cosines. This is a widely used representation of the orientation of an image.' + '' + 'There are also a few options for different resampling modes, zooms etc. You can also flip between voxel space (as would be displayed by Analyze) or world space (the orientation that SPM considers the image to be in). If you are re-orienting the images, make sure that world space is specified. Blobs (from activation studies) can be superimposed on the images and the intensity windowing can also be changed.' + '' + 'If you have put your images in the correct file format, then (possibly after specifying some rigid-body rotations):' + ' The top-left image is coronal with the top (superior) of the head displayed at the top and the left shown on the left. This is as if the subject is viewed from behind.' + ' The bottom-left image is axial with the front (anterior) of the head at the top and the left shown on the left. This is as if the subject is viewed from above.' + ' The top-right image is sagittal with the front (anterior) of the head at the left and the top of the head shown at the top. This is as if the subject is viewed from the left.' + '/*\begin{figure} \begin{center} \includegraphics[width=150mm]{images/disp1} \end{center} \caption{The Display routine. \label{disp1}}\end{figure} */' + }'; disp.prog = @disp_image; + %========================================================================== function disp_image(job) spm_image('Init', job.data{1}); diff --git a/config/spm_cfg_ecat.m b/config/spm_cfg_ecat.m index 7d80b33d..efc6b62e 100644 --- a/config/spm_cfg_ecat.m +++ b/config/spm_cfg_ecat.m @@ -3,7 +3,7 @@ %__________________________________________________________________________ % Copyright (C) 2005-2011 Wellcome Trust Centre for Neuroimaging -% $Id: spm_cfg_ecat.m 4466 2011-09-07 16:50:29Z guillaume $ +% $Id: spm_cfg_ecat.m 6952 2016-11-25 16:03:13Z guillaume $ %-------------------------------------------------------------------------- @@ -47,7 +47,10 @@ ecat.tag = 'ecat'; ecat.name = 'ECAT Import'; ecat.val = {data opts }; -ecat.help = {'ECAT 7 Conversion. ECAT 7 is the image data format used by the more recent CTI PET scanners.'}; +ecat.help = { + 'ECAT 7 Conversion.' + 'ECAT 7 is the image data format used by the more recent CTI PET scanners.' + }'; ecat.prog = @convert_ecat; ecat.vout = @vout; ecat.modality = {'PET'}; diff --git a/config/spm_cfg_eeg.m b/config/spm_cfg_eeg.m index 79fda0c6..3a158a07 100644 --- a/config/spm_cfg_eeg.m +++ b/config/spm_cfg_eeg.m @@ -3,7 +3,7 @@ %__________________________________________________________________________ % Copyright (C) 2008-2014 Wellcome Trust Centre for Neuroimaging -% $Id: spm_cfg_eeg.m 6878 2016-09-16 07:57:06Z gareth $ +% $Id: spm_cfg_eeg.m 7206 2017-11-09 16:27:30Z gareth $ %-------------------------------------------------------------------------- % M/EEG preprocessing @@ -15,7 +15,8 @@ meegprep.values = {spm_cfg_eeg_epochs spm_cfg_eeg_prepare spm_cfg_eeg_montage spm_cfg_eeg_filter... spm_cfg_eeg_bc spm_cfg_eeg_artefact spm_cfg_eeg_downsample spm_cfg_eeg_merge... spm_cfg_eeg_fuse spm_cfg_eeg_combineplanar spm_cfg_eeg_reduce spm_cfg_eeg_crop... - spm_cfg_eeg_remove_bad_trials spm_cfg_eeg_spatial_confounds spm_cfg_eeg_correct_sensor_data}; + spm_cfg_eeg_remove_bad_trials spm_cfg_eeg_spatial_confounds spm_cfg_eeg_correct_sensor_data... + spm_cfg_eeg_opmsetup}; %-------------------------------------------------------------------------- % M/EEG averaging @@ -52,7 +53,7 @@ source.name = 'Source reconstruction'; source.help = {'M/EEG source reconstruction.'}; %source.values = { spm_cfg_eeg_inv_headmodel, spm_cfg_eeg_inv_headmodelhelmet, spm_cfg_eeg_inv_invert, spm_cfg_eeg_inv_invertiter ,spm_cfg_eeg_inv_simulate,spm_cfg_eeg_inv_mix, spm_cfg_eeg_inv_results, spm_cfg_eeg_inv_extract,spm_cfg_eeg_inv_coregshift,spm_cfg_eeg_inv_sensorshift, spm_cfg_eeg_inv_post, spm_cfg_eeg_inv_patchdef, spm_cfg_eeg_inv_prepro, spm_cfg_eeg_inv_priors,spm_cfg_eeg_inv_optimize}; -source.values = { spm_cfg_eeg_inv_headmodel, spm_cfg_eeg_inv_headmodelhelmet, spm_cfg_eeg_inv_invert, spm_cfg_eeg_inv_invertiter ,spm_cfg_eeg_inv_simulate,spm_cfg_eeg_inv_mix, spm_cfg_eeg_inv_results, spm_cfg_eeg_inv_extract,spm_cfg_eeg_inv_coregshift,spm_cfg_eeg_inv_sensorshift}; +source.values = { spm_cfg_eeg_inv_headmodel, spm_cfg_eeg_inv_headmodelhelmet, spm_cfg_eeg_inv_invert, spm_cfg_eeg_inv_invertiter ,spm_cfg_eeg_inv_simulate,spm_cfg_eeg_inv_mix, spm_cfg_eeg_inv_results, spm_cfg_eeg_inv_extract,spm_cfg_eeg_inv_coregshift,spm_cfg_eeg_inv_sensorshift, spm_cfg_eeg_dipfit}; %-------------------------------------------------------------------------- % M/EEG Modelling diff --git a/config/spm_cfg_eeg_artefact.m b/config/spm_cfg_eeg_artefact.m index d61f8b1a..7f338e50 100644 --- a/config/spm_cfg_eeg_artefact.m +++ b/config/spm_cfg_eeg_artefact.m @@ -1,10 +1,10 @@ function artefact = spm_cfg_eeg_artefact % Configuration file for M/EEG artefact detection %__________________________________________________________________________ -% Copyright (C) 2008-2012 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2008-2016 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_cfg_eeg_artefact.m 5592 2013-07-24 16:25:55Z vladimir $ +% $Id: spm_cfg_eeg_artefact.m 7085 2017-06-01 10:42:01Z vladimir $ %-------------------------------------------------------------------------- @@ -27,7 +27,7 @@ mode.val = {'reject'}; mode.values = {'reject', 'mark'}; mode.help = {'Action mode reject - to set trials and channels as bad',... - 'mark - just create artefact events, set channels as bad if mostly artefactual'}; + 'mark - just create artefact events, set channels as bad if mostly artefactual.'}; %-------------------------------------------------------------------------- % badchanthresh @@ -50,14 +50,17 @@ fun = cfg_choice; fun.tag = 'fun'; fun.name = 'Detection algorithm'; +fun.values = cell(1,numel(artefact_funs)); for i = 1:numel(artefact_funs) fun.values{i} = feval(spm_file(artefact_funs{i},'basename')); end +fun.help = {''}; methods = cfg_branch; methods.tag = 'methods'; methods.name = 'Method'; methods.val = {spm_cfg_eeg_channel_selector, fun}; +methods.help = {''}; %-------------------------------------------------------------------------- % methodsrep @@ -65,7 +68,7 @@ methodsrep = cfg_repeat; methodsrep.tag = 'methodsrep'; methodsrep.name = 'How to look for artefacts'; -methodsrep.help = {'Choose channels and methods for artefact detection'}; +methodsrep.help = {'Choose channels and methods for artefact detection.'}; methodsrep.values = {methods}; methodsrep.num = [1 Inf]; @@ -89,7 +92,7 @@ append.labels = {'yes', 'no'}; append.val = {true}; append.values = {true, false}; -append.help = {'Append new artefacts to already marked or overwrite'}; +append.help = {'Append new artefacts to already marked or overwrite.'}; %-------------------------------------------------------------------------- % M/EEG Artefact detection @@ -111,6 +114,8 @@ S.D = job.D{1}; S.mode = job.mode; S.badchanthresh = job.badchanthresh; +S.prefix = job.prefix; +S.append = job.append; for i = 1:numel(job.methods) S.methods(i).channels = spm_cfg_eeg_channel_selector(job.methods(i).channels); diff --git a/config/spm_cfg_eeg_average.m b/config/spm_cfg_eeg_average.m index 5615aed4..d4257ff1 100644 --- a/config/spm_cfg_eeg_average.m +++ b/config/spm_cfg_eeg_average.m @@ -1,12 +1,12 @@ function average = spm_cfg_eeg_average -% configuration file for M/EEG epoching -%_______________________________________________________________________ -% Copyright (C) 2008-2012 Wellcome Trust Centre for Neuroimaging +% Configuration file for M/EEG epoching +%__________________________________________________________________________ +% Copyright (C) 2008-2016 Wellcome Trust Centre for Neuroimaging % Stefan Kiebel -% $Id: spm_cfg_eeg_average.m 5624 2013-08-30 11:06:38Z vladimir $ +% $Id: spm_cfg_eeg_average.m 6926 2016-11-09 22:13:19Z guillaume $ -rev = '$Rev: 5624 $'; +rev = '$Rev: 6926 $'; D = cfg_files; D.tag = 'D'; D.name = 'File Name'; @@ -18,6 +18,7 @@ standard.tag = 'standard'; standard.name = 'Standard'; standard.val = {false}; +standard.help = {''}; ks = cfg_entry; ks.tag = 'ks'; @@ -57,11 +58,12 @@ robust.tag = 'robust'; robust.name = 'Robust'; robust.val = {ks, bycondition, savew, removebad}; +robust.help = {''}; userobust = cfg_choice; userobust.tag = 'userobust'; userobust.name = 'Averaging type'; -userobust.help = {'choose between using standard and robust averaging'}; +userobust.help = {'choose between using standard and robust averaging.'}; userobust.values = {standard, robust}; userobust.val = {standard}; @@ -69,7 +71,7 @@ plv.tag = 'plv'; plv.name = 'Compute phase-locking value'; plv.help = {'Compute phase-locking value rather than average the phase',... - 'This option is only relevant for TF-phase datasets'}; + 'This option is only relevant for TF-phase datasets.'}; plv.labels = {'Yes', 'No'}; plv.values = {true, false}; plv.val = {false}; diff --git a/config/spm_cfg_eeg_cfc.m b/config/spm_cfg_eeg_cfc.m index e04c3e94..05544a02 100644 --- a/config/spm_cfg_eeg_cfc.m +++ b/config/spm_cfg_eeg_cfc.m @@ -1,10 +1,10 @@ function cfc = spm_cfg_eeg_cfc % Configuration file for M/EEG cross-frequency coupling analysis %__________________________________________________________________________ -% Copyright (C) 2014 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2014-2016 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_cfg_eeg_cfc.m 6211 2014-09-29 10:17:49Z vladimir $ +% $Id: spm_cfg_eeg_cfc.m 6929 2016-11-14 13:07:31Z guillaume $ %-------------------------------------------------------------------------- @@ -24,6 +24,7 @@ condlabel.tag = 'conditions'; condlabel.name = 'Condition label'; condlabel.strtype = 's'; +condlabel.help = {''}; conditions = cfg_repeat; conditions.tag = 'condrepeat'; @@ -62,9 +63,10 @@ regressors.tag = 'regressors'; regressors.name = 'Regressors of interest'; regressors.num = [1 Inf]; +regressors.help = {'Regressors of interest'}; reg_funs = {'spm_eeg_regressors_tfpower.m', 'spm_eeg_regressors_tfphase.m'}; - +regressors.values = cell(1,numel(reg_funs)); for i = 1:numel(reg_funs) regressors.values{i} = feval(spm_file(reg_funs{i},'basename')); end @@ -76,9 +78,11 @@ confounds.tag = 'confounds'; confounds.name = 'Confounds'; confounds.num = [0 Inf]; +confounds.help = {'Confounds'}; reg_funs = spm_select('List',spm('dir'),'^spm_eeg_regressors_.*\.m$'); reg_funs = cellstr(reg_funs); +confounds.values = cell(1,numel(reg_funs)); for i = 1:numel(reg_funs) confounds.values{i} = feval(spm_file(reg_funs{i},'basename')); end diff --git a/config/spm_cfg_eeg_channel_selector.m b/config/spm_cfg_eeg_channel_selector.m index fae20b3c..0b2730bb 100644 --- a/config/spm_cfg_eeg_channel_selector.m +++ b/config/spm_cfg_eeg_channel_selector.m @@ -1,21 +1,22 @@ function channels = spm_cfg_eeg_channel_selector(jobtree) % generic M/EEG channel selector based on label and type -%_______________________________________________________________________ -% Copyright (C) 2010 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2010-2016 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_cfg_eeg_channel_selector.m 6535 2015-08-25 11:45:26Z vladimir $ +% $Id: spm_cfg_eeg_channel_selector.m 6926 2016-11-09 22:13:19Z guillaume $ if nargin == 0 || ischar(jobtree) chanall = cfg_const; chanall.tag = 'all'; chanall.name = 'All'; chanall.val = {'all'}; + chanall.help = {''}; type = cfg_menu; type.tag = 'type'; type.name = 'Select channels by type'; - type.help = {'Select channels by type'}; + type.help = {'Select channels by type.'}; type.labels = {'MEG', 'MEGPLANAR', 'MEGMAG', 'MEGGRAD', 'MEGCOMB','EEG', 'EOG', 'ECG', 'EMG', 'LFP', 'SRC', 'PHYS', 'ILAM', 'Other', 'REF', 'REFMAG', 'REFGRAD'}; type.values = {'MEG', 'MEGPLANAR', 'MEGMAG', 'MEGGRAD', 'MEGCOMB','EEG', 'EOG', 'ECG', 'EMG', 'LFP', 'SRC', 'PHYS', 'ILAM', 'Other', 'REF', 'REFMAG', 'REFGRAD'}; @@ -38,6 +39,7 @@ chanfile.name = 'Channel file'; chanfile.filter = 'mat'; chanfile.num = [1 1]; + chanfile.help = {''}; channels = cfg_repeat; channels.tag = 'channels'; @@ -50,6 +52,7 @@ end channels.num = [1 Inf]; channels.val = {chanall}; + channels.help = {'Channel selection.'}; else channels = {}; for j = 1:numel(jobtree) diff --git a/config/spm_cfg_eeg_convert.m b/config/spm_cfg_eeg_convert.m index de30279a..b024a582 100644 --- a/config/spm_cfg_eeg_convert.m +++ b/config/spm_cfg_eeg_convert.m @@ -1,10 +1,10 @@ function convert = spm_cfg_eeg_convert -% configuration file for data conversion -%_______________________________________________________________________ -% Copyright (C) 2008-2012 Wellcome Trust Centre for Neuroimaging +% Configuration file for M/EEG data conversion +%__________________________________________________________________________ +% Copyright (C) 2008-2016 Wellcome Trust Centre for Neuroimaging % Stefan Kiebel -% $Id: spm_cfg_eeg_convert.m 6214 2014-09-29 12:30:45Z vladimir $ +% $Id: spm_cfg_eeg_convert.m 6926 2016-11-09 22:13:19Z guillaume $ dataset = cfg_files; dataset.tag = 'dataset'; @@ -24,66 +24,77 @@ readall.tag = 'readall'; readall.name = 'Read all'; readall.val = {1}; +readall.help = {''}; continuous = cfg_choice; continuous.tag = 'continuous'; continuous.name = 'Continuous'; continuous.values = {timewin, readall}; continuous.val = {readall}; +continuous.help = {''}; usetrials = cfg_const; usetrials.tag = 'usetrials'; usetrials.name = 'Trials defined in data'; usetrials.val = {1}; +usetrials.help = {''}; trlfile = cfg_files; trlfile.tag = 'trlfile'; trlfile.name = 'Trial File'; trlfile.filter = 'mat'; trlfile.num = [1 1]; +trlfile.help = {''}; conditionlabel = cfg_entry; conditionlabel.tag = 'conditionlabel'; conditionlabel.name = 'Condition label'; conditionlabel.strtype = 's'; +conditionlabel.help = {''}; eventtype = cfg_entry; eventtype.tag = 'eventtype'; eventtype.name = 'Event type'; eventtype.strtype = 's'; +eventtype.help = {''}; eventvalue = cfg_entry; eventvalue.tag = 'eventvalue'; eventvalue.name = 'Event value'; -eventvalue.strtype = 'e'; +eventvalue.strtype = 'r'; +eventvalue.help = {''}; trialdef = cfg_branch; trialdef.tag = 'trialdef'; trialdef.name = 'Trial'; trialdef.val = {conditionlabel, eventtype, eventvalue}; +trialdef.help = {''}; define1 = cfg_repeat; define1.tag = 'unused'; define1.name = 'Trial definitions'; define1.num = [1 Inf]; define1.values = {trialdef}; +define1.help = {''}; define = cfg_branch; define.tag = 'define'; define.name = 'Define trial'; define.val = {timewin define1}; +define.help = {''}; epoched = cfg_choice; epoched.tag = 'epoched'; epoched.name = 'Epoched'; epoched.values = {usetrials trlfile define}; +epoched.help = {''}; mode = cfg_choice; mode.tag = 'mode'; mode.name = 'Reading mode'; mode.values = {continuous, epoched}; mode.val = {continuous}; -mode.help = {'Select whether you want to convert to continuous or epoched data'}; +mode.help = {'Select whether you want to convert to continuous or epoched data.'}; outfile = cfg_entry; outfile.tag = 'outfile'; @@ -110,7 +121,7 @@ blocksize.strtype = 'r'; blocksize.val = {3276800}; blocksize.num = [1 1]; -blocksize.help = {'size of blocks used internally to split large files default ~100Mb'}; +blocksize.help = {'size of blocks used internally to split large files default ~100Mb.'}; checkboundary = cfg_menu; checkboundary.tag = 'checkboundary'; @@ -119,7 +130,7 @@ checkboundary.val = {1}; checkboundary.values = {1,0}; checkboundary.help = {'Check if there are breaks in the file and do not read',... - 'across those breaks (recommended) or ignore them'}; + 'across those breaks (recommended) or ignore them.'}; saveorigheader = cfg_menu; saveorigheader.tag = 'saveorigheader'; @@ -127,7 +138,7 @@ saveorigheader.labels = {'Yes', 'No'}; saveorigheader.val = {0}; saveorigheader.values = {1,0}; -saveorigheader.help = {'Keep the original data header which might be useful for some later analyses'}; +saveorigheader.help = {'Keep the original data header which might be useful for some later analyses.'}; inputformat = cfg_entry; inputformat.tag = 'inputformat'; @@ -135,14 +146,14 @@ inputformat.strtype = 's'; inputformat.val = {'autodetect'}; inputformat.num = [1 inf]; -inputformat.help = {'Force the reader to assume a particular data format (usually not necessary)'}; +inputformat.help = {'Force the reader to assume a particular data format (usually not necessary).'}; convert = cfg_exbranch; convert.tag = 'convert'; convert.name = 'Conversion'; convert.val = {dataset mode spm_cfg_eeg_channel_selector outfile... eventpadding blocksize checkboundary saveorigheader inputformat}; -convert.help = {'Converts EEG/MEG data.'}; +convert.help = {'Convert EEG/MEG data.'}; convert.prog = @eeg_convert; convert.vout = @vout_eeg_convert; convert.modality = {'EEG'}; diff --git a/config/spm_cfg_eeg_convert2images.m b/config/spm_cfg_eeg_convert2images.m index 2dea40c3..531e6107 100644 --- a/config/spm_cfg_eeg_convert2images.m +++ b/config/spm_cfg_eeg_convert2images.m @@ -1,11 +1,11 @@ function convert2images = spm_cfg_eeg_convert2images -% configuration file for writing voxel-based images from SPM M/EEG format, +% Configuration file for writing voxel-based images from SPM M/EEG format, % as a time-series of 2Dimages -%_______________________________________________________________________ -% Copyright (C) 2008-2012 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2008-2016 Wellcome Trust Centre for Neuroimaging % Stefan Kiebel -% $Id: spm_cfg_eeg_convert2images.m 6535 2015-08-25 11:45:26Z vladimir $ +% $Id: spm_cfg_eeg_convert2images.m 6926 2016-11-09 22:13:19Z guillaume $ %-------------------------------------------------------------------------- % D @@ -33,7 +33,7 @@ 'frequency' 'average'}'; mode.values = mode.labels; -mode.help = {'Select the mode for conversion to images'}; +mode.help = {'Select the mode for conversion to images.'}; %-------------------------------------------------------------------------- % timewin @@ -64,6 +64,7 @@ condlabel.tag = 'conditions'; condlabel.name = 'Condition label'; condlabel.strtype = 's'; +condlabel.help = {''}; conditions = cfg_repeat; conditions.tag = 'condrepeat'; @@ -79,7 +80,7 @@ prefix = cfg_entry; prefix.tag = 'prefix'; prefix.name = 'Directory prefix'; -prefix.help = {'Specify the string to be prepended to the output directory name'}; +prefix.help = {'Specify the string to be prepended to the output directory name.'}; prefix.strtype = 's'; prefix.num = [0 Inf]; prefix.val = {''}; @@ -89,12 +90,13 @@ convert2images.tag = 'convert2images'; convert2images.name = 'Convert2Images'; convert2images.val = {D, mode, conditions, spm_cfg_eeg_channel_selector, timewin, freqwin, prefix}; -convert2images.help = {'Convert SPM M/EEG data to voxel-based images'}; +convert2images.help = {'Convert SPM M/EEG data to voxel-based images.'}; convert2images.prog = @run_convert2images; convert2images.vout = @vout_convert2images; convert2images.modality = {'EEG'}; +%========================================================================== function out = run_convert2images(job) S = job; @@ -104,8 +106,7 @@ [out.files, out.dir{1}] = spm_eeg_convert2images(S); - -%------------------------------------------------------------------------ +%========================================================================== function dep = vout_convert2images(varargin) % Output file names will be saved in a struct with field .files dep(1) = cfg_dep; @@ -117,4 +118,3 @@ dep(2).sname = 'M/EEG images folder'; dep(2).src_output = substruct('.','dir'); dep(2).tgt_spec = cfg_findspec({{'filter','dir','strtype','e'}}); - diff --git a/config/spm_cfg_eeg_dipfit.m b/config/spm_cfg_eeg_dipfit.m new file mode 100644 index 00000000..25b251d6 --- /dev/null +++ b/config/spm_cfg_eeg_dipfit.m @@ -0,0 +1,352 @@ +function dipfit = spm_cfg_eeg_dipfit +% Configuration file for configuring imaging source inversion +% reconstruction +%__________________________________________________________________________ +% Copyright (C) 2010-2016 Wellcome Trust Centre for Neuroimaging + +% Gareth Barnes + + +D = cfg_files; +D.tag = 'D'; +D.name = 'M/EEG datasets'; +D.filter = 'mat'; +D.num = [1 Inf]; +D.help = {'Select the M/EEG mat files.'}; + +val = cfg_entry; +val.tag = 'val'; +val.name = 'Inversion index'; +val.strtype = 'n'; +val.help = {'Index of the cell in D.inv where the forward model can be found and the results will be stored.'}; +val.val = {1}; + +all = cfg_const; +all.tag = 'all'; +all.name = 'All'; +all.val = {1}; +all.help = {''}; + +condlabel = cfg_entry; +condlabel.tag = 'condlabel'; +condlabel.name = 'Condition label'; +condlabel.strtype = 's'; +condlabel.val = {''}; +condlabel.help = {''}; + +conditions = cfg_repeat; +conditions.tag = 'conditions'; +conditions.name = 'Conditions'; +conditions.help = {'Specify the labels of the conditions to be included in the inversion'}; +conditions.num = [1 Inf]; +conditions.values = {condlabel}; +conditions.val = {condlabel}; + +whatconditions = cfg_choice; +whatconditions.tag = 'whatconditions'; +whatconditions.name = 'What conditions to include?'; +whatconditions.values = {all, conditions}; +whatconditions.val = {all}; +whatconditions.help = {'What conditions to include?'}; + + +woi = cfg_entry; +woi.tag = 'woi'; +woi.name = 'Time window of interest'; +woi.strtype = 'r'; +woi.num = [1 2]; +woi.val = {[-Inf Inf]}; +woi.help = {'Time window to include in the inversion (ms)'}; + + +hanning = cfg_menu; +hanning.tag = 'hanning'; +hanning.name = 'PST Hanning window'; +hanning.help = {'Multiply the time series by a Hanning taper to emphasize the central part of the response.'}; +hanning.labels = {'yes', 'no'}; +hanning.values = {1, 0}; +hanning.val = {1}; + + +locs = cfg_entry; +locs.tag = 'locs'; +locs.name = 'Prior Source locations'; +locs.strtype = 'r'; +locs.num = [Inf 3]; +locs.help = {'Input source locations as n x 3 matrix'}; +locs.val = {zeros(0, 3)}; + +locvar = cfg_entry; +locvar.tag = 'locvar'; +locvar.name = 'Prior Source location variance'; +locvar.strtype = 'r'; +locvar.num = [Inf 3]; +locvar.help = {'Source location variance as n x 3 matrix. So [100 100 100] means approx 10mm uncertainty in any direction'}; +locvar.val = {ones(1, 3)*100}; + +moms = cfg_entry; +moms.tag = 'moms'; +moms.name = 'Prior Source moments'; +moms.strtype = 'r'; +moms.num = [Inf 3]; +moms.help = {'Input source moments as n x 3 matrix. If unsure of orientation leave this as zeros'}; +moms.val = {zeros(1, 3)}; + +momvar = cfg_entry; +momvar.tag = 'momvar'; +momvar.name = 'Prior Source moment variance'; +momvar.strtype = 'r'; +momvar.num = [Inf 3]; +momvar.help = {'Source moment variance as n x 3 matrix. So [100 100 100] means that expect to have magnitudes of around 10nAm'}; +momvar.val = {ones(1, 3)*100}; + +niter = cfg_entry; +niter.tag = 'niter'; +niter.name = 'Number of fit iterations'; +niter.strtype = 'n'; +niter.help = {'Number of restarts of algorithm to avoid local extrema'}; +niter.val = {10}; + +modality = cfg_menu; +modality.tag = 'modality'; +modality.name = 'Select modalities'; +modality.help = {'Select modalities for the inversion (only relevant for multimodal datasets).'}; +modality.labels = {'EEG', 'MEG', 'EEG+MEG'}; +modality.values = { + {'EEG'} + {'MEG'} + {'EEG', 'MEG'} + }'; +modality.val = {{'MEG'}}; + +dipfit = cfg_exbranch; +dipfit.tag = 'dipfit'; +dipfit.name = 'Bayesian Dipole fit'; +dipfit.val = {D, val, whatconditions, woi, locs, locvar,moms,momvar, niter,modality}; +dipfit.help = {'Run imaging source reconstruction'}; +dipfit.prog = @run_dipfit; +dipfit.vout = @vout_dipfit; +%dipfit.modality = {'MEG'}; + +function out = run_dipfit(job) + + + + +D = {}; + +for i = 1:numel(job.D) + D{i} = spm_eeg_load(job.D{i}); + + D{i}.val = job.val; + + D{i}.con = 1; + + if ~isfield(D{i}, 'inv') + error('Forward model is missing for subject %d.', i); + elseif numel(D{i}.inv)1 && isfield(D{i}.inv{D{i}.val-1}, 'forward') + D{i}.inv{D{i}.val} = D{i}.inv{D{i}.val-1}; + warning('Duplicating the last forward model for subject %d.', i); + else + error('Forward model is missing for subject %d.', i); + end + end + +end +D=D{1}; +megind=D.indchantype(job.modality); +megind=setdiff(megind,D.badchannels); + +usesamples=intersect(find(D.time>=job.woi(1)./1000),find(D.time<=job.woi(2)./1000)); + +condind=strmatch(job.whatconditions.condlabel,D.conditions) + + +% if length(condstr)>1, +% error('not implemented for more than 1 condition yet'); +% end; + +fitdata=D(megind,usesamples,condind); + + +pos=coor2D(D)'; %Uses info in MEG datafile (D) to print list of 2D locations of each channel (pos) +labels=num2str(megind'); %Prints numerical label of each channel (labels) + + + + +s0_mni=job.locs; +w0_mni=job.moms; +diags_s0_mni=job.locvar; +diags_w0_mni=job.momvar; + +ndips=size(job.locs,1); %% single dipole +%% Set up the forward model +val=D.val; %Use the most recent forward model saved in D +P=[]; +P.y=mean(fitdata,2); %Z=avdata at each sensor at 'fitind' (timepoint identified in VB_ECD_FindPeak) +P.forward.sens = D.inv{val}.datareg.sensors; +P.forward.vol = D.inv{val}.forward.vol; +P.modality = D.modality; +P.Ic = megind; +P.channels = D.chanlabels(P.Ic); + +spm_eeg_plotScalpData(P.y,pos,labels); +%% Transform to mni space +M1 = D.inv{val}.datareg.toMNI; +[U, L, V] = svd(M1(1:3, 1:3)); +orM1(1:3,1:3) =U*V'; %For switching orientation between meg and mni space + + +mnivol = ft_transform_vol(M1, P.forward.vol); %Used for inside head calculation + + +%% Put priors in ctf space +alldiag_Wcov=[]; +alldiag_Scov=[]; + +figure; +hold on; + +for d=1:ndips, + + ind=(d-1)*3+1:d*3; + Priors.mu_w0(ind)= orM1*w0_mni(ind)'; + + ctfpos=D.inv{val}.datareg.fromMNI*[s0_mni(ind) 1]'; + plot3(ctfpos(1)./1000,ctfpos(2)./1000,ctfpos(3)./1000,'r*'); + Priors.mu_s0(ind)=ctfpos(1:3); % ./1000; + alldiag_Wcov(ind)=ones(3,1)*diags_w0_mni(d); + alldiag_Scov(ind)=ones(3,1)*diags_s0_mni(d); +end; + + + +Priors.mu_s0=spm_vec(Priors.mu_s0); +Priors.mu_w0=spm_vec(Priors.mu_w0); +Priors.S_s0=diag(alldiag_Scov); +Priors.S_w0= diag(alldiag_Wcov); + + +P.priors=Priors; + +%% Calculate the covariance of the raw data + +%% Next line calculates the SNR at each sensor, for the peak you've identified + +%% The SNRamp is the average SNR for the peak you've identified across all sensors +SNRamp=3; + +%% So, the SNR obviously varies across the brain, and is different at each sensor. How much of the variance observed in the sensor data is due to noise, and how much is due to real signal? +%P.priors.hE=log(SNRamp^2); %Expected log precision of data +P.priors.hE=log(SNRamp); %% seemed to be closets to value arrived at in line serach %Expected log precision of data +%% run a line search over hE values +%hevals=[0.001 0.1 0.5 1 2] % 1 2 5 10] + +%P.priors.hE=hevals(hind); %% log(SNRamp^2); %Expected log precision of data +hcpval=-2; %; %% was -2 +P.priors.hC=exp(hcpval); %varSNR; % variability of the above precision + +%% This is the range of possible SNR values at each sensor that we're willing to expect. If the Hcpval is small, the range will be small. +disp('approx amp SNR range:') +exp(P.priors.hE/2-2*sqrt(P.priors.hC)) +exp(P.priors.hE/2+2*sqrt(P.priors.hC)) + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%% Start the VB-ECD iterations for the ith subject +data = spm_eeg_inv_get_vol_sens(D, val, [], 'inv', P.modality); +P.forward.vol = data.(P.modality(1:3)).vol; +if ischar(P.forward.vol) + P.forward.vol = ft_read_vol(P.forward.vol); +end +P.forward.sens = data.(P.modality(1:3)).sens; +P.forward.siunits = data.siunits; +% M1 = data.transforms.toMNI; +% [U, L, V] = svd(M1(1:3, 1:3)); +% orM1(1:3,1:3) = U*V'; %For switching orientation between meg and mni space + +if isempty(P.Ic) + error(['The specified modality (' P.modality ') is missing from file ' D.fname]); +else + P.channels = D.chanlabels(P.Ic); +end +P.forward.chanunits = D.units(P.Ic); +[P.forward.vol, P.forward.sens] = ft_prepare_vol_sens( ... + P.forward.vol, P.forward.sens, 'channel', P.channels); +plot3(P.forward.sens.chanpos(:,1),P.forward.sens.chanpos(:,2),P.forward.sens.chanpos(:,3),'bo'); + +for j=1:job.niter; + Pout(j) = spm_eeg_inv_vbecd(P); + varresids(j) = var(Pout(j).y-Pout(j).ypost); + pov(j) = 100*(1-varresids(j)/var(Pout(j).y)); %Percent variance explained + allF(j) = Pout(j).F; + dip_mom = reshape(Pout(j).post_mu_w,3,length(Pout(j).post_mu_w)/3); + dip_amp(j,:) = sqrt(dot(dip_mom,dip_mom)); + megloc = reshape(Pout(j).post_mu_s,3,length(Pout(j).post_mu_s)/3); %Loc of dip (3 x n_dip) + mniloc{j} = D.inv{val}.datareg.toMNI*[megloc;ones(1,size(megloc,2))]; %Actual MNI location (with scaling) + megmom{j} = reshape(Pout(j).post_mu_w,3,length(Pout(j).post_mu_w)/3); %Moments of dip (3 x n_dip) +end %For j in serial loop + +%%%% Save VB-ECD results into Output structure and overwrite datafile + +[maxF,maxind]=max(allF); + + +inverse=[]; +inverse.F=maxF; +inverse.modelmniloc=mniloc{maxind}; +inverse.modelmnimom=megmom{maxind}; +inverse.Pout=Pout(maxind); +inverse.P=P; +D.inv{job.val}.inverse=inverse; + +hf = spm_figure('FindWin','Graphics'); +figure(hf); +clf; +subplot(3,2,1); +plot(inverse.Pout.y,inverse.Pout.ypost,'o',inverse.Pout.y,inverse.Pout.y,':'); +xlabel('measured');ylabel('modelled'); + +axesY = axes(... + 'Position',[0.02 0.3 0.3 0.2],... + 'hittest','off'); +in.f = hf; +in.noButtons = 1; +in.ParentAxes = axesY; + + +spm_eeg_plotScalpData(P.y,D.coor2D',P.channels,in) +title(axesY,'measured data') + +axesY = axes(... + 'Position',[0.5 0.3 0.6 0.2],... + 'hittest','off'); + +in.ParentAxes=axesY; +spm_eeg_plotScalpData(inverse.Pout.ypost,D.coor2D',P.channels,in) +title(axesY,'Modelled data') + + +if ~iscell(D) + D = {D}; +end + + +for i = 1:numel(D) + save(D{i}); +end + +out.D = job.D; + +function dep = vout_dipfit(job) +% Output is always in field "D", no matter how job is structured +dep = cfg_dep; +dep.sname = 'M/EEG dataset(s) after imaging source reconstruction'; +% reference field "D" from output +dep.src_output = substruct('.','D'); +% this can be entered into any evaluated input +dep.tgt_spec = cfg_findspec({{'filter','mat'}}); + diff --git a/config/spm_cfg_eeg_epochs.m b/config/spm_cfg_eeg_epochs.m index 8eb6b8b3..5713e194 100644 --- a/config/spm_cfg_eeg_epochs.m +++ b/config/spm_cfg_eeg_epochs.m @@ -1,10 +1,10 @@ function epoch = spm_cfg_eeg_epochs % Configuration file for M/EEG epoching %__________________________________________________________________________ -% Copyright (C) 2008-2013 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2008-2016 Wellcome Trust Centre for Neuroimaging % Stefan Kiebel -% $Id: spm_cfg_eeg_epochs.m 5377 2013-04-02 17:07:57Z vladimir $ +% $Id: spm_cfg_eeg_epochs.m 7095 2017-06-07 10:15:59Z vladimir $ D = cfg_files; @@ -53,16 +53,19 @@ conditionlabel.tag = 'conditionlabel'; conditionlabel.name = 'Condition label'; conditionlabel.strtype = 's'; +conditionlabel.help = {''}; eventtype = cfg_entry; eventtype.tag = 'eventtype'; eventtype.name = 'Event type'; eventtype.strtype = 's'; +eventtype.help = {''}; eventvalue = cfg_entry; eventvalue.tag = 'eventvalue'; eventvalue.name = 'Event value'; eventvalue.strtype = 'e'; +eventvalue.help = {''}; trlshift = cfg_entry; trlshift.tag = 'trlshift'; @@ -77,16 +80,19 @@ trialdef.tag = 'trialdef'; trialdef.name = 'Trial'; trialdef.val = {conditionlabel eventtype eventvalue, trlshift}; +trialdef.help = {''}; define1 = cfg_repeat; define1.tag = 'unused'; define1.name = 'Trial definitions'; define1.values = {trialdef}; +define1.help = {''}; define = cfg_branch; define.tag = 'define'; define.name = 'Define trial'; define.val = {timewin define1}; +define.help = {''}; % input via trialdef trialength = cfg_entry; @@ -100,7 +106,7 @@ arbitrary.tag = 'arbitrary'; arbitrary.name = 'Arbitrary trials'; arbitrary.val = {trialength, conditionlabel}; -arbitrary.help = {'Epoch the data in arbitray fixed length trials (e.g. for spectral analysis'}; +arbitrary.help = {'Epoch the data in arbitray fixed length trials (e.g. for spectral analysis).'}; trlchoice = cfg_choice; trlchoice.tag = 'trialchoice'; diff --git a/config/spm_cfg_eeg_firstlevel.m b/config/spm_cfg_eeg_firstlevel.m index 7a070e3d..4096c0a3 100644 --- a/config/spm_cfg_eeg_firstlevel.m +++ b/config/spm_cfg_eeg_firstlevel.m @@ -3,9 +3,9 @@ %_______________________________________________________________________ % Copyright (C) 2013 Wellcome Trust Centre for Neuroimaging -% $Id: spm_cfg_eeg_firstlevel.m 6818 2016-06-21 09:42:45Z peter $ +% $Id: spm_cfg_eeg_firstlevel.m 6929 2016-11-14 13:07:31Z guillaume $ -rev = '$Rev: 6818 $'; +rev = '$Rev: 6929 $'; % --------------------------------------------------------------------- % units Units for design @@ -39,7 +39,7 @@ utime.name = 'Microtime resolution'; utime.help = { 'The microtime resolution, t, is the number of time-bins per input sample used when building regressors. ' - 'Can be modified to make the output up- or downsampled with respect to the input' + 'Can be modified to make the output up- or downsampled with respect to the input.' }'; utime.strtype = 'r'; utime.num = [1 1]; @@ -52,6 +52,7 @@ timing.tag = 'timing'; timing.name = 'Timing parameters'; timing.val = {timewin units utime}; +timing.help = {'Timing parameters'}; % --------------------------------------------------------------------- % D M/EEG datasets @@ -62,7 +63,7 @@ D.name = 'M/EEG dataset'; D.filter = 'mat'; D.num = [1 1]; -D.help = {'Select the M/EEG mat file'}; +D.help = {'Select the M/EEG mat file.'}; % --------------------------------------------------------------------- % name Name @@ -70,7 +71,7 @@ name = cfg_entry; name.tag = 'name'; name.name = 'Name'; -name.help = {'Condition Name'}; +name.help = {'Condition Name.'}; name.strtype = 's'; name.num = [1 Inf]; % --------------------------------------------------------------------- @@ -100,16 +101,19 @@ manual.tag = 'manual'; manual.name = 'Specify manually'; manual.val = {onset duration}; +manual.help = {''}; eventtype = cfg_entry; eventtype.tag = 'eventtype'; eventtype.name = 'Event type'; eventtype.strtype = 's'; +eventtype.help = {''}; eventvalue = cfg_entry; eventvalue.tag = 'eventvalue'; eventvalue.name = 'Event value'; -eventvalue.strtype = 'e'; +eventvalue.strtype = 'r'; +eventvalue.help = {''}; trlshift = cfg_entry; trlshift.tag = 'trlshift'; @@ -124,6 +128,7 @@ event.tag = 'event'; event.name = 'Event'; event.val = {eventtype eventvalue trlshift}; +event.help = {''}; % --------------------------------------------------------------------- % @@ -133,6 +138,8 @@ fromdata.name = 'Take from dataset'; fromdata.values = {event}; fromdata.num = [1 Inf]; +fromdata.help = {''}; + % --------------------------------------------------------------------- % bases How to define events % --------------------------------------------------------------------- @@ -253,7 +260,7 @@ multi = cfg_files; multi.tag = 'multi'; multi.name = 'Multiple conditions'; -multi.val{1} = {''}; +multi.val = {{''}}; multi.help = { 'Select the *.mat file containing details of your multiple experimental conditions. ' '' @@ -328,7 +335,7 @@ multi_conv_reg = cfg_files; multi_conv_reg.tag = 'multi_conv_reg'; multi_conv_reg.name = 'Multiple convolution regressors'; -multi_conv_reg.val{1} = {''}; +multi_conv_reg.val = {{''}}; multi_conv_reg.help = { 'Select the *.mat/*.txt file containing details of your multiple regressors. ' '' @@ -362,7 +369,7 @@ multi_reg = cfg_files; multi_reg.tag = 'multi_reg'; multi_reg.name = 'Multiple regressors'; -multi_reg.val{1} = {''}; +multi_reg.val = {{''}}; multi_reg.help = { 'Select the *.mat/*.txt file containing details of your multiple regressors. ' '' @@ -496,12 +503,13 @@ prefix.val = {'C'}; % --------------------------------------------------------------------- -% eeg_design MEEG model specification +% convmodel M/EEG convolution modelling % --------------------------------------------------------------------- -convmodel = cfg_exbranch; -convmodel.tag = 'convmodel'; -convmodel.name = 'Convolution modelling'; -convmodel.val = {spm_cfg_eeg_channel_selector timing sess bases volt, prefix}; +convmodel = cfg_exbranch; +convmodel.tag = 'convmodel'; +convmodel.name = 'Convolution modelling'; +convmodel.val = {spm_cfg_eeg_channel_selector timing sess bases volt, prefix}; +convmodel.help = {'M/EEG convolution modelling'}; convmodel.prog = @eeg_run; convmodel.vout = @vout_eeg; convmodel.modality = {'EEG'}; @@ -523,4 +531,4 @@ dep(2) = cfg_dep; dep(2).sname = 'Estimated M/EEG datafile'; dep(2).src_output = substruct('.','Dfname'); -dep(2).tgt_spec = cfg_findspec({{'filter','mat'}}); \ No newline at end of file +dep(2).tgt_spec = cfg_findspec({{'filter','mat'}}); diff --git a/config/spm_cfg_eeg_inv_extract.m b/config/spm_cfg_eeg_inv_extract.m index 14b6df17..9c1344f1 100644 --- a/config/spm_cfg_eeg_inv_extract.m +++ b/config/spm_cfg_eeg_inv_extract.m @@ -5,7 +5,7 @@ % Copyright (C) 2011 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_cfg_eeg_inv_extract.m 5377 2013-04-02 17:07:57Z vladimir $ +% $Id: spm_cfg_eeg_inv_extract.m 6924 2016-11-09 11:38:00Z guillaume $ D = cfg_files; D.tag = 'D'; @@ -53,7 +53,7 @@ rad.strtype = 'r'; rad.num = [1 1]; rad.val = {5}; -woi.help = {'Radius around each location to extract an eigenvariate from (mm).'}; +rad.help = {'Radius around each location to extract an eigenvariate from (mm).'}; type = cfg_menu; type.tag = 'type'; diff --git a/config/spm_cfg_eeg_inv_headmodel.m b/config/spm_cfg_eeg_inv_headmodel.m index 9d4d582d..b532dff1 100644 --- a/config/spm_cfg_eeg_inv_headmodel.m +++ b/config/spm_cfg_eeg_inv_headmodel.m @@ -1,10 +1,10 @@ function headmodel = spm_cfg_eeg_inv_headmodel % Configuration file for specifying the head model for source reconstruction %__________________________________________________________________________ -% Copyright (C) 2010-2013 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2010-2016 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_cfg_eeg_inv_headmodel.m 6545 2015-09-11 12:10:19Z vladimir $ +% $Id: spm_cfg_eeg_inv_headmodel.m 7169 2017-09-19 10:42:27Z vladimir $ D = cfg_files; @@ -32,6 +32,7 @@ template.tag = 'template'; template.name = 'Template'; template.val = {1}; +template.help = {''}; mri = cfg_files; mri.tag = 'mri'; @@ -88,6 +89,7 @@ meshes.name = 'Mesh source'; meshes.values = {template, mri, custom}; meshes.val = {template}; +meshes.help = {''}; meshres = cfg_menu; meshres.tag = 'meshres'; @@ -133,6 +135,7 @@ specification.tag = 'specification'; specification.name = 'How to specify?'; specification.values = {select, type}; +specification.help = {''}; fiducial = cfg_branch; fiducial.tag = 'fiducial'; @@ -160,6 +163,7 @@ coregspecify.tag = 'coregspecify'; coregspecify.name = 'Specify coregistration parameters'; coregspecify.val = {fiducials, useheadshape}; +coregspecify.help = {''}; coregdefault = cfg_const; coregdefault.tag = 'coregdefault'; @@ -167,11 +171,25 @@ coregdefault.help = {'No coregistration is necessary because default EEG sensor locations were used'}; coregdefault.val = {1}; +fidjson = cfg_files; +fidjson.tag = 'fidjson'; +fidjson.name = 'BIDS json file'; +fidjson.filter = '.*_fid.json$'; +fidjson.num = [1 1]; +fidjson.help = {'Select BIDS json file with fiducials.'}; + +coregbids = cfg_branch; +coregbids.tag = 'coregbids'; +coregbids.name = 'Coregistration based on BIDS json file'; +coregbids.val = {fidjson, useheadshape}; +coregbids.help = {'Coregistration based on BIDS json file'}; + coregistration = cfg_choice; coregistration.tag = 'coregistration'; coregistration.name = 'Coregistration'; -coregistration.values = {coregspecify, coregdefault}; +coregistration.values = {coregspecify, coregdefault, coregbids}; coregistration.val = {coregspecify}; +coregistration.help = {'Coregistration'}; eeg = cfg_menu; eeg.tag = 'eeg'; @@ -193,6 +211,7 @@ forward.tag = 'forward'; forward.name = 'Forward model'; forward.val = {eeg, meg}; +forward.help = {'Forward model'}; headmodel = cfg_exbranch; headmodel.tag = 'headmodel'; @@ -283,6 +302,30 @@ %---------------------------------------------------------------------- if isfield(job.coregistration, 'coregdefault') D = spm_eeg_inv_datareg_ui(D); + elseif isfield(job.coregistration, 'coregbids') + meegfid = D.fiducials; + + fidbids = spm_jsonread(char(job.coregistration.coregbids.fidjson)); + + if ~(isa(sMRI, 'char') && isequal(spm_file(sMRI, 'basename'), spm_file(fidbids.IntendedFor, 'basename'))) + warning('The BIDS fiducials might be intended for a different structural image than used here.'); + end + + fidlabel = fieldnames(fidbids.CoilCoordinates); + selection = spm_match_str(meegfid.fid.label, fidlabel); + meegfid.fid.pnt = meegfid.fid.pnt(selection, :); + meegfid.fid.label = meegfid.fid.label(selection); + + mrifid = []; + mrifid.pnt = D.inv{val}.mesh.fid.pnt; + mrifid.fid.pnt = []; + mrifid.fid.label = fidlabel; + + for j = 1:numel(fidlabel) + mrifid.fid.pnt(j, :) = reshape(fidbids.CoilCoordinates.(fidlabel{j}), 1, 3); + end + + D = spm_eeg_inv_datareg_ui(D, D.val, meegfid, mrifid, job.coregistration.coregbids.useheadshape); else meegfid = D.fiducials; selection = spm_match_str(meegfid.fid.label, {job.coregistration.coregspecify.fiducial.fidname}); diff --git a/config/spm_cfg_eeg_inv_headmodelhelmet.m b/config/spm_cfg_eeg_inv_headmodelhelmet.m index d91882ca..dbb9568e 100644 --- a/config/spm_cfg_eeg_inv_headmodelhelmet.m +++ b/config/spm_cfg_eeg_inv_headmodelhelmet.m @@ -2,10 +2,10 @@ % Configuration file for specifying the head model for source reconstruction % This is for registration using new helmet design. %__________________________________________________________________________ -% Copyright (C) 2012-2013 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2012-2016 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_cfg_eeg_inv_headmodelhelmet.m 6002 2014-05-21 09:54:48Z gareth $ +% $Id: spm_cfg_eeg_inv_headmodelhelmet.m 6926 2016-11-09 22:13:19Z guillaume $ D = cfg_files; @@ -33,6 +33,7 @@ template.tag = 'template'; template.name = 'Template'; template.val = {1}; +template.help = {''}; mri = cfg_files; mri.tag = 'mri'; @@ -89,6 +90,7 @@ meshes.name = 'Mesh source'; meshes.values = {template, mri, custom}; meshes.val = {template}; +meshes.help = {''}; meshres = cfg_menu; meshres.tag = 'meshres'; @@ -134,6 +136,7 @@ specification.tag = 'specification'; specification.name = 'How to specify?'; specification.values = {select, type}; +specification.help = {''}; fiducial = cfg_branch; fiducial.tag = 'fiducial'; @@ -161,6 +164,7 @@ coregspecify.tag = 'coregspecify'; coregspecify.name = 'Specify coregistration parameters'; coregspecify.val = {fiducials, useheadshape}; +coregspecify.help = {''}; % coregdefault = cfg_const; % coregdefault.tag = 'coregdefault'; @@ -191,6 +195,7 @@ coregistration.name = 'Coregistration'; coregistration.values = {coregspecify, coregdefault}; coregistration.val = {coregspecify}; +coregistration.help = {'Coregistration'}; eeg = cfg_menu; eeg.tag = 'eeg'; @@ -212,6 +217,7 @@ forward.tag = 'forward'; forward.name = 'Forward model'; forward.val = {eeg, meg}; +forward.help = {'Forward model'}; headmodelhelmet = cfg_exbranch; headmodelhelmet.tag = 'headmodelhelmet'; diff --git a/config/spm_cfg_eeg_inv_invert.m b/config/spm_cfg_eeg_inv_invert.m index cc131cc3..5523d347 100644 --- a/config/spm_cfg_eeg_inv_invert.m +++ b/config/spm_cfg_eeg_inv_invert.m @@ -1,11 +1,11 @@ function invert = spm_cfg_eeg_inv_invert -% configuration file for configuring imaging source inversion +% Configuration file for configuring imaging source inversion % reconstruction -%_______________________________________________________________________ -% Copyright (C) 2010 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2010-2016 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_cfg_eeg_inv_invert.m 6885 2016-09-19 15:54:29Z vladimir $ +% $Id: spm_cfg_eeg_inv_invert.m 7076 2017-05-19 12:47:36Z vladimir $ D = cfg_files; D.tag = 'D'; @@ -25,12 +25,14 @@ all.tag = 'all'; all.name = 'All'; all.val = {1}; +all.help = {''}; condlabel = cfg_entry; condlabel.tag = 'condlabel'; condlabel.name = 'Condition label'; condlabel.strtype = 's'; condlabel.val = {''}; +condlabel.help = {''}; conditions = cfg_repeat; conditions.tag = 'conditions'; @@ -45,6 +47,7 @@ whatconditions.name = 'What conditions to include?'; whatconditions.values = {all, conditions}; whatconditions.val = {all}; +whatconditions.help = {'What conditions to include?'}; standard = cfg_const; standard.tag = 'standard'; @@ -120,6 +123,7 @@ radius.strtype = 'r'; radius.num = [1 1]; radius.val = {32}; +radius.help = {''}; mask = cfg_files; mask.tag = 'mask'; @@ -152,7 +156,7 @@ modality.tag = 'modality'; modality.name = 'Select modalities'; modality.help = {'Select modalities for the inversion (only relevant for multimodal datasets).'}; -modality.labels = {'All', 'EEG', 'MEG', 'MEGPLANAR', 'EEG+MEG', 'MEG+MEGPLANAR', 'EEG+MEGPLANAR'}; +modality.labels = {'All', 'EEG', 'MEG', 'MEGPLANAR', 'EEG+MEG', 'MEG+MEGPLANAR', 'EEG+MEGPLANAR', 'EEG+MEG+MEGPLANAR'}; modality.values = { {'All'} {'EEG'} @@ -161,6 +165,7 @@ {'EEG', 'MEG'} {'MEG', 'MEGPLANAR'} {'EEG', 'MEGPLANAR'} + {'EEG', 'MEG', 'MEGPLANAR'} }'; modality.val = {{'All'}}; diff --git a/config/spm_cfg_eeg_inv_invertiter.m b/config/spm_cfg_eeg_inv_invertiter.m index 83e65f03..58014212 100644 --- a/config/spm_cfg_eeg_inv_invertiter.m +++ b/config/spm_cfg_eeg_inv_invertiter.m @@ -4,7 +4,7 @@ % Copyright (C) 2010 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_cfg_eeg_inv_invertiter.m 6887 2016-09-20 08:01:36Z gareth $ +% $Id: spm_cfg_eeg_inv_invertiter.m 7127 2017-06-29 09:25:24Z gareth $ D = cfg_files; D.tag = 'D'; @@ -375,7 +375,8 @@ end; crossU=a.U; else - crossU={a.U}; + disp('loading old format spatial mode file'); + crossU{1}=a.U; end; else %% if isempty U mode file A=[]; @@ -538,8 +539,9 @@ Nchans=D{1}.nchannels; -crosserr=zeros(Nblocks,1); -allrms=zeros(Nblocks,1); +crosserr=zeros(Nblocks,Ntestchans); +allrms=zeros(Nblocks,Ntestchans); +allfract=zeros(Nblocks,Ntestchans); crossF=zeros(Nblocks,1); xvalchans=testchans.*0; for b=1:Nblocks, @@ -579,7 +581,7 @@ if inverse.Han, W = repmat(spm_hanning(length(It))',length(Ic),1); %% use hanning unless specified else - W=ones(length(It),length(Ic)); + W=ones(length(Ic),length(It)); end; @@ -587,8 +589,10 @@ fprintf('\n Cross val iteration %d of %d, first two chans:%d, %d..\n',b,Nblocks,testchans(b,1),testchans(b,2)); errpred=0; rmstot=0; + fracterr=0; fprintf('Running cross val..'); + for t=1:length(Ik), traindata=squeeze((D{1}(Ic,It,Ik(t)))); @@ -598,12 +602,27 @@ Ypred=Lfull*Jtrain; %% now predict test channels based on trained source estimate Ymeas=squeeze((D{1}(megind(testchans(b,:)),It,Ik(t)))); % test channels - not used in inversion Ymeas=Ymeas.*W(1:size(testchans,2),:)*T; - errpred=errpred+sqrt(mean((sum(Ypred(badmegind,:)-Ymeas).^2))); % asusming same model in trial and test (i.e. not necessarily time locked) - rmstot=rmstot+sqrt(mean(sum(Ymeas.^2))); + err2=(Ypred(badmegind,:)-Ymeas).^2; + sig2=Ymeas.^2; + diff2=err2./sig2; + rmsdiff=sqrt(mean(diff2,2)); %% root of the mean (over temporal modes) of (error^2/ signal.^2) per chan + rmserr=sqrt(mean(err2,2));%% root of the mean (over temporal modes) of error^2 per chan + rmssig=sqrt(mean(sig2,2)); %root of the mean (over temporal modes) of signal^2 per chan - end; - crosserr(b)=errpred; - allrms(b)=rmstot; + + + + errpred=errpred+rmserr; + rmstot=rmstot+rmssig; + + fracterr=fracterr+rmsdiff; + + + end; % for trials + + crosserr(b,:)=errpred./length(Ik); %per test channel temporal mode per trial + allrms(b,:)=rmstot./length(Ik); %per test channel temporal mode per trial + allfract(b,:)=fracterr./length(Ik); %per test channel temporal mode per trial end; %if pctest>0 @@ -615,6 +634,8 @@ D{1}.inv{val}.inverse.crosserr=crosserr; D{1}.inv{val}.inverse.crossF=crossF; D{1}.inv{val}.inverse.allrms=allrms; +D{1}.inv{val}.inverse.allfract=allfract; + D{1}.inv{val}.inverse.xvalchans=xvalchans; D{1} = badchannels(D{1}, 1:Nchans, 0); %% set all chans to good @@ -628,7 +649,7 @@ save(D{i}); if savecopyinv, %% actually going to save the dataset anyway- badchannels need to be set right outinvname=[D{i}.path filesep job.isstandard.custom.outinv '_' D{i}.fname]; - fprintf(sprintf('\nNB. Original dataset is being updated and a copy of inversion results written to %s',outinvname)); + fprintf('\n Original dataset is being updated and a copy of inversion results written to %s\n',outinvname); inv=D{i}.inv{val}; spmfilename=D{i}.fname; diff --git a/config/spm_cfg_eeg_inv_priors.m b/config/spm_cfg_eeg_inv_priors.m index 8b511076..04b72b7b 100644 --- a/config/spm_cfg_eeg_inv_priors.m +++ b/config/spm_cfg_eeg_inv_priors.m @@ -1,11 +1,10 @@ function priors = spm_cfg_eeg_inv_priors -% configuration file to set up priors for M/EEG source -% reconstruction -%_______________________________________________________________________ -% Copyright (C) 2010 Wellcome Trust Centre for Neuroimaging +% Configuration file to set up priors for M/EEG source reconstruction +%__________________________________________________________________________ +% Copyright (C) 2010-2017 Wellcome Trust Centre for Neuroimaging % Gareth Barnes -% $Id: spm_cfg_eeg_inv_priors.m 6498 2015-07-15 19:13:31Z gareth $ +% $Id: spm_cfg_eeg_inv_priors.m 7110 2017-06-15 11:45:05Z guillaume $ D = cfg_files; @@ -234,26 +233,23 @@ priors.prog = @add_priors; priors.vout = @vout_priors; - +%========================================================================== function out = add_priors(job) - - - val=job.val; D = spm_eeg_load(job.D{val}); -if ~isfield(D.inv{job.val}.inverse,'L'), +if ~isfield(D.inv{job.val}.inverse,'L') error('Need to set up spatial modes first'); else UL=D.inv{val}.inverse.L; %% dimension reduced lead field matrix -end; +end [a1,b1,c1]=fileparts(D.fname); priordir=[D.path filesep job.priorname '_' b1]; -if ~isdir(priordir), +if exist(priordir,'dir') ~= 7 fprintf('Making directory for priors: %s\n',priordir); mkdir(priordir); else @@ -263,16 +259,16 @@ count=size(priorfiles,1); fprintf('Found %d existing priors in this directory\n',count); - if job.clean, + if job.clean fprintf('Deleting existing priors\n'); - for f=1:count, + for f=1:count delete(deblank(priorfiles(f,:))); - end; + end else fprintf('Keeping existing priors\n'); - end; + end -end; +end mesh=D.inv{val}.forward.mesh; %% assume this is in metres @@ -280,21 +276,21 @@ Ns=size(mesh.vert,1); -%% Set up sensor level prior +% Set up sensor level prior Qe{1}=eye(size(UL,1)).*job.sensorlevel; Qp={}; %% source level covariance or svd components -%% add in functional (from other modalities or experiment) hypotheses +% add in functional (from other modalities or experiment) hypotheses -for i=1:numel(job.priortype), %% move through different prior specifications +for i=1:numel(job.priortype) %% move through different prior specifications allIp=[]; Qp=[]; - %% RANDOM PATCH CENTRES - if isfield(job.priortype{i},'randpatch'), + % RANDOM PATCH CENTRES + if isfield(job.priortype{i},'randpatch') base=job.priortype{i}.randpatch; @@ -302,7 +298,7 @@ Npatchiter = base.niter; probfile=base.probfile; - if isempty(probfile), + if isempty(probfile) prob=ones(Ns,1)./Ns; else @@ -312,23 +308,23 @@ M0.vertices=probmesh.vertices; M0.faces=probmesh.faces; - if size(probmesh.vertices,1)==size(mesh.vert,1), + if size(probmesh.vertices,1)==size(mesh.vert,1) % fprintf('NB smoothing prior with 20 iterations\n'); %prob=spm_mesh_smooth(M0,data',20); prob=data; else error('Gifti mesh size does not match'); - end; - end; - if sum(prob)>1.01, + end + end + if sum(prob)>1.01 warning('Rescaling bias file to unit sum'); - end; + end prob=prob./sum(prob); Ip=[]; - disp(sprintf('Using %d iterations of %d random patches',Npatchiter,Np)); + fprintf('Using %d iterations of %d random patches\n',Npatchiter,Np); allIp=sparse(Npatchiter,Np); @@ -338,23 +334,23 @@ figure; hold on; - for j=1:Npatchiter, + for j=1:Npatchiter - for k=1:Np, + for k=1:Np pval=max(prob)*(k-1)./Np; sind=find(prob>=pval); randind=randperm(length(sind)); allIp(j,k)=sind(randind(1)); dum(allIp(j,k))=dum(allIp(j,k))+1; - end; + end %end; %% IF plot(1:length(prob),dum,'.'); drawnow; - end; % for j + end % for j fprintf('Sampled %3.2f percent of cortex (%d vertices) \n',100*length(find(dum>0))./length(dum),length(find(dum>0))); - end; % random patch + end % random patch - %% FIXED PATCH CENTRES FROM FILE + % FIXED PATCH CENTRES FROM FILE if isfield(job.priortype{i},'fixedpatch') base=job.priortype{i}.fixedpatch; @@ -362,28 +358,28 @@ dum=load(char(base.fixedfile)); catch error('failed to load fixedpatch file'); - end; - if ~isfield(dum,'Ip'), + end + if ~isfield(dum,'Ip') error('Need to have patch indices in structure Ip'); - end; + end allIp=dum.Ip; rows=base.fixedrows; lastrow=min(rows(2),size(allIp,1)); rowind=[rows(1):lastrow]; allIp=allIp(rowind,:); - end; % fixed patch + end % fixed patch %%%%%%%%%%%%%%% FIXED OR RANDOM PATCHES - if isfield(job.priortype{i},'fixedpatch') || isfield(job.priortype{i},'randpatch'), + if isfield(job.priortype{i},'fixedpatch') || isfield(job.priortype{i},'randpatch') - %% Set up patches on cortical surface determined by indices of allIp - %% one prior files per row of Ip + % Set up patches on cortical surface determined by indices of allIp + % one prior files per row of Ip [Qp,Qe,allpriornames]=spm_eeg_invert_setuppatches(allIp,mesh,base,priordir,Qe,UL); - end; % if fixedpatch or randpatch + end % if fixedpatch or randpatch % figure; @@ -437,27 +433,27 @@ %%%%%%%%%%% FUNCTIONALLY DEFINED PRIORS - if isfield(job.priortype{i},'funcpriors'), + if isfield(job.priortype{i},'funcpriors') base=job.priortype{i}.funcpriors; P = char(base.priorsmask); priors{i}.priortype='funcpriors'; priors{i}.priorfname=P; - disp(sprintf('Using priors from file %s',P)); + fprintf('Using priors from file %s\n',P); P=priors{i}.priorfname; [p,f,e] = fileparts(P); switch lower(e) case '.mat' a=load(P); - if isfield(a,'Qp'), + if isfield(a,'Qp') - disp('REplacing sensor and source posterior distribution'); - for f=1:numel(a.Qp), + disp('Replacing sensor and source posterior distribution'); + for f=1:numel(a.Qp) Qp{end+1}=a.Qp{f}; - end; + end - %% now need to compress the original Qe (say 275 channels) into reduced channel form + % now need to compress the original Qe (say 275 channels) into reduced channel form U=D.inv{val}.inverse.U{1}; %% get spatial modes definition disp('NOT SURE IF WE NEED TO RESCALE FOR CHAN REDUCTION'); scaleU=size(a.Qe,1)./size(U,1); % white noise power pwer channel reduce with number of channels @@ -470,7 +466,7 @@ else disp('loading just source level posterior'); Qp{end+1}=a.pQ; - end; + end @@ -493,7 +489,7 @@ Qp{end+1} = a.pQ; otherwise error('Unknown file type.'); - end; % switch + end % switch idnum=randi(1e6); @@ -501,19 +497,19 @@ fprintf('Saving %s\n',priorfname); F=[]; % no associated free energy value save(priorfname,'Qp','Qe','UL','F'); - end; % func priors + end % func priors - %% POPULAR PRIORS + % POPULAR PRIORS - if isfield(job.priortype{i},'popularpars'), + if isfield(job.priortype{i},'popularpars') base=job.priortype{i}.popularpars; - disp(sprintf('Adding prior covariance matrix for %s algorithm',base.popular)); + fprintf('Adding prior covariance matrix for %s algorithm\n',base.popular); - if strcmp(base.popular,'sparseEBB'), + if strcmp(base.popular,'sparseEBB') - %% calculate power on cortical surface - %% using beamformer assumptions + % calculate power on cortical surface + % using beamformer assumptions AYYA=D.inv{val}.inverse.AYYA; InvCov = spm_inv(AYYA); @@ -524,11 +520,11 @@ for bk = 1:Ns normpower = 1/(UL(:,bk)'*UL(:,bk)); Sourcepower(bk) = 1/(UL(:,bk)'*InvCov*UL(:,bk)); - %% normalise power by unit noise through lead fields + % normalise power by unit noise through lead fields allsource(bk) = Sourcepower(bk)./normpower; end - %% now get local maxima on mesh + % now get local maxima on mesh M.vertices=mesh.vert; M.faces=mesh.face; @@ -547,12 +543,12 @@ [Qp,Qe,allpriornames]=spm_eeg_invert_setuppatches(Ip,mesh,base,priordir,Qe{1},UL); - end; % sparse EBB + end % sparse EBB - if strcmp(base.popular,'EBB'), + if strcmp(base.popular,'EBB') - %% calculate power on cortical surface - %% using beamformer assumptions + % calculate power on cortical surface + % using beamformer assumptions AYYA=D.inv{val}.inverse.AYYA; InvCov = spm_inv(AYYA); @@ -563,7 +559,7 @@ for bk = 1:Ns normpower = 1/(UL(:,bk)'*UL(:,bk)); Sourcepower(bk) = 1/(UL(:,bk)'*InvCov*UL(:,bk)); - %% normalise power by unit noise through lead fields + % normalise power by unit noise through lead fields allsource(bk) = Sourcepower(bk)./normpower; end @@ -571,7 +567,7 @@ plot(allsource); legend('EBB'); hold on; - %% now get local maxima on mesh + % now get local maxima on mesh M.vertices=mesh.vert; M.faces=mesh.face; warning('Smoothing not used'); @@ -585,9 +581,9 @@ F=[]; save(priorfname,'Qp','Qe','UL','F'); - end; % EBB + end % EBB - if strcmp(base.popular,'COH'), + if strcmp(base.popular,'COH') % create minimum norm prior %------------------------------------------------------------------ @@ -597,7 +593,7 @@ M=[];M.faces=mesh.face;M.vertices=mesh.vert; dist=spm_mesh_distmtx(M,1); ind2=find(dist>0); - ind=find(dist0); %% indices of OPM chans in headcast + + + + +%%%%%%%%%%%% READ IN LABVIEW BINARY FILE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% containing the actual recorded data for OPMs and trigger channels +labviewfile=cell2mat(job.lbv); +[a1,b1,c1]=fileparts(labviewfile); +fprintf('\nReading binary file %s', labviewfile); +[time,B]=eb_read_lvm(labviewfile,timeind); +srate=1./mean(diff(time)); +fprintf('\nRead %d samples of %d channels at %3.2fHz sampling rate\n',size(B,1),size(B,2),srate); +% every second column is a radial sensor + +alltrigs=round(job.trigind); %% the adc channels containing the triggers + +megData = B(:,[opmadcind alltrigs])'; %% get data from the adcchannels that the OPMs were connected to. + + +outbase=sprintf('spm_%s_%s.dat',job.prefix,b1); %% name of output file + + +%% convert to SPM +if exist(outbase), + warning('SPM file already exists, OVERWRITING'); + D=spm_eeg_load(outbase); + D.delete; +end; + +D = spm_opm_convert(megData,outbase,srate,job.convert); + + +%% set appropriate Channel labels and types +Nopmchans=size(opm2slot,1); +D = chanlabels(D,1:Nopmchans,opm2slot(:,1)); +D = chantype(D,megind,'MEG'); +D = chantype(D,find(slotind==-1),'Ref'); +D=chantype(D,length(opmadcind)+1:length(opmadcind)+length(alltrigs),'Trig') +for f=1:length(alltrigs), + D=chanlabels(D,length(opmadcind)+1:length(opmadcind)+length(alltrigs),sprintf('tr%d',alltrigs(f))); +end; +save(D); + +%% slot positions and orientation into MEG object +% this table maps positions/orientations to headcast numbers and sensor +% labels + +if length(megind)~=size(posor,1) + error('File size mismatch'); +end; +figure; hold on; +grad.label = opm2slot(megind,1); %% names of the MEG channels in headcast +megpos=[];meglabels=[]; +for f=1:length(megind), %% megind indexes into slotind which gives the index into posor + castind=slotind(megind(f)); + grad.coilpos(f,:) = posor(castind,1:3); + grad.coilori(f,:) = posor(castind,4:6); + %plot3(grad.coilpos(f,1),grad.coilpos(f,2),grad.coilpos(f,3),'r.'); + %text(grad.coilpos(f,1),grad.coilpos(f,2),grad.coilpos(f,3),grad.label{f}); +end; + + +grad.tra = eye(numel(grad.label)); + + + +grad.chanunit = repmat({'T'}, numel(grad.label), 1); %% grad units always in Tesla (data units in fT) +grad = ft_datatype_sens(grad, 'amplitude', 'T', 'distance', 'mm'); + +D = sensors(D, 'MEG', grad); + +%% ORIENT SENSORS IN 2D BASED ON MEAN ORIENTATION +n1=mean(grad.coilori); n1= n1./sqrt(dot(n1,n1)); +t1=cross(n1,[0 0 1]); +t2=cross(t1,n1); + +for f=1:length(megind), + pos2d(f,1)=dot(grad.coilpos(f,:),t1); + pos2d(f,2)=dot(grad.coilpos(f,:),t2); + plot(pos2d(f,1),pos2d(f,2),'r.'); + text(pos2d(f,1),pos2d(f,2),grad.label{f}); +end; + +S=[]; %% SET SENSOR 2D POS +S.D=D; +S.xy= pos2d'; +S.label=grad.label; +S.task='setcoor2d'; +D=spm_eeg_prep(S); +D.save; +pos=D.coor2D'; +% for f=1:length(megind), +% +% h=text(pos(f,1),pos(f,2)+10,grad.label{f}); +% set(h,'color','m'); +% end; + +D.save; + +%%%%%%%%%%%%%% NOW COREGISTER - easiest to do this here as the opms and +%%%%%%%%%%%%%% head are defined in same native mri space +%% working from native to native space so fiducials should give identity transform + +newfid=[]; +newfid.fid.label = {'nas', 'lpa', 'rpa'}'; +newfid.fid.pnt=job.fid; + +mri_fids=newfid.fid.pnt; %%% the MRI fiducials will be the same as the MEG as everything is defined in native space for OPMs +D = fiducials(D, newfid); +save(D); +%%%%% now write out a bids format file to be read by coreg procedure + +[a1,b1,c1]=fileparts(cell2mat(job.M)); +json_fid = []; + +%json_fid.IntendedFor = cell2mat(fullfile(job.M)); +json_fid.IntendedFor = [b1 c1]; %% does not like full path for some reason +json_fid.AnatomicalMRICoordinateSystem = 'other'; +json_fid.AnatomicalMRICoordinateUnits = 'mm'; +json_fid.CoilCoordinates.nas = spm_vec(mri_fids(1, :)); +json_fid.CoilCoordinates.lpa = spm_vec(mri_fids(2, :)); +json_fid.CoilCoordinates.rpa = spm_vec(mri_fids(3, :)); +json_fid.CoilCoordinateSystem = 'native'; +json_fid.CoilCoordinateUnits = 'mm'; + +jsonname=[a1 filesep b1 '_fid.json']; +spm_jsonwrite(jsonname, json_fid); + +%test=spm_jsonread(jsonname); + + + +figure; + +plot3(posor(:,1),posor(:,2),posor(:,3),'ro'); hold on; +text(posor(:,1),posor(:,2),posor(:,3),slotname); +plot3(mri_fids(:,1),mri_fids(:,2),mri_fids(:,3),'m*'); +text(mri_fids(1,1),mri_fids(1,2),mri_fids(1,3),'nasion'); +text(mri_fids(2,1),mri_fids(2,2),mri_fids(2,3),'lpa'); +text(mri_fids(3,1),mri_fids(3,2),mri_fids(3,3),'rpa'); +fprintf('\n Will need to coregister later using the BIDS json file created here') + +figure; + + + +%% bandpass filter +fprintf('\n Filtering %d to %d Hz \n', job.band(1), job.band(2)); +S = []; +S.D = D; +S.type = 'butterworth'; +S.band = 'bandpass'; +S.freq = job.band; +S.dir = 'twopass'; +S.order = 2; +nD = spm_eeg_filter(S); + + +%%%%%%%%%%%%%%%%%epoching %%%%%%%%%%%%%% + +% this will be different for different datasets + +ev=[];cond={}; + +figure; %% ASSUME ONE BIT PER TRIG CHANNEL FOR NOW AND THRESHOLD AT 2* std deviation + +for f=1:length(alltrigs), + subplot(length(alltrigs),1,f); + thresh=std((B(:,alltrigs(f))))*2; + trigs=find(diff(B(:,alltrigs(f))>thresh)==1)+1; + plot(D.time,B(:,alltrigs(f))',D.time,ones(size(D.time))*thresh,':',D.time(trigs),ones(size(trigs))*thresh*2,'r*'); + legend(num2str(alltrigs(f)),'thresh','events'); xlabel('time');ylabel('adc value') + title('trigger'); + for j=1:length(trigs), + cond{j+length(ev)}=num2str(alltrigs(f)); + end; + ev = [ev; trigs]; %% trigger samples +end; + +fprintf('\n Epoching'); +offsettime=job.epwin(1)/1000; +duration=diff(job.epwin)/1000; +offsetsamples=round(offsettime.*nD.fsample); +durationsamples=round(duration.*nD.fsample); +begsample=ev+offsetsamples; +offset=offsetsamples.*ones(size(begsample)); +endsample=begsample+durationsamples; +%% should be in format : begin sample, end sample, offset +trl = round([begsample endsample offset]); +S = []; +S.D = nD; +S.trl = trl; +S.conditionlabels =cond; +S.bc = 0; +S.prefix = 'e_'; +eD = spm_eeg_epochs(S); + + +%% reference noise cancellation +refInd = selectchannels(eD,'Ref'); +%%spm_opm_denoise(D,refD,derivative,gs,update,prefix) +fprintf('\n Reference noise cancellation with flags %d %d', job.ncan(1),job.ncan(2)); +dD = spm_opm_denoise(eD,eD(refInd,:,:),job.ncan(1),job.ncan(2),1,'d'); + + +save(dD); + + +out.D = {fullfile(dD.path, dD.fname)}; +out.json={jsonname}; + +fprintf('\n Finished setup'); + + +function dep = vout_opmsetup(job) +% return dependencies +% Output is always in field "D", no matter how job is structured +dep = cfg_dep; +dep.sname = 'Prepared M/EEG Data'; +% reference field "D" from output +dep.src_output = substruct('.','D'); +% this can be entered into any evaluated input +dep.tgt_spec = cfg_findspec({{'filter','mat'}}); +%dep.tgt_spec = cfg_findspec({{'strtype','e'}}); + + +dep(2) = cfg_dep; +dep(2).sname = 'M/EEG fiducial information'; +dep(2).src_output = substruct('.','json'); +% this can be entered into any file selector +dep(2).tgt_spec = cfg_findspec({{'filter','mat'}}); + +% if job.phase +% dep(3) = cfg_dep; +% dep(3).sname = 'M/EEG time-frequency phase dataset'; +% dep(3).src_output = substruct('.','Dtph'); +% % this can be entered into any evaluated input +% dep(3).tgt_spec = cfg_findspec({{'strtype','e'}}); +% +% dep(4) = cfg_dep; +% dep(4).sname = 'M/EEG time-frequency phase dataset'; +% dep(4).src_output = substruct('.','Dtphname'); +% % this can be entered into any file selector +% dep(4).tgt_spec = cfg_findspec({{'filter','mat'}}); +% end +% diff --git a/config/spm_cfg_eeg_prepare.m b/config/spm_cfg_eeg_prepare.m index ccb085d6..0b44ab8b 100644 --- a/config/spm_cfg_eeg_prepare.m +++ b/config/spm_cfg_eeg_prepare.m @@ -1,12 +1,12 @@ function prepare = spm_cfg_eeg_prepare -% configuration file for the prepare tool -%_______________________________________________________________________ -% Copyright (C) 2012 Wellcome Trust Centre for Neuroimaging +% Configuration file for the prepare tool +%__________________________________________________________________________ +% Copyright (C) 2012-2016 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_cfg_eeg_prepare.m 6320 2015-01-27 16:18:40Z vladimir $ +% $Id: spm_cfg_eeg_prepare.m 7169 2017-09-19 10:42:27Z vladimir $ -rev = '$Rev: 6320 $'; +rev = '$Rev: 7169 $'; D = cfg_files; D.tag = 'D'; @@ -19,7 +19,14 @@ defaulttype.tag = 'defaulttype'; defaulttype.name = 'Set channel types to default'; defaulttype.val = {1}; -defaulttype.help = {'Reset all channel types to default'}; +defaulttype.help = {'Reset all channel types to default.'}; + +bidschantype = cfg_files; +bidschantype.tag = 'bidschantype'; +bidschantype.name = 'Set channel types from BIDS tsv'; +bidschantype.filter = '.*_channels.tsv$'; +bidschantype.num = [1 1]; +bidschantype.help = {'Select BIDS tsv file and set channel types based on it.'}; newtype = cfg_menu; newtype.tag = 'newtype'; @@ -27,56 +34,56 @@ newtype.labels = {'EEG', 'EOG', 'ECG', 'EMG', 'LFP', 'PHYS', 'ILAM', 'Other'}; newtype.val = {'Other'}; newtype.values = {'EEG', 'EOG', 'ECG', 'EMG', 'LFP', 'PHYS', 'ILAM', 'Other'}; -newtype.help = {'Select the new channel type to set'}; +newtype.help = {'Select the new channel type to set.'}; settype = cfg_branch; settype.tag = 'settype'; settype.name = 'Set channel type'; settype.val = {spm_cfg_eeg_channel_selector, newtype}; -settype.help = {'Select the new channel type to set'}; +settype.help = {'Select the new channel type to set.'}; rawmeg = cfg_files; rawmeg.tag = 'rawmeg'; rawmeg.name = 'Select MEG dataset'; rawmeg.filter = 'any'; rawmeg.num = [1 1]; -rawmeg.help = {'Select the MEG dataset to copy sensors from'}; +rawmeg.help = {'Select the MEG dataset to copy sensors from.'}; loadmegsens = cfg_branch; loadmegsens.tag = 'loadmegsens'; loadmegsens.name = 'Load MEG sensors'; loadmegsens.val = {rawmeg}; -loadmegsens.help = {'Reload MEG sensor representation from raw dataset'}; +loadmegsens.help = {'Reload MEG sensor representation from raw dataset.'}; megfid = cfg_files; megfid.tag = 'megfid'; megfid.name = 'Select MEG headshape file'; megfid.filter = 'any'; megfid.num = [1 1]; -megfid.help = {'Select the file to read MEG headshape from'}; +megfid.help = {'Select the file to read MEG headshape from.'}; fidname = cfg_entry; fidname.tag = 'fidname'; fidname.name = 'MEG fiducial label'; fidname.strtype = 's'; -fidname.help = {'Label of a fiducial point as specified in the MEG dataset'}; +fidname.help = {'Label of a fiducial point as specified in the MEG dataset.'}; hsname = cfg_entry; hsname.tag = 'hsname'; hsname.name = 'Surface point label'; hsname.strtype = 's'; -hsname.help = {'Label of a fiducial point as specified in the surface points file'}; +hsname.help = {'Label of a fiducial point as specified in the surface points file.'}; matching = cfg_branch; matching.tag = 'matching'; matching.name = 'Matching pair'; -matching.help = {'Specify a matching pair of labeled point in the dataset and surface points'}; +matching.help = {'Specify a matching pair of labeled point in the dataset and surface points.'}; matching.val = {fidname, hsname}; fiducials = cfg_repeat; fiducials.tag = 'fiducials'; fiducials.name = 'Fiducials'; -fiducials.help = {'Specify at least 3 matching pairs of fiducials to coregister the surface points to the sensors'}; +fiducials.help = {'Specify at least 3 matching pairs of fiducials to coregister the surface points to the sensors.'}; fiducials.num = [3 Inf]; fiducials.values = {matching}; fiducials.val = {matching matching matching}; @@ -85,28 +92,28 @@ headshape.tag = 'headshape'; headshape.name = 'Load MEG fiducials\headshape'; headshape.val = {megfid, fiducials}; -headshape.help = {'Load MEG fiducials or headshape from a file'}; +headshape.help = {'Load MEG fiducials or headshape from a file.'}; nasfid = cfg_entry; nasfid.tag = 'nasfid'; nasfid.name = 'Nasion'; nasfid.strtype = 's'; nasfid.val = {'nas'}; -nasfid.help = {'Enter the nasion fiducial label'}; +nasfid.help = {'Enter the nasion fiducial label.'}; lpafid = cfg_entry; lpafid.tag = 'lpafid'; lpafid.name = 'Left'; lpafid.strtype = 's'; lpafid.val = {'lpa'}; -lpafid.help = {'Enter the left fiducial label'}; +lpafid.help = {'Enter the left fiducial label.'}; rpafid = cfg_entry; rpafid.tag = 'rpafid'; rpafid.name = 'Right'; rpafid.strtype = 's'; rpafid.val = {'rpa'}; -rpafid.help = {'Enter the right fiducial label'}; +rpafid.help = {'Enter the right fiducial label.'}; multimodal = cfg_branch; multimodal.tag = 'multimodal'; @@ -118,72 +125,73 @@ defaulteegsens.tag = 'defaulteegsens'; defaulteegsens.name = 'Assign default EEG sensors'; defaulteegsens.val = {multimodal}; -defaulteegsens.help = {'Set EEG sensor locations to SPM template'}; +defaulteegsens.help = {'Set EEG sensor locations to SPM template.'}; eegsens = cfg_files; eegsens.tag = 'eegsens'; eegsens.name = 'Select EEG sensors file'; eegsens.filter = 'any'; eegsens.num = [1 1]; -eegsens.help = {'Select the file with EEG electrode coordinates (e.g. Polhemus or SFP)'}; +eegsens.help = {'Select the file with EEG electrode coordinates (e.g. Polhemus or SFP).'}; -nomatch = cfg_const; -nomatch.tag = 'nomatch'; +nomatch = cfg_const; +nomatch.tag = 'nomatch'; nomatch.name = 'Not necessary'; nomatch.val = {1}; +nomatch.help = {''}; megmatch = cfg_choice; megmatch.name = 'Match fiducials to MEG'; megmatch.tag = 'megmatch'; megmatch.values = {nomatch, fiducials}; megmatch.val = {nomatch}; -megmatch.help = {'Match EEG fiducials to MEG fiducials (only for multimodal datasets)'}; +megmatch.help = {'Match EEG fiducials to MEG fiducials (only for multimodal datasets).'}; loadeegsens = cfg_branch; loadeegsens.tag = 'loadeegsens'; loadeegsens.name = 'Load EEG sensors'; loadeegsens.val = {eegsens, megmatch}; -loadeegsens.help = {'Load EEG electrode locations'}; +loadeegsens.help = {'Load EEG electrode locations.'}; refsens = cfg_branch; refsens.tag = 'refsens'; refsens.name = 'Select reference sensors'; refsens.val = {spm_cfg_eeg_channel_selector('notype')}; refsens.help = {'Select the sensors to which the EEG recording was referenced',... - '(select ''All'' for average reference)'}; + '(select ''All'' for average reference).'}; montage = cfg_files; montage.tag = 'montage'; montage.name = 'Select montage file'; montage.filter = 'mat'; montage.num = [1 1]; -montage.help = {'Select montage file that specifies the referencing'}; +montage.help = {'Select montage file that specifies the referencing.'}; seteegref = cfg_choice; seteegref.tag = 'seteegref'; seteegref.name = 'Define EEG referencing'; seteegref.values = {refsens, montage}; seteegref.val = {refsens}; -seteegref.help = {'Define the way EEG channels were derived from sensors'}; +seteegref.help = {'Define the way EEG channels were derived from sensors.'}; project3dEEG = cfg_const; project3dEEG.tag = 'project3dEEG'; project3dEEG.name = 'Project EEG sensors to 2D'; project3dEEG.val = {1}; -project3dEEG.help = {'Project EEG sensor locations to 2D'}; +project3dEEG.help = {'Project EEG sensor locations to 2D.'}; project3dMEG = cfg_const; project3dMEG.tag = 'project3dMEG'; project3dMEG.name = 'Project MEG sensors to 2D'; project3dMEG.val = {1}; -project3dMEG.help = {'Project MEG sensor locations to 2D'}; +project3dMEG.help = {'Project MEG sensor locations to 2D.'}; loadtemplate = cfg_files; loadtemplate.tag = 'loadtemplate'; loadtemplate.name = 'Load channel template file'; loadtemplate.filter = 'mat'; loadtemplate.num = [1 1]; -loadtemplate.help = {'Specify 2D channel locations by loading a template file'}; +loadtemplate.help = {'Specify 2D channel locations by loading a template file.'}; status = cfg_menu; status.tag = 'status'; @@ -191,19 +199,28 @@ status.labels = {'GOOD', 'BAD'}; status.val = {1}; status.values = {0, 1}; -status.help = {'Select the new channel type to set'}; +status.help = {'Select the new channel type to set.'}; setbadchan = cfg_branch; setbadchan.tag = 'setbadchan'; setbadchan.name = 'Set/unset bad channels'; setbadchan.val = {spm_cfg_eeg_channel_selector, status}; -setbadchan.help = {'Set or clear bad flag for channels'}; +setbadchan.help = {'Set or clear bad flag for channels.'}; + +bidschanstatus = cfg_files; +bidschanstatus.tag = 'bidschanstatus'; +bidschanstatus.name = 'Set bad channels from BIDS tsv'; +bidschanstatus.filter = '.*_channels.tsv$'; +bidschanstatus.num = [1 1]; +bidschanstatus.help = {'Select BIDS tsv file and set channel status based on it.'}; + fname = cfg_entry; fname.tag = 'fname'; fname.name = 'Output file name'; fname.strtype = 's'; fname.val = {'avref_montage.mat'}; +fname.help = {''}; avref = cfg_branch; avref.tag = 'avref'; @@ -216,20 +233,21 @@ condlabel.tag = 'label'; condlabel.name = 'Condition label'; condlabel.strtype = 's'; +condlabel.help = {''}; condlist = cfg_repeat; condlist.tag = 'condlist'; condlist.name = 'Specify conditions list'; condlist.num = [1 Inf]; condlist.values = {condlabel}; -condlist.help = {'Specify the conditions order manually as a list'}; +condlist.help = {'Specify the conditions order manually as a list.'}; condfile = cfg_files; condfile.tag = 'condfile'; condfile.name = 'Read from conditions file'; condfile.filter = 'mat'; condfile.num = [1 1]; -condfile.help = {'Select a mat-file with cell array of condition labels'}; +condfile.help = {'Select a mat-file with cell array of condition labels.'}; sortconditions = cfg_choice; sortconditions.name = 'Sort conditions'; @@ -238,19 +256,41 @@ sortconditions.val = {condlist}; sortconditions.help = {'Specify conditions order.'}; +eventfile = cfg_files; +eventfile.tag = 'eventfile'; +eventfile.name = 'BIDS tsv file'; +eventfile.filter = '.*_events.tsv$'; +eventfile.num = [1 1]; +eventfile.help = {'File to load events from'}; + +replace = cfg_menu; +replace.tag = 'replace'; +replace.name = 'Replace existing events'; +replace.labels = {'Replace', 'Add'}; +replace.val = {1}; +replace.values = {1, 0}; +replace.help = {'Replace exisitng events or add to them'}; + +bidsevents = cfg_branch; +bidsevents.tag = 'bidsevents'; +bidsevents.name = 'Load events from BIDS tsv file'; +bidsevents.help = {'Load events from BIDS tsv file.'}; +bidsevents.val = {eventfile, replace}; + task = cfg_repeat; task.tag = 'task'; task.name = 'Select task(s)'; task.num = [1 Inf]; -task.values = {defaulttype, settype, loadmegsens, headshape,... +task.values = {defaulttype, bidschantype, settype, loadmegsens, headshape,... defaulteegsens, loadeegsens, seteegref, project3dEEG, project3dMEG,... - loadtemplate, setbadchan, avref, sortconditions}; + loadtemplate, setbadchan, bidschanstatus, avref, sortconditions, bidsevents}; +task.help = {'Select task(s).'}; prepare = cfg_exbranch; prepare.tag = 'prepare'; prepare.name = 'Prepare'; prepare.val = {D, task}; -prepare.help = {'Converts EEG/MEG data.'}; +prepare.help = {'Prepare EEG/MEG data.'}; prepare.prog = @eeg_prepare; prepare.vout = @vout_eeg_prepare; prepare.modality = {'EEG'}; @@ -265,6 +305,10 @@ case 'defaulttype' S.task = 'defaulttype'; D = spm_eeg_prep(S); + case 'bidschantype' + S.task = 'bidschantype'; + S.filename = char(job.task{i}.bidschantype); + D = spm_eeg_prep(S); case 'settype' S.task = 'settype'; S.type = job.task{i}.settype.newtype; @@ -328,6 +372,10 @@ S.task = 'setbadchan'; S.channels = spm_cfg_eeg_channel_selector(job.task{i}.setbadchan.channels); S.status = job.task{i}.setbadchan.status; + D = spm_eeg_prep(S); + case 'bidschanstatus' + S.task = 'bidschanstatus'; + S.filename = char(job.task{i}.bidschanstatus); D = spm_eeg_prep(S); case 'avref' eegchan = D.indchantype('EEG'); @@ -358,6 +406,12 @@ else S.condlist = char(job.task{i}.sortconditions.condfile); end + D = spm_eeg_prep(S); + case 'bidsevents' + S.task = 'loadbidsevents'; + S.filename = char(job.task{i}.bidsevents.eventfile); + S.replace = job.task{i}.bidsevents.replace; + D = spm_eeg_prep(S); end end diff --git a/config/spm_cfg_eeg_reduce.m b/config/spm_cfg_eeg_reduce.m index 2a59d6ee..132a7a22 100644 --- a/config/spm_cfg_eeg_reduce.m +++ b/config/spm_cfg_eeg_reduce.m @@ -4,7 +4,7 @@ % Copyright (C) 2010-2012 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_cfg_eeg_reduce.m 6829 2016-07-07 10:16:46Z vladimir $ +% $Id: spm_cfg_eeg_reduce.m 6929 2016-11-14 13:07:31Z guillaume $ %-------------------------------------------------------------------------- @@ -23,10 +23,12 @@ %-------------------------------------------------------------------------- method = cfg_choice; method.tag = 'method'; -method.name = 'Reduction method '; +method.name = 'Reduction method'; +method.help = {'Reduction method'}; specest_funs = spm_select('List',spm('dir'),'^spm_eeg_reduce_.*\.m$'); specest_funs = cellstr(specest_funs); +method.values = cell(1,numel(specest_funs)); for i = 1:numel(specest_funs) method.values{i} = feval(spm_file(specest_funs{i},'basename')); end diff --git a/config/spm_cfg_eeg_regressors.m b/config/spm_cfg_eeg_regressors.m index cb3a1487..cad832b1 100644 --- a/config/spm_cfg_eeg_regressors.m +++ b/config/spm_cfg_eeg_regressors.m @@ -4,7 +4,7 @@ % Copyright (C) 2014 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_cfg_eeg_regressors.m 6186 2014-09-22 11:31:11Z vladimir $ +% $Id: spm_cfg_eeg_regressors.m 6929 2016-11-14 13:07:31Z guillaume $ %-------------------------------------------------------------------------- @@ -22,11 +22,13 @@ %-------------------------------------------------------------------------- methods = cfg_repeat; methods.tag = 'methods'; -methods.name = 'Generation method '; +methods.name = 'Generation method'; methods.num = [1 Inf]; +methods.help = {'Generation method'}; reg_funs = spm_select('List',spm('dir'),'^spm_eeg_regressors_.*\.m$'); reg_funs = cellstr(reg_funs); +methods.values = cell(1,numel(reg_funs)); for i = 1:numel(reg_funs) methods.values{i} = feval(spm_file(reg_funs{i},'basename')); end diff --git a/config/spm_cfg_eeg_spatial_confounds.m b/config/spm_cfg_eeg_spatial_confounds.m index f7ef3b7d..b323997b 100644 --- a/config/spm_cfg_eeg_spatial_confounds.m +++ b/config/spm_cfg_eeg_spatial_confounds.m @@ -1,10 +1,10 @@ function sconfounds = spm_cfg_eeg_spatial_confounds % configuration file for reading montage files -%_______________________________________________________________________ -% Copyright (C) 2014 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2014-2016 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_cfg_eeg_spatial_confounds.m 6625 2015-12-03 21:49:24Z vladimir $ +% $Id: spm_cfg_eeg_spatial_confounds.m 6926 2016-11-09 22:13:19Z guillaume $ D = cfg_files; D.tag = 'D'; @@ -25,6 +25,7 @@ condlabel.tag = 'conditions'; condlabel.name = 'Condition label'; condlabel.strtype = 's'; +condlabel.help = {''}; conditions = cfg_repeat; conditions.tag = 'condrepeat'; @@ -39,7 +40,7 @@ ncomp.name = 'Number of components'; ncomp.strtype = 'n'; ncomp.num = [1 1]; -ncomp.help = {'Number of confound components to keep'}; +ncomp.help = {'Number of confound components to keep.'}; threshold = cfg_entry; threshold.tag = 'threshold'; @@ -93,7 +94,7 @@ clr.tag = 'clear'; clr.name = 'Clear'; clr.val = {1}; -clr.help = {'Clear previously defined spatial confounds'}; +clr.help = {'Clear previously defined spatial confounds.'}; mode = cfg_repeat; mode.tag = 'mode'; @@ -105,7 +106,7 @@ sconfounds.tag = 'sconfounds'; sconfounds.name = 'Define spatial confounds'; sconfounds.val = {D, mode}; -sconfounds.help = {'Define spatial confounds for topography-based correction of artefacts'}; +sconfounds.help = {'Define spatial confounds for topography-based correction of artefacts.'}; sconfounds.prog = @eeg_sconfounds; sconfounds.vout = @vout_eeg_sconfounds; sconfounds.modality = {'EEG'}; diff --git a/config/spm_cfg_eeg_tf.m b/config/spm_cfg_eeg_tf.m index b7b84b53..1386ffd0 100644 --- a/config/spm_cfg_eeg_tf.m +++ b/config/spm_cfg_eeg_tf.m @@ -4,7 +4,7 @@ % Copyright (C) 2010-2011 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_cfg_eeg_tf.m 6029 2014-05-30 18:52:03Z vladimir $ +% $Id: spm_cfg_eeg_tf.m 6929 2016-11-14 13:07:31Z guillaume $ %-------------------------------------------------------------------------- @@ -55,10 +55,12 @@ %-------------------------------------------------------------------------- method = cfg_choice; method.tag = 'method'; -method.name = 'Spectral estimation '; +method.name = 'Spectral estimation'; +method.help = {'Spectral estimation'}; specest_funs = spm_select('List',spm('dir'),'^spm_eeg_specest_.*\.m$'); specest_funs = cellstr(specest_funs); +method.values = cell(1,numel(specest_funs)); for i = 1:numel(specest_funs) method.values{i} = feval(spm_file(specest_funs{i},'basename')); end diff --git a/config/spm_cfg_exp_frames.m b/config/spm_cfg_exp_frames.m index 1dcc4172..067a59db 100644 --- a/config/spm_cfg_exp_frames.m +++ b/config/spm_cfg_exp_frames.m @@ -1,9 +1,9 @@ function exp_frames = spm_cfg_exp_frames % SPM Configuration file for Expand image frames %__________________________________________________________________________ -% Copyright (C) 2009-2014 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2009-2016 Wellcome Trust Centre for Neuroimaging -% $Id: spm_cfg_exp_frames.m 5956 2014-04-16 14:34:25Z guillaume $ +% $Id: spm_cfg_exp_frames.m 6952 2016-11-25 16:03:13Z guillaume $ %-------------------------------------------------------------------------- @@ -34,7 +34,7 @@ exp_frames.tag = 'exp_frames'; exp_frames.name = 'Expand image frames'; exp_frames.val = {files frames }; -exp_frames.help = {'Returns a list of image filenames with appended frame numbers.'}; +exp_frames.help = {'Return a list of image filenames with appended frame numbers.'}; exp_frames.prog = @run_frames; exp_frames.vout = @vout_frames; diff --git a/config/spm_cfg_factorial_design.m b/config/spm_cfg_factorial_design.m index 5fed5548..80d15942 100644 --- a/config/spm_cfg_factorial_design.m +++ b/config/spm_cfg_factorial_design.m @@ -1,10 +1,10 @@ function factorial_design = spm_cfg_factorial_design % SPM Configuration file for second-level models %__________________________________________________________________________ -% Copyright (C) 2005-2015 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2016 Wellcome Trust Centre for Neuroimaging % Will Penny -% $Id: spm_cfg_factorial_design.m 6333 2015-02-11 13:14:23Z guillaume $ +% $Id: spm_cfg_factorial_design.m 6952 2016-11-25 16:03:13Z guillaume $ %-------------------------------------------------------------------------- @@ -747,7 +747,7 @@ cov = cfg_files; cov.tag = 'files'; cov.name = 'File(s)'; -cov.val{1} = {''}; +cov.val = {{''}}; cov.help = { 'Select the *.mat/*.txt file(s) containing details of your multiple covariates. ' '' @@ -1035,14 +1035,15 @@ factorial_design.name = 'Factorial design specification'; factorial_design.val = {dir des generic generic2 masking globalc globalm}; factorial_design.help = { - 'This interface configures the design matrix, describing the general linear model, data specification, and other parameters necessary for the statistical analysis. These parameters are saved in a configuration file (SPM.mat), which can then be passed on to spm_spm.m which estimates the design. This is achieved by pressing the ''Estimate'' button. Inference on these estimated parameters is then handled by the SPM results section. ' - '' - 'This interface is used for setting up analyses of PET data, morphometric data, or ''second level'' (''random effects'') fMRI data, where first level models can be used to produce appropriate summary data that are then used as raw data for the second-level analysis. For example, a simple t-test on contrast images from the first-level turns out to be a random-effects analysis with random subject effects, inferring for the population based on a particular sample of subjects.' - '' - 'A separate interface handles design configuration for first level fMRI time series.' - '' - 'Various data and parameters need to be supplied to specify the design (1) the image files, (2) indicators of the corresponding condition/subject/group (2) any covariates, nuisance variables, or design matrix partitions (3) the type of global normalisation (if any) (4) grand mean scaling options (5) thresholds and masks defining the image volume to analyse. The interface supports a comprehensive range of options for all these parameters.' -}'; + 'Configuration of the design matrix, describing the general linear model, data specification, and other parameters necessary for the statistical analysis.' + 'These parameters are saved in a configuration file (SPM.mat), which can then be passed on to spm_spm.m which estimates the design. This is achieved by pressing the ''Estimate'' button. Inference on these estimated parameters is then handled by the SPM results section. ' + '' + 'This interface is used for setting up analyses of PET data, morphometric data, or ''second level'' (''random effects'') fMRI data, where first level models can be used to produce appropriate summary data that are then used as raw data for the second-level analysis. For example, a simple t-test on contrast images from the first-level turns out to be a random-effects analysis with random subject effects, inferring for the population based on a particular sample of subjects.' + '' + 'A separate interface handles design configuration for first level fMRI time series.' + '' + 'Various data and parameters need to be supplied to specify the design (1) the image files, (2) indicators of the corresponding condition/subject/group (2) any covariates, nuisance variables, or design matrix partitions (3) the type of global normalisation (if any) (4) grand mean scaling options (5) thresholds and masks defining the image volume to analyse. The interface supports a comprehensive range of options for all these parameters.' + }'; factorial_design.prog = @spm_run_factorial_design; factorial_design.vout = @vout_stats; diff --git a/config/spm_cfg_fmri_data.m b/config/spm_cfg_fmri_data.m index 72e01b1a..4fffd4dd 100644 --- a/config/spm_cfg_fmri_data.m +++ b/config/spm_cfg_fmri_data.m @@ -1,9 +1,9 @@ function fmri_data = spm_cfg_fmri_data % SPM Configuration file for fMRI data specification %__________________________________________________________________________ -% Copyright (C) 2005-2014 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2016 Wellcome Trust Centre for Neuroimaging -% $Id: spm_cfg_fmri_data.m 6088 2014-07-03 17:57:09Z guillaume $ +% $Id: spm_cfg_fmri_data.m 6952 2016-11-25 16:03:13Z guillaume $ %-------------------------------------------------------------------------- @@ -12,7 +12,10 @@ scans = cfg_files; scans.tag = 'scans'; scans.name = 'Scans'; -scans.help = {'Select the fMRI scans for this session. They must all have the same image dimensions, orientation, voxel size etc.'}; +scans.help = { + 'Select the fMRI scans for this session.' + 'They must all have the same image dimensions, orientation, voxel size etc.' + }'; scans.filter = {'image','mesh'}; scans.ufilter = '.*'; scans.num = [1 Inf]; @@ -34,8 +37,11 @@ mask = cfg_files; mask.tag = 'mask'; mask.name = 'Explicit mask'; -mask.val{1} = {''}; -mask.help = {'Specify an image for explicitly masking the analysis. A sensible option here is to use a segmention of structural images to specify a within-brain mask. If you select that image as an explicit mask then only those voxels in the brain will be analysed. This both speeds the estimation and restricts SPMs/PPMs to within-brain voxels. Alternatively, if such structural images are unavailable or no masking is required, then leave this field empty.'}; +mask.val = {{''}}; +mask.help = { + 'Specify an image for explicitly masking the analysis.' + 'A sensible option here is to use a segmention of structural images to specify a within-brain mask. If you select that image as an explicit mask then only those voxels in the brain will be analysed. This both speeds the estimation and restricts SPMs/PPMs to within-brain voxels. Alternatively, if such structural images are unavailable or no masking is required, then leave this field empty.' + }'; mask.filter = {'image','mesh'}; mask.ufilter = '.*'; mask.num = [0 1]; @@ -46,8 +52,8 @@ fmri_data = cfg_exbranch; fmri_data.tag = 'fmri_data'; fmri_data.name = 'fMRI data specification'; -fmri_data.val = {scans spmmat mask }; -fmri_data.help = {'Select the data and optional explicit mask for a specified design'}; +fmri_data.val = {scans spmmat mask}; +fmri_data.help = {'Select data and optional explicit mask for a specified fMRI design'}; fmri_data.prog = @spm_run_fmri_data; fmri_data.vout = @vout_stats; fmri_data.modality = {'FMRI'}; diff --git a/config/spm_cfg_fmri_design.m b/config/spm_cfg_fmri_design.m index 4af72b9a..48857f0c 100644 --- a/config/spm_cfg_fmri_design.m +++ b/config/spm_cfg_fmri_design.m @@ -1,9 +1,9 @@ function fmri_design = spm_cfg_fmri_design % SPM Configuration file for fMRI model specification (design only) %_______________________________________________________________________ -% Copyright (C) 2005-2014 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2016 Wellcome Trust Centre for Neuroimaging -% $Id: spm_cfg_fmri_design.m 6818 2016-06-21 09:42:45Z peter $ +% $Id: spm_cfg_fmri_design.m 6952 2016-11-25 16:03:13Z guillaume $ % --------------------------------------------------------------------- @@ -230,7 +230,7 @@ multi = cfg_files; multi.tag = 'multi'; multi.name = 'Multiple conditions'; -multi.val{1} = {''}; +multi.val = {{''}}; multi.help = { 'Select the *.mat file containing details of your multiple experimental conditions. ' '' @@ -305,7 +305,7 @@ multi_reg = cfg_files; multi_reg.tag = 'multi_reg'; multi_reg.name = 'Multiple regressors'; -multi_reg.val{1} = {''}; +multi_reg.val = {{''}}; multi_reg.help = { 'Select the *.mat/*.txt file(s) containing details of your multiple regressors. ' '' @@ -596,51 +596,51 @@ fmri_design.name = 'fMRI model specification (design only)'; fmri_design.val = {dir timing generic generic1 bases volt xGlobal gMT cvi }; fmri_design.help = { - 'Statistical analysis of fMRI data uses a mass-univariate approach based on General Linear Models (GLMs). It comprises the following steps (1) specification of the GLM design matrix, fMRI data files and filtering (2) estimation of GLM paramaters using classical or Bayesian approaches and (3) interrogation of results using contrast vectors to produce Statistical Parametric Maps (SPMs) or Posterior Probability Maps (PPMs).' - '' - 'The design matrix defines the experimental design and the nature of hypothesis testing to be implemented. The design matrix has one row for each scan and one column for each effect or explanatory variable. (eg. regressor or stimulus function). You can build design matrices with separable session-specific partitions. Each partition may be the same (in which case it is only necessary to specify it once) or different. ' - '' - 'Responses can be either event- or epoch related, the only distinction is the duration of the underlying input or stimulus function. Mathematically they are both modeled by convolving a series of delta (stick) or box functions (u), indicating the onset of an event or epoch with a set of basis functions. These basis functions model the hemodynamic convolution, applied by the brain, to the inputs. This convolution can be first-order or a generalized convolution modeled to second order (if you specify the Volterra option). The same inputs are used by the Hemodynamic model or Dynamic Causal Models which model the convolution explicitly in terms of hidden state variables. ' - '' - 'Basis functions can be used to plot estimated responses to single events once the parameters (i.e. basis function coefficients) have been estimated. The importance of basis functions is that they provide a graceful transition between simple fixed response models (like the box-car) and finite impulse response (FIR) models, where there is one basis function for each scan following an event or epoch onset. The nice thing about basis functions, compared to FIR models, is that data sampling and stimulus presentation does not have to be synchronized thereby allowing a uniform and unbiased sampling of peri-stimulus time.' - '' - 'Event-related designs may be stochastic or deterministic. Stochastic designs involve one of a number of trial-types occurring with a specified probability at successive intervals in time. These probabilities can be fixed (stationary designs) or time-dependent (modulated or non-stationary designs). The most efficient designs obtain when the probabilities of every trial type are equal. A critical issue in stochastic designs is whether to include null events If you wish to estimate the evoked response to a specific event type (as opposed to differential responses) then a null event must be included (even if it is not modeled explicitly).' - '' - 'In SPM, analysis of data from multiple subjects typically proceeds in two stages using models at two ''levels''. The ''first level'' models are used to implement a within-subject analysis. Typically there will be as many first level models as there are subjects. Analysis proceeds as described using the ''Specify first level'' and ''Estimate'' options. The results of these analyses can then be presented as ''case studies''. More often, however, one wishes to make inferences about the population from which the subjects were drawn. This is an example of a ''Random-Effects (RFX) analysis'' (or, more properly, a mixed-effects analysis). In SPM, RFX analysis is implemented using the ''summary-statistic'' approach where contrast images from each subject are used as summary measures of subject responses. These are then entered as data into a ''second level'' model. ' -}'; + 'Specification of a General Linear Model for statistical analysis of fMRI data (design only).' + '' + 'It comprises the following steps (1) specification of the GLM design matrix, fMRI data files and filtering (2) estimation of GLM paramaters using classical or Bayesian approaches and (3) interrogation of results using contrast vectors to produce Statistical Parametric Maps (SPMs) or Posterior Probability Maps (PPMs).' + '' + 'The design matrix defines the experimental design and the nature of hypothesis testing to be implemented. The design matrix has one row for each scan and one column for each effect or explanatory variable. (eg. regressor or stimulus function). You can build design matrices with separable session-specific partitions. Each partition may be the same (in which case it is only necessary to specify it once) or different. ' + '' + 'Responses can be either event- or epoch related, the only distinction is the duration of the underlying input or stimulus function. Mathematically they are both modeled by convolving a series of delta (stick) or box functions (u), indicating the onset of an event or epoch with a set of basis functions. These basis functions model the hemodynamic convolution, applied by the brain, to the inputs. This convolution can be first-order or a generalized convolution modeled to second order (if you specify the Volterra option). The same inputs are used by the Hemodynamic model or Dynamic Causal Models which model the convolution explicitly in terms of hidden state variables. ' + '' + 'Basis functions can be used to plot estimated responses to single events once the parameters (i.e. basis function coefficients) have been estimated. The importance of basis functions is that they provide a graceful transition between simple fixed response models (like the box-car) and finite impulse response (FIR) models, where there is one basis function for each scan following an event or epoch onset. The nice thing about basis functions, compared to FIR models, is that data sampling and stimulus presentation does not have to be synchronized thereby allowing a uniform and unbiased sampling of peri-stimulus time.' + '' + 'Event-related designs may be stochastic or deterministic. Stochastic designs involve one of a number of trial-types occurring with a specified probability at successive intervals in time. These probabilities can be fixed (stationary designs) or time-dependent (modulated or non-stationary designs). The most efficient designs obtain when the probabilities of every trial type are equal. A critical issue in stochastic designs is whether to include null events If you wish to estimate the evoked response to a specific event type (as opposed to differential responses) then a null event must be included (even if it is not modeled explicitly).' + '' + 'In SPM, analysis of data from multiple subjects typically proceeds in two stages using models at two ''levels''. The ''first level'' models are used to implement a within-subject analysis. Typically there will be as many first level models as there are subjects. Analysis proceeds as described using the ''Specify first level'' and ''Estimate'' options. The results of these analyses can then be presented as ''case studies''. More often, however, one wishes to make inferences about the population from which the subjects were drawn. This is an example of a ''Random-Effects (RFX) analysis'' (or, more properly, a mixed-effects analysis). In SPM, RFX analysis is implemented using the ''summary-statistic'' approach where contrast images from each subject are used as summary measures of subject responses. These are then entered as data into a ''second level'' model. ' + }'; fmri_design.prog = @spm_run_fmri_spec; fmri_design.vout = @vout_stats; fmri_design.modality = {'FMRI'}; -%------------------------------------------------------------------------- -%------------------------------------------------------------------------ + +%========================================================================== function t = cond_check(job) t = {}; -if (numel(job.onset) ~= numel(job.duration)) && (numel(job.duration)~=1), +if (numel(job.onset) ~= numel(job.duration)) && (numel(job.duration)~=1) t = {sprintf('"%s": Number of event onsets (%d) does not match the number of durations (%d).',... job.name, numel(job.onset),numel(job.duration))}; -end; -for i=1:numel(job.pmod), - if numel(job.onset) ~= numel(job.pmod(i).param), +end +for i=1:numel(job.pmod) + if numel(job.onset) ~= numel(job.pmod(i).param) t = {t{:}, sprintf('"%s" & "%s":Number of event onsets (%d) does not equal the number of parameters (%d).',... job.name, job.pmod(i).name, numel(job.onset),numel(job.pmod(i).param))}; - end; -end; -return; -%------------------------------------------------------------------------- + end +end -%------------------------------------------------------------------------- + +%========================================================================== function t = sess_check(sess) t = {}; -for i=1:numel(sess.regress), - if sess.nscan ~= numel(sess.regress(i).val), +for i=1:numel(sess.regress) + if sess.nscan ~= numel(sess.regress(i).val) t = {t{:}, sprintf('Num scans (%d) ~= Num regress[%d] (%d).',numel(sess.nscan),i,numel(sess.regress(i).val))}; - end; -end; -return; -%------------------------------------------------------------------------- + end +end + -%------------------------------------------------------------------------- +%========================================================================== function dep = vout_stats(job) dep(1) = cfg_dep; dep(1).sname = 'SPM.mat File'; diff --git a/config/spm_cfg_fmri_est.m b/config/spm_cfg_fmri_est.m index 4a7b95da..5fc0fb5b 100644 --- a/config/spm_cfg_fmri_est.m +++ b/config/spm_cfg_fmri_est.m @@ -1,9 +1,9 @@ function fmri_est = spm_cfg_fmri_est % SPM Configuration file for Model Estimation %__________________________________________________________________________ -% Copyright (C) 2005-2013 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2016 Wellcome Trust Centre for Neuroimaging -% $Id: spm_cfg_fmri_est.m 5959 2014-04-16 17:14:33Z will $ +% $Id: spm_cfg_fmri_est.m 6952 2016-11-25 16:03:13Z guillaume $ %========================================================================== @@ -13,9 +13,9 @@ spmmat.tag = 'spmmat'; spmmat.name = 'Select SPM.mat'; spmmat.help = { - 'Select the SPM.mat file that contains the design specification. ' - 'The directory containing this file is known as the input directory.' -}'; + 'Select the SPM.mat file that contains the design specification.' + 'The directory containing this file is known as the input directory.' + }'; spmmat.filter = 'mat'; spmmat.ufilter = '^SPM\.mat$'; spmmat.num = [1 1]; @@ -28,10 +28,11 @@ Classical.name = 'Classical'; Classical.val = {1}; Classical.help = { - 'Model parameters are estimated using Restricted Maximum Likelihood (ReML). This assumes the error correlation structure is the same at each voxel. This correlation can be specified using either an AR(1) or an Independent and Identically Distributed (IID) error model. These options are chosen at the model specification stage. ReML estimation should be applied to spatially smoothed functional images.' - '' - 'After estimation, specific profiles of parameters are tested using a linear compound or contrast with the T or F statistic. The resulting statistical map constitutes an SPM. The SPM{T}/{F} is then characterised in terms of focal or regional differences by assuming that (under the null hypothesis) the components of the SPM (ie. residual fields) behave as smooth stationary Gaussian fields.' -}'; + 'Model parameters are estimated using Restricted Maximum Likelihood (ReML).' + 'This assumes the error correlation structure is the same at each voxel. This correlation can be specified using either an AR(1) or an Independent and Identically Distributed (IID) error model. These options are chosen at the model specification stage. ReML estimation should be applied to spatially smoothed functional images.' + '' + 'After estimation, specific profiles of parameters are tested using a linear compound or contrast with the T or F statistic. The resulting statistical map constitutes an SPM. The SPM{T}/{F} is then characterised in terms of focal or regional differences by assuming that (under the null hypothesis) the components of the SPM (ie. residual fields) behave as smooth stationary Gaussian fields.' + }'; %-------------------------------------------------------------------------- % volBlocktype Block type @@ -404,7 +405,10 @@ fmri_est.tag = 'fmri_est'; fmri_est.name = 'Model estimation'; fmri_est.val = {spmmat write_residuals method}; -fmri_est.help = {'Model parameters can be estimated using classical (ReML - Restricted Maximum Likelihood) or Bayesian algorithms. After parameter estimation, the RESULTS button can be used to specify contrasts that will produce Statistical Parametric Maps (SPMs) or Posterior Probability Maps (PPMs) and tables of statistics.'}; +fmri_est.help = { + 'Estimation of model parameters using classical (ReML - Restricted Maximum Likelihood) or Bayesian algorithms.' + 'After parameter estimation, the ''Results'' button can be used to specify contrasts that will produce Statistical Parametric Maps (SPMs) or Posterior Probability Maps (PPMs) and tables of statistics.' + }'; fmri_est.prog = @spm_run_fmri_est; fmri_est.vout = @vout_stats; fmri_est.modality = {'FMRI' 'PET' 'EEG'}; diff --git a/config/spm_cfg_fmri_spec.m b/config/spm_cfg_fmri_spec.m index dbf60f9f..5ccbeada 100644 --- a/config/spm_cfg_fmri_spec.m +++ b/config/spm_cfg_fmri_spec.m @@ -1,9 +1,9 @@ function fmri_spec = spm_cfg_fmri_spec % SPM Configuration file for fMRI model specification %__________________________________________________________________________ -% Copyright (C) 2005-2015 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2016 Wellcome Trust Centre for Neuroimaging -% $Id: spm_cfg_fmri_spec.m 6818 2016-06-21 09:42:45Z peter $ +% $Id: spm_cfg_fmri_spec.m 6952 2016-11-25 16:03:13Z guillaume $ %-------------------------------------------------------------------------- @@ -33,7 +33,10 @@ RT = cfg_entry; RT.tag = 'RT'; RT.name = 'Interscan interval'; -RT.help = {'Interscan interval, TR, (specified in seconds). This is the time between acquiring a plane of one volume and the same plane in the next volume. It is assumed to be constant throughout.'}; +RT.help = { + 'Interscan interval, TR, (specified in seconds).' + 'This is the time between acquiring a plane of one volume and the same plane in the next volume. It is assumed to be constant throughout.' + }'; RT.strtype = 'r'; RT.num = [1 1]; @@ -44,10 +47,9 @@ fmri_t.tag = 'fmri_t'; fmri_t.name = 'Microtime resolution'; fmri_t.help = { - 'The microtime resolution, t, is the number of time-bins per scan used when building regressors. ' - 'If you have performed slice-timing correction, change this parameter to match the number of slices specified there; otherwise, you would typically not need to change this.' - '' -}'; + 'The microtime resolution, t, is the number of time-bins per scan used when building regressors.' + 'If you have performed slice-timing correction, change this parameter to match the number of slices specified there; otherwise, you would typically not need to change this.' + }'; fmri_t.strtype = 'n'; fmri_t.num = [1 1]; fmri_t.def = @(val)spm_get_defaults('stats.fmri.t', val{:}); @@ -59,13 +61,12 @@ fmri_t0.tag = 'fmri_t0'; fmri_t0.name = 'Microtime onset'; fmri_t0.help = { - 'The microtime onset, t0, is the reference time-bin at which the regressors are resampled to coincide with data acquisition.' - 'If you have performed slice-timing correction, you must change this parameter to match the reference slice specified there.' - 'Otherwise, you might still want to change this if you have non-interleaved acquisition and you wish to sample the regressors so that they are appropriate for a slice in a particular part of the brain.' - 'For example, if t0 = 1, then the regressors will be appropriate for the first slice; if t0=t, then the regressors will be appropriate for the last slice.' - 'Setting t0 = t/2 is a good compromise if you are interested in slices at the beginning and end of the acquisition, or if you have interleaved data, or if you have 3D EPI data.' - '' -}'; + 'The microtime onset, t0, is the reference time-bin at which the regressors are resampled to coincide with data acquisition.' + 'If you have performed slice-timing correction, you must change this parameter to match the reference slice specified there.' + 'Otherwise, you might still want to change this if you have non-interleaved acquisition and you wish to sample the regressors so that they are appropriate for a slice in a particular part of the brain.' + 'For example, if t0 = 1, then the regressors will be appropriate for the first slice; if t0=t, then the regressors will be appropriate for the last slice.' + 'Setting t0 = t/2 is a good compromise if you are interested in slices at the beginning and end of the acquisition, or if you have interleaved data, or if you have 3D EPI data.' + }'; fmri_t0.strtype = 'n'; fmri_t0.num = [1 1]; fmri_t0.def = @(val)spm_get_defaults('stats.fmri.t0', val{:}); @@ -78,10 +79,11 @@ timing.name = 'Timing parameters'; timing.val = {units RT fmri_t fmri_t0 }; timing.help = { - 'Specify various timing parameters needed to construct the design matrix. This includes the units of the design specification and the interscan interval.' - '' - 'Also, with longs TRs you may want to shift the regressors so that they are aligned to a particular slice. This is effected by changing the microtime resolution and onset. ' -}'; + 'Specify various timing parameters needed to construct the design matrix.' + 'This includes the units of the design specification and the interscan interval.' + '' + 'Also, with longs TRs you may want to shift the regressors so that they are aligned to a particular slice. This is effected by changing the microtime resolution and onset. ' + }'; %-------------------------------------------------------------------------- % scans Scans @@ -89,7 +91,7 @@ scans = cfg_files; scans.tag = 'scans'; scans.name = 'Scans'; -scans.help = {'Select the fMRI scans for this session. They must all have the same image dimensions, orientation, voxel size etc.'}; +scans.help = {'Select the fMRI scans for this session. They must all have the same image dimensions, orientation, voxel size etc.'}; scans.filter = {'image','mesh'}; scans.ufilter = '.*'; scans.num = [1 Inf]; @@ -100,7 +102,7 @@ name = cfg_entry; name.tag = 'name'; name.name = 'Name'; -name.help = {'Condition Name'}; +name.help = {'Condition Name.'}; name.strtype = 's'; name.num = [1 Inf]; @@ -110,7 +112,7 @@ onset = cfg_entry; onset.tag = 'onset'; onset.name = 'Onsets'; -onset.help = {'Specify a vector of onset times for this condition type. '}; +onset.help = {'Specify a vector of onset times for this condition type.'}; onset.strtype = 'r'; onset.num = [Inf 1]; @@ -120,7 +122,10 @@ duration = cfg_entry; duration.tag = 'duration'; duration.name = 'Durations'; -duration.help = {'Specify the event durations. Epoch and event-related responses are modeled in exactly the same way but by specifying their different durations. Events are specified with a duration of 0. If you enter a single number for the durations it will be assumed that all trials conform to this duration. If you have multiple different durations, then the number must match the number of onset times.'}; +duration.help = { + 'Specify the event durations.' + 'Epoch and event-related responses are modeled in exactly the same way but by specifying their different durations. Events are specified with a duration of 0. If you enter a single number for the durations it will be assumed that all trials conform to this duration. If you have multiple different durations, then the number must match the number of onset times.' + }'; duration.strtype = 'r'; duration.num = [Inf 1]; @@ -131,10 +136,10 @@ tmod.tag = 'tmod'; tmod.name = 'Time Modulation'; tmod.help = { - 'This option allows for the characterisation of linear or nonlinear time effects. For example, 1st order modulation would model the stick functions and a linear change of the stick function heights over time. Higher order modulation will introduce further columns that contain the stick functions scaled by time squared, time cubed etc.' - '' - 'Interactions or response modulations can enter at two levels. Firstly the stick function itself can be modulated by some parametric variate (this can be time or some trial-specific variate like reaction time) modeling the interaction between the trial and the variate or, secondly interactions among the trials themselves can be modeled using a Volterra series formulation that accommodates interactions over time (and therefore within and between trial types).' -}'; + 'This option allows for the characterisation of linear or nonlinear time effects. For example, 1st order modulation would model the stick functions and a linear change of the stick function heights over time. Higher order modulation will introduce further columns that contain the stick functions scaled by time squared, time cubed etc.' + '' + 'Interactions or response modulations can enter at two levels. Firstly the stick function itself can be modulated by some parametric variate (this can be time or some trial-specific variate like reaction time) modeling the interaction between the trial and the variate or, secondly interactions among the trials themselves can be modeled using a Volterra series formulation that accommodates interactions over time (and therefore within and between trial types).' + }'; tmod.labels = { 'No Time Modulation' '1st order Time Modulation' @@ -190,12 +195,12 @@ pmod = cfg_branch; pmod.tag = 'pmod'; pmod.name = 'Parameter'; -pmod.val = {name1 param poly }; +pmod.val = {name1 param poly}; pmod.help = { - 'Model interactions with user specified parameters. This allows nonlinear effects relating to some other measure to be modelled in the design matrix.' - '' - 'Interactions or response modulations can enter at two levels. Firstly the stick function itself can be modulated by some parametric variate (this can be time or some trial-specific variate like reaction time) modeling the interaction between the trial and the variate or, secondly interactions among the trials themselves can be modeled using a Volterra series formulation that accommodates interactions over time (and therefore within and between trial types).' -}'; + 'Model interactions with user specified parameters. This allows nonlinear effects relating to some other measure to be modelled in the design matrix.' + '' + 'Interactions or response modulations can enter at two levels. Firstly the stick function itself can be modulated by some parametric variate (this can be time or some trial-specific variate like reaction time) modeling the interaction between the trial and the variate or, secondly interactions among the trials themselves can be modeled using a Volterra series formulation that accommodates interactions over time (and therefore within and between trial types).' + }'; %-------------------------------------------------------------------------- % generic Parametric Modulations @@ -204,7 +209,7 @@ generic2.tag = 'generic'; generic2.name = 'Parametric Modulations'; generic2.help = {'The stick function itself can be modulated by some parametric variate (this can be time or some trial-specific variate like reaction time) modeling the interaction between the trial and the variate. The events can be modulated by zero or more parameters.'}; -generic2.values = {pmod }; +generic2.values = {pmod}; generic2.num = [0 Inf]; %-------------------------------------------------------------------------- @@ -226,7 +231,10 @@ cond.name = 'Condition'; cond.val = {name onset duration tmod generic2 porth}; cond.check = @cond_check; -cond.help = {'An array of input functions is contructed, specifying occurrence events or epochs (or both). These are convolved with a basis set at a later stage to give regressors that enter into the design matrix. Interactions of evoked responses with some parameter (time or a specified variate) enter at this stage as additional columns in the design matrix with each trial multiplied by the [expansion of the] trial-specific parameter. The 0th order expansion is simply the main effect in the first column.'}; +cond.help = { + 'An array of input functions is contructed, specifying occurrence events or epochs (or both).' + 'These are convolved with a basis set at a later stage to give regressors that enter into the design matrix. Interactions of evoked responses with some parameter (time or a specified variate) enter at this stage as additional columns in the design matrix with each trial multiplied by the [expansion of the] trial-specific parameter. The 0th order expansion is simply the main effect in the first column.' + }'; %-------------------------------------------------------------------------- % generic Conditions @@ -234,7 +242,10 @@ generic1 = cfg_repeat; generic1.tag = 'generic'; generic1.name = 'Conditions'; -generic1.help = {'You are allowed to combine both event- and epoch-related responses in the same model and/or regressor. Any number of condition (event or epoch) types can be specified. Epoch and event-related responses are modeled in exactly the same way by specifying their onsets [in terms of onset times] and their durations. Events are specified with a duration of 0. If you enter a single number for the durations it will be assumed that all trials conform to this duration.For factorial designs, one can later associate these experimental conditions with the appropriate levels of experimental factors. '}; +generic1.help = { + 'You are allowed to combine both event- and epoch-related responses in the same model and/or regressor.' + 'Any number of condition (event or epoch) types can be specified. Epoch and event-related responses are modeled in exactly the same way by specifying their onsets [in terms of onset times] and their durations. Events are specified with a duration of 0. If you enter a single number for the durations it will be assumed that all trials conform to this duration. For factorial designs, one can later associate these experimental conditions with the appropriate levels of experimental factors.' + }'; generic1.values = {cond }; generic1.num = [0 Inf]; @@ -244,37 +255,37 @@ multi = cfg_files; multi.tag = 'multi'; multi.name = 'Multiple conditions'; -multi.val{1} = {''}; +multi.val = {{''}}; multi.help = { - 'Select the *.mat file containing details of your multiple experimental conditions. ' - '' - 'If you have multiple conditions then entering the details a condition at a time is very inefficient. This option can be used to load all the required information in one go. You will first need to create a *.mat file containing the relevant information. ' - '' - 'This *.mat file must include the following cell arrays (each 1 x n): names, onsets and durations. eg. names=cell(1,5), onsets=cell(1,5), durations=cell(1,5), then names{2}=''SSent-DSpeak'', onsets{2}=[3 5 19 222], durations{2}=[0 0 0 0], contain the required details of the second condition. These cell arrays may be made available by your stimulus delivery program, eg. COGENT. The duration vectors can contain a single entry if the durations are identical for all events. Optionally, a (1 x n) cell array named orth can also be included, with a 1 or 0 for each condition to indicate whether parameteric modulators should be orthogonalised.' - '' - 'Time and Parametric effects can also be included. For time modulation include a cell array (1 x n) called tmod. It should have a have a single number in each cell. Unused cells may contain either a 0 or be left empty. The number specifies the order of time modulation from 0 = No Time Modulation to 6 = 6th Order Time Modulation. eg. tmod{3} = 1, modulates the 3rd condition by a linear time effect.' - '' - 'For parametric modulation include a structure array, which is up to 1 x n in size, called pmod. n must be less than or equal to the number of cells in the names/onsets/durations cell arrays. The structure array pmod must have the fields: name, param and poly. Each of these fields is in turn a cell array to allow the inclusion of one or more parametric effects per column of the design. The field name must be a cell array containing strings. The field param is a cell array containing a vector of parameters. Remember each parameter must be the same length as its corresponding onsets vector. The field poly is a cell array (for consistency) with each cell containing a single number specifying the order of the polynomial expansion from 1 to 6.' - '' - 'Note that each condition is assigned its corresponding entry in the structure array (condition 1 parametric modulators are in pmod(1), condition 2 parametric modulators are in pmod(2), etc. Within a condition multiple parametric modulators are accessed via each fields cell arrays. So for condition 1, parametric modulator 1 would be defined in pmod(1).name{1}, pmod(1).param{1}, and pmod(1).poly{1}. A second parametric modulator for condition 1 would be defined as pmod(1).name{2}, pmod(1).param{2} and pmod(1).poly{2}. If there was also a parametric modulator for condition 2, then remember the first modulator for that condition is in cell array 1: pmod(2).name{1}, pmod(2).param{1}, and pmod(2).poly{1}. If some, but not all conditions are parametrically modulated, then the non-modulated indices in the pmod structure can be left blank. For example, if conditions 1 and 3 but not condition 2 are modulated, then specify pmod(1) and pmod(3). Similarly, if conditions 1 and 2 are modulated but there are 3 conditions overall, it is only necessary for pmod to be a 1 x 2 structure array.' - '' - 'EXAMPLE:' - 'Make an empty pmod structure: ' - ' pmod = struct(''name'',{''''},''param'',{},''poly'',{});' - 'Specify one parametric regressor for the first condition: ' - ' pmod(1).name{1} = ''regressor1'';' - ' pmod(1).param{1} = [1 2 4 5 6];' - ' pmod(1).poly{1} = 1;' - 'Specify 2 parametric regressors for the second condition: ' - ' pmod(2).name{1} = ''regressor2-1'';' - ' pmod(2).param{1} = [1 3 5 7]; ' - ' pmod(2).poly{1} = 1;' - ' pmod(2).name{2} = ''regressor2-2'';' - ' pmod(2).param{2} = [2 4 6 8 10];' - ' pmod(2).poly{2} = 1;' - '' - 'The parametric modulator should be mean corrected if appropriate. Unused structure entries should have all fields left empty.' -}'; + 'Select the *.mat file containing details of your multiple experimental conditions.' + '' + 'If you have multiple conditions then entering the details a condition at a time is very inefficient. This option can be used to load all the required information in one go. You will first need to create a *.mat file containing the relevant information. ' + '' + 'This *.mat file must include the following cell arrays (each 1 x n): names, onsets and durations. eg. names=cell(1,5), onsets=cell(1,5), durations=cell(1,5), then names{2}=''SSent-DSpeak'', onsets{2}=[3 5 19 222], durations{2}=[0 0 0 0], contain the required details of the second condition. These cell arrays may be made available by your stimulus delivery program, eg. COGENT. The duration vectors can contain a single entry if the durations are identical for all events. Optionally, a (1 x n) cell array named orth can also be included, with a 1 or 0 for each condition to indicate whether parameteric modulators should be orthogonalised.' + '' + 'Time and Parametric effects can also be included. For time modulation include a cell array (1 x n) called tmod. It should have a have a single number in each cell. Unused cells may contain either a 0 or be left empty. The number specifies the order of time modulation from 0 = No Time Modulation to 6 = 6th Order Time Modulation. eg. tmod{3} = 1, modulates the 3rd condition by a linear time effect.' + '' + 'For parametric modulation include a structure array, which is up to 1 x n in size, called pmod. n must be less than or equal to the number of cells in the names/onsets/durations cell arrays. The structure array pmod must have the fields: name, param and poly. Each of these fields is in turn a cell array to allow the inclusion of one or more parametric effects per column of the design. The field name must be a cell array containing strings. The field param is a cell array containing a vector of parameters. Remember each parameter must be the same length as its corresponding onsets vector. The field poly is a cell array (for consistency) with each cell containing a single number specifying the order of the polynomial expansion from 1 to 6.' + '' + 'Note that each condition is assigned its corresponding entry in the structure array (condition 1 parametric modulators are in pmod(1), condition 2 parametric modulators are in pmod(2), etc. Within a condition multiple parametric modulators are accessed via each fields cell arrays. So for condition 1, parametric modulator 1 would be defined in pmod(1).name{1}, pmod(1).param{1}, and pmod(1).poly{1}. A second parametric modulator for condition 1 would be defined as pmod(1).name{2}, pmod(1).param{2} and pmod(1).poly{2}. If there was also a parametric modulator for condition 2, then remember the first modulator for that condition is in cell array 1: pmod(2).name{1}, pmod(2).param{1}, and pmod(2).poly{1}. If some, but not all conditions are parametrically modulated, then the non-modulated indices in the pmod structure can be left blank. For example, if conditions 1 and 3 but not condition 2 are modulated, then specify pmod(1) and pmod(3). Similarly, if conditions 1 and 2 are modulated but there are 3 conditions overall, it is only necessary for pmod to be a 1 x 2 structure array.' + '' + 'EXAMPLE:' + 'Make an empty pmod structure: ' + ' pmod = struct(''name'',{''''},''param'',{},''poly'',{});' + 'Specify one parametric regressor for the first condition: ' + ' pmod(1).name{1} = ''regressor1'';' + ' pmod(1).param{1} = [1 2 4 5 6];' + ' pmod(1).poly{1} = 1;' + 'Specify 2 parametric regressors for the second condition: ' + ' pmod(2).name{1} = ''regressor2-1'';' + ' pmod(2).param{1} = [1 3 5 7]; ' + ' pmod(2).poly{1} = 1;' + ' pmod(2).name{2} = ''regressor2-2'';' + ' pmod(2).param{2} = [2 4 6 8 10];' + ' pmod(2).poly{2} = 1;' + '' + 'The parametric modulator should be mean corrected if appropriate. Unused structure entries should have all fields left empty.' + }'; multi.filter = 'mat'; multi.ufilter = '.*'; multi.num = [0 1]; @@ -285,7 +296,7 @@ name = cfg_entry; name.tag = 'name'; name.name = 'Name'; -name.help = {'Enter name of regressor eg. First movement parameter'}; +name.help = {'Enter name of regressor eg. First movement parameter.'}; name.strtype = 's'; name.num = [1 Inf]; @@ -295,7 +306,7 @@ val = cfg_entry; val.tag = 'val'; val.name = 'Value'; -val.help = {'Enter the vector of regressor values'}; +val.help = {'Enter the vector of regressor values.'}; val.strtype = 'r'; val.num = [Inf 1]; @@ -314,7 +325,10 @@ generic2 = cfg_repeat; generic2.tag = 'generic'; generic2.name = 'Regressors'; -generic2.help = {'Regressors are additional columns included in the design matrix, which may model effects that would not be convolved with the haemodynamic response. One such example would be the estimated movement parameters, which may confound the data.'}; +generic2.help = { + 'Regressors are additional columns included in the design matrix, which may model effects that would not be convolved with the haemodynamic response.' + 'One such example would be the estimated movement parameters, which may confound the data.' + }'; generic2.values = {regress }; generic2.num = [0 Inf]; @@ -324,16 +338,16 @@ multi_reg = cfg_files; multi_reg.tag = 'multi_reg'; multi_reg.name = 'Multiple regressors'; -multi_reg.val{1} = {''}; +multi_reg.val = {{''}}; multi_reg.help = { - 'Select the *.mat/*.txt file(s) containing details of your multiple regressors. ' - '' - 'If you have multiple regressors eg. realignment parameters, then entering the details a regressor at a time is very inefficient. This option can be used to load all the required information in one go. ' - '' - 'You will first need to create a *.mat file containing a matrix R or a *.txt file containing the regressors. Each column of R will contain a different regressor. Unless the regressor names are given in a cell array called ''names'' in the MAT-file containing variable R, the regressors will be named R1, R2, R3, ..etc.' - '' - 'You can also select a PPI.mat file and SPM will automatically create regressors from fields PPI.ppi, PPI.Y and PPI.P.' -}'; + 'Select the *.mat/*.txt file(s) containing details of your multiple regressors.' + '' + 'If you have multiple regressors eg. realignment parameters, then entering the details a regressor at a time is very inefficient. This option can be used to load all the required information in one go. ' + '' + 'You will first need to create a *.mat file containing a matrix R or a *.txt file containing the regressors. Each column of R will contain a different regressor. Unless the regressor names are given in a cell array called ''names'' in the MAT-file containing variable R, the regressors will be named R1, R2, R3, ..etc.' + '' + 'You can also select a PPI.mat file and SPM will automatically create regressors from fields PPI.ppi, PPI.Y and PPI.P.' + }'; multi_reg.filter = 'mat'; multi_reg.ufilter = '.*'; multi_reg.num = [0 Inf]; @@ -344,7 +358,10 @@ hpf = cfg_entry; hpf.tag = 'hpf'; hpf.name = 'High-pass filter'; -hpf.help = {'The default high-pass filter cutoff is 128 seconds.Slow signal drifts with a period longer than this will be removed. Use ''explore design'' to ensure this cut-off is not removing too much experimental variance. High-pass filtering is implemented using a residual forming matrix (i.e. it is not a convolution) and is simply to a way to remove confounds without estimating their parameters explicitly. The constant term is also incorporated into this filter matrix.'}; +hpf.help = { + 'The default high-pass filter cutoff is 128 seconds. Slow signal drifts with a period longer than this will be removed.' + 'Use ''explore design'' to ensure this cut-off is not removing too much experimental variance. High-pass filtering is implemented using a residual forming matrix (i.e. it is not a convolution) and is simply to a way to remove confounds without estimating their parameters explicitly.' + }'; hpf.strtype = 'r'; hpf.num = [1 1]; hpf.def = @(val)spm_get_defaults('stats.fmri.hpf', val{:}); @@ -357,7 +374,10 @@ sess.name = 'Subject/Session'; sess.val = {scans generic1 multi generic2 multi_reg hpf }; sess.check = @sess_check; -sess.help = {'The design matrix for fMRI data consists of one or more separable, session-specific partitions. These partitions are usually either one per subject, or one per fMRI scanning session for that subject.'}; +sess.help = { + 'The design matrix for fMRI data consists of one or more separable, session-specific partitions.' + 'These partitions are usually either one per subject, or one per fMRI scanning session for that subject.' + }; %-------------------------------------------------------------------------- % generic Data & Design @@ -366,10 +386,10 @@ generic.tag = 'generic'; generic.name = 'Data & Design'; generic.help = { - 'The design matrix defines the experimental design and the nature of hypothesis testing to be implemented. The design matrix has one row for each scan and one column for each effect or explanatory variable. (e.g. regressor or stimulus function). ' - '' - 'This allows you to build design matrices with separable session-specific partitions. Each partition may be the same (in which case it is only necessary to specify it once) or different. Responses can be either event- or epoch related, where the latter model involves prolonged and possibly time-varying responses to state-related changes in experimental conditions. Event-related response are modelled in terms of responses to instantaneous events. Mathematically they are both modelled by convolving a series of delta (stick) or box-car functions, encoding the input or stimulus function. with a set of hemodynamic basis functions.' -}'; + 'The design matrix defines the experimental design and the nature of hypothesis testing to be implemented. The design matrix has one row for each scan and one column for each effect or explanatory variable. (e.g. regressor or stimulus function). ' + '' + 'This allows you to build design matrices with separable session-specific partitions. Each partition may be the same (in which case it is only necessary to specify it once) or different. Responses can be either event- or epoch related, where the latter model involves prolonged and possibly time-varying responses to state-related changes in experimental conditions. Event-related response are modelled in terms of responses to instantaneous events. Mathematically they are both modelled by convolving a series of delta (stick) or box-car functions, encoding the input or stimulus function. with a set of hemodynamic basis functions.' + }'; generic.values = {sess }; generic.num = [1 Inf]; @@ -379,7 +399,7 @@ name = cfg_entry; name.tag = 'name'; name.name = 'Name'; -name.help = {'Name of factor, eg. ''Repetition'' '}; +name.help = {'Name of this factor.'}; name.strtype = 's'; name.num = [1 Inf]; @@ -389,7 +409,7 @@ levels = cfg_entry; levels.tag = 'levels'; levels.name = 'Levels'; -levels.help = {'Enter number of levels for this factor, eg. 2'}; +levels.help = {'Number of levels for this factor.'}; levels.strtype = 'n'; levels.num = [Inf 1]; @@ -400,7 +420,7 @@ fact.tag = 'fact'; fact.name = 'Factor'; fact.val = {name levels }; -fact.help = {'Add a new factor to your experimental design'}; +fact.help = {'Add a new factor to your experimental design.'}; %-------------------------------------------------------------------------- % generic Factorial design @@ -409,14 +429,14 @@ generic1.tag = 'generic'; generic1.name = 'Factorial design'; generic1.help = { - 'If you have a factorial design then SPM can automatically generate the contrasts necessary to test for the main effects and interactions. ' - '' - 'This includes the F-contrasts necessary to test for these effects at the within-subject level (first level) and the simple contrasts necessary to generate the contrast images for a between-subject (second-level) analysis.' - '' - 'To use this option, create as many factors as you need and provide a name and number of levels for each. SPM assumes that the condition numbers of the first factor change slowest, the second factor next slowest etc. It is best to write down the contingency table for your design to ensure this condition is met. This table relates the levels of each factor to the conditions. ' - '' - 'For example, if you have 2-by-3 design your contingency table has two rows and three columns where the the first factor spans the rows, and the second factor the columns. The numbers of the conditions are 1,2,3 for the first row and 4,5,6 for the second. ' -}'; + 'If you have a factorial design then SPM can automatically generate the contrasts necessary to test for the main effects and interactions. ' + '' + 'This includes the F-contrasts necessary to test for these effects at the within-subject level (first level) and the simple contrasts necessary to generate the contrast images for a between-subject (second-level) analysis.' + '' + 'To use this option, create as many factors as you need and provide a name and number of levels for each. SPM assumes that the condition numbers of the first factor change slowest, the second factor next slowest etc. It is best to write down the contingency table for your design to ensure this condition is met. This table relates the levels of each factor to the conditions. ' + '' + 'For example, if you have 2-by-3 design your contingency table has two rows and three columns where the the first factor spans the rows, and the second factor the columns. The numbers of the conditions are 1,2,3 for the first row and 4,5,6 for the second. ' + }'; generic1.values = {fact }; generic1.num = [0 Inf]; @@ -426,7 +446,10 @@ derivs = cfg_menu; derivs.tag = 'derivs'; derivs.name = 'Model derivatives'; -derivs.help = {'Model HRF Derivatives. The canonical HRF combined with time and dispersion derivatives comprise an ''informed'' basis set, as the shape of the canonical response conforms to the hemodynamic response that is commonly observed. The incorporation of the derivate terms allow for variations in subject-to-subject and voxel-to-voxel responses. The time derivative allows the peak response to vary by plus or minus a second and the dispersion derivative allows the width of the response to vary. The informed basis set requires an SPM{F} for inference. T-contrasts over just the canonical are perfectly valid but assume constant delay/dispersion. The informed basis set compares favourably with eg. FIR bases on many data sets. '}; +derivs.help = { + 'Model HRF Derivatives. The canonical HRF combined with time and dispersion derivatives comprise an ''informed'' basis set, as the shape of the canonical response conforms to the hemodynamic response that is commonly observed.' + 'The incorporation of the derivate terms allow for variations in subject-to-subject and voxel-to-voxel responses. The time derivative allows the peak response to vary by plus or minus a second and the dispersion derivative allows the width of the response to vary. The informed basis set requires an SPM{F} for inference. T-contrasts over just the canonical are perfectly valid but assume constant delay/dispersion. The informed basis set compares favourably with eg. FIR bases on many data sets. ' + }'; derivs.labels = { 'No derivatives' 'Time derivatives' @@ -442,7 +465,10 @@ hrf.tag = 'hrf'; hrf.name = 'Canonical HRF'; hrf.val = {derivs }; -hrf.help = {'Canonical Hemodynamic Response Function. This is the default option. Contrasts of these effects have a physical interpretation and represent a parsimonious way of characterising event-related responses. This option is also useful if you wish to look separately at activations and deactivations (this is implemented using a t-contrast with a +1 or -1 entry over the canonical regressor). '}; +hrf.help = { + 'Canonical Hemodynamic Response Function.' + 'This is the default option. Contrasts of these effects have a physical interpretation and represent a parsimonious way of characterising event-related responses. This option is also useful if you wish to look separately at activations and deactivations (this is implemented using a t-contrast with a +1 or -1 entry over the canonical regressor).' + }'; %-------------------------------------------------------------------------- % length Window length @@ -450,7 +476,7 @@ length = cfg_entry; length.tag = 'length'; length.name = 'Window length'; -length.help = {'Post-stimulus window length (in seconds)'}; +length.help = {'Post-stimulus window length (in seconds).'}; length.strtype = 'r'; length.num = [1 1]; @@ -460,7 +486,7 @@ order = cfg_entry; order.tag = 'order'; order.name = 'Order'; -order.help = {'Number of basis functions'}; +order.help = {'Number of basis functions.'}; order.strtype = 'n'; order.num = [1 1]; @@ -479,7 +505,7 @@ length = cfg_entry; length.tag = 'length'; length.name = 'Window length'; -length.help = {'Post-stimulus window length (in seconds)'}; +length.help = {'Post-stimulus window length (in seconds).'}; length.strtype = 'r'; length.num = [1 1]; @@ -489,7 +515,7 @@ order = cfg_entry; order.tag = 'order'; order.name = 'Order'; -order.help = {'Number of basis functions'}; +order.help = {'Number of basis functions.'}; order.strtype = 'n'; order.num = [1 1]; @@ -508,7 +534,7 @@ length = cfg_entry; length.tag = 'length'; length.name = 'Window length'; -length.help = {'Post-stimulus window length (in seconds)'}; +length.help = {'Post-stimulus window length (in seconds).'}; length.strtype = 'r'; length.num = [1 1]; @@ -623,7 +649,7 @@ mask = cfg_files; mask.tag = 'mask'; mask.name = 'Explicit mask'; -mask.val{1} = {''}; +mask.val = {{''}}; mask.help = {'Specify an image for explicitly masking the analysis. ' 'If masking is not required, you can leave this field empty.' ['A sensible option here is to use a segmention of structural images to specify a within-brain mask. ',... @@ -658,18 +684,20 @@ fmri_spec.name = 'fMRI model specification'; fmri_spec.val = {dir timing generic generic1 bases volt xGlobal gMT mask cvi }; fmri_spec.help = { - 'Statistical analysis of fMRI data uses a mass-univariate approach based on General Linear Models (GLMs). It comprises the following steps (1) specification of the GLM design matrix, fMRI data files and filtering (2) estimation of GLM paramaters using classical or Bayesian approaches and (3) interrogation of results using contrast vectors to produce Statistical Parametric Maps (SPMs) or Posterior Probability Maps (PPMs).' - '' - 'The design matrix defines the experimental design and the nature of hypothesis testing to be implemented. The design matrix has one row for each scan and one column for each effect or explanatory variable. (eg. regressor or stimulus function). You can build design matrices with separable session-specific partitions. Each partition may be the same (in which case it is only necessary to specify it once) or different. ' - '' - 'Responses can be either event- or epoch related, the only distinction is the duration of the underlying input or stimulus function. Mathematically they are both modeled by convolving a series of delta (stick) or box functions (u), indicating the onset of an event or epoch with a set of basis functions. These basis functions model the hemodynamic convolution, applied by the brain, to the inputs. This convolution can be first-order or a generalized convolution modeled to second order (if you specify the Volterra option). The same inputs are used by the Hemodynamic model or Dynamic Causal Models which model the convolution explicitly in terms of hidden state variables. ' - '' - 'Basis functions can be used to plot estimated responses to single events once the parameters (i.e. basis function coefficients) have been estimated. The importance of basis functions is that they provide a graceful transition between simple fixed response models (like the box-car) and finite impulse response (FIR) models, where there is one basis function for each scan following an event or epoch onset. The nice thing about basis functions, compared to FIR models, is that data sampling and stimulus presentation does not have to be synchronized thereby allowing a uniform and unbiased sampling of peri-stimulus time.' - '' - 'Event-related designs may be stochastic or deterministic. Stochastic designs involve one of a number of trial-types occurring with a specified probability at successive intervals in time. These probabilities can be fixed (stationary designs) or time-dependent (modulated or non-stationary designs). The most efficient designs obtain when the probabilities of every trial type are equal. A critical issue in stochastic designs is whether to include null events If you wish to estimate the evoked response to a specific event type (as opposed to differential responses) then a null event must be included (even if it is not modeled explicitly).' - '' - 'In SPM, analysis of data from multiple subjects typically proceeds in two stages using models at two ''levels''. The ''first level'' models are used to implement a within-subject analysis. Typically there will be as many first level models as there are subjects. Analysis proceeds as described using the ''Specify first level'' and ''Estimate'' options. The results of these analyses can then be presented as ''case studies''. More often, however, one wishes to make inferences about the population from which the subjects were drawn. This is an example of a ''Random-Effects (RFX) analysis'' (or, more properly, a mixed-effects analysis). In SPM, RFX analysis is implemented using the ''summary-statistic'' approach where contrast images from each subject are used as summary measures of subject responses. These are then entered as data into a ''second level'' model. ' -}'; + 'Statistical analysis of fMRI data using a mass-univariate approach based on General Linear Models (GLMs).' + '' + 'It comprises the following steps (1) specification of the GLM design matrix, fMRI data files and filtering (2) estimation of GLM paramaters using classical or Bayesian approaches and (3) interrogation of results using contrast vectors to produce Statistical Parametric Maps (SPMs) or Posterior Probability Maps (PPMs).' + '' + 'The design matrix defines the experimental design and the nature of hypothesis testing to be implemented. The design matrix has one row for each scan and one column for each effect or explanatory variable. (eg. regressor or stimulus function). You can build design matrices with separable session-specific partitions. Each partition may be the same (in which case it is only necessary to specify it once) or different. ' + '' + 'Responses can be either event- or epoch related, the only distinction is the duration of the underlying input or stimulus function. Mathematically they are both modeled by convolving a series of delta (stick) or box functions (u), indicating the onset of an event or epoch with a set of basis functions. These basis functions model the hemodynamic convolution, applied by the brain, to the inputs. This convolution can be first-order or a generalized convolution modeled to second order (if you specify the Volterra option). The same inputs are used by the Hemodynamic model or Dynamic Causal Models which model the convolution explicitly in terms of hidden state variables. ' + '' + 'Basis functions can be used to plot estimated responses to single events once the parameters (i.e. basis function coefficients) have been estimated. The importance of basis functions is that they provide a graceful transition between simple fixed response models (like the box-car) and finite impulse response (FIR) models, where there is one basis function for each scan following an event or epoch onset. The nice thing about basis functions, compared to FIR models, is that data sampling and stimulus presentation does not have to be synchronized thereby allowing a uniform and unbiased sampling of peri-stimulus time.' + '' + 'Event-related designs may be stochastic or deterministic. Stochastic designs involve one of a number of trial-types occurring with a specified probability at successive intervals in time. These probabilities can be fixed (stationary designs) or time-dependent (modulated or non-stationary designs). The most efficient designs obtain when the probabilities of every trial type are equal. A critical issue in stochastic designs is whether to include null events If you wish to estimate the evoked response to a specific event type (as opposed to differential responses) then a null event must be included (even if it is not modeled explicitly).' + '' + 'In SPM, analysis of data from multiple subjects typically proceeds in two stages using models at two ''levels''. The ''first level'' models are used to implement a within-subject analysis. Typically there will be as many first level models as there are subjects. Analysis proceeds as described using the ''Specify first level'' and ''Estimate'' options. The results of these analyses can then be presented as ''case studies''. More often, however, one wishes to make inferences about the population from which the subjects were drawn. This is an example of a ''Random-Effects (RFX) analysis'' (or, more properly, a mixed-effects analysis). In SPM, RFX analysis is implemented using the ''summary-statistic'' approach where contrast images from each subject are used as summary measures of subject responses. These are then entered as data into a ''second level'' model. ' + }'; fmri_spec.prog = @spm_run_fmri_spec; fmri_spec.vout = @vout_stats; fmri_spec.modality = {'FMRI'}; diff --git a/config/spm_cfg_imcalc.m b/config/spm_cfg_imcalc.m index a287e61e..c5e7faac 100644 --- a/config/spm_cfg_imcalc.m +++ b/config/spm_cfg_imcalc.m @@ -1,9 +1,9 @@ function imcalc = spm_cfg_imcalc % SPM Configuration file for ImCalc %__________________________________________________________________________ -% Copyright (C) 2008-2015 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2008-2017 Wellcome Trust Centre for Neuroimaging -% $Id: spm_cfg_imcalc.m 6536 2015-08-26 13:53:45Z guillaume $ +% $Id: spm_cfg_imcalc.m 7216 2017-11-15 12:25:28Z guillaume $ %-------------------------------------------------------------------------- % input Input Images @@ -34,7 +34,7 @@ outdir = cfg_files; outdir.tag = 'outdir'; outdir.name = 'Output Directory'; -outdir.val{1} = {''}; +outdir.val = {{''}}; outdir.help = {'Files produced by this function will be written into this output directory. If no directory is given, images will be written to current working directory. If both output filename and output directory contain a directory, then output filename takes precedence.'}; outdir.filter = 'dir'; outdir.ufilter = '.*'; @@ -47,18 +47,18 @@ expression.tag = 'expression'; expression.name = 'Expression'; expression.help = { - 'Example expressions (f):' - ' * Mean of six images (select six images)' - ' f = ''(i1+i2+i3+i4+i5+i6)/6''' - ' * Make a binary mask image at threshold of 100' - ' f = ''i1>100''' - ' * Make a mask from one image and apply to another' - ' f = ''i2.*(i1>100)''' - ' - here the first image is used to make the mask, which is applied to the second image' - ' * Sum of n images' - ' f = ''i1 + i2 + i3 + i4 + i5 + ...''' - ' * Sum of n images (when reading data into a data-matrix - use dmtx arg)' - ' f = ''sum(X)''' + 'Example expressions:' + ' * Mean of six images (select six images)' + ' (i1+i2+i3+i4+i5+i6)/6' + ' * Make a binary mask image at threshold of 100' + ' i1>100' + ' * Make a mask from one image and apply to another' + ' i2.*(i1>100)' + ' [here the first image is used to make the mask, which is applied to the second image]' + ' * Sum of n images' + ' i1 + i2 + i3 + i4 + i5 + ...' + ' * Sum of n images (when reading data into a data-matrix - use the Data Matrix option)' + ' sum(X)' }'; expression.strtype = 's'; expression.num = [2 Inf]; @@ -80,7 +80,7 @@ value.tag = 'value'; value.name = 'Value'; value.help = {'Value of the variable.'}; -value.strtype = 'e'; +value.strtype = 'r'; value.num = [Inf Inf]; %-------------------------------------------------------------------------- @@ -108,7 +108,7 @@ dmtx = cfg_menu; dmtx.tag = 'dmtx'; dmtx.name = 'Data Matrix'; -dmtx.help = {'If the dmtx flag is set, then images are read into a data matrix X (rather than into separate variables i1, i2, i3,...). The data matrix should be referred to as X, and contains images in rows. Computation is plane by plane, so in data-matrix mode, X is a NxK matrix, where N is the number of input images [prod(size(Vi))], and K is the number of voxels per plane [prod(Vi(1).dim(1:2))].'}; +dmtx.help = {'If this flag is set, then images are read into a data matrix X (rather than into separate variables i1, i2, i3,...). The data matrix should be referred to as X, and contains images in rows. Computation is plane by plane, so in data-matrix mode, X is a NxK matrix, where N is the number of input images [prod(size(Vi))], and K is the number of voxels per plane [prod(Vi(1).dim(1:2))].'}; dmtx.labels = {'No - don''t read images into data matrix' 'Yes - read images into data matrix'}'; dmtx.values = {0 1}; @@ -171,9 +171,13 @@ 'INT32 - signed int' 'FLOAT32 - single prec. float' 'FLOAT64 - double prec. float' + 'INT8 - signed char' + 'UINT16 - unsigned short' + 'UINT32 - unsigned int' }'; dtype.values = {spm_type('uint8') spm_type('int16') spm_type('int32') ... - spm_type('float32') spm_type('float64')}; + spm_type('float32') spm_type('float64') spm_type('int8') ... + spm_type('uint16') spm_type('uint32')}; dtype.val = {spm_type('int16')}; %-------------------------------------------------------------------------- @@ -192,7 +196,10 @@ imcalc.tag = 'imcalc'; imcalc.name = 'Image Calculator'; imcalc.val = {input output outdir expression generic options }; -imcalc.help = {'The image calculator is for performing user-specified algebraic manipulations on a set of images, with the result being written out as an image. The user is prompted to supply images to work on, a filename for the output image, and the expression to evaluate. The expression should be a standard MATLAB expression, within which the images should be referred to as i1, i2, i3,... etc.'}; +imcalc.help = { + 'The image calculator is for performing user-specified algebraic manipulations on a set of images.' + 'The result is being written out as an image. The user is prompted to supply images to work on, a filename for the output image, and the expression to evaluate. The expression should be a standard MATLAB expression, within which the images should be referred to as i1, i2, i3,... etc.' + }'; imcalc.prog = @my_spm_imcalc; imcalc.vout = @vout; diff --git a/config/spm_cfg_minc.m b/config/spm_cfg_minc.m index 8e7e9a18..065bacd5 100644 --- a/config/spm_cfg_minc.m +++ b/config/spm_cfg_minc.m @@ -3,7 +3,7 @@ %__________________________________________________________________________ % Copyright (C) 2005-2011 Wellcome Trust Centre for Neuroimaging -% $Id: spm_cfg_minc.m 4466 2011-09-07 16:50:29Z guillaume $ +% $Id: spm_cfg_minc.m 6952 2016-11-25 16:03:13Z guillaume $ %-------------------------------------------------------------------------- @@ -65,7 +65,10 @@ minc.tag = 'minc'; minc.name = 'MINC Import'; minc.val = {data opts}; -minc.help = {'MINC Conversion. MINC is the image data format used for exchanging data within the ICBM community, and the format used by the MNI software tools. It is based on NetCDF. MINC is no longer supported for reading images into SPM, so MINC files need to be converted to NIFTI format in order to use them. See http://www.bic.mni.mcgill.ca/software/ for more information.'}; +minc.help = { + 'MINC Conversion.' + 'MINC is the image data format used for exchanging data within the ICBM community, and the format used by the MNI software tools. It is based on NetCDF. MINC is no longer supported for reading images into SPM, so MINC files need to be converted to NIFTI format in order to use them. See http://www.bic.mni.mcgill.ca/software/ for more information.' + }'; minc.prog = @spm_run_minc; minc.vout = @vout; diff --git a/config/spm_cfg_model_review.m b/config/spm_cfg_model_review.m index 2e204404..028949c0 100644 --- a/config/spm_cfg_model_review.m +++ b/config/spm_cfg_model_review.m @@ -1,10 +1,10 @@ function review = spm_cfg_model_review % SPM Configuration file for Model Review %__________________________________________________________________________ -% Copyright (C) 2014 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2014-2016 Wellcome Trust Centre for Neuroimaging % Guillaume Flandin -% $Id: spm_cfg_model_review.m 6148 2014-09-03 15:49:04Z guillaume $ +% $Id: spm_cfg_model_review.m 6952 2016-11-25 16:03:13Z guillaume $ %-------------------------------------------------------------------------- @@ -132,7 +132,7 @@ review.tag = 'review'; review.name = 'Model review'; review.val = {spmmat display print}; -review.help = {''}; +review.help = {'Review a General linear Model.'}; review.prog = @spm_run_model_review; review.modality = {'FMRI' 'PET' 'EEG'}; diff --git a/config/spm_cfg_norm.m b/config/spm_cfg_norm.m index c5ae24f4..e53d340b 100644 --- a/config/spm_cfg_norm.m +++ b/config/spm_cfg_norm.m @@ -1,10 +1,10 @@ function normalise = spm_cfg_norm % SPM Configuration file for Spatial Normalisation %__________________________________________________________________________ -% Copyright (C) 2012-2014 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2012-2016 Wellcome Trust Centre for Neuroimaging % John Ashburner -% $Id: spm_cfg_norm.m 6772 2016-04-19 10:21:41Z john $ +% $Id: spm_cfg_norm.m 6952 2016-11-25 16:03:13Z guillaume $ %-------------------------------------------------------------------------- @@ -332,7 +332,10 @@ vol = cfg_files; vol.tag = 'vol'; vol.name = 'Image to Align'; -vol.help = {'The image that the template (atlas) data is warped into alignment with. The result is a set of warps, which can be applied to this image, or any other image that is in register with it.'}; +vol.help = { + 'The image that the template (atlas) data is warped into alignment with.' + 'The result is a set of warps, which can be applied to this image, or any other image that is in register with it.' + }'; vol.filter = 'image'; vol.ufilter = '.*'; vol.num = [1 1]; @@ -359,7 +362,10 @@ resample = cfg_files; resample.tag = 'resample'; resample.name = 'Images to Write'; -resample.help = {'These are the images for warping according to the estimated parameters. They can be any images that are in register with the image used to generate the deformation.'}; +resample.help = { + 'These are the images for warping according to the estimated parameters.' + 'They can be any images that are in register with the image used to generate the deformation.' + }'; resample.filter = 'image'; resample.ufilter = '.*'; resample.num = [1 Inf]; @@ -372,7 +378,7 @@ subj.tag = 'subj'; subj.name = 'Subject'; subj.val = {vol}; -subj.help = {'Data for this subject. The same parameters are used within subject.'}; +subj.help = {'Data for this subject. The same parameters are used within subject.'}; %-------------------------------------------------------------------------- % esubjs Data @@ -391,7 +397,7 @@ subj.tag = 'subj'; subj.name = 'Subject'; subj.val = {def resample}; -subj.help = {'Data for this subject. The same parameters are used within subject.'}; +subj.help = {'Data for this subject. The same parameters are used within subject.'}; %-------------------------------------------------------------------------- % wsubjs Data @@ -410,7 +416,7 @@ subj.tag = 'subj'; subj.name = 'Subject'; subj.val = {vol resample}; -subj.help = {'Data for this subject. The same parameters are used within subject.'}; +subj.help = {'Data for this subject. The same parameters are used within subject.'}; %-------------------------------------------------------------------------- % ewsubjs Data @@ -430,12 +436,12 @@ est.name = 'Normalise: Estimate'; est.val = {esubjs eoptions}; est.help = { - 'Spatial normalisation is now done via the segmentation routine (which was known as ``New Segment'''' in SPM8). The algorithm is essentially the same as that described in the Unified Segmentation paper /* \cite{ashburner05}*/, except for (i) a slightly different treatment of the mixing proportions, (ii) the use of an improved registration model, (iii) the ability to use multi-spectral data, (iv) an extended set of tissue probability maps, which allows a different treatment of voxels outside the brain.' + 'Spatial normalisation performed via the segmentation routine.' '' - 'Note that on a 32 bit computer, the most memory that SPM or any other program can use at any time is 4Gbytes (or sometimes only 2Gbytes). This is because the largest number that can be represented with 32 bits is 4,294,967,295, which limits how much memory may be addressed by any one process. Out of memory errors may occasionally be experienced when trying to work with large images. 64-bit computers can usually handle such cases.' - '' - 'If you encounter problems with spatial normalisation, it is advisable to use the Check reg button to see how well aligned the original data are with the MNI-space templates released with SPM. If mis-alignment is greater than about 3cm and 15 degrees, you could try to manually re-position the images prior to attempting to align them. This may be done using the Display button.' - }'; + 'The algorithm (which was known as ``New Segment'''' in SPM8) is essentially the same as that described in the Unified Segmentation paper /* \cite{ashburner05}*/, except for (i) a slightly different treatment of the mixing proportions, (ii) the use of an improved registration model, (iii) the ability to use multi-spectral data, (iv) an extended set of tissue probability maps, which allows a different treatment of voxels outside the brain.' + '' + 'If you encounter problems with spatial normalisation, it is advisable to use the Check reg button to see how well aligned the original data are with the MNI-space templates released with SPM. If mis-alignment is greater than about 3cm and 15 degrees, you could try to manually re-position the images prior to attempting to align them. This may be done using the Display button.' + }'; est.prog = @spm_run_norm; est.vout = @vout_est; @@ -446,7 +452,8 @@ write.tag = 'write'; write.name = 'Normalise: Write'; write.val = {wsubjs woptions}; -write.help = {'Allows previously estimated warps (stored in ``y_''''imagename``_sn.mat'''' files) to be applied to series of images.'}; +write.help = { + 'Apply previously estimated warps (stored in ``y_''''imagename``_sn.mat'''' files) to series of images.'}; write.prog = @spm_run_norm; write.vout = @vout_write; @@ -457,9 +464,12 @@ estwrite.tag = 'estwrite'; estwrite.name = 'Normalise: Estimate & Write'; estwrite.val = {ewsubjs eoptions woptions}; -estwrite.help = {'Computes the warp that best aligns the template (atlas) to the individual''s image, inverting it and writing the result to the file `y_''imagename''.nii''. This option also allows the contents of the `y_''imagename''.nii'' files to be applied to a series of images.' -'' -'Note that if you encounter problems with spatial normalisation, it is often advisable to use the Check reg button to see how well aligned the original data are with the MNI-space templates released with SPM. If mis-alignment is greater than about 3cm and 15 degrees, you could try to manually re-position the images. This may be done using the Display button.'}; +estwrite.help = { + 'Compute the warp that best aligns the template (atlas) to the individual''s image, invert it and write the result to the file `y_''imagename''.nii''.' + 'This option also allows the contents of the `y_''imagename''.nii'' files to be applied to a series of images.' + '' + 'Note that if you encounter problems with spatial normalisation, it is often advisable to use the Check reg button to see how well aligned the original data are with the MNI-space templates released with SPM. If mis-alignment is greater than about 3cm and 15 degrees, you could try to manually re-position the images. This may be done using the Display button.' + }; estwrite.prog = @spm_run_norm; estwrite.vout = @vout_estwrite; diff --git a/config/spm_cfg_preproc8.m b/config/spm_cfg_preproc8.m index 34831a26..2bcb1613 100644 --- a/config/spm_cfg_preproc8.m +++ b/config/spm_cfg_preproc8.m @@ -1,10 +1,10 @@ function preproc = spm_cfg_preproc8 % Configuration file for 'Combined Segmentation and Spatial Normalisation' %__________________________________________________________________________ -% Copyright (C) 2008-2014 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2008-2016 Wellcome Trust Centre for Neuroimaging % John Ashburner -% $Id: spm_cfg_preproc8.m 6798 2016-05-20 11:53:33Z john $ +% $Id: spm_cfg_preproc8.m 6952 2016-11-25 16:03:13Z guillaume $ %-------------------------------------------------------------------------- @@ -13,7 +13,10 @@ vols = cfg_files; vols.tag = 'vols'; vols.name = 'Volumes'; -vols.help = {'Select scans from this channel for processing. If multiple channels are used (eg T1 & T2), then the same order of subjects must be specified for each channel and they must be in register (same position, size, voxel dims etc..).'}; +vols.help = { + 'Select scans from this channel for processing.' + 'If multiple channels are used (eg T1 & T2), then the same order of subjects must be specified for each channel and they must be in register (same position, size, voxel dims etc..).' + }'; vols.filter = 'image'; vols.ufilter = '.*'; vols.num = [1 Inf]; @@ -26,11 +29,11 @@ biasreg.tag = 'biasreg'; biasreg.name = 'Bias regularisation'; biasreg.help = { - 'MR images are usually corrupted by a smooth, spatially varying artifact that modulates the intensity of the image (bias). These artifacts, although not usually a problem for visual inspection, can impede automated processing of the images.' - '' - 'An important issue relates to the distinction between intensity variations that arise because of bias artifact due to the physics of MR scanning, and those that arise due to different tissue properties. The objective is to model the latter by different tissue classes, while modelling the former with a bias field. We know a priori that intensity variations due to MR physics tend to be spatially smooth, whereas those due to different tissue types tend to contain more high frequency information. A more accurate estimate of a bias field can be obtained by including prior knowledge about the distribution of the fields likely to be encountered by the correction algorithm. For example, if it is known that there is little or no intensity non-uniformity, then it would be wise to penalise large values for the intensity non-uniformity parameters. This regularisation can be placed within a Bayesian context, whereby the penalty incurred is the negative logarithm of a prior probability for any particular pattern of non-uniformity.' - 'Knowing what works best should be a matter of empirical exploration. For example, if your data has very little intensity non-uniformity artifact, then the bias regularisation should be increased. This effectively tells the algorithm that there is very little bias in your data, so it does not try to model it.' - }'; + 'MR images are usually corrupted by a smooth, spatially varying artifact that modulates the intensity of the image (bias). These artifacts, although not usually a problem for visual inspection, can impede automated processing of the images.' + '' + 'An important issue relates to the distinction between intensity variations that arise because of bias artifact due to the physics of MR scanning, and those that arise due to different tissue properties. The objective is to model the latter by different tissue classes, while modelling the former with a bias field. We know a priori that intensity variations due to MR physics tend to be spatially smooth, whereas those due to different tissue types tend to contain more high frequency information. A more accurate estimate of a bias field can be obtained by including prior knowledge about the distribution of the fields likely to be encountered by the correction algorithm. For example, if it is known that there is little or no intensity non-uniformity, then it would be wise to penalise large values for the intensity non-uniformity parameters. This regularisation can be placed within a Bayesian context, whereby the penalty incurred is the negative logarithm of a prior probability for any particular pattern of non-uniformity.' + 'Knowing what works best should be a matter of empirical exploration. For example, if your data has very little intensity non-uniformity artifact, then the bias regularisation should be increased. This effectively tells the algorithm that there is very little bias in your data, so it does not try to model it.' + }'; biasreg.labels = { 'no regularisation (0)' 'extremely light regularisation (0.00001)' @@ -59,7 +62,10 @@ biasfwhm = cfg_menu; biasfwhm.tag = 'biasfwhm'; biasfwhm.name = 'Bias FWHM'; -biasfwhm.help = {'FWHM of Gaussian smoothness of bias. If your intensity non-uniformity is very smooth, then choose a large FWHM. This will prevent the algorithm from trying to model out intensity variation due to different tissue types. The model for intensity non-uniformity is one of i.i.d. Gaussian noise that has been smoothed by some amount, before taking the exponential. Note also that smoother bias fields need fewer parameters to describe them. This means that the algorithm is faster for smoother intensity non-uniformities.'}; +biasfwhm.help = { + 'FWHM of Gaussian smoothness of bias.' + 'If your intensity non-uniformity is very smooth, then choose a large FWHM. This will prevent the algorithm from trying to model out intensity variation due to different tissue types. The model for intensity non-uniformity is one of i.i.d. Gaussian noise that has been smoothed by some amount, before taking the exponential. Note also that smoother bias fields need fewer parameters to describe them. This means that the algorithm is faster for smoother intensity non-uniformities.' + }'; biasfwhm.labels = { '30mm cutoff' '40mm cutoff' @@ -100,7 +106,10 @@ write = cfg_menu; write.tag = 'write'; write.name = 'Save Bias Corrected'; -write.help = {'This is the option to save a bias corrected version of your images from this channel, or/and the estimated bias field. MR images are usually corrupted by a smooth, spatially varying artifact that modulates the intensity of the image (bias). These artifacts, although not usually a problem for visual inspection, can impede automated processing of the images. The bias corrected version should have more uniform intensities within the different types of tissues.'}; +write.help = { + 'Option to save a bias corrected version of your images from this channel, or/and the estimated bias field.' + 'MR images are usually corrupted by a smooth, spatially varying artifact that modulates the intensity of the image (bias). These artifacts, although not usually a problem for visual inspection, can impede automated processing of the images. The bias corrected version should have more uniform intensities within the different types of tissues.' + }'; write.labels = { 'Save Nothing' 'Save Bias Corrected' @@ -122,7 +131,10 @@ channel.tag = 'channel'; channel.name = 'Channel'; channel.val = {vols biasreg biasfwhm write }; -channel.help = {'Specify a channel for processing. If multiple channels are used (eg PD & T2), then the same order of subjects must be specified for each channel and they must be in register (same position, size, voxel dims etc..). The different channels can be treated differently in terms of inhomogeneity correction etc. You may wish to correct some channels and save the corrected images, whereas you may wish not to do this for other channels.'}; +channel.help = { + 'Specify a channel for processing.' + 'If multiple channels are used (eg PD & T2), then the same order of subjects must be specified for each channel and they must be in register (same position, size, voxel dims etc..). The different channels can be treated differently in terms of inhomogeneity correction etc. You may wish to correct some channels and save the corrected images, whereas you may wish not to do this for other channels.' + }'; %-------------------------------------------------------------------------- % data Data @@ -131,7 +143,10 @@ data.tag = 'data'; data.name = 'Data'; data.val = {channel }; -data.help = {'Specify the number of different channels (for multi-spectral classification). If you have scans of different contrasts for each of the subjects, then it is possible to combine the information from them in order to improve the segmentation accuracy. Note that only the first channel of data is used for the initial affine registration with the tissue probability maps.'}; +data.help = { + 'Specify the number of different channels (for multi-spectral classification).' + 'If you have scans of different contrasts for each of the subjects, then it is possible to combine the information from them in order to improve the segmentation accuracy. Note that only the first channel of data is used for the initial affine registration with the tissue probability maps.' + }'; data.values = {channel }; data.num = [1 Inf]; @@ -142,12 +157,13 @@ tpm.tag = 'tpm'; tpm.name = 'Tissue probability map'; tpm.help = { - 'Select the tissue probability image for this class. These should be maps of eg grey matter, white matter or cerebro-spinal fluid probability. A nonlinear deformation field is estimated that best overlays the tissue probability maps on the individual subjects'' image.' - '' - 'Rather than assuming stationary prior probabilities based upon mixing proportions, additional information is used, based on other subjects'' brain images. Priors are usually generated by registering a large number of subjects together, assigning voxels to different tissue types and averaging tissue classes over subjects. Three tissue classes are used: grey matter, white matter and cerebro-spinal fluid. A fourth class is also used, which is simply one minus the sum of the first three. These maps give the prior probability of any voxel in a registered image being of any of the tissue classes - irrespective of its intensity.' - '' - 'The model is refined further by allowing the tissue probability maps to be deformed according to a set of estimated parameters. This allows spatial normalisation and segmentation to be combined into the same model.' - }'; + 'Select the tissue probability image for this class.' + 'These should be maps of eg grey matter, white matter or cerebro-spinal fluid probability. A nonlinear deformation field is estimated that best overlays the tissue probability maps on the individual subjects'' image.' + '' + 'Rather than assuming stationary prior probabilities based upon mixing proportions, additional information is used, based on other subjects'' brain images. Priors are usually generated by registering a large number of subjects together, assigning voxels to different tissue types and averaging tissue classes over subjects. Three tissue classes are used: grey matter, white matter and cerebro-spinal fluid. A fourth class is also used, which is simply one minus the sum of the first three. These maps give the prior probability of any voxel in a registered image being of any of the tissue classes - irrespective of its intensity.' + '' + 'The model is refined further by allowing the tissue probability maps to be deformed according to a set of estimated parameters. This allows spatial normalisation and segmentation to be combined into the same model.' + }'; tpm.filter = 'image'; tpm.ufilter = '.*'; tpm.num = [1 1]; @@ -160,9 +176,10 @@ ngaus.tag = 'ngaus'; ngaus.name = 'Num. Gaussians'; ngaus.help = { - 'The number of Gaussians used to represent the intensity distribution for each tissue class can be greater than one. In other words, a tissue probability map may be shared by several clusters. The assumption of a single Gaussian distribution for each class does not hold for a number of reasons. In particular, a voxel may not be purely of one tissue type, and instead contain signal from a number of different tissues (partial volume effects). Some partial volume voxels could fall at the interface between different classes, or they may fall in the middle of structures such as the thalamus, which may be considered as being either grey or white matter. Various other image segmentation approaches use additional clusters to model such partial volume effects. These generally assume that a pure tissue class has a Gaussian intensity distribution, whereas intensity distributions for partial volume voxels are broader, falling between the intensities of the pure classes. Unlike these partial volume segmentation approaches, the model adopted here simply assumes that the intensity distribution of each class may not be Gaussian, and assigns belonging probabilities according to these non-Gaussian distributions. Typical numbers of Gaussians could be two for grey matter, two for white matter, two for CSF, three for bone, four for other soft tissues and two for air (background).' - 'Note that if any of the Num. Gaussians is set to non-parametric, then a non-parametric approach will be used to model the tissue intensities. This may work for some images (eg CT), but not others - and it has not been optimised for multi-channel data. Note that it is likely to be especially problematic for images with poorly behaved intensity histograms due to aliasing effects that arise from having discrete values on the images.' - }'; + 'The number of Gaussians used to represent the intensity distribution for each tissue class can be greater than one.' + 'In other words, a tissue probability map may be shared by several clusters. The assumption of a single Gaussian distribution for each class does not hold for a number of reasons. In particular, a voxel may not be purely of one tissue type, and instead contain signal from a number of different tissues (partial volume effects). Some partial volume voxels could fall at the interface between different classes, or they may fall in the middle of structures such as the thalamus, which may be considered as being either grey or white matter. Various other image segmentation approaches use additional clusters to model such partial volume effects. These generally assume that a pure tissue class has a Gaussian intensity distribution, whereas intensity distributions for partial volume voxels are broader, falling between the intensities of the pure classes. Unlike these partial volume segmentation approaches, the model adopted here simply assumes that the intensity distribution of each class may not be Gaussian, and assigns belonging probabilities according to these non-Gaussian distributions. Typical numbers of Gaussians could be two for grey matter, two for white matter, two for CSF, three for bone, four for other soft tissues and two for air (background).' + 'Note that if any of the Num. Gaussians is set to non-parametric, then a non-parametric approach will be used to model the tissue intensities. This may work for some images (eg CT), but not others - and it has not been optimised for multi-channel data. Note that it is likely to be especially problematic for images with poorly behaved intensity histograms due to aliasing effects that arise from having discrete values on the images.' + }'; ngaus.labels = { '1' '2' @@ -195,11 +212,11 @@ native.name = 'Native Tissue'; native.help = {'The native space option allows you to produce a tissue class image (c*) that is in alignment with the original/* (see Figure \ref{seg1})*/. It can also be used for ``importing'''' into a form that can be used with the Dartel toolbox (rc*).'}; native.labels = { - 'None' - 'Native Space' - 'Dartel Imported' - 'Native + Dartel Imported' - }'; + 'None' + 'Native Space' + 'Dartel Imported' + 'Native + Dartel Imported' + }'; native.values = { [0 0] [1 0] @@ -215,11 +232,11 @@ warped.tag = 'warped'; warped.name = 'Warped Tissue'; warped.help = { - 'You can produce spatially normalised versions of the tissue class - both with (mwc*) and without (wc*) modulation (see below). These can be used for voxel-based morphometry. All you need to do is smooth them and do the stats.' - '' - '``Modulation'''' is to compensate for the effect of spatial normalisation. When warping a series of images to match a template, it is inevitable that volumetric differences will be introduced into the warped images. For example, if one subject''s temporal lobe has half the volume of that of the template, then its volume will be doubled during spatial normalisation. This will also result in a doubling of the voxels labelled grey matter. In order to remove this confound, the spatially normalised grey matter (or other tissue class) is adjusted by multiplying by its relative volume before and after warping. If warping results in a region doubling its volume, then the correction will halve the intensity of the tissue label. This whole procedure has the effect of preserving the total amount of grey matter signal in the normalised partitions. Actually, in this version of SPM the warped data are not scaled by the Jacobian determinants when generating the "modulated" data. Instead, the original voxels are projected into their new location in the warped images. This exactly preserves the tissue count, but has the effect of introducing aliasing artifacts - especially if the original data are at a lower resolution than the warped images. Smoothing should reduce this artifact though.' - 'Note also that the "unmodulated" data are generated slightly differently in this version of SPM. In this version, the projected data are corrected using a kind of smoothing procedure. This is not done exactly as it should be done (to save computational time), but it does a reasonable job. It also has the effect of extrapolating the warped tissue class images beyond the range of the original data. This extrapolation is not perfect, as it is only an estimate, but it may still be a good thing to do.' - }'; + 'You can produce spatially normalised versions of the tissue class - both with (mwc*) and without (wc*) modulation (see below). These can be used for voxel-based morphometry. All you need to do is smooth them and do the stats.' + '' + '``Modulation'''' is to compensate for the effect of spatial normalisation. When warping a series of images to match a template, it is inevitable that volumetric differences will be introduced into the warped images. For example, if one subject''s temporal lobe has half the volume of that of the template, then its volume will be doubled during spatial normalisation. This will also result in a doubling of the voxels labelled grey matter. In order to remove this confound, the spatially normalised grey matter (or other tissue class) is adjusted by multiplying by its relative volume before and after warping. If warping results in a region doubling its volume, then the correction will halve the intensity of the tissue label. This whole procedure has the effect of preserving the total amount of grey matter signal in the normalised partitions. Actually, in this version of SPM the warped data are not scaled by the Jacobian determinants when generating the "modulated" data. Instead, the original voxels are projected into their new location in the warped images. This exactly preserves the tissue count, but has the effect of introducing aliasing artifacts - especially if the original data are at a lower resolution than the warped images. Smoothing should reduce this artifact though.' + 'Note also that the "unmodulated" data are generated slightly differently in this version of SPM. In this version, the projected data are corrected using a kind of smoothing procedure. This is not done exactly as it should be done (to save computational time), but it does a reasonable job. It also has the effect of extrapolating the warped tissue class images beyond the range of the original data. This extrapolation is not perfect, as it is only an estimate, but it may still be a good thing to do.' + }'; warped.labels = { 'None' 'Modulated' @@ -258,10 +275,10 @@ % Change to: ngaus = [2 2 2 3 4 2]; nval = {[1 0],[1 0],[1 0],[1 0],[1 0],[0 0]}; for k=1:numel(ngaus), - tissue.val{1}.val{1} = {[tpm_nam ',' num2str(k)]}; - tissue.val{2}.val = {ngaus(k)}; - tissue.val{3}.val = {nval{k}}; - tissues.val{k} = tissue; + tissue.val{1}.val = {{[tpm_nam ',' num2str(k)]}}; + tissue.val{2}.val = {ngaus(k)}; + tissue.val{3}.val = {nval{k}}; + tissues.val{k} = tissue; end tissues.help = {'The data for each subject are classified into a number of different tissue types. The tissue types are defined according to tissue probability maps, which define the prior probability of finding a tissue type at a particular location. Typically, the order of tissues is grey matter, white matter, CSF, bone, soft tissue and air/background (if using tpm/TPM.nii).'}; @@ -285,10 +302,11 @@ cleanup.tag = 'cleanup'; cleanup.name = 'Clean Up'; cleanup.help = { - 'This uses a crude routine for extracting the brain from segmented images. It begins by taking the white matter, and eroding it a couple of times to get rid of any odd voxels. The algorithm continues on to do conditional dilations for several iterations, where the condition is based upon gray or white matter being present.This identified region is then used to clean up the grey and white matter partitions. Note that the fluid class will also be cleaned, such that aqueous and vitreous humour in the eyeballs, as well as other assorted fluid regions (except CSF) will be removed.' - '' - 'If you find pieces of brain being chopped out in your data, then you may wish to disable or tone down the cleanup procedure. Note that the procedure uses a number of assumptions about what each tissue class refers to. If a different set of tissue priors are used, then this routine should be disabled.' -}'; + 'This uses a crude routine for extracting the brain from segmented images.' + 'It begins by taking the white matter, and eroding it a couple of times to get rid of any odd voxels. The algorithm continues on to do conditional dilations for several iterations, where the condition is based upon gray or white matter being present.This identified region is then used to clean up the grey and white matter partitions. Note that the fluid class will also be cleaned, such that aqueous and vitreous humour in the eyeballs, as well as other assorted fluid regions (except CSF) will be removed.' + '' + 'If you find pieces of brain being chopped out in your data, then you may wish to disable or tone down the cleanup procedure. Note that the procedure uses a number of assumptions about what each tissue class refers to. If a different set of tissue priors are used, then this routine should be disabled.' + }'; cleanup.labels = { 'Dont do cleanup' 'Light Clean' @@ -304,13 +322,13 @@ reg.tag = 'reg'; reg.name = 'Warping Regularisation'; reg.help = {... -'Registration involves simultaneously minimising two terms. One of these is a measure of similarity between the images (mean-squared difference in the current situation), whereas the other is a measure of the roughness of the deformations. This measure of roughness involves the sum of the following terms:',... -'* Absolute displacements need to be penalised by a tiny amount. The first element encodes the amount of penalty on these. Ideally, absolute displacements should not be penalised, but it is necessary for technical reasons.',... -'* The `membrane energy'' of the deformation is penalised (2nd element), usually by a relatively small amount. This penalises the sum of squares of the derivatives of the velocity field (ie the sum of squares of the elements of the Jacobian tensors).',... -'* The `bending energy'' is penalised (3rd element). This penalises the sum of squares of the 2nd derivatives of the velocity.',... -'* Linear elasticity regularisation is also included (4th and 5th elements). The first parameter (mu) is similar to that for linear elasticity, except it penalises the sum of squares of the Jacobian tensors after they have been made symmetric (by averaging with the transpose). This term essentially penalises length changes, without penalising rotations.',... -'* The final term also relates to linear elasticity, and is the weight that denotes how much to penalise changes to the divergence of the velocities (lambda). This divergence is a measure of the rate of volumetric expansion or contraction.',... -'The amount of regularisation determines the tradeoff between the terms. More regularisation gives smoother deformations, where the smoothness measure is determined by the bending energy of the deformations.'}; + 'Registration involves simultaneously minimising two terms. One of these is a measure of similarity between the images (mean-squared difference in the current situation), whereas the other is a measure of the roughness of the deformations. This measure of roughness involves the sum of the following terms:',... + '* Absolute displacements need to be penalised by a tiny amount. The first element encodes the amount of penalty on these. Ideally, absolute displacements should not be penalised, but it is necessary for technical reasons.',... + '* The `membrane energy'' of the deformation is penalised (2nd element), usually by a relatively small amount. This penalises the sum of squares of the derivatives of the velocity field (ie the sum of squares of the elements of the Jacobian tensors).',... + '* The `bending energy'' is penalised (3rd element). This penalises the sum of squares of the 2nd derivatives of the velocity.',... + '* Linear elasticity regularisation is also included (4th and 5th elements). The first parameter (mu) is similar to that for linear elasticity, except it penalises the sum of squares of the Jacobian tensors after they have been made symmetric (by averaging with the transpose). This term essentially penalises length changes, without penalising rotations.',... + '* The final term also relates to linear elasticity, and is the weight that denotes how much to penalise changes to the divergence of the velocities (lambda). This divergence is a measure of the rate of volumetric expansion or contraction.',... + 'The amount of regularisation determines the tradeoff between the terms. More regularisation gives smoother deformations, where the smoothness measure is determined by the bending energy of the deformations.'}; reg.strtype = 'r'; reg.num = [1 5]; reg.val = {[0 0.001 0.5 0.05 0.2]}; @@ -322,10 +340,10 @@ affreg.tag = 'affreg'; affreg.name = 'Affine Regularisation'; affreg.help = { - 'The procedure is a local optimisation, so it needs reasonable initial starting estimates. Images should be placed in approximate alignment using the Display function of SPM before beginning. A Mutual Information affine registration with the tissue probability maps (D''Agostino et al, 2004) is used to achieve approximate alignment. Note that this step does not include any model for intensity non-uniformity. This means that if the procedure is to be initialised with the affine registration, then the data should not be too corrupted with this artifact.If there is a lot of intensity non-uniformity, then manually position your image in order to achieve closer starting estimates, and turn off the affine registration.' - '' - 'Affine registration into a standard space can be made more robust by regularisation (penalising excessive stretching or shrinking). The best solutions can be obtained by knowing the approximate amount of stretching that is needed (e.g. ICBM templates are slightly bigger than typical brains, so greater zooms are likely to be needed). For example, if registering to an image in ICBM/MNI space, then choose this option. If registering to a template that is close in size, then select the appropriate option for this.' - }'; + 'The procedure is a local optimisation, so it needs reasonable initial starting estimates. Images should be placed in approximate alignment using the Display function of SPM before beginning. A Mutual Information affine registration with the tissue probability maps (D''Agostino et al, 2004) is used to achieve approximate alignment. Note that this step does not include any model for intensity non-uniformity. This means that if the procedure is to be initialised with the affine registration, then the data should not be too corrupted with this artifact.If there is a lot of intensity non-uniformity, then manually position your image in order to achieve closer starting estimates, and turn off the affine registration.' + '' + 'Affine registration into a standard space can be made more robust by regularisation (penalising excessive stretching or shrinking). The best solutions can be obtained by knowing the approximate amount of stretching that is needed (e.g. ICBM templates are slightly bigger than typical brains, so greater zooms are likely to be needed). For example, if registering to an image in ICBM/MNI space, then choose this option. If registering to a template that is close in size, then select the appropriate option for this.' + }'; affreg.labels = { 'No Affine Registration' 'ICBM space template - European brains' @@ -348,7 +366,11 @@ smo = cfg_entry; smo.tag = 'fwhm'; smo.name = 'Smoothness'; -smo.help = {'For PET or SPECT, set this value to about 5 mm, or more if the images have smoother noise. For MRI, you can usually use a value of 0 mm. This is used to derive a fudge factor to account for correlations between neighbouring voxels. Smoother data have more spatial correlations, rendering the assumptions of the model inaccurate.'}; +smo.help = { + 'This is used to derive a fudge factor to account for correlations between neighbouring voxels.' + 'Smoother data have more spatial correlations, rendering the assumptions of the model inaccurate.' + 'For PET or SPECT, set this value to about 5 mm, or more if the images have smoother noise. For MRI, you can usually use a value of 0 mm.' + }'; smo.strtype = 'r'; smo.num = [1 1]; smo.val = {0}; @@ -359,7 +381,10 @@ samp = cfg_entry; samp.tag = 'samp'; samp.name = 'Sampling distance'; -samp.help = {'This encodes the approximate distance between sampled points when estimating the model parameters. Smaller values use more of the data, but the procedure is slower and needs more memory. Determining the ``best'''' setting involves a compromise between speed and accuracy.'}; +samp.help = { + 'This encodes the approximate distance between sampled points when estimating the model parameters.' + 'Smaller values use more of the data, but the procedure is slower and needs more memory. Determining the ``best'''' setting involves a compromise between speed and accuracy.' + }'; samp.strtype = 'r'; samp.num = [1 1]; samp.val = {3}; @@ -370,7 +395,10 @@ write = cfg_menu; write.tag = 'write'; write.name = 'Deformation Fields'; -write.help = {'Deformation fields can be saved to disk, and used by the Deformations Utility. For spatially normalising images to MNI space, you will need the forward deformation, whereas for spatially normalising (eg) GIFTI surface files, you''ll need the inverse. It is also possible to transform data in MNI space on to the individual subject, which also requires the inverse transform. Deformations are saved as .nii files, which contain three volumes to encode the x, y and z coordinates.'}; +write.help = { + 'Deformation fields can be saved to disk, and used by the Deformations Utility.' + 'For spatially normalising images to MNI space, you will need the forward deformation, whereas for spatially normalising (eg) GIFTI surface files, you''ll need the inverse. It is also possible to transform data in MNI space on to the individual subject, which also requires the inverse transform. Deformations are saved as .nii files, which contain three volumes to encode the x, y and z coordinates.' + }; write.labels = { 'None' 'Inverse' @@ -393,7 +421,9 @@ warp.name = 'Warping & MRF'; warp.val = {mrf cleanup reg affreg smo samp write}; warp.help = { -'A number of warping options are provided, but the main one that you could consider changing is the one for specifying whether deformation fields or inverse deformation fields should be generated.'}; + 'A number of warping options.' + 'The main one that you could consider changing is the one for specifying whether deformation fields or inverse deformation fields should be generated.' + }'; %-------------------------------------------------------------------------- % preproc Segment @@ -401,14 +431,16 @@ preproc = cfg_exbranch; preproc.tag = 'preproc'; preproc.name = 'Segment'; -preproc.val = {data tissues warp }; +preproc.val = {data tissues warp}; preproc.help = { - 'This procedure is an extension of the old unified segmentation algorithm (and was known as "New Segment" in SPM8). The algorithm is essentially the same as that described in the Unified Segmentation paper, except for (i) a slightly different treatment of the mixing proportions, (ii) the use of an improved registration model, (iii) the ability to use multi-spectral data, (iv) an extended set of tissue probability maps, which allows a different treatment of voxels outside the brain. Some of the options in the toolbox do not yet work, and it has not yet been seamlessly integrated into the SPM8 software. Also, the extended tissue probability maps need further refinement. The current versions were crudely generated (by JA) using data that was kindly provided by Cynthia Jongen of the Imaging Sciences Institute at Utrecht, NL.' - '' - 'This function segments, bias corrects and spatially normalises - all in the same model/* \cite{ashburner05}*/. Many investigators use tools within older versions of SPM for a technique that has become known as "optimised" voxel-based morphometry (VBM). VBM performs region-wise volumetric comparisons among populations of subjects. It requires the images to be spatially normalised, segmented into different tissue classes, and smoothed, prior to performing statistical tests/* \cite{wright_vbm,am_vbmreview,ashburner00b,john_should}*/. The "optimised" pre-processing strategy involved spatially normalising subjects'' brain images to a standard space, by matching grey matter in these images, to a grey matter reference. The historical motivation behind this approach was to reduce the confounding effects of non-brain (e.g. scalp) structural variability on the registration. Tissue classification in older versions of SPM required the images to be registered with tissue probability maps. After registration, these maps represented the prior probability of different tissue classes being found at each location in an image. Bayes rule can then be used to combine these priors with tissue type probabilities derived from voxel intensities, to provide the posterior probability.' - '' - 'This procedure was inherently circular, because the registration required an initial tissue classification, and the tissue classification requires an initial registration. This circularity is resolved here by combining both components into a single generative model. This model also includes parameters that account for image intensity non-uniformity. Estimating the model parameters (for a maximum a posteriori solution) involves alternating among classification, bias correction and registration steps. This approach provides better results than simple serial applications of each component.' - }'; + 'Segmentation, bias correction and spatially normalisation - all in the same model.' + '' + 'This procedure is an extension of the old unified segmentation algorithm (and was known as "New Segment" in SPM8). The algorithm is essentially the same as that described in the Unified Segmentation paper /* \cite{ashburner05}*/, except for (i) a slightly different treatment of the mixing proportions, (ii) the use of an improved registration model, (iii) the ability to use multi-spectral data, (iv) an extended set of tissue probability maps, which allows a different treatment of voxels outside the brain. Some of the options in the toolbox do not yet work, and it has not yet been seamlessly integrated into the SPM8 software. Also, the extended tissue probability maps need further refinement. The current versions were crudely generated (by JA) using data that was kindly provided by Cynthia Jongen of the Imaging Sciences Institute at Utrecht, NL.' + '' + 'This function segments, bias corrects and spatially normalises - all in the same model/* \cite{ashburner05}*/. Many investigators use tools within older versions of SPM for a technique that has become known as "optimised" voxel-based morphometry (VBM). VBM performs region-wise volumetric comparisons among populations of subjects. It requires the images to be spatially normalised, segmented into different tissue classes, and smoothed, prior to performing statistical tests/* \cite{wright_vbm,am_vbmreview,ashburner00b,john_should}*/. The "optimised" pre-processing strategy involved spatially normalising subjects'' brain images to a standard space, by matching grey matter in these images, to a grey matter reference. The historical motivation behind this approach was to reduce the confounding effects of non-brain (e.g. scalp) structural variability on the registration. Tissue classification in older versions of SPM required the images to be registered with tissue probability maps. After registration, these maps represented the prior probability of different tissue classes being found at each location in an image. Bayes rule can then be used to combine these priors with tissue type probabilities derived from voxel intensities, to provide the posterior probability.' + '' + 'This procedure was inherently circular, because the registration required an initial tissue classification, and the tissue classification requires an initial registration. This circularity is resolved here by combining both components into a single generative model. This model also includes parameters that account for image intensity non-uniformity. Estimating the model parameters (for a maximum a posteriori solution) involves alternating among classification, bias correction and registration steps. This approach provides better results than simple serial applications of each component.' + }'; preproc.prog = @spm_local_preproc_run; preproc.vout = @vout; @@ -428,14 +460,14 @@ cdep(end).src_output = substruct('.','param','()',{':'}); cdep(end).tgt_spec = cfg_findspec({{'filter','mat','strtype','e'}}); -for i=1:numel(job.channel), - if job.channel(i).write(1), +for i=1:numel(job.channel) + if job.channel(i).write(1) cdep(end+1) = cfg_dep; cdep(end).sname = sprintf('Bias Field (%d)',i); cdep(end).src_output = substruct('.','channel','()',{i},'.','biasfield','()',{':'}); cdep(end).tgt_spec = cfg_findspec({{'filter','image','strtype','e'}}); end - if job.channel(i).write(2), + if job.channel(i).write(2) cdep(end+1) = cfg_dep; cdep(end).sname = sprintf('Bias Corrected (%d)',i); cdep(end).src_output = substruct('.','channel','()',{i},'.','biascorr','()',{':'}); @@ -443,26 +475,26 @@ end end -for i=1:numel(job.tissue), - if job.tissue(i).native(1), +for i=1:numel(job.tissue) + if job.tissue(i).native(1) cdep(end+1) = cfg_dep; cdep(end).sname = sprintf('c%d Images',i); cdep(end).src_output = substruct('.','tiss','()',{i},'.','c','()',{':'}); cdep(end).tgt_spec = cfg_findspec({{'filter','image','strtype','e'}}); end - if job.tissue(i).native(2), + if job.tissue(i).native(2) cdep(end+1) = cfg_dep; cdep(end).sname = sprintf('rc%d Images',i); cdep(end).src_output = substruct('.','tiss','()',{i},'.','rc','()',{':'}); cdep(end).tgt_spec = cfg_findspec({{'filter','image','strtype','e'}}); end - if job.tissue(i).warped(1), + if job.tissue(i).warped(1) cdep(end+1) = cfg_dep; cdep(end).sname = sprintf('wc%d Images',i); cdep(end).src_output = substruct('.','tiss','()',{i},'.','wc','()',{':'}); cdep(end).tgt_spec = cfg_findspec({{'filter','image','strtype','e'}}); end - if job.tissue(i).warped(2), + if job.tissue(i).warped(2) cdep(end+1) = cfg_dep; cdep(end).sname = sprintf('mwc%d Images',i); cdep(end).src_output = substruct('.','tiss','()',{i},'.','mwc','()',{':'}); @@ -470,14 +502,14 @@ end end -if job.warp.write(1), +if job.warp.write(1) cdep(end+1) = cfg_dep; cdep(end).sname = 'Inverse Deformations'; cdep(end).src_output = substruct('.','invdef','()',{':'}); cdep(end).tgt_spec = cfg_findspec({{'filter','image','strtype','e'}}); end -if job.warp.write(2), +if job.warp.write(2) cdep(end+1) = cfg_dep; cdep(end).sname = 'Forward Deformations'; cdep(end).src_output = substruct('.','fordef','()',{':'}); diff --git a/config/spm_cfg_print.m b/config/spm_cfg_print.m index 8d81a232..092550a5 100644 --- a/config/spm_cfg_print.m +++ b/config/spm_cfg_print.m @@ -3,7 +3,7 @@ %__________________________________________________________________________ % Copyright (C) 2005-2012 Wellcome Trust Centre for Neuroimaging -% $Id: spm_cfg_print.m 4902 2012-09-05 18:56:48Z guillaume $ +% $Id: spm_cfg_print.m 6924 2016-11-09 11:38:00Z guillaume $ %-------------------------------------------------------------------------- % opts Printing Format @@ -65,6 +65,7 @@ fig.name = 'Figure to print'; fig.values = {figname, fighandle}; fig.val = {figname}; +fig.help = {'Figure to print'}; %-------------------------------------------------------------------------- % cfg_print Print figure diff --git a/config/spm_cfg_realign.m b/config/spm_cfg_realign.m index d4856b57..42e98ed3 100644 --- a/config/spm_cfg_realign.m +++ b/config/spm_cfg_realign.m @@ -1,9 +1,9 @@ function realign = spm_cfg_realign % SPM Configuration file for Realign %__________________________________________________________________________ -% Copyright (C) 2005-2014 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2016 Wellcome Trust Centre for Neuroimaging -% $Id: spm_cfg_realign.m 6148 2014-09-03 15:49:04Z guillaume $ +% $Id: spm_cfg_realign.m 6952 2016-11-25 16:03:13Z guillaume $ %-------------------------------------------------------------------------- @@ -12,7 +12,10 @@ data = cfg_files; data.tag = 'data'; data.name = 'Session'; -data.help = {'Select scans for this session. In the coregistration step, the sessions are first realigned to each other, by aligning the first scan from each session to the first scan of the first session. Then the images within each session are aligned to the first image of the session. The parameter estimation is performed this way because it is assumed (rightly or not) that there may be systematic differences in the images between sessions.'}; +data.help = { + 'Select scans for this session.' + 'In the coregistration step, the sessions are first realigned to each other, by aligning the first scan from each session to the first scan of the first session. Then the images within each session are aligned to the first image of the session. The parameter estimation is performed this way because it is assumed (rightly or not) that there may be systematic differences in the images between sessions.' + }'; data.filter = 'image'; data.ufilter = '.*'; data.num = [1 Inf]; @@ -24,7 +27,10 @@ generic = cfg_repeat; generic.tag = 'generic'; generic.name = 'Data'; -generic.help = {'Add new sessions for this subject. In the coregistration step, the sessions are first realigned to each other, by aligning the first scan from each session to the first scan of the first session. Then the images within each session are aligned to the first image of the session. The parameter estimation is performed this way because it is assumed (rightly or not) that there may be systematic differences in the images between sessions.'}; +generic.help = { + 'Add new sessions for this subject.' + 'In the coregistration step, the sessions are first realigned to each other, by aligning the first scan from each session to the first scan of the first session. Then the images within each session are aligned to the first image of the session. The parameter estimation is performed this way because it is assumed (rightly or not) that there may be systematic differences in the images between sessions.' + }'; generic.values = {data}; generic.num = [1 Inf]; @@ -34,7 +40,10 @@ quality = cfg_entry; quality.tag = 'quality'; quality.name = 'Quality'; -quality.help = {'Quality versus speed trade-off. Highest quality (1) gives most precise results, whereas lower qualities gives faster realignment. The idea is that some voxels contribute little to the estimation of the realignment parameters. This parameter is involved in selecting the number of voxels that are used.'}; +quality.help = { + 'Quality versus speed trade-off.' + 'Highest quality (1) gives most precise results, whereas lower qualities gives faster realignment. The idea is that some voxels contribute little to the estimation of the realignment parameters. This parameter is involved in selecting the number of voxels that are used.' + }'; quality.strtype = 'r'; quality.num = [1 1]; quality.extras = [0 1]; @@ -46,7 +55,10 @@ sep = cfg_entry; sep.tag = 'sep'; sep.name = 'Separation'; -sep.help = {'The separation (in mm) between the points sampled in the reference image. Smaller sampling distances gives more accurate results, but will be slower.'}; +sep.help = { + 'The separation (in mm) between the points sampled in the reference image.' + 'Smaller sampling distances gives more accurate results, but will be slower.' + }'; sep.strtype = 'r'; sep.num = [1 1]; sep.def = @(val)spm_get_defaults('realign.estimate.sep', val{:}); @@ -58,12 +70,12 @@ fwhm.tag = 'fwhm'; fwhm.name = 'Smoothing (FWHM)'; fwhm.help = { - 'The FWHM of the Gaussian smoothing kernel (mm) applied to the images before estimating the realignment parameters.' - '' - ' * PET images typically use a 7 mm kernel.' - '' - ' * MRI images typically use a 5 mm kernel.' -}'; + 'The FWHM of the Gaussian smoothing kernel (mm) applied to the images before estimating the realignment parameters.' + '' + ' * PET images typically use a 7 mm kernel.' + '' + ' * MRI images typically use a 5 mm kernel.' + }'; fwhm.strtype = 'r'; fwhm.num = [1 1]; fwhm.def = @(val)spm_get_defaults('realign.estimate.fwhm', val{:}); @@ -75,12 +87,12 @@ rtm.tag = 'rtm'; rtm.name = 'Num Passes'; rtm.help = { - 'Register to first: Images are registered to the first image in the series. Register to mean: A two pass procedure is used in order to register the images to the mean of the images after the first realignment.' - '' - 'PET images are typically registered to the mean. This is because PET data are more noisy than fMRI and there are fewer of them, so time is less of an issue.' - '' - 'MRI images are typically registered to the first image. The more accurate way would be to use a two pass procedure, but this probably wouldn''t improve the results so much and would take twice as long to run.' -}'; + 'Register to first: Images are registered to the first image in the series. Register to mean: A two pass procedure is used in order to register the images to the mean of the images after the first realignment.' + '' + 'PET images are typically registered to the mean. This is because PET data are more noisy than fMRI and there are fewer of them, so time is less of an issue.' + '' + 'MRI images are typically registered to the first image. The more accurate way would be to use a two pass procedure, but this probably wouldn''t improve the results so much and would take twice as long to run.' + }'; rtm.labels = { 'Register to first' 'Register to mean' @@ -94,7 +106,10 @@ interp = cfg_menu; interp.tag = 'interp'; interp.name = 'Interpolation'; -interp.help = {'The method by which the images are sampled when estimating the optimum transformation. Higher degree interpolation methods provide the better interpolation, but they are slower because they use more neighbouring voxels /* \cite{thevenaz00a,unser93a,unser93b}*/. '}; +interp.help = { + 'The method by which the images are sampled when estimating the optimum transformation.' + 'Higher degree interpolation methods provide the better interpolation, but they are slower because they use more neighbouring voxels /* \cite{thevenaz00a,unser93a,unser93b}*/.' + }'; interp.labels = { 'Trilinear (1st Degree)' '2nd Degree B-Spline' @@ -114,10 +129,11 @@ wrap.tag = 'wrap'; wrap.name = 'Wrapping'; wrap.help = { - 'This indicates which directions in the volumes the values should wrap around in. For example, in MRI scans, the images wrap around in the phase encode direction, so (e.g.) the subject''s nose may poke into the back of the subject''s head. These are typically:' - ' No wrapping - for PET or images that have already been spatially transformed. Also the recommended option if you are not really sure.' - ' Wrap in Y - for (un-resliced) MRI where phase encoding is in the Y direction (voxel space).' -}'; + 'Directions in the volumes the values should wrap around in.' + 'For example, in MRI scans, the images wrap around in the phase encode direction, so (e.g.) the subject''s nose may poke into the back of the subject''s head. These are typically:' + ' No wrapping - for PET or images that have already been spatially transformed. Also the recommended option if you are not really sure.' + ' Wrap in Y - for (un-resliced) MRI where phase encoding is in the Y direction (voxel space).' + }'; wrap.labels = { 'No wrap' 'Wrap X' @@ -139,7 +155,11 @@ weight.tag = 'weight'; weight.name = 'Weighting'; weight.val = {''}; -weight.help = {'The option of providing a weighting image to weight each voxel of the reference image differently when estimating the realignment parameters. The weights are proportional to the inverses of the standard deviations. This would be used, for example, when there is a lot of extra-brain motion - e.g., during speech, or when there are serious artifacts in a particular region of the images.'}; +weight.help = { + 'Optional weighting image to weight each voxel of the reference image differently when estimating the realignment parameters.' + 'The weights are proportional to the inverses of the standard deviations.' + 'This would be used, for example, when there is a lot of extra-brain motion - e.g., during speech, or when there are serious artifacts in a particular region of the images.' + }'; weight.filter = 'image'; weight.ufilter = '.*'; weight.num = [0 1]; @@ -162,10 +182,12 @@ estimate.name = 'Realign: Estimate'; estimate.val = {generic eoptions}; estimate.help = { - 'This routine realigns a time-series of images acquired from the same subject using a least squares approach and a 6 parameter (rigid body) spatial transformation/* \cite{friston95a}*/. The first image in the list specified by the user is used as a reference to which all subsequent scans are realigned. The reference scan does not have to the the first chronologically and it may be wise to chose a "representative scan" in this role.' - '' - 'The aim is primarily to remove movement artefact in fMRI and PET time-series (or more generally longitudinal studies). The headers are modified for each of the input images, such that. they reflect the relative orientations of the data. The details of the transformation are displayed in the results window as plots of translation and rotation. A set of realignment parameters are saved for each session, named rp_*.txt. These can be modelled as confounds within the general linear model/* \cite{friston95a}*/.' -}'; + 'Realign a time-series of images acquired from the same subject using a least squares approach and a 6 parameter (rigid body) spatial transformation/* \cite{friston95a}*/.' + '' + 'The first image in the list specified by the user is used as a reference to which all subsequent scans are realigned. The reference scan does not have to the the first chronologically and it may be wise to chose a "representative scan" in this role.' + '' + 'The aim is primarily to remove movement artefact in fMRI and PET time-series (or more generally longitudinal studies). The headers are modified for each of the input images, such that. they reflect the relative orientations of the data. The details of the transformation are displayed in the results window as plots of translation and rotation. A set of realignment parameters are saved for each session, named rp_*.txt. These can be modelled as confounds within the general linear model/* \cite{friston95a}*/.' + }'; estimate.prog = @spm_run_realign; estimate.vout = @vout_estimate; @@ -188,14 +210,16 @@ which.tag = 'which'; which.name = 'Resliced images'; which.help = { - 'All Images (1..n) : This reslices all the images - including the first image selected - which will remain in its original position.' - '' - 'Images 2..n : Reslices images 2..n only. Useful for if you wish to reslice (for example) a PET image to fit a structural MRI, without creating a second identical MRI volume.' - '' - 'All Images + Mean Image : In addition to reslicing the images, it also creates a mean of the resliced image.' - '' - 'Mean Image Only : Creates the mean resliced image only.' -}'; + 'Specify the images to reslice.' + '' + 'All Images (1..n) : This reslices all the images - including the first image selected - which will remain in its original position.' + '' + 'Images 2..n : Reslices images 2..n only. Useful for if you wish to reslice (for example) a PET image to fit a structural MRI, without creating a second identical MRI volume.' + '' + 'All Images + Mean Image : In addition to reslicing the images, it also creates a mean of the resliced image.' + '' + 'Mean Image Only : Creates the mean resliced image only.' + }'; which.labels = { ' All Images (1..n)' 'Images 2..n' @@ -211,7 +235,10 @@ interp = cfg_menu; interp.tag = 'interp'; interp.name = 'Interpolation'; -interp.help = {'The method by which the images are sampled when being written in a different space. Nearest Neighbour is fastest, but not recommended for image realignment. Trilinear Interpolation is probably OK for PET, but not so suitable for fMRI because higher degree interpolation generally gives better results/* \cite{thevenaz00a,unser93a,unser93b}*/. Although higher degree methods provide better interpolation, but they are slower because they use more neighbouring voxels. Fourier Interpolation/* \cite{eddy96,cox99}*/ is another option, but note that it is only implemented for purely rigid body transformations. Voxel sizes must all be identical and isotropic.'}; +interp.help = { + 'The method by which the images are sampled when being written in a different space.' + 'Nearest Neighbour is fastest, but not recommended for image realignment. Trilinear Interpolation is probably OK for PET, but not so suitable for fMRI because higher degree interpolation generally gives better results/* \cite{thevenaz00a,unser93a,unser93b}*/. Although higher degree methods provide better interpolation, but they are slower because they use more neighbouring voxels. Fourier Interpolation/* \cite{eddy96,cox99}*/ is another option, but note that it is only implemented for purely rigid body transformations. Voxel sizes must all be identical and isotropic.' + }'; interp.labels = { 'Nearest neighbour' 'Trilinear' @@ -233,10 +260,11 @@ wrap.tag = 'wrap'; wrap.name = 'Wrapping'; wrap.help = { - 'This indicates which directions in the volumes the values should wrap around in. For example, in MRI scans, the images wrap around in the phase encode direction, so (e.g.) the subject''s nose may poke into the back of the subject''s head. These are typically:' - ' No wrapping - for PET or images that have already been spatially transformed.' - ' Wrap in Y - for (un-resliced) MRI where phase encoding is in the Y direction (voxel space).' -}'; + 'This indicates which directions in the volumes the values should wrap around in.' + 'For example, in MRI scans, the images wrap around in the phase encode direction, so (e.g.) the subject''s nose may poke into the back of the subject''s head. These are typically:' + ' No wrapping - for PET or images that have already been spatially transformed.' + ' Wrap in Y - for (un-resliced) MRI where phase encoding is in the Y direction (voxel space).' + }'; wrap.labels = { 'No wrap' 'Wrap X' @@ -292,7 +320,10 @@ write.tag = 'write'; write.name = 'Realign: Reslice'; write.val = {data roptions}; -write.help = {'This function reslices a series of registered images such that they match the first image selected voxel-for-voxel. The resliced images are named the same as the originals, except that they are prefixed by ''r''.'}; +write.help = { + 'Reslice a series of registered images such that they match the first image selected voxel-for-voxel.' + 'The resliced images are named the same as the originals, except that they are prefixed by ''r''.' + }'; write.prog = @spm_run_realign; write.vout = @vout_reslice; @@ -302,7 +333,10 @@ data = cfg_files; data.tag = 'data'; data.name = 'Session'; -data.help = {'Select scans for this session. In the coregistration step, the sessions are first realigned to each other, by aligning the first scan from each session to the first scan of the first session. Then the images within each session are aligned to the first image of the session. The parameter estimation is performed this way because it is assumed (rightly or not) that there may be systematic differences in the images between sessions.'}; +data.help = { + 'Select scans for this session.' + 'In the coregistration step, the sessions are first realigned to each other, by aligning the first scan from each session to the first scan of the first session. Then the images within each session are aligned to the first image of the session. The parameter estimation is performed this way because it is assumed (rightly or not) that there may be systematic differences in the images between sessions.' + }'; data.filter = 'image'; data.ufilter = '.*'; data.num = [1 Inf]; @@ -314,7 +348,10 @@ generic = cfg_repeat; generic.tag = 'generic'; generic.name = 'Data'; -generic.help = {'Add new sessions for this subject. In the coregistration step, the sessions are first realigned to each other, by aligning the first scan from each session to the first scan of the first session. Then the images within each session are aligned to the first image of the session. The parameter estimation is performed this way because it is assumed (rightly or not) that there may be systematic differences in the images between sessions.'}; +generic.help = { + 'Add new sessions for this subject.' + 'In the coregistration step, the sessions are first realigned to each other, by aligning the first scan from each session to the first scan of the first session. Then the images within each session are aligned to the first image of the session. The parameter estimation is performed this way because it is assumed (rightly or not) that there may be systematic differences in the images between sessions.' + }'; generic.values = {data }; generic.num = [1 Inf]; @@ -326,10 +363,12 @@ estwrite.name = 'Realign: Estimate & Reslice'; estwrite.val = {generic eoptions roptions }; estwrite.help = { - 'This routine realigns a time-series of images acquired from the same subject using a least squares approach and a 6 parameter (rigid body) spatial transformation/* \cite{friston95a}*/. The first image in the list specified by the user is used as a reference to which all subsequent scans are realigned. The reference scan does not have to be the first chronologically and it may be wise to chose a "representative scan" in this role.' - '' - 'The aim is primarily to remove movement artefact in fMRI and PET time-series (or more generally longitudinal studies) /* \cite{ashburner97bir}*/. The headers are modified for each of the input images, such that. they reflect the relative orientations of the data. The details of the transformation are displayed in the results window as plots of translation and rotation. A set of realignment parameters are saved for each session, named rp_*.txt. After realignment, the images are resliced such that they match the first image selected voxel-for-voxel. The resliced images are named the same as the originals, except that they are prefixed by ''r''.' -}'; + 'Realign a time-series of images acquired from the same subject using a least squares approach and a 6 parameter (rigid body) spatial transformation/* \cite{friston95a}*/.' + '' + 'The first image in the list specified by the user is used as a reference to which all subsequent scans are realigned. The reference scan does not have to be the first chronologically and it may be wise to chose a "representative scan" in this role.' + '' + 'The aim is primarily to remove movement artefact in fMRI and PET time-series (or more generally longitudinal studies) /* \cite{ashburner97bir}*/. The headers are modified for each of the input images, such that. they reflect the relative orientations of the data. The details of the transformation are displayed in the results window as plots of translation and rotation. A set of realignment parameters are saved for each session, named rp_*.txt. After realignment, the images are resliced such that they match the first image selected voxel-for-voxel. The resliced images are named the same as the originals, except that they are prefixed by ''r''.' + }'; estwrite.prog = @spm_run_realign; estwrite.vout = @vout_estwrite; diff --git a/config/spm_cfg_realignunwarp.m b/config/spm_cfg_realignunwarp.m index 2297bac6..d62b74f7 100644 --- a/config/spm_cfg_realignunwarp.m +++ b/config/spm_cfg_realignunwarp.m @@ -1,9 +1,9 @@ function realignunwarp = spm_cfg_realignunwarp % SPM Configuration file for Realign & Unwarp %__________________________________________________________________________ -% Copyright (C) 2005-2014 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2016 Wellcome Trust Centre for Neuroimaging -% $Id: spm_cfg_realignunwarp.m 6148 2014-09-03 15:49:04Z guillaume $ +% $Id: spm_cfg_realignunwarp.m 6952 2016-11-25 16:03:13Z guillaume $ %-------------------------------------------------------------------------- @@ -13,9 +13,9 @@ scans.tag = 'scans'; scans.name = 'Images'; scans.help = { - 'Select scans for this session. ' - 'In the coregistration step, the sessions are first realigned to each other, by aligning the first scan from each session to the first scan of the first session. Then the images within each session are aligned to the first image of the session. The parameter estimation is performed this way because it is assumed (rightly or not) that there may be systematic differences in the images between sessions.' -}'; + 'Select scans for this session.' + 'In the coregistration step, the sessions are first realigned to each other, by aligning the first scan from each session to the first scan of the first session. Then the images within each session are aligned to the first image of the session. The parameter estimation is performed this way because it is assumed (rightly or not) that there may be systematic differences in the images between sessions.' + }'; scans.filter = 'image'; scans.ufilter = '.*'; scans.num = [1 Inf]; @@ -27,7 +27,10 @@ pmscan = cfg_files; pmscan.tag = 'pmscan'; pmscan.name = 'Phase map (vdm* file)'; -pmscan.help = {'Select pre-calculated phase map, or leave empty for no phase correction. The vdm* file is assumed to be already in alignment with the first scan of the first session.'}; +pmscan.help = { + 'Select pre-calculated phase map, or leave empty for no phase correction.' + 'The vdm* file is assumed to be already in alignment with the first scan of the first session.' + }'; pmscan.filter = 'image'; pmscan.ufilter = '^vdm5_.*'; pmscan.num = [0 1]; @@ -42,10 +45,10 @@ data.name = 'Session'; data.val = {scans pmscan}; data.help = { - 'Only add similar session data to a realign+unwarp branch, i.e., choose Data or Data+phase map for all sessions, but don''t use them interchangeably.' - '' - 'In the coregistration step, the sessions are first realigned to each other, by aligning the first scan from each session to the first scan of the first session. Then the images within each session are aligned to the first image of the session. The parameter estimation is performed this way because it is assumed (rightly or not) that there may be systematic differences in the images between sessions.' -}'; + 'Only add similar session data to a realign+unwarp branch, i.e., choose Data or Data+phase map for all sessions, but don''t use them interchangeably.' + '' + 'In the coregistration step, the sessions are first realigned to each other, by aligning the first scan from each session to the first scan of the first session. Then the images within each session are aligned to the first image of the session. The parameter estimation is performed this way because it is assumed (rightly or not) that there may be systematic differences in the images between sessions.' + }'; %-------------------------------------------------------------------------- % generic Data @@ -63,7 +66,10 @@ quality = cfg_entry; quality.tag = 'quality'; quality.name = 'Quality'; -quality.help = {'Quality versus speed trade-off. Highest quality (1) gives most precise results, whereas lower qualities gives faster realignment. The idea is that some voxels contribute little to the estimation of the realignment parameters. This parameter is involved in selecting the number of voxels that are used.'}; +quality.help = { + 'Quality versus speed trade-off.' + 'Highest quality (1) gives most precise results, whereas lower qualities gives faster realignment. The idea is that some voxels contribute little to the estimation of the realignment parameters. This parameter is involved in selecting the number of voxels that are used.' + }'; quality.strtype = 'r'; quality.num = [1 1]; quality.extras = [0 1]; @@ -75,7 +81,9 @@ sep = cfg_entry; sep.tag = 'sep'; sep.name = 'Separation'; -sep.help = {'The separation (in mm) between the points sampled in the reference image. Smaller sampling distances gives more accurate results, but will be slower.'}; +sep.help = { + 'The separation (in mm) between the points sampled in the reference image.' + 'Smaller sampling distances gives more accurate results, but will be slower.'}; sep.strtype = 'r'; sep.num = [1 1]; sep.def = @(val)spm_get_defaults('realign.estimate.sep', val{:}); @@ -87,12 +95,12 @@ fwhm.tag = 'fwhm'; fwhm.name = 'Smoothing (FWHM)'; fwhm.help = { - 'The FWHM of the Gaussian smoothing kernel (mm) applied to the images before estimating the realignment parameters.' - '' - ' * PET images typically use a 7 mm kernel.' - '' - ' * MRI images typically use a 5 mm kernel.' -}'; + 'The FWHM of the Gaussian smoothing kernel (mm) applied to the images before estimating the realignment parameters.' + '' + ' * PET images typically use a 7 mm kernel.' + '' + ' * MRI images typically use a 5 mm kernel.' + }'; fwhm.strtype = 'r'; fwhm.num = [1 1]; fwhm.def = @(val)spm_get_defaults('realign.estimate.fwhm', val{:}); @@ -104,12 +112,12 @@ rtm.tag = 'rtm'; rtm.name = 'Num Passes'; rtm.help = { - 'Register to first: Images are registered to the first image in the series. Register to mean: A two pass procedure is used in order to register the images to the mean of the images after the first realignment.' - '' - ' * PET images are typically registered to the mean.' - '' - ' * MRI images are typically registered to the first image.' -}'; + 'Register to first: Images are registered to the first image in the series. Register to mean: A two pass procedure is used in order to register the images to the mean of the images after the first realignment.' + '' + ' * PET images are typically registered to the mean.' + '' + ' * MRI images are typically registered to the first image.' + }'; rtm.labels = { 'Register to first' 'Register to mean' @@ -123,7 +131,10 @@ einterp = cfg_menu; einterp.tag = 'einterp'; einterp.name = 'Interpolation'; -einterp.help = {'The method by which the images are sampled when estimating the optimum transformation. Higher degree interpolation methods provide the better interpolation, but they are slower because they use more neighbouring voxels /* \cite{thevenaz00a,unser93a,unser93b}*/. '}; +einterp.help = { + 'The method by which the images are sampled when estimating the optimum transformation.' + 'Higher degree interpolation methods provide the better interpolation, but they are slower because they use more neighbouring voxels /* \cite{thevenaz00a,unser93a,unser93b}*/.' + }'; einterp.labels = { 'Nearest neighbour' 'Trilinear' @@ -144,12 +155,11 @@ ewrap.tag = 'ewrap'; ewrap.name = 'Wrapping'; ewrap.help = { - 'These are typically: ' - ['* No wrapping - for images that have already been ' ... - 'spatially transformed.'] - ['* Wrap in Y - for (un-resliced) MRI where phase ' ... - 'encoding is in the Y direction (voxel space).'] -}'; + 'This indicates which directions in the volumes the values should wrap around in.' + 'These are typically:' + '* No wrapping - for images that have already been spatially transformed.' + '* Wrap in Y - for (un-resliced) MRI where phase encoding is in the Y direction (voxel space).' + }'; ewrap.labels = { 'No wrap' 'Wrap X' @@ -171,7 +181,10 @@ weight.tag = 'weight'; weight.name = 'Weighting'; weight.val = {''}; -weight.help = {'The option of providing a weighting image to weight each voxel of the reference image differently when estimating the realignment parameters. The weights are proportional to the inverses of the standard deviations. For example, when there is a lot of extra-brain motion - e.g., during speech, or when there are serious artifacts in a particular region of the images.'}; +weight.help = { + 'Optional weighting image to weight each voxel of the reference image differently when estimating the realignment parameters.' + 'The weights are proportional to the inverses of the standard deviations. For example, when there is a lot of extra-brain motion - e.g., during speech, or when there are serious artifacts in a particular region of the images.' + }'; weight.filter = 'image'; weight.ufilter = '.*'; weight.num = [0 1]; @@ -192,7 +205,10 @@ basfcn = cfg_menu; basfcn.tag = 'basfcn'; basfcn.name = 'Basis Functions'; -basfcn.help = {'Number of basis functions to use for each dimension. If the third dimension is left out, the order for that dimension is calculated to yield a roughly equal spatial cut-off in all directions. Default: [12 12 *]'}; +basfcn.help = { + 'Number of basis functions to use for each dimension.' + 'If the third dimension is left out, the order for that dimension is calculated to yield a roughly equal spatial cut-off in all directions. Default: [12 12 *]' + }'; basfcn.labels = { '8x8x*' '10x10x*' @@ -209,10 +225,10 @@ regorder.tag = 'regorder'; regorder.name = 'Regularisation'; regorder.help = { - 'Unwarp looks for the solution that maximises the likelihood (minimises the variance) while simultaneously maximising the smoothness of the estimated field (c.f. Lagrange multipliers). This parameter determines how to balance the compromise between these (i.e. the value of the multiplier). Test it on your own data (if you can be bothered) or go with the defaults. ' - '' - 'Regularisation of derivative fields is based on the regorder''th (spatial) derivative of the field. The choices are 0, 1, 2, or 3. Default: 1' -}'; + 'Unwarp looks for the solution that maximises the likelihood (minimises the variance) while simultaneously maximising the smoothness of the estimated field (c.f. Lagrange multipliers). This parameter determines how to balance the compromise between these (i.e. the value of the multiplier). Test it on your own data (if you can be bothered) or go with the defaults. ' + '' + 'Regularisation of derivative fields is based on the regorder''th (spatial) derivative of the field. The choices are 0, 1, 2, or 3. Default: 1' + }'; regorder.labels = { '0' '1' @@ -243,7 +259,10 @@ jm = cfg_menu; jm.tag = 'jm'; jm.name = 'Jacobian deformations'; -jm.help = {'In the defaults there is also an option to include Jacobian intensity modulation when estimating the fields. "Jacobian intensity modulation" refers to the dilution/concentration of intensity that ensue as a consequence of the distortions. Think of a semi-transparent coloured rubber sheet that you hold against a white background. If you stretch a part of the sheet (induce distortions) you will see the colour fading in that particular area. In theory it is a brilliant idea to include also these effects when estimating the field (see e.g. Andersson et al, NeuroImage 20:870-888). In practice for this specific problem it is NOT a good idea. Default: No'}; +jm.help = { + 'Option to include Jacobian intensity modulation when estimating the fields.' + '"Jacobian intensity modulation" refers to the dilution/concentration of intensity that ensue as a consequence of the distortions. Think of a semi-transparent coloured rubber sheet that you hold against a white background. If you stretch a part of the sheet (induce distortions) you will see the colour fading in that particular area. In theory it is a brilliant idea to include also these effects when estimating the field (see e.g. Andersson et al, NeuroImage 20:870-888). In practice for this specific problem it is NOT a good idea. Default: No' + }'; jm.labels = { 'Yes' 'No' @@ -258,16 +277,18 @@ fot.tag = 'fot'; fot.name = 'First-order effects'; fot.help = { - 'Theoretically (ignoring effects of shimming) one would expect the field to depend only on subject out-of-plane rotations. Hence the default choice ("Pitch and Roll", i.e., [4 5]). Go with that unless you have very good reasons to do otherwise' - '' - 'Vector of first order effects to model. Movements to be modelled are referred to by number. 1= x translation; 2= y translation; 3= z translation 4 = x rotation, 5 = y rotation and 6 = z rotation.' - '' - 'To model pitch & roll enter: [4 5]' - '' - 'To model all movements enter: [1:6]' - '' - 'Otherwise enter a customised set of movements to model' -}'; + 'Vector of first order effects to model.' + '' + 'Theoretically (ignoring effects of shimming) one would expect the field to depend only on subject out-of-plane rotations. Hence the default choice ("Pitch and Roll", i.e., [4 5]). Go with that unless you have very good reasons to do otherwise' + '' + 'Movements to be modelled are referred to by number. 1= x translation; 2= y translation; 3= z translation 4 = x rotation, 5 = y rotation and 6 = z rotation.' + '' + 'To model pitch & roll enter: [4 5]' + '' + 'To model all movements enter: [1:6]' + '' + 'Otherwise enter a customised set of movements to model' + }'; fot.strtype = 'n'; fot.num = [1 Inf]; fot.def = @(val)spm_get_defaults('unwarp.estimate.foe', val{:}); @@ -279,24 +300,25 @@ sot.tag = 'sot'; sot.name = 'Second-order effects'; sot.help = { - 'List of second order terms to model second derivatives of. This is entered as a vector of movement parameters similar to first order effects, or leave blank for NONE' - '' - 'Movements to be modelled are referred to by number:' - '' - '1= x translation; 2= y translation; 3= z translation 4 = x rotation, 5 = y rotation and 6 = z rotation.' - '' - 'To model the interaction of pitch & roll enter: [4 5]' - '' - 'To model all movements enter: [1:6]' - '' - 'The vector will be expanded into an n x 2 matrix of effects. For example [4 5] will be expanded to:' - '' - '[ 4 4' - '' - ' 4 5' - '' - ' 5 5 ]' -}'; + 'List of second order terms to model second derivatives of.' + 'This is entered as a vector of movement parameters similar to first order effects, or leave blank for NONE.' + '' + 'Movements to be modelled are referred to by number:' + '' + '1= x translation; 2= y translation; 3= z translation 4 = x rotation, 5 = y rotation and 6 = z rotation.' + '' + 'To model the interaction of pitch & roll enter: [4 5]' + '' + 'To model all movements enter: [1:6]' + '' + 'The vector will be expanded into an n x 2 matrix of effects. For example [4 5] will be expanded to:' + '' + '[ 4 4' + '' + ' 4 5' + '' + ' 5 5 ]' + }'; sot.strtype = 'n'; sot.num = [Inf Inf]; sot.def = @(val)spm_get_defaults('unwarp.estimate.soe', val{:}); @@ -318,7 +340,7 @@ rem = cfg_menu; rem.tag = 'rem'; rem.name = 'Re-estimate movement params'; -rem.help = {'Re-estimation means that movement-parameters should be re-estimated at each unwarping iteration. Default: Yes.'}; +rem.help = {'Re-estimation means that movement-parameters should be re-estimated at each unwarping iteration.'}; rem.labels = { 'Yes' 'No' @@ -332,7 +354,7 @@ noi = cfg_entry; noi.tag = 'noi'; noi.name = 'Number of Iterations'; -noi.help = {'Maximum number of iterations. Default: 5.'}; +noi.help = {'Maximum number of iterations.'}; noi.strtype = 'n'; noi.num = [1 1]; noi.def = @(val)spm_get_defaults('unwarp.estimate.noi', val{:}); @@ -343,7 +365,10 @@ expround = cfg_menu; expround.tag = 'expround'; expround.name = 'Taylor expansion point'; -expround.help = {'Point in position space to perform Taylor-expansion around. Choices are (''First'', ''Last'' or ''Average''). ''Average'' should (in principle) give the best variance reduction. If a field-map acquired before the time-series is supplied then expansion around the ''First'' MIGHT give a slightly better average geometric fidelity.'}; +expround.help = { + 'Point in position space to perform Taylor-expansion around.' + 'Choices are (''First'', ''Last'' or ''Average''). ''Average'' should (in principle) give the best variance reduction. If a field-map acquired before the time-series is supplied then expansion around the ''First'' MIGHT give a slightly better average geometric fidelity.' + }; expround.labels = { 'Average' 'First' @@ -372,12 +397,13 @@ uwwhich.tag = 'uwwhich'; uwwhich.name = 'Resliced images (unwarp)?'; uwwhich.help = { - 'All Images (1..n) ' - ' This reslices and unwarps all the images. ' - ' ' - 'All Images + Mean Image ' - ' In addition to reslicing the images, it also creates a mean of the resliced images.' -}'; + 'Specify the images to reslice.' + 'All Images (1..n) ' + ' This reslices and unwarps all the images. ' + ' ' + 'All Images + Mean Image ' + ' In addition to reslicing the images, it also creates a mean of the resliced images.' + }'; uwwhich.labels = { ' All Images (1..n)' ' All Images + Mean Image' @@ -391,7 +417,10 @@ rinterp = cfg_menu; rinterp.tag = 'rinterp'; rinterp.name = 'Interpolation'; -rinterp.help = {'The method by which the images are sampled when being written in a different space. Nearest Neighbour is fastest, but not recommended for image realignment. Trilinear Interpolation is probably OK for PET, but not so suitable for fMRI because higher degree interpolation generally gives better results/* \cite{thevenaz00a,unser93a,unser93b}*/. Although higher degree methods provide better interpolation, but they are slower because they use more neighbouring voxels.'}; +rinterp.help = { + 'The method by which the images are sampled when being written in a different space.' + 'Nearest Neighbour is fastest, but not recommended for image realignment. Trilinear Interpolation is probably OK for PET, but not so suitable for fMRI because higher degree interpolation generally gives better results/* \cite{thevenaz00a,unser93a,unser93b}*/. Although higher degree methods provide better interpolation, but they are slower because they use more neighbouring voxels.' + }'; rinterp.labels = { 'Nearest neighbour' 'Trilinear' @@ -412,12 +441,11 @@ wrap.tag = 'wrap'; wrap.name = 'Wrapping'; wrap.help = { - 'These are typically: ' - ['* No wrapping - for images that have already been ' ... - 'spatially transformed.'] - ['* Wrap in Y - for (un-resliced) MRI where phase ' ... - 'encoding is in the Y direction (voxel space).'] -}'; + 'This indicates which directions in the volumes the values should wrap around in.' + 'These are typically:' + '* No wrapping - for images that have already been spatially transformed.' + '* Wrap in Y - for (un-resliced) MRI where phase encoding is in the Y direction (voxel space).' + }'; wrap.labels = { 'No wrap' 'Wrap X' @@ -474,39 +502,39 @@ realignunwarp.name = 'Realign & Unwarp'; realignunwarp.val = {generic eoptions uweoptions uwroptions}; realignunwarp.help = { - 'Within-subject registration and unwarping of time series.' - '' - 'The realignment part of this routine realigns a time-series of images acquired from the same subject using a least squares approach and a 6 parameter (rigid body) spatial transformation. The first image in the list specified by the user is used as a reference to which all subsequent scans are realigned. The reference scan does not have to the the first chronologically and it may be wise to chose a "representative scan" in this role.' - '' - 'The aim is primarily to remove movement artefact in fMRI and PET time-series (or more generally longitudinal studies). This affects the header of each of the input images which contains details about the voxel-to-world mapping. The details of the transformation are displayed in the results window as plots of translation and rotation. A set of realignment parameters are saved for each session, named rp_*.txt.' - '' - 'In the coregistration step, the sessions are first realigned to each other, by aligning the first scan from each session to the first scan of the first session. Then the images within each session are aligned to the first image of the session. The parameter estimation is performed this way because it is assumed (rightly or not) that there may be systematic differences in the images between sessions.' - '' - 'See spm_uw_estimate.m for a detailed description of the implementation.' - '' - 'Even after realignment there is considerable variance in fMRI time series that covary with, and is most probably caused by, subject movements/* \cite{ja_geometric}*/. It is also the case that this variance is typically large compared to experimentally induced variance. Anyone interested can include the estimated movement parameters as covariates in the design matrix, and take a look at an F-contrast encompassing those columns. It is quite dramatic. The result is loss of sensitivity, and if movements are correlated to task specificity. I.e. we may mistake movement induced variance for true activations. The problem is well known, and several solutions have been suggested. A quite pragmatic (and conservative) solution is to include the estimated movement parameters (and possibly squared) as covariates in the design matrix. Since we typically have loads of degrees of freedom in fMRI we can usually afford this. The problems occur when movements are correlated with the task, since the strategy above will discard "good" and "bad" variance alike (i.e. remove also "true" activations).' - '' - 'The "covariate" strategy described above was predicated on a model where variance was assumed to be caused by "spin history" effects, but will work pretty much equally good/bad regardless of what the true underlying cause is. Others have assumed that the residual variance is caused mainly by errors introduced by the interpolation kernel in the resampling step of the realignment. One has tried to solve this through higher order resampling (huge Sinc kernels, or k-space resampling). Unwarp is based on a different hypothesis regarding the residual variance. EPI images are not particularly faithful reproductions of the object, and in particular there are severe geometric distortions in regions where there is an air-tissue interface (e.g. orbitofrontal cortex and the anterior medial temporal lobes). In these areas in particular the observed image is a severely warped version of reality, much like a funny mirror at a fair ground. When one moves in front of such a mirror ones image will distort in different ways and ones head may change from very elongated to seriously flattened. If we were to take digital snapshots of the reflection at these different positions it is rather obvious that realignment will not suffice to bring them into a common space.' - '' - 'The situation is similar with EPI images, and an image collected for a given subject position will not be identical to that collected at another. We call this effect susceptibility-by-movement interaction. Unwarp is predicated on the assumption that the susceptibility-by-movement interaction is responsible for a sizable part of residual movement related variance.' - '' - 'Assume that we know how the deformations change when the subject changes position (i.e. we know the derivatives of the deformations with respect to subject position). That means that for a given time series and a given set of subject movements we should be able to predict the "shape changes" in the object and the ensuing variance in the time series. It also means that, in principle, we should be able to formulate the inverse problem, i.e. given the observed variance (after realignment) and known (estimated) movements we should be able to estimate how deformations change with subject movement. We have made an attempt at formulating such an inverse model, and at solving for the "derivative fields". A deformation field can be thought of as little vectors at each position in space showing how that particular location has been deflected. A "derivative field" is then the rate of change of those vectors with respect to subject movement. Given these "derivative fields" we should be able to remove the variance caused by the susceptibility-by-movement interaction. Since the underlying model is so restricted we would also expect experimentally induced variance to be preserved. Our experiments have also shown this to be true.' - '' - 'In theory it should be possible to estimate also the "static" deformation field, yielding an unwarped (to some true geometry) version of the time series. In practise that doesn''t really seem to work. Hence, the method deals only with residual movement related variance induced by the susceptibility-by-movement interaction. This means that the time-series will be undistorted to some "average distortion" state rather than to the true geometry. If one wants additionally to address the issue of anatomical fidelity one should combine Unwarp with a measured fieldmap.' - '' - 'The description above can be thought of in terms of a Taylor expansion of the field as a function of subject movement. Unwarp alone will estimate the first (and optionally second, see below) order terms of this expansion. It cannot estimate the zeroth order term (the distortions common to all scans in the time series) since that doesn''t introduce (almost) any variance in the time series. The measured fieldmap takes the role of the zeroth order term. Refer to the FieldMap toolbox and the documents FieldMap.man and FieldMap_principles.man for a description of how to obtain fieldmaps in the format expected by Unwarp.' - '' - 'If we think of the field as a function of subject movement it should in principle be a function of six variables since rigid body movement has six degrees of freedom. However, the physics of the problem tells us that the field should not depend on translations nor on rotation in a plane perpendicular to the magnetic flux. Hence it should in principle be sufficient to model the field as a function of out-of-plane rotations (i.e. pitch and roll). One can object to this in terms of the effects of shimming (object no longer immersed in a homogenous field) that introduces a dependence on all movement parameters. In addition SPM/Unwarp cannot really tell if the transversal slices it is being passed are really perpendicular to the flux or not. In practice it turns out thought that it is never (at least we haven''t seen any case) necessary to include more than Pitch and Roll. This is probably because the individual movement parameters are typically highly correlated anyway, which in turn is probably because most heads that we scan are attached to a neck around which rotations occur. On the subject of Taylor expansion we should mention that there is the option to use a second-order expansion (through the defaults) interface. This implies estimating also the rate-of-change w.r.t. to some movement parameter of the rate-of-change of the field w.r.t. some movement parameter (colloquially known as a second derivative). It can be quite interesting to watch (and it is amazing that it is possible) but rarely helpful/necessary.' - '' - 'In the defaults there is also an option to include Jacobian intensity modulation when estimating the fields. "Jacobian intensity modulation" refers to the dilution/concentration of intensity that ensue as a consequence of the distortions. Think of a semi-transparent coloured rubber sheet that you hold against a white background. If you stretch a part of the sheet (induce distortions) you will see the colour fading in that particular area. In theory it is a brilliant idea to include also these effects when estimating the field (see e.g. Andersson et al, NeuroImage 20:870-888). In practice for this specific problem it is NOT a good idea.' - '' - 'It should be noted that this is a method intended to correct data afflicted by a particular problem. If there is little movement in your data to begin with this method will do you little good. If on the other hand there is appreciable movement in your data (>1deg) it will remove some of that unwanted variance. If, in addition, movements are task related it will do so without removing all your "true" activations. The method attempts to minimise total (across the image volume) variance in the data set. It should be realised that while (for small movements) a rather limited portion of the total variance is removed, the susceptibility-by-movement interaction effects are quite localised to "problem" areas. Hence, for a subset of voxels in e.g. frontal-medial and orbitofrontal cortices and parts of the temporal lobes the reduction can be quite dramatic (>90). The advantages of using Unwarp will also depend strongly on the specifics of the scanner and sequence by which your data has been acquired. When using the latest generation scanners distortions are typically quite small, and distortion-by-movement interactions consequently even smaller. A small check list in terms of distortions is ' - 'a) Fast gradients->short read-out time->small distortions ' - 'b) Low field (i.e. <3T)->small field changes->small distortions ' - 'c) Low res (64x64)->short read-out time->small distortions ' - 'd) SENSE/SMASH->short read-out time->small distortions ' - 'If you can tick off all points above chances are you have minimal distortions to begin with and Unwarp might not be of use to you.' -}'; + 'Within-subject registration and unwarping of time series.' + '' + 'The realignment part of this routine realigns a time-series of images acquired from the same subject using a least squares approach and a 6 parameter (rigid body) spatial transformation. The first image in the list specified by the user is used as a reference to which all subsequent scans are realigned. The reference scan does not have to the the first chronologically and it may be wise to chose a "representative scan" in this role.' + '' + 'The aim is primarily to remove movement artefact in fMRI and PET time-series (or more generally longitudinal studies). This affects the header of each of the input images which contains details about the voxel-to-world mapping. The details of the transformation are displayed in the results window as plots of translation and rotation. A set of realignment parameters are saved for each session, named rp_*.txt.' + '' + 'In the coregistration step, the sessions are first realigned to each other, by aligning the first scan from each session to the first scan of the first session. Then the images within each session are aligned to the first image of the session. The parameter estimation is performed this way because it is assumed (rightly or not) that there may be systematic differences in the images between sessions.' + '' + 'See spm_uw_estimate.m for a detailed description of the implementation.' + '' + 'Even after realignment there is considerable variance in fMRI time series that covary with, and is most probably caused by, subject movements/* \cite{ja_geometric}*/. It is also the case that this variance is typically large compared to experimentally induced variance. Anyone interested can include the estimated movement parameters as covariates in the design matrix, and take a look at an F-contrast encompassing those columns. It is quite dramatic. The result is loss of sensitivity, and if movements are correlated to task specificity. I.e. we may mistake movement induced variance for true activations. The problem is well known, and several solutions have been suggested. A quite pragmatic (and conservative) solution is to include the estimated movement parameters (and possibly squared) as covariates in the design matrix. Since we typically have loads of degrees of freedom in fMRI we can usually afford this. The problems occur when movements are correlated with the task, since the strategy above will discard "good" and "bad" variance alike (i.e. remove also "true" activations).' + '' + 'The "covariate" strategy described above was predicated on a model where variance was assumed to be caused by "spin history" effects, but will work pretty much equally good/bad regardless of what the true underlying cause is. Others have assumed that the residual variance is caused mainly by errors introduced by the interpolation kernel in the resampling step of the realignment. One has tried to solve this through higher order resampling (huge Sinc kernels, or k-space resampling). Unwarp is based on a different hypothesis regarding the residual variance. EPI images are not particularly faithful reproductions of the object, and in particular there are severe geometric distortions in regions where there is an air-tissue interface (e.g. orbitofrontal cortex and the anterior medial temporal lobes). In these areas in particular the observed image is a severely warped version of reality, much like a funny mirror at a fair ground. When one moves in front of such a mirror ones image will distort in different ways and ones head may change from very elongated to seriously flattened. If we were to take digital snapshots of the reflection at these different positions it is rather obvious that realignment will not suffice to bring them into a common space.' + '' + 'The situation is similar with EPI images, and an image collected for a given subject position will not be identical to that collected at another. We call this effect susceptibility-by-movement interaction. Unwarp is predicated on the assumption that the susceptibility-by-movement interaction is responsible for a sizable part of residual movement related variance.' + '' + 'Assume that we know how the deformations change when the subject changes position (i.e. we know the derivatives of the deformations with respect to subject position). That means that for a given time series and a given set of subject movements we should be able to predict the "shape changes" in the object and the ensuing variance in the time series. It also means that, in principle, we should be able to formulate the inverse problem, i.e. given the observed variance (after realignment) and known (estimated) movements we should be able to estimate how deformations change with subject movement. We have made an attempt at formulating such an inverse model, and at solving for the "derivative fields". A deformation field can be thought of as little vectors at each position in space showing how that particular location has been deflected. A "derivative field" is then the rate of change of those vectors with respect to subject movement. Given these "derivative fields" we should be able to remove the variance caused by the susceptibility-by-movement interaction. Since the underlying model is so restricted we would also expect experimentally induced variance to be preserved. Our experiments have also shown this to be true.' + '' + 'In theory it should be possible to estimate also the "static" deformation field, yielding an unwarped (to some true geometry) version of the time series. In practise that doesn''t really seem to work. Hence, the method deals only with residual movement related variance induced by the susceptibility-by-movement interaction. This means that the time-series will be undistorted to some "average distortion" state rather than to the true geometry. If one wants additionally to address the issue of anatomical fidelity one should combine Unwarp with a measured fieldmap.' + '' + 'The description above can be thought of in terms of a Taylor expansion of the field as a function of subject movement. Unwarp alone will estimate the first (and optionally second, see below) order terms of this expansion. It cannot estimate the zeroth order term (the distortions common to all scans in the time series) since that doesn''t introduce (almost) any variance in the time series. The measured fieldmap takes the role of the zeroth order term. Refer to the FieldMap toolbox and the documents FieldMap.man and FieldMap_principles.man for a description of how to obtain fieldmaps in the format expected by Unwarp.' + '' + 'If we think of the field as a function of subject movement it should in principle be a function of six variables since rigid body movement has six degrees of freedom. However, the physics of the problem tells us that the field should not depend on translations nor on rotation in a plane perpendicular to the magnetic flux. Hence it should in principle be sufficient to model the field as a function of out-of-plane rotations (i.e. pitch and roll). One can object to this in terms of the effects of shimming (object no longer immersed in a homogenous field) that introduces a dependence on all movement parameters. In addition SPM/Unwarp cannot really tell if the transversal slices it is being passed are really perpendicular to the flux or not. In practice it turns out thought that it is never (at least we haven''t seen any case) necessary to include more than Pitch and Roll. This is probably because the individual movement parameters are typically highly correlated anyway, which in turn is probably because most heads that we scan are attached to a neck around which rotations occur. On the subject of Taylor expansion we should mention that there is the option to use a second-order expansion (through the defaults) interface. This implies estimating also the rate-of-change w.r.t. to some movement parameter of the rate-of-change of the field w.r.t. some movement parameter (colloquially known as a second derivative). It can be quite interesting to watch (and it is amazing that it is possible) but rarely helpful/necessary.' + '' + 'In the defaults there is also an option to include Jacobian intensity modulation when estimating the fields. "Jacobian intensity modulation" refers to the dilution/concentration of intensity that ensue as a consequence of the distortions. Think of a semi-transparent coloured rubber sheet that you hold against a white background. If you stretch a part of the sheet (induce distortions) you will see the colour fading in that particular area. In theory it is a brilliant idea to include also these effects when estimating the field (see e.g. Andersson et al, NeuroImage 20:870-888). In practice for this specific problem it is NOT a good idea.' + '' + 'It should be noted that this is a method intended to correct data afflicted by a particular problem. If there is little movement in your data to begin with this method will do you little good. If on the other hand there is appreciable movement in your data (>1deg) it will remove some of that unwanted variance. If, in addition, movements are task related it will do so without removing all your "true" activations. The method attempts to minimise total (across the image volume) variance in the data set. It should be realised that while (for small movements) a rather limited portion of the total variance is removed, the susceptibility-by-movement interaction effects are quite localised to "problem" areas. Hence, for a subset of voxels in e.g. frontal-medial and orbitofrontal cortices and parts of the temporal lobes the reduction can be quite dramatic (>90). The advantages of using Unwarp will also depend strongly on the specifics of the scanner and sequence by which your data has been acquired. When using the latest generation scanners distortions are typically quite small, and distortion-by-movement interactions consequently even smaller. A small check list in terms of distortions is ' + 'a) Fast gradients->short read-out time->small distortions ' + 'b) Low field (i.e. <3T)->small field changes->small distortions ' + 'c) Low res (64x64)->short read-out time->small distortions ' + 'd) SENSE/SMASH->short read-out time->small distortions ' + 'If you can tick off all points above chances are you have minimal distortions to begin with and Unwarp might not be of use to you.' + }'; realignunwarp.prog = @spm_run_realignunwarp; realignunwarp.vout = @vout_realignunwarp; realignunwarp.modality = {'PET','FMRI'}; diff --git a/config/spm_cfg_render.m b/config/spm_cfg_render.m index dfc2d706..7a9c1587 100644 --- a/config/spm_cfg_render.m +++ b/config/spm_cfg_render.m @@ -1,9 +1,9 @@ function rendering = spm_cfg_render % SPM Configuration file for Render %__________________________________________________________________________ -% Copyright (C) 2013 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2013-2016 Wellcome Trust Centre for Neuroimaging -% $Id: spm_cfg_render.m 6217 2014-09-29 17:54:33Z guillaume $ +% $Id: spm_cfg_render.m 6925 2016-11-09 17:23:40Z guillaume $ %========================================================================== % Extract @@ -190,10 +190,10 @@ rendfile = cfg_files; rendfile.tag = 'rendfile'; rendfile.name = 'Render File'; -rendfile.help = {'File containing the images to render on to'}; +rendfile.help = {'File containing the images to render on to.'}; rendfile.filter = {'mat','mesh'}; rendfile.ufilter = '.*'; -rendfile.num = [1 2]; +rendfile.num = [1 1]; %-------------------------------------------------------------------------- % render Display Surface diff --git a/config/spm_cfg_reorient.m b/config/spm_cfg_reorient.m index d0f501de..b03ebb95 100644 --- a/config/spm_cfg_reorient.m +++ b/config/spm_cfg_reorient.m @@ -4,7 +4,7 @@ % Copyright (C) 2006-2015 Wellcome Trust Centre for Neuroimaging % Volkmar Glauche -% $Id: spm_cfg_reorient.m 6656 2015-12-24 16:49:52Z guillaume $ +% $Id: spm_cfg_reorient.m 6952 2016-11-25 16:03:13Z guillaume $ %-------------------------------------------------------------------------- @@ -114,7 +114,10 @@ reorient.tag = 'reorient'; reorient.name = 'Reorient Images'; reorient.val = {srcfiles transform prefix}; -reorient.help = {'This facility allows to reorient images in a batch. The reorientation parameters can be given either as a 4x4 matrix or as parameters as defined for spm_matrix.m. The new image orientation will be computed by PRE-multiplying the original orientation matrix with the supplied matrix.'}; +reorient.help = { + 'Reorient images given a set of parameters.' + 'The reorientation parameters can be given either as a 4x4 matrix or as parameters as defined for spm_matrix.m. The new image orientation will be computed by PRE-multiplying the original orientation matrix with the supplied matrix.' + }'; reorient.prog = @spm_run_reorient; reorient.vout = @vout; diff --git a/config/spm_cfg_results.m b/config/spm_cfg_results.m index 57e0e26b..cc81c73c 100644 --- a/config/spm_cfg_results.m +++ b/config/spm_cfg_results.m @@ -3,7 +3,7 @@ %__________________________________________________________________________ % Copyright (C) 2005-2016 Wellcome Trust Centre for Neuroimaging -% $Id: spm_cfg_results.m 6896 2016-10-03 16:53:31Z guillaume $ +% $Id: spm_cfg_results.m 6952 2016-11-25 16:03:13Z guillaume $ %-------------------------------------------------------------------------- @@ -361,7 +361,7 @@ results.tag = 'results'; results.name = 'Results Report'; results.val = {spmmat generic units export}; -results.help = {''}; +results.help = {'Statistical inference.'}; results.prog = @spm_run_results; results.vout = @vout_results; diff --git a/config/spm_cfg_sendmail.m b/config/spm_cfg_sendmail.m index a82e2ac9..c2b53e99 100644 --- a/config/spm_cfg_sendmail.m +++ b/config/spm_cfg_sendmail.m @@ -3,7 +3,7 @@ %_______________________________________________________________________ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging -% $Id: spm_cfg_sendmail.m 4442 2011-08-26 14:53:10Z guillaume $ +% $Id: spm_cfg_sendmail.m 6929 2016-11-14 13:07:31Z guillaume $ % --------------------------------------------------------------------- % Recipient @@ -40,7 +40,7 @@ attachments = cfg_files; attachments.tag = 'attachments'; attachments.name = 'Attachments'; -attachments.val{1} = {}; +attachments.val = {{}}; attachments.help = {'List of files to attach and send along with the message.'}; attachments.filter = '.*'; attachments.ufilter = '.*'; diff --git a/config/spm_cfg_smooth.m b/config/spm_cfg_smooth.m index 332831d4..594a9bf7 100644 --- a/config/spm_cfg_smooth.m +++ b/config/spm_cfg_smooth.m @@ -1,9 +1,9 @@ function smooth = spm_cfg_smooth % SPM Configuration file for Smooth %__________________________________________________________________________ -% Copyright (C) 2005-2014 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2016 Wellcome Trust Centre for Neuroimaging -% $Id: spm_cfg_smooth.m 6148 2014-09-03 15:49:04Z guillaume $ +% $Id: spm_cfg_smooth.m 6952 2016-11-25 16:03:13Z guillaume $ %-------------------------------------------------------------------------- @@ -11,11 +11,14 @@ %-------------------------------------------------------------------------- data = cfg_files; data.tag = 'data'; -data.name = 'Images to Smooth'; -data.help = {'Specify the images to smooth. The smoothed images are written to the same subdirectories as the original images and are prefixed with a ''s''. The prefix can be changed by an option setting.'}; +data.name = 'Images to smooth'; +data.help = { + 'Specify the images to smooth.' + 'The smoothed images are written to the same subdirectories as the original images with a configurable prefix.' + }'; data.filter = 'image'; data.ufilter = '.*'; -data.num = [0 Inf]; +data.num = [1 Inf]; data.preview = @(f) spm_check_registration(char(f)); %-------------------------------------------------------------------------- @@ -24,7 +27,10 @@ fwhm = cfg_entry; fwhm.tag = 'fwhm'; fwhm.name = 'FWHM'; -fwhm.help = {'Specify the full-width at half maximum (FWHM) of the Gaussian smoothing kernel in mm. Three values should be entered, denoting the FWHM in the x, y and z directions.'}; +fwhm.help = { + 'Full width at half maximum (FWHM) of the Gaussian smoothing kernel in mm.' + 'Three values should be entered, denoting the FWHM in the x, y and z directions.' + }'; fwhm.strtype = 'r'; fwhm.num = [1 3]; fwhm.def = @(val)spm_get_defaults('smooth.fwhm', val{:}); @@ -35,7 +41,10 @@ dtype = cfg_menu; dtype.tag = 'dtype'; dtype.name = 'Data Type'; -dtype.help = {'Data-type of output images. SAME indicates the same datatype as the original images.'}; +dtype.help = { + 'Data type of the output images.' + '''SAME'' indicates the same data type as the original images.' + }'; dtype.labels = { 'SAME' 'UINT8 - unsigned char' @@ -53,8 +62,10 @@ im = cfg_menu; im.tag = 'im'; im.name = 'Implicit masking'; -im.help = {'An "implicit mask" is a mask implied by a particular voxel value (0 for images with integer type, NaN for float images).' - 'If set to ''Yes'', the implicit masking of the input image is preserved in the smoothed image.'}; +im.help = { + 'An "implicit mask" is a mask implied by a particular voxel value (0 for images with integer type, NaN for float images).' + 'If set to ''Yes'', the implicit masking of the input image is preserved in the smoothed image.' + }'; im.labels = {'Yes' 'No'}; im.values = {1 0}; im.val = {0}; @@ -64,8 +75,8 @@ %-------------------------------------------------------------------------- prefix = cfg_entry; prefix.tag = 'prefix'; -prefix.name = 'Filename Prefix'; -prefix.help = {'Specify the string to be prepended to the filenames of the smoothed image file(s). Default prefix is ''s''.'}; +prefix.name = 'Filename prefix'; +prefix.help = {'String to be prepended to the filenames of the smoothed image file(s). Default prefix is ''s''.'}; prefix.strtype = 's'; prefix.num = [1 Inf]; prefix.def = @(val)spm_get_defaults('smooth.prefix', val{:}); @@ -77,7 +88,10 @@ smooth.tag = 'smooth'; smooth.name = 'Smooth'; smooth.val = {data fwhm dtype im prefix}; -smooth.help = {'This is for smoothing (or convolving) image volumes with a Gaussian kernel of a specified width. It is used as a preprocessing step to suppress noise and effects due to residual differences in functional and gyral anatomy during inter-subject averaging.'}; +smooth.help = { + 'Smooth (ie convolve) image volumes with a Gaussian kernel of a specified width.' + 'It is used as a preprocessing step to suppress noise and effects due to residual differences in functional and gyral anatomy during inter-subject averaging.' + }'; smooth.prog = @spm_run_smooth; smooth.vout = @vout; diff --git a/config/spm_cfg_split.m b/config/spm_cfg_split.m index 0d5d6c20..90377479 100644 --- a/config/spm_cfg_split.m +++ b/config/spm_cfg_split.m @@ -4,7 +4,7 @@ % Copyright (C) 2014 Wellcome Trust Centre for Neuroimaging % Guillaume Flandin -% $Id: spm_cfg_split.m 6583 2015-10-28 10:30:38Z volkmar $ +% $Id: spm_cfg_split.m 6929 2016-11-14 13:07:31Z guillaume $ %-------------------------------------------------------------------------- @@ -24,7 +24,7 @@ outdir = cfg_files; outdir.tag = 'outdir'; outdir.name = 'Output Directory'; -outdir.val{1} = {''}; +outdir.val = {{''}}; outdir.help = {'Specify the output directory. If no directory is given, files will be written in the same directory than the input 4D file.'}; outdir.filter = 'dir'; outdir.ufilter = '.*'; diff --git a/config/spm_cfg_st.m b/config/spm_cfg_st.m index d71dc4ac..01c8fe30 100644 --- a/config/spm_cfg_st.m +++ b/config/spm_cfg_st.m @@ -1,9 +1,9 @@ function st = spm_cfg_st % SPM Configuration file for Slice Timing Correction %__________________________________________________________________________ -% Copyright (C) 2005-2014 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2016 Wellcome Trust Centre for Neuroimaging -% $Id: spm_cfg_st.m 6148 2014-09-03 15:49:04Z guillaume $ +% $Id: spm_cfg_st.m 6952 2016-11-25 16:03:13Z guillaume $ %-------------------------------------------------------------------------- % scans Session @@ -14,7 +14,7 @@ scans.help = {'Select images to slice-time correct.'}; scans.filter = 'image'; scans.ufilter = '.*'; -scans.num = [2 Inf]; +scans.num = [1 Inf]; scans.preview = @(f) spm_check_registration(char(f)); %-------------------------------------------------------------------------- @@ -53,9 +53,13 @@ ta = cfg_entry; ta.tag = 'ta'; ta.name = 'TA'; -ta.help = {'Enter the TA (in seconds). It is usually calculated as TR-(TR/nslices). You can simply enter this equation with the variables replaced by appropriate numbers.' - '' - 'If the next two items are entered in milliseconds, this entry will not be used and can be set to 0.'}; +ta.help = { + 'Enter the TA (in seconds). It is usually calculated as TR-(TR/nslices).' + '' + 'You can simply enter this equation with the variables replaced by appropriate numbers.' + '' + 'If the next two items are entered in milliseconds, this entry will not be used and can be set to 0.' + }'; ta.strtype = 'r'; ta.num = [1 1]; @@ -66,30 +70,31 @@ so.tag = 'so'; so.name = 'Slice order'; so.help = { - 'Enter the slice order. Bottom slice = 1. Sequence types and examples of code to enter are given below:' - '' - ' ascending (first slice=bottom): [1:1:nslices]' - '' - ' descending (first slice=top): [nslices:-1:1]' - '' - ' interleaved (middle-top):' - ' for k = 1:nslices' - ' round((nslices-k)/2 + (rem((nslices-k),2) * (nslices - 1)/2)) + 1,' - ' end' - '' - ' interleaved (bottom -> up): [1:2:nslices 2:2:nslices]' - '' - ' interleaved (top -> down): [nslices:-2:1, nslices-1:-2:1]' - '' - 'Alternatively you can enter the slice timing in ms for each slice individually.' - 'If doing so, the next item (Reference Slice) will contain a reference time (in ms) instead of the slice index of the reference slice.' - 'For Siemens scanners, this can be acquired in MATLAB from the dicom header as follows (use any volume after the first one):' - ' hdr = spm_dicom_headers(''dicom.ima'');' - ' slice_times = hdr{1}.Private_0019_1029' - 'Note that slice ordering is assumed to be from foot to head. If it is not, enter instead: TR - INTRASCAN_TIME - SLICE_TIMING_VECTOR' - -}'; -so.strtype = 'e'; + 'Enter the slice order.' + '' + 'Bottom slice = 1. Sequence types and examples of code to enter are given below:' + '' + ' ascending (first slice=bottom): [1:1:nslices]' + '' + ' descending (first slice=top): [nslices:-1:1]' + '' + ' interleaved (middle-top):' + ' for k = 1:nslices' + ' round((nslices-k)/2 + (rem((nslices-k),2) * (nslices - 1)/2)) + 1,' + ' end' + '' + ' interleaved (bottom -> up): [1:2:nslices 2:2:nslices]' + '' + ' interleaved (top -> down): [nslices:-2:1, nslices-1:-2:1]' + '' + 'Alternatively you can enter the slice timing in ms for each slice individually.' + 'If doing so, the next item (Reference Slice) will contain a reference time (in ms) instead of the slice index of the reference slice.' + 'For Siemens scanners, this can be acquired in MATLAB from the dicom header as follows (use any volume after the first one):' + ' hdr = spm_dicom_headers(''dicom.ima'');' + ' slice_times = hdr{1}.Private_0019_1029' + 'Note that slice ordering is assumed to be from foot to head. If it is not, enter instead: TR - INTRASCAN_TIME - SLICE_TIMING_VECTOR' + }'; +so.strtype = 'r'; so.num = [1 Inf]; %-------------------------------------------------------------------------- @@ -101,7 +106,7 @@ refslice.help = {'Enter the reference slice.' '' 'If slice times are provided instead of slice indices in the previous item, this value should represent a reference time (in ms) instead of the slice index of the reference slice.'}; -refslice.strtype = 'e'; +refslice.strtype = 'r'; refslice.num = [1 1]; %-------------------------------------------------------------------------- @@ -110,7 +115,7 @@ prefix = cfg_entry; prefix.tag = 'prefix'; prefix.name = 'Filename Prefix'; -prefix.help = {'Specify the string to be prepended to the filenames of the slice-time corrected image file(s). Default prefix is ''a''.'}; +prefix.help = {'Specify the string to be prepended to the filenames of the slice-time corrected image file(s).','Default prefix is ''a''.'}; prefix.strtype = 's'; prefix.num = [1 Inf]; prefix.def = @(val)spm_get_defaults('slicetiming.prefix', val{:}); @@ -121,26 +126,28 @@ st = cfg_exbranch; st.tag = 'st'; st.name = 'Slice Timing'; -st.val = {generic nslices tr ta so refslice prefix }; +st.val = {generic nslices tr ta so refslice prefix}; st.help = { - 'Correct differences in image acquisition time between slices. Slice-time corrected files are prepended with an ''a''.' - '' - 'Note: The sliceorder arg that specifies slice acquisition order is a vector of N numbers, where N is the number of slices per volume. Each number refers to the position of a slice within the image file. The order of numbers within the vector is the temporal order in which those slices were acquired. To check the order of slices within an image file, use the SPM Display option and move the cross-hairs to a voxel co-ordinate of z=1. This corresponds to a point in the first slice of the volume.' - '' - 'The function corrects differences in slice acquisition times. This routine is intended to correct for the staggered order of slice acquisition that is used during echo-planar scanning. The correction is necessary to make the data on each slice correspond to the same point in time. Without correction, the data on one slice will represent a point in time as far removed as 1/2 the TR from an adjacent slice (in the case of an interleaved sequence).' - '' - 'This routine "shifts" a signal in time to provide an output vector that represents the same (continuous) signal sampled starting either later or earlier. This is accomplished by a simple shift of the phase of the sines that make up the signal. Recall that a Fourier transform allows for a representation of any signal as the linear combination of sinusoids of different frequencies and phases. Effectively, we will add a constant to the phase of every frequency, shifting the data in time.' - '' - 'Shifter - This is the filter by which the signal will be convolved to introduce the phase shift. It is constructed explicitly in the Fourier domain. In the time domain, it may be described as an impulse (delta function) that has been shifted in time the amount described by TimeShift. The correction works by lagging (shifting forward) the time-series data on each slice using sinc-interpolation. This results in each time series having the values that would have been obtained had the slice been acquired at the same time as the reference slice. To make this clear, consider a neural event (and ensuing hemodynamic response) that occurs simultaneously on two adjacent slices. Values from slice "A" are acquired starting at time zero, simultaneous to the neural event, while values from slice "B" are acquired one second later. Without correction, the "B" values will describe a hemodynamic response that will appear to have began one second EARLIER on the "B" slice than on slice "A". To correct for this, the "B" values need to be shifted towards the Right, i.e., towards the last value.' - '' - 'This correction assumes that the data are band-limited (i.e. there is no meaningful information present in the data at a frequency higher than that of the Nyquist). This assumption is support by the study of Josephs et al (1997, NeuroImage) that obtained event-related data at an effective TR of 166 msecs. No physio-logical signal change was present at frequencies higher than our typical Nyquist (0.25 HZ).' - '' - 'When using the slice timing correction it is very important that you input the correct slice order, and if there is any uncertainty then users are encouraged to work with their physicist to determine the actual slice acquisition order.' - '' - 'One can also consider augmenting the model by including the temporal derivative in the informed basis set instead of slice timing, which can account for +/- 1 second of changes in timing.' - '' - 'Written by Darren Gitelman at Northwestern U., 1998. Based (in large part) on ACQCORRECT.PRO from Geoff Aguirre and Eric Zarahn at U. Penn.' - }'; + 'Correct differences in image acquisition time between slices.' + '' + 'Slice-time corrected files are prepended with an ''a''.' + '' + 'Note: The sliceorder arg that specifies slice acquisition order is a vector of N numbers, where N is the number of slices per volume. Each number refers to the position of a slice within the image file. The order of numbers within the vector is the temporal order in which those slices were acquired. To check the order of slices within an image file, use the SPM Display option and move the cross-hairs to a voxel co-ordinate of z=1. This corresponds to a point in the first slice of the volume.' + '' + 'The function corrects differences in slice acquisition times. This routine is intended to correct for the staggered order of slice acquisition that is used during echo-planar scanning. The correction is necessary to make the data on each slice correspond to the same point in time. Without correction, the data on one slice will represent a point in time as far removed as 1/2 the TR from an adjacent slice (in the case of an interleaved sequence).' + '' + 'This routine "shifts" a signal in time to provide an output vector that represents the same (continuous) signal sampled starting either later or earlier. This is accomplished by a simple shift of the phase of the sines that make up the signal. Recall that a Fourier transform allows for a representation of any signal as the linear combination of sinusoids of different frequencies and phases. Effectively, we will add a constant to the phase of every frequency, shifting the data in time.' + '' + 'Shifter - This is the filter by which the signal will be convolved to introduce the phase shift. It is constructed explicitly in the Fourier domain. In the time domain, it may be described as an impulse (delta function) that has been shifted in time the amount described by TimeShift. The correction works by lagging (shifting forward) the time-series data on each slice using sinc-interpolation. This results in each time series having the values that would have been obtained had the slice been acquired at the same time as the reference slice. To make this clear, consider a neural event (and ensuing hemodynamic response) that occurs simultaneously on two adjacent slices. Values from slice "A" are acquired starting at time zero, simultaneous to the neural event, while values from slice "B" are acquired one second later. Without correction, the "B" values will describe a hemodynamic response that will appear to have began one second EARLIER on the "B" slice than on slice "A". To correct for this, the "B" values need to be shifted towards the Right, i.e., towards the last value.' + '' + 'This correction assumes that the data are band-limited (i.e. there is no meaningful information present in the data at a frequency higher than that of the Nyquist). This assumption is support by the study of Josephs et al (1997, NeuroImage) that obtained event-related data at an effective TR of 166 msecs. No physio-logical signal change was present at frequencies higher than our typical Nyquist (0.25 HZ).' + '' + 'When using the slice timing correction it is very important that you input the correct slice order, and if there is any uncertainty then users are encouraged to work with their physicist to determine the actual slice acquisition order.' + '' + 'One can also consider augmenting the model by including the temporal derivative in the informed basis set instead of slice timing, which can account for +/- 1 second of changes in timing.' + '' + 'Written by Darren Gitelman at Northwestern U., 1998. Based (in large part) on ACQCORRECT.PRO from Geoff Aguirre and Eric Zarahn at U. Penn.' + }'; st.prog = @spm_run_st; st.vout = @vout; st.modality = {'FMRI'}; diff --git a/config/spm_cfg_tissue_volumes.m b/config/spm_cfg_tissue_volumes.m index 8d9cb6a2..4c768777 100644 --- a/config/spm_cfg_tissue_volumes.m +++ b/config/spm_cfg_tissue_volumes.m @@ -3,12 +3,12 @@ % % See also: spm_run_tissue_volumes, spm_summarise %__________________________________________________________________________ -% Copyright (C) 2013 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2013-2016 Wellcome Trust Centre for Neuroimaging % Ged Ridgway -% $Id: spm_cfg_tissue_volumes.m 5647 2013-09-20 13:03:44Z ged $ +% $Id: spm_cfg_tissue_volumes.m 6952 2016-11-25 16:03:13Z guillaume $ + -%% mat = cfg_files; mat.tag = 'matfiles'; mat.name = 'Segmentation mat-files'; @@ -19,7 +19,6 @@ 'Select the ''seg8.mat'' files containing the segmentation parameters.' }; -%% T = cfg_entry; T.tag = 'tmax'; T.name = 'Maximum tissue class'; @@ -28,7 +27,8 @@ T.val = {3}; T.help = { ['Specify the maximum tissue class, T, where tissues 1:T will be ' ... - 'measured. The default of 3 corresponds to GM, WM and CSF for the ' ... + 'measured.'] + ['The default of 3 corresponds to GM, WM and CSF for the ' ... 'default tissue prior probability maps ''TPM.nii,1'' to ''TPM.nii,3'''] '' ['The sum of these tissues will also be computed, which by ' ... @@ -37,7 +37,6 @@ 'volume (known as TBV or PBV), which is also often of interest.'] }; -%% mask = cfg_files; mask.tag = 'mask'; mask.name = 'Mask image'; @@ -45,8 +44,8 @@ mask.num = [0 1]; mask.val = {{fullfile(spm('dir'), 'tpm', 'mask_ICV.nii,1')}}; mask.help = { - ['Optional binary mask image in same space as TPMs (e.g. MNI); ' ... - 'only voxels inside this mask will count for the total volume.'] + 'Optional binary mask image in same space as TPMs (e.g. MNI).' + 'Only voxels inside this mask will count for the total volume.' '' ['The default mask excludes the eyes, which might otherwise be ' ... 'counted in the fluid tissue class (that includes cerebrospinal, ' ... @@ -59,19 +58,19 @@ outf.strtype = 's'; outf.val = {''}; outf.help = { - ['Filename for saving results. Segmentation filenames and volumes ' ... + 'Filename for saving results.' + ['Segmentation filenames and volumes ' ... 'will be stored in CSV format (comma-separated variables).'] '' 'This can be empty; results will appear in the MATLAB command window.' }; -%% tvol = cfg_exbranch; tvol.tag = 'tvol'; tvol.name = 'Tissue Volumes'; tvol.val = {mat T mask outf}; tvol.help = { - 'Computes total tissue volumes (in litres) from segmentation results.' + 'Compute total tissue volumes (in litres) from segmentation results.' '' ['Only the seg8.mat files are required, but if modulated warped ' ... 'segmentations (mwc*) are found they will be reused, saving time ' ... diff --git a/config/spm_cfg_voi.m b/config/spm_cfg_voi.m index 6fdc9ce6..746571f5 100644 --- a/config/spm_cfg_voi.m +++ b/config/spm_cfg_voi.m @@ -4,7 +4,7 @@ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Guillaume Flandin -% $Id: spm_cfg_voi.m 5652 2013-09-25 09:36:22Z volkmar $ +% $Id: spm_cfg_voi.m 6925 2016-11-09 17:23:40Z guillaume $ % ------------------------------------------------------------------------- % spmmat Select SPM.mat @@ -150,7 +150,7 @@ mp.tag = 'spm'; mp.name = 'SPM index'; mp.help = {'SPM index'}; -mp.strtype = 'e'; +mp.strtype = 'n'; mp.num = [1 1]; % ------------------------------------------------------------------------- diff --git a/config/spm_make_manual.m b/config/spm_make_manual.m index b117ac99..c9e2a80c 100644 --- a/config/spm_make_manual.m +++ b/config/spm_make_manual.m @@ -1,10 +1,10 @@ function spm_make_manual(c) % Convert a job configuration tree into a series of LaTeX documents %__________________________________________________________________________ -% Copyright (C) 2005-2014 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % John Ashburner -% $Id: spm_make_manual.m 6163 2014-09-11 12:27:04Z guillaume $ +% $Id: spm_make_manual.m 7019 2017-02-16 10:49:48Z guillaume $ if ~nargin, c = spm_cfg; end @@ -176,7 +176,7 @@ function write_help(hlp,fp) end end -str = []; +str = ''; pen = 1; for i=1:numel(st) str = [str clean_latex(str0(pen:st(i)-1)) str0(st(i)+2:en(i)-1)]; diff --git a/config/spm_make_standalone.m b/config/spm_make_standalone.m index 7014e7d0..4a28864a 100644 --- a/config/spm_make_standalone.m +++ b/config/spm_make_standalone.m @@ -1,75 +1,77 @@ -function spm_make_standalone(outdir) +function spm_make_standalone(outdir, gateway, contentsver) % Compile SPM as a standalone executable using the MATLAB compiler % http://www.mathworks.com/products/compiler/ % -% This will generate a standalone program, which can be run -% outside MATLAB, and therefore does not use up a MATLAB licence. +% This will generate a standalone application, which can be run outside +% MATLAB, and therefore does not require a MATLAB licence. % % On Windows: -% spm12_wxx.exe -% spm12_wxx.exe run +% spm12.exe +% spm12.exe run % % On Linux/Mac: % ./run_spm12.sh % ./run_spm12.sh run % % The first command starts SPM in interactive mode with GUI. The second -% executes a batch file or starts the Batch Editor if empty. +% executes a batch file or starts the Batch Editor if none is provided. % +% Full list of options is accessible from: +% ./run_spm12.sh --help +% +% When deployed, compiled applications will require the MATLAB Runtime: +% http://www.mathworks.com/products/compiler/mcr/ +% % See spm_standalone.m %__________________________________________________________________________ -% Copyright (C) 2010-2015 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2010-2017 Wellcome Trust Centre for Neuroimaging % Guillaume Flandin -% $Id: spm_make_standalone.m 6416 2015-04-21 15:34:10Z guillaume $ +% $Id: spm_make_standalone.m 7091 2017-06-05 14:46:00Z guillaume $ + -%-Care of startup.m +%-Check startup.m %-------------------------------------------------------------------------- -% see http://www.mathworks.com/support/solutions/data/1-QXFMQ.html?1-QXFMQ if exist('startup','file') warning('A startup.m has been detected in %s.\n',... fileparts(which('startup'))); end -if ~nargin, outdir = fullfile(spm('dir'),'..','spm_exec'); mkdir(outdir); end +%-Input arguments +%-------------------------------------------------------------------------- +if ~nargin + outdir = fullfile(spm('Dir'),'..','standalone'); + if ~exist(outdir,'dir'), mkdir(outdir); end +end +if nargin < 2 || isempty(gateway), gateway = 'spm_standalone.m'; end +if nargin < 3, contentsver = ''; end %========================================================================== %-Static listing of SPM toolboxes %========================================================================== -fid = fopen(fullfile(spm('dir'),'config','spm_cfg_static_tools.m'),'wt'); +fid = fopen(fullfile(spm('Dir'),'config','spm_cfg_static_tools.m'),'wt'); fprintf(fid,'function values = spm_cfg_static_tools\n'); fprintf(fid,... '%% Static listing of all batch configuration files in the SPM toolbox folder\n'); -% create code to insert toolbox config -%-Toolbox autodetection %-Get the list of toolbox directories tbxdir = fullfile(spm('Dir'),'toolbox'); -d = dir(tbxdir); d = {d([d.isdir]).name}; -dd = regexp(d,'^\.'); -%(Beware, regexp returns an array if input cell array is of dim 0 or 1) -if ~iscell(dd), dd = {dd}; end -d = {'' d{cellfun('isempty',dd)}}; +d = [tbxdir; cellstr(spm_select('FPList',tbxdir,'dir'))]; ft = {}; %-Look for '*_cfg_*.m' files in these directories -for i=1:length(d) - d2 = fullfile(tbxdir,d{i}); - di = dir(d2); di = {di(~[di.isdir]).name}; - f2 = regexp(di,'.*_cfg_.*\.m$'); - if ~iscell(f2), f2 = {f2}; end - fi = di(~cellfun('isempty',f2)); +for i=1:numel(d) + fi = spm_select('List',d{i},'.*_cfg_.*\.m$'); if ~isempty(fi) - ft = [ft(:); fi(:)]; + ft = [ft(:); cellstr(fi)]; end end -if ~isempty(ft) - if isempty(ft) - ftstr = ''; - else - ft = cellfun(@(cft)strtok(cft,'.'),ft,'UniformOutput',false); - ftstr = sprintf('%s ', ft{:}); - end - fprintf(fid,'values = {%s};\n', ftstr); +%-Create code to insert toolbox config +if isempty(ft) + ftstr = ''; +else + ft = spm_file(ft,'basename'); + ftstr = sprintf('%s ', ft{:}); end +fprintf(fid,'values = {%s};\n', ftstr); fclose(fid); %========================================================================== @@ -83,15 +85,24 @@ function spm_make_standalone(outdir) sts = copyfile(fullfile(spm('Dir'),'Contents.m'),... fullfile(spm('Dir'),'Contents.txt')); if ~sts, warning('Copy of Contents.m failed.'); end +if ~isempty(contentsver) + % Format: 'xxxx (SPMx) dd-mmm-yyyy' + f = fileread(fullfile(spm('Dir'),'Contents.txt')); + f = regexprep(f,'% Version \S+ \S+ \S+',['% Version ' contentsver]); + fid = fopen(fullfile(spm('Dir'),'Contents.txt'),'w'); + fprintf(fid,'%s',f); + fclose(fid); +end %========================================================================== %-Compilation %========================================================================== opts = {'-p',fullfile(matlabroot,'toolbox','signal')}; +if ~exist(opts{2},'dir'), opts = {}; end mcc('-m', '-C', '-v',... '-o',lower(spm('Ver')),... '-d',outdir,... '-N',opts{:},... '-R','-singleCompThread',... '-a',spm('Dir'),... - 'spm_standalone.m'); + gateway); diff --git a/config/spm_rewrite_job.m b/config/spm_rewrite_job.m index 3b0b1043..e7ab9a6f 100644 --- a/config/spm_rewrite_job.m +++ b/config/spm_rewrite_job.m @@ -1,9 +1,9 @@ function job = spm_rewrite_job(job) % Rewrite a batch job for SPM12 %__________________________________________________________________________ -% Copyright (C) 2012-2016 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2012-2017 Wellcome Trust Centre for Neuroimaging -% $Id: spm_rewrite_job.m 6898 2016-10-04 17:06:23Z guillaume $ +% $Id: spm_rewrite_job.m 7063 2017-04-19 10:49:44Z guillaume $ try @@ -80,11 +80,11 @@ end try - if isequal(job.stats.results.print, false) + if isequal(job.stats.results.print, false) || isequal(job.stats.results.print, 'no') job.stats.results.export = {}; job.stats.results = rmfield(job.stats.results,'print'); end - if isequal(job.stats.results.print, true) + if isequal(job.stats.results.print, true) || isequal(job.stats.results.print, 'yes') job.stats.results.print = spm_get_defaults('ui.print'); end try, N = numel(job.stats.results.export)+1; catch, N = 1; end @@ -201,6 +201,15 @@ end end +try + if numel(job.tools.longit) > 1 + ws = warning('off','backtrace'); + warning('Only converting first item of the "Longitudinal Registration" module.'); + warning(ws); + end + job.tools.longit = job.tools.longit{1}; +end + try util = char(fieldnames(job.util)); if ismember(util, {'cdir','md','deletefiles','movefile'}) diff --git a/config/spm_run_con.m b/config/spm_run_con.m index 3b04ee06..dc15a182 100644 --- a/config/spm_run_con.m +++ b/config/spm_run_con.m @@ -5,9 +5,9 @@ % Output: % out - struct containing contrast and SPM{.} images filename %__________________________________________________________________________ -% Copyright (C) 2005-2016 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging -% $Id: spm_run_con.m 6764 2016-04-05 18:05:20Z guillaume $ +% $Id: spm_run_con.m 7093 2017-06-05 16:34:04Z guillaume $ spm('FnBanner','spm_contrasts.m'); @@ -83,14 +83,16 @@ %-------------------------------------------------------------------------- if bayes_con if ~isfield(SPM.PPM,'xCon') + SPM.PPM.xCon = []; for ii=1:length(SPM.xCon) SPM.PPM.xCon(ii).PSTAT = 'T'; end end end -%-Specify & estimate contrasts +%-Specify contrasts %-------------------------------------------------------------------------- +Ic = []; for i = 1:length(job.consess) %-T-contrast @@ -237,7 +239,7 @@ names = {name}; end - %-Estimate newly created contrasts + %-Store newly created contrasts in SPM.xCon %---------------------------------------------------------------------- for k=1:numel(cons) @@ -260,17 +262,20 @@ end %-Append to SPM.xCon - % SPM will automatically save any contrasts that evaluate successfully %------------------------------------------------------------------ if isempty(SPM.xCon) SPM.xCon = DxCon; elseif ~isempty(DxCon) SPM.xCon(end+1) = DxCon; end - SPM = spm_contrasts(SPM,length(SPM.xCon)); + Ic = [Ic length(SPM.xCon)]; end end +%-Estimate newly created contrasts (and save SPM.mat) +%-------------------------------------------------------------------------- +if ~isempty(Ic), SPM = spm_contrasts(SPM,Ic); end + fprintf('%-40s: %30s\n','Completed',spm('time')) %-# %-Change back directory @@ -282,8 +287,8 @@ out.spmmat = job.spmmat; %out.spmvar = SPM; if isfield(SPM, 'xCon') && ~isempty(SPM.xCon) - Vcon = [SPM.xCon.Vcon]; %cat(1,SPM.xCon.Vcon); - Vspm = [SPM.xCon.Vspm]; %cat(1,SPM.xCon.Vspm); + Vcon = [SPM.xCon.Vcon]; % [SPM.xCon(Ic).Vcon] ? + Vspm = [SPM.xCon.Vspm]; % [SPM.xCon(Ic).Vspm] ? elseif isfield(SPM, 'PPM') && ~isempty(SPM.PPM) Vcon = cat(1,SPM.PPM.xCon.Vcon); Vspm = cat(1,SPM.PPM.xCon.Vspm); diff --git a/config/spm_run_dcm_bms.m b/config/spm_run_dcm_bms.m index 4d1125e8..83bc3332 100644 --- a/config/spm_run_dcm_bms.m +++ b/config/spm_run_dcm_bms.m @@ -17,10 +17,10 @@ % Copyright (C) 2009-2015 Wellcome Trust Centre for Neuroimaging % CC Chen & Maria Joao Rosa -% $Id: spm_run_dcm_bms.m 6888 2016-09-21 10:52:45Z peter $ +% $Id: spm_run_dcm_bms.m 7101 2017-06-08 12:36:13Z peter $ -SVNid = '$Rev: 6888 $'; +SVNid = '$Rev: 7101 $'; %-Say hello %-------------------------------------------------------------------------- @@ -216,10 +216,11 @@ M = DCM.DCM.M; - if isfield(DCM.DCM, 'xY') && ~isstruct(DCM.DCM.xY) - Y = DCM.DCM.xY; % not fMRI - else + str = spm_dcm_identify(DCM.DCM); + if strcmp(str,'fMRI') || strcmp(str,'fMRI_CSD') Y = DCM.DCM.Y; % fMRI + else + Y = DCM.DCM.xY; % not fMRI end if isfield(M,'FS') diff --git a/config/spm_run_dicom.m b/config/spm_run_dicom.m index 2e8d3403..17a3efe5 100644 --- a/config/spm_run_dicom.m +++ b/config/spm_run_dicom.m @@ -7,12 +7,11 @@ % Output: % out - computation results, usually a struct variable. %__________________________________________________________________________ -% Copyright (C) 2005-2011 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging -% $Id: spm_run_dicom.m 6376 2015-03-12 15:15:57Z john $ +% $Id: spm_run_dicom.m 7201 2017-11-08 11:13:25Z guillaume $ -wd = pwd; if ~isempty(job.outdir{1}) out_dir = job.outdir{1}; else @@ -25,7 +24,8 @@ root_dir = job.root; end -hdr = spm_dicom_headers(char(job.data), true); +essentials = ~job.convopts.meta; +hdr = spm_dicom_headers(char(job.data),essentials); sel = true(size(hdr)); if ~isempty(job.protfilter) && ~strcmp(job.protfilter, '.*') psel = cellfun(@(h)isfield(h, 'ProtocolName'), hdr); @@ -35,5 +35,4 @@ pnames(ssel) = cellfun(@(h)subsref(h, substruct('.','SequenceName')), hdr(ssel), 'UniformOutput', false); sel(psel|ssel) = ~cellfun(@isempty,regexp(pnames(psel|ssel), job.protfilter)); end -out = spm_dicom_convert(hdr(sel),'all',root_dir,job.convopts.format,out_dir); - +out = spm_dicom_convert(hdr(sel),'all',root_dir,job.convopts.format,out_dir,job.convopts.meta); diff --git a/config/spm_run_fmri_est.m b/config/spm_run_fmri_est.m index 8f1d8545..5258ec38 100644 --- a/config/spm_run_fmri_est.m +++ b/config/spm_run_fmri_est.m @@ -8,9 +8,10 @@ % Output: % out - computation results, usually a struct variable. %__________________________________________________________________________ -% Copyright (C) 2005-2013 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging + +% $Id: spm_run_fmri_est.m 7057 2017-04-13 16:45:49Z guillaume $ -% $Id: spm_run_fmri_est.m 5809 2013-12-20 14:30:22Z guillaume $ %-Load SPM.mat file %-------------------------------------------------------------------------- @@ -36,6 +37,8 @@ %---------------------------------------------------------------------- if isfield(SPM,'factor') && ~isempty(SPM.factor) && SPM.factor(1).levels > 1 + Ic = []; + %-Generate contrasts %------------------------------------------------------------------ cons = spm_design_contrasts(SPM); @@ -49,12 +52,12 @@ [c,I] = spm_conman('ParseCon',con,SPM.xX.xKXs,STAT); if all(I) DxCon = spm_FcUtil('Set',name,STAT,'c',c,SPM.xX.xKXs); - if isempty(SPM.xCon), + if isempty(SPM.xCon) SPM.xCon = DxCon; else SPM.xCon(end+1) = DxCon; end - SPM = spm_contrasts(SPM,length(SPM.xCon)); + Ic = [Ic length(SPM.xCon)]; end end @@ -78,18 +81,27 @@ [c,I] = spm_conman('ParseCon',con,SPM.xX.xKXs,STAT); if all(I) DxCon = spm_FcUtil('Set',name,STAT,'c',c,SPM.xX.xKXs); - if isempty(SPM.xCon), + if isempty(SPM.xCon) SPM.xCon = DxCon; else SPM.xCon(end+1) = DxCon; end - SPM = spm_contrasts(SPM,length(SPM.xCon)); + Ic = [Ic length(SPM.xCon)]; end end end + %-Estimate constrasts + %------------------------------------------------------------------ + if ~isempty(Ic) + spm('FnBanner','spm_contrasts.m'); + SPM = spm_contrasts(SPM,Ic); + end + end + %-Residuals + %---------------------------------------------------------------------- if job.write_residuals VRes = spm_write_residuals(SPM,NaN); end @@ -154,17 +166,17 @@ %-Regression coefficient priors %-------------------------------------------------------------------------- switch job.method.Bayesian.signal - case 'UGL', + case 'UGL' SPM.PPM.priors.W = 'Spatial - UGL'; - case 'GMRF', + case 'GMRF' SPM.PPM.priors.W = 'Spatial - GMRF'; - case 'LORETA', + case 'LORETA' SPM.PPM.priors.W = 'Spatial - LORETA'; - case 'WGL', + case 'WGL' SPM.PPM.priors.W = 'Spatial - WGL'; - case 'Global', + case 'Global' SPM.PPM.priors.W = 'Voxel - Shrinkage'; - case 'Uninformative', + case 'Uninformative' SPM.PPM.priors.W = 'Voxel - Uninformative'; otherwise error('Unknown prior for W in Bayesian 1st level estimation.'); @@ -227,7 +239,7 @@ DxCon.name = name; DxCon.c = con'; - if isempty(SPM.xCon), + if isempty(SPM.xCon) SPM.xCon = DxCon; else SPM.xCon(end+1) = DxCon; @@ -254,7 +266,7 @@ DxCon = []; end - if isempty(SPM.xCon), + if isempty(SPM.xCon) SPM.xCon = DxCon; else SPM.xCon(end+1) = DxCon; @@ -292,4 +304,3 @@ %out.spmvar = SPM; cd(original_dir); fprintf('Done\n') -return diff --git a/config/spm_run_realign.m b/config/spm_run_realign.m index 3e96b2de..38ca8315 100644 --- a/config/spm_run_realign.m +++ b/config/spm_run_realign.m @@ -7,9 +7,9 @@ % Output: % out - computation results, usually a struct variable. %__________________________________________________________________________ -% Copyright (C) 2005-2011 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging -% $Id: spm_run_realign.m 6554 2015-09-11 17:21:23Z guillaume $ +% $Id: spm_run_realign.m 7141 2017-07-26 09:05:05Z guillaume $ P = cell(size(job.data)); @@ -46,6 +46,7 @@ %-Dependencies %-------------------------------------------------------------------------- +if isempty(P), out = struct([]); return; end if isfield(job,'eoptions') for i=1:numel(job.data) out.sess(i).cfiles = job.data{i}; @@ -54,7 +55,7 @@ end if isfield(job,'roptions') - if job.roptions.which(1) == 1, s = 1; else s = 0; end + if job.roptions.which(1) == 1, s = 1; else, s = 0; end if ischar(job.data{1}), job.data = {job.data}; end for k=1:numel(job.data) rfiles = cell(numel(job.data{k})-s,1); diff --git a/config/spm_run_voi.m b/config/spm_run_voi.m index ee5f2250..24f6bd81 100644 --- a/config/spm_run_voi.m +++ b/config/spm_run_voi.m @@ -7,10 +7,10 @@ % Output: % out - computation results, usually a struct variable. %__________________________________________________________________________ -% Copyright (C) 2008-2015 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2008-2017 Wellcome Trust Centre for Neuroimaging % Guillaume Flandin -% $Id: spm_run_voi.m 6301 2015-01-12 17:23:08Z guillaume $ +% $Id: spm_run_voi.m 7210 2017-11-10 16:33:17Z guillaume $ %-Load SPM.mat @@ -19,6 +19,11 @@ load(fullfile(swd,'SPM.mat')); SPM.swd = swd; +%-Output directory +%-------------------------------------------------------------------------- +[odir,job.name] = fileparts(job.name); +if isempty(odir), odir = swd; end + %-Initialise VOI voxels coordinates %-------------------------------------------------------------------------- [x,y,z] = ndgrid(1:SPM.xVol.DIM(1),1:SPM.xVol.DIM(2),1:SPM.xVol.DIM(3)); @@ -38,7 +43,7 @@ %-Save VOI as image %-------------------------------------------------------------------------- -Vm = struct('fname', fullfile(swd, ['VOI_' job.name '_mask' spm_file_ext]), ... +Vm = struct('fname', fullfile(odir, ['VOI_' job.name '_mask' spm_file_ext]), ... 'dim', SPM.xVol.DIM', ... 'dt', [spm_type('uint8') spm_platform('bigend')], ... 'mat', SPM.xVol.M, ... @@ -60,29 +65,34 @@ xSPM.M = SPM.xVol.M; % irrelevant here if ~isempty(xY.Ic), cwd = pwd; cd(SPM.swd); end % to find beta images +SPM.swd = odir; [Y,xY] = spm_regions(xSPM,SPM,[],xY); -if ~isempty(xY.Ic), cd(cwd); end +if ~isempty(xY(1).Ic), cd(cwd); end %-Save first eigenimage %-------------------------------------------------------------------------- -Ve = struct('fname', fullfile(swd, ['VOI_' job.name '_eigen' spm_file_ext]), ... - 'dim', SPM.xVol.DIM', ... - 'dt', [spm_type('float32') spm_platform('bigend')], ... - 'mat', SPM.xVol.M, ... - 'pinfo', [1 0 0]', ... - 'descrip', 'VOI: first eigenimage'); -Ve = spm_create_vol(Ve); -eigimg = double(voi); -eigimg(voi) = xY.v; -Ve = spm_write_vol(Ve,eigimg); +sess = ''; +for s=1:numel(xY) + if isfield(SPM,'Sess'), sess = sprintf('_%i',xY(s).Sess); end + Ve = struct('fname', fullfile(odir, ['VOI_' job.name sess '_eigen' spm_file_ext]), ... + 'dim', SPM.xVol.DIM', ... + 'dt', [spm_type('float32') spm_platform('bigend')], ... + 'mat', SPM.xVol.M, ... + 'pinfo', [1 0 0]', ... + 'descrip', 'VOI: first eigenimage'); + Ve = spm_create_vol(Ve); + eigimg = double(voi); + eigimg(voi) = xY(s).v; + Ve = spm_write_vol(Ve,eigimg); +end %-Export results %-------------------------------------------------------------------------- assignin('base','Y',Y); assignin('base','xY',xY); -if isfield(SPM,'Sess'), s = sprintf('_%i',xY.Sess); else s = ''; end -out.voimat = cellstr(fullfile(swd,['VOI_' job.name s '.mat'])); +if isfield(SPM,'Sess'), sess = sprintf('_%i',xY(1).Sess); else sess = ''; end +out.voimat = cellstr(fullfile(odir,['VOI_' job.name sess '.mat'])); out.voiimg = cellstr(Vm.fname); out.voieig = cellstr(Ve.fname); diff --git a/external/Makefile.fieldtrip b/external/Makefile.fieldtrip index 3803eb04..9ec4a469 100644 --- a/external/Makefile.fieldtrip +++ b/external/Makefile.fieldtrip @@ -4,7 +4,7 @@ # Copyright (C) 2009-2016 Wellcome Trust Centre for Neuroimaging # # Guillaume Flandin -# $Id: Makefile.fieldtrip 6732 2016-02-24 14:23:08Z guillaume $ +# $Id: Makefile.fieldtrip 7053 2017-04-03 11:04:13Z guillaume $ include ../src/Makefile.var @@ -66,22 +66,29 @@ tarball: all $(TAR) -cf fieldtrip_mex.tar $(FIELDTRIP) fieldtrip/src/%.$(SUF) : fieldtrip/src/%.c - $(MEX) $< -outdir $(dir $<) $(MEXEND) + $(MEX) $< $(MEXEND) + $(MOVE) $*.$(SUF) $(dir $<) fieldtrip/src/lmoutr.$(SUF): fieldtrip/src/lmoutr.c fieldtrip/src/geometry.c fieldtrip/src/geometry.h - $(MEX) $< -outdir $(dir $<) fieldtrip/src/geometry.c $(MEXEND) + $(MEX) $< fieldtrip/src/geometry.c $(MEXEND) + $(MOVE) lmoutr.$(SUF) $(dir $<) fieldtrip/src/routlm.$(SUF): fieldtrip/src/routlm.c fieldtrip/src/geometry.c fieldtrip/src/geometry.h - $(MEX) $< -outdir $(dir $<) fieldtrip/src/geometry.c $(MEXEND) + $(MEX) $< fieldtrip/src/geometry.c $(MEXEND) + $(MOVE) routlm.$(SUF) $(dir $<) fieldtrip/src/ptriproj.$(SUF): fieldtrip/src/ptriproj.c fieldtrip/src/geometry.c fieldtrip/src/geometry.h - $(MEX) $< -outdir $(dir $<) fieldtrip/src/geometry.c $(MEXEND) + $(MEX) $< fieldtrip/src/geometry.c $(MEXEND) + $(MOVE) ptriproj.$(SUF) $(dir $<) fieldtrip/src/solid_angle.$(SUF): fieldtrip/src/solid_angle.c fieldtrip/src/geometry.c fieldtrip/src/geometry.h - $(MEX) $< -outdir $(dir $<) fieldtrip/src/geometry.c $(MEXEND) + $(MEX) $< fieldtrip/src/geometry.c $(MEXEND) + $(MOVE) solid_angle.$(SUF) $(dir $<) fieldtrip/src/ltrisect.$(SUF): fieldtrip/src/ltrisect.c fieldtrip/src/geometry.c fieldtrip/src/geometry.h - $(MEX) $< -outdir $(dir $<) fieldtrip/src/geometry.c $(MEXEND) + $(MEX) $< fieldtrip/src/geometry.c $(MEXEND) + $(MOVE) ltrisect.$(SUF) $(dir $<) fieldtrip/src/plinproj.$(SUF): fieldtrip/src/plinproj.c fieldtrip/src/geometry.c fieldtrip/src/geometry.h - $(MEX) $< -outdir $(dir $<) fieldtrip/src/geometry.c $(MEXEND) + $(MEX) $< fieldtrip/src/geometry.c $(MEXEND) + $(MOVE) plinproj.$(SUF) $(dir $<) diff --git a/external/bemcp/bem_Cii_cog.c b/external/bemcp/bem_Cii_cog.c index 4aebe3d0..9c2ee96a 100644 --- a/external/bemcp/bem_Cii_cog.c +++ b/external/bemcp/bem_Cii_cog.c @@ -1,10 +1,10 @@ /* -En entree : ind_tr, XYZv, weight, defl -En Sortie : Cii_cog - -weight=(sig[0]-sig[1])/((sig[0]+sig[1])*2.*pi) ; + Input : ind_tr, XYZv, weight, defl + Output : Cii_cog + weight = (sig[0]-sig[1])/((sig[0]+sig[1])*2.*pi) ; */ + #include #include "mex.h" @@ -16,8 +16,8 @@ void Cii_cog(double C[], double ind_tr[], int Ntri, double XYZv[], int Nvert, double r1[3], r2[3], r3[3], det, den, d1, d2, d3 ; int i, j, u, v, w ; - printf("Ntri = %d\n",Ntri); - printf("weight = %f , defl = %f \n",weight,defl) ; + /*printf("Ntri = %d\n",Ntri);*/ + /*printf("weight = %f , defl = %f \n",weight,defl) ;*/ for (i=0;iK1Vy0wUiCIS09VAO_)%m?%SL?ANT@a7;qYl!)#&m)rB(U zOC5F|r&FV1e1tzt0GsJB{!zk&j+j`H82!i0_{dlB!IsD?NImC%-#5^BntRUqopbKF z=icw$+dH!5$IU5^eaI|uTB8afH(J{aN{wx_H(;JIsK!&H?>z6g;84LO3D>ZCz9%5zsxpdDLaP-$xwQh+zgCZ{z$k z&Ue9AVu(G%^*cG=%y}p0`-wwN^spuvEpq#>#St7>%wBB{Uah_<&7QTxv7%_Y!dTB> zZSlfNDu`*nowvryU5Ky5=7q@~aUQsM}EYVe4P?2!0l$u;McRmuT1h&ev%v zi-fh8`G3>=D760KeE(jbkIaI;L>h*Yk~UVBj+Ja+aVhbeNhx5A@;W9}*5mk6V#;*5 zaP>WIpHQgTh}`O3gBsx;%9fugAl2MTm2VvUA`EHI&3DdsHui@B0nD$^k%<=h! zh-n|@eH_mr-qb@IEN?>tt%Q^`#?UGaXZj3<9AAi(PV0x-a_AEz`RC~ExAkw55^Vv( zeHJO%whuL>ld_B~{?X|Zx<+bFpul|ZL!i{#K8*fo!8L`3CsCDJzkTB8BgQSLvJKIV z(}%ZMy*sfG%${gVVMk#-4%4>?!{4pIaIB|X8fn`OyGy$ohmTu#AHs!X$K^4aN&CpE z6_PyRK{YunAx~tOJnW)kCf@k`uJd7+iFOqW7!Ox#TcKi^G&w8lQKMs_u;R&^ZZyE%UH` z5G`T04z5D(gv}PeK`92=;%8Ivp=BxClg?QT%y9JuII&-PA)xWSa6bA`f5d!oRewcw(BM5f2kBqdiWF_cmHb5f6;EfhNBBc!fI>&{GH z73p82d1t2IL3#+_8{xE_r>%LPR ziHnR^JWctxp%r62%3W$l%I{H5p5Zg4{2rx>d-^HAN15fGKFaS=-b0|~_b8_Srr$y7 z9cW!A|M{sP#Bqbl7nL2nOHs8XA62f`yRTGMqAJO;ET%OnK^0^W*pwd-%vtTRNj~D& zh_+Y*S==nK$(VdrO5T`RC;uuX`?Fp08D$R@A)oF@uBujAC`)20fQKY{Z}h&F=>5}& zQ*<_@5hLB4h%OP?Z_|$P-ZDHk_-Xno@kG8+25&h0=D3>7bQprpN8u00TDpw{c*WUd z??%@u1Rq`~6t<%L0={!Dk66&Uk#4AHx$U~=3=4`MPL#Y*JYw8k^r9$+jg}JaVr{^X zE^I9jafMhQ{h+Ja3@KLz#uta}bb%9LwVb|%>BXxfMh)s#nhX)$Pel6P8eLCB9_Xm@ zMpAUYB2i65lY9n(K({7QM)T7xNYoCmRfSkLOjmjB0lG?&G$CZ+9Qwjg>-Dl8=s+&O zBi>gReV|S1V@)2>>W0DUkXc{00XR_I z>_};)>++NU=c|MBZy)^)G!CsbA+v|x6i6P}R)gs^q|4)QuqIS`*&}GKW`)`3RJ-`n zk!8;_whIm}51I8p-Cmeoj!&xPHfRa7umRW>Sk0b=1IRNl8(3{l)vBFM&|2GU9uKSN z1{kb;oTY%(Rft7G2Bo`FUpO^F8{l0`|mvEIOAE24Ir-&ZNddE?Sc=VT@`Rs{Y$JDeyDfDO#MPAZ|G!0aCgIY{Qh4x zxGM*IKAue9#r=qwP$>)nYjiUoR5rF7CY`XUF=&{vLtVo%m~3oeI9_82vn~mSu)?F(v-Rv~+$lutR-fCHT iiz4Yq$b^UE|K4yeu!pHw;*FfQrr!zw!eF%N>3;yvc4j94 delta 3068 zcmZ8j4Qx}_6~5PhiSvVFC&3PC>_>i@I0V~a1D7=(aZ{R?Dw+~eq-^wOWe}2$6@r`* ziEi;`47jd~*%4h@byJc018CDq-BcE$QYbVDXg}$gs!(lG*u?Zqr!_=_(K7LN&VBDC zbVs`9obTLo&OP_uckjD@-CwRqEbx=UJY%gHLLY8g{2s|8Jk`dTY-8NoHy0_7$ZN9&4#U_16f>(BNz5+IAaPr z^Avs`y$d%@ZvKeigRt7%#eXUE1AEBGG4pAh`4;1R*wVc6n^ z-g=AIg|qC`C+XA6{R56o_8l%bZHd}{xO233-_Uchf!qyCD~BqZ2ST>0F+WWLiG&IH z$v&K;urSuX)W?|*bs9jzHnM66x6;Zw?(4sbcB8-YRa$oo>$$K0w%(6Ik2h01Z5U&t zk|djGVUKs+O3XoQ#>&S+Ou#gSN&aM=*fNsq4`vwv23- z6OlReWwA0j9odCF%HxzJQwx<6EA7cN9z=-=pMp8NuPcHMQMKwK8rGpIZ=BnAeah-Z zm2ZnadFjG{!*>uX!Ssnp2L`gOI8JO8x^K}7S|Mj5P4LZSR3t;M*H zi;mWrvZNL~|EA$ozg)W+Y3M@#GZt1ws^ z;zRHX@`vDZX`QLO2>w-C#|z*rtLGo()|Z*M>Be2ySl-Tm4L>T6@aJ;xm3uf(!tYo7 zj30$w$NsU)xJt_UFI4q2XF}yaDZ|wrAyXZiY(n)-;;J*al4rbzuass|@y zUeZT}KH?(%oTl5NiF;=JHZl>QT%Vv-P9G>%euGLhH7)ejsCTEvFdcThDdJ+10L=o7 zR0{9|4J>EeP8pME#qJ7aw-)%A0H6Pdsv6lSz&b6kRe)QfC*~92BmyxHj30Xd-Fh6q zUFc5S1udT%kNRjm-Bm+>~emOazz7_-=n;|oZq8#FXi_rAE5q~^qVRDG+G}` zeSVg)$LLJmQ<_AGr9n<2O4nE;oO`T!ykbcoZkMe zG?mot?sR*D@>giAPy+*1jfD<+czXdq{ba3Z2!)oU4t`!%+VM0V{;#U;MtKryDx2C~L+jggCq`FPbRII5+jb?2UbJPbFIkS7%?GSyMf&C5 ziY`6aDq*-X$St`Om0>%K*M|62xLUg@ioYO1x?ps{6B(HPLqv2L5*dG4x(tc((CziL zjpJuUMD-BO(dCUqcQnzA-cNTfQ6IeG4e~*_EcGx1zUhGu&*EdJ|E9QH}V!3 z^8ErNsn>rx1@w-P#YQ>cjS|j|e`d6aL%!kU%l8Wx9}Yo5WVzSjLU3;O08nFmne zjC`)Ox@(T;bJSOxC9v0o&$YeaT-#+Dt%C2Y4VdCCcwz0+IBsEWkdH!5AXsCpjgeJ* zz}-}{@NB?c^P2uei<5{h8^m$Bsm9@0AjtE%^8qu5KL@Jtw4D#S`7QW3;N}eaLhiOA oJQLb`QA=%{D3@;k|M#VrqHt-6hXwD<{WSCszWmaJfptIrA6(M4DgXcg diff --git a/external/bemcp/bem_Cii_cog.mexmaci64 b/external/bemcp/bem_Cii_cog.mexmaci64 index 7b51bb5980ae0a10f21196a4a2f21acb8a18c75b..46bc57e55f00086d62db75e4b2c021702672ccf2 100755 GIT binary patch literal 9128 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 literal 13400 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 Zd($=g=k;m&Z2eTdU0nTHDG570`XQT|A8Q%VSQ zbU9zwiH}{TUecYNW_p=MS(hS)h038R=go48Mm7<>S;`@CuJ1du!~X4$p1aTY_w)OC zx4OK#yiHadY+&z`1>ato7RJ#b{$3Z{>hn5zDQkZ)9y%K-?S~F z$2JKOt&8Ycm5ZF>SPfmt()wd@MGb>m2~Hs?c#>p0N1n%{qN%Y6%|r-&OIF}9l2S}Q zm!v10O+&~A!G9WsP-{b4YV;&md6f&I`^X(U7Ox;9C9CnKLk*JUxIwR|Ef#v$_U?mp ziQv|}P~udjAx-d>455HMBcRRj^eO^&Ef~%a1&K~bcv?ri-52}rfCM4It`cgJg^rf1 zQr`&dQ-!>aPM_+Y0*3QCb_foIw|J|!xJxMR9N*$~`vv!i*`&VQhbXu&}LaW z)gy&kzhLi&WOwkA=sE5NFm$-weerbgGOI&d3fMxPW0a?dF{3-l%DCY4lNA$7YM(Web?R&C++D~d1^FL zSCn%H9P>@3r$&L_Qajg+XFiQIM$MKxMKeV1gE>_+-zT#a6>`03jweUKOcu>%@>Fy= zc92ccTIsiNYGiLTleP(rux=yB_QzUSmlw%c$^GbWV(P&bLM7n@8#xk_rv5$^hI<1} z=Lc!V6>>9XJbsZRDQ#F!<|rq~{ZQ;|CmWQMyiGJ)$pK{w&L*dog;1eYjl+c`UzLdq z$WoP7F%?SYh7$@%gGxI*8yw>?+rkC&%Z{tis~RUmnpIEZR)W>DKo+SdfLyC~!F+w{ zw#>S8SjSR$Qejh(5msm_g#O_RbG`O%Pk-303cD5IgeuZKjK(&ijh!pcf)34DWM^z@ zbjb^c^`fT-Z@0V=Oy?0&pgBktiDT&IL}Y11E(YnT&QM@?yoYTiqvDeA5n_&W;*Dfy z-0pGCNYRprd_5vvAT4Tz9%V_`!~M98OpVt|>!1QYz@pj*nFw_O zt-t|b2e1xU0+ayxzyv@8{H{Z&2j~REwl4#r<3J;D4d?*|02SnuflMG9$OB4%H-UO! zGq4TVr9-voC>Wj4No@6?tNym(LqYR^0)PYbKsq1?2FD zZ{)-AkAuEICMG7yc$jfMnU**jze6e$Q%mk^kw*O_(i|SL!ey}XtrQ&Fkk}T8!Q)4z zLt9Pk0j&7KMdF( zngzQQPx}#5!7l&`fyQ`*%85Gl&_S(KTFXF*Mn6u!K_6?}Z~Vp>pS>j8pPgrFH=Q&2 zO_xpGrXEws)MpwrNz4lKFmt*&%WN>uF#lriHQzH2n1|6Rw25Zve0nBbK`*D@p?A_> z&|lNd^iT8^`X)UnJZ3rLX6l(8%-75@=0q)XiaE~&nA?mpCpkx- z6Vu)%Pb#T_F7I_IxMTKYpg!&r`Bfc3F{;_ zo6Tiytb?7$mb2^F4)#3z8ymwVabvjgoRQ+)=KT zJH^fWk@Is`xa-_4?k@Ky_XMxx oK?uR)LTB}z`nD;8$VSUz;R;6#xJL diff --git a/external/bemcp/bem_Cii_cog.mexw64 b/external/bemcp/bem_Cii_cog.mexw64 index ea7d8b81e1cf01bb9b6d123a532c1a5a6dca1fcb..104d677164172964e66446cab5e6e588bec59689 100755 GIT binary patch delta 3193 zcmeHJZBSI#89sN}g#{MxF0cq2FuQm_34!d0CKxqBvY4~!#cnE{;uKRx8C+9am<-!t zrrM>fB;H)tfga7!)|p^xrp|;;iP%;FB_!lI8MUvX8aiI9$$Gs!PM`(z_AzZp{Q&9&GG$%jJ- zz6LHyk7Z;zBwi=gWc%w0c^=++zD@eJrCu8Hd3aK?OHc9Z(h}*%<1Wh;=_l6WsG_z{ zHE&4dk&CYrSmI^}5hVdSrv_7Vc)1oa~6xw!QcG0))1t5(riM1sBM%r)m`fx!~(4T*+$v9 zfN7(27;|gZ<`k`i58GbPd|Gw}z9M{e=3k{Y?#QZpdDwC%J((RwIT!2D>t;w-;uuYQiHO@w7^7rTI^h~63c3&y4;rivyinlzrkB(N)J z$Y5jnJ7`EAsG8IDfMy=Jwugta7kjZ~UFl6$v=fwJCW>~Hh725~trCAL+q;P&6o!i- z)NSA>?FEX)=Ap`6>67o2yN*&nVkj|8dLK;~`3Gp9@X5cv))x#5c4m44)4@w|X=eUIPHX~{h20WIL6 z+^=VTQ_y$$o4Fe^KPmzJ4!1fsW^NUf@GXvhX)FKKu`bGr3DGN_H1wl}USw#ep)H2K zwNT`IYUn9LpELAPL$5P5gFbJ54I5bOruVqG9J+fg0!%y0v?<+PE%?A?rrPdSid$g& zoWGT~GZ26=kdXH#aNLd6r&U`W9Ce8qMSi=6f%Yuw>>R}3@l=NBv7+dH^btfODb41o zW}hmu;bhjb zxcgZ#Mm*0C2&gqBNJ`zp6~i(IdUafkxH~VM@o)5-x`@yj+cYHvCrbuy*GIB2m7B0x zY|R{i^!U)*7htJ%R%1YyqMiP|$i{o8yDuRUkZOL$FUqY|6)*Fq z_xgDx$L>izw%9#Oq>gDeA8&DnrDOaZ=W6MP{GPMi;$O@cxi(1`_zu_B_Mvh@uD^;c z7sr}DQ>I?-w4v}|!AZ;0N$x0Y zUDoZyWGY@V^d3X+HS{1f%5W)G9Kox+<}(*270J}ySNLm%KIu(t0cHcM%TY%ZrLy_9YmLO)Nd7S1d=e zUQuc2VngT1{DNg7YOlu}@XbDv#t%(AZ{iUXUo&y9iRo-YcA54L6Tfd_hlvd)?tVPo zV$j4xX^fKJnvMw*Cr$jw#DAE0+eEwBVUdZoCeBZ2yO}p{x0?2P6B|riX5gcQP}5Ol z;=L8=rZXm9HF0VMACfAq{u1IG@)hu|g)Tm}@b6IzArt5YM_UN_a2X*!v==-GnGp6V zFFAE5ha6AklA$RFdF5;#*?DXM2_Kfp3&T#*vfD*g_U4nN;R52lRYgj#Jwl2JFnkU0jXdBh=O;Z6|GxtNmkP`;ePcXPdRD5M|3`K+?yoq! zd1-~+25EDQa}ojkg?rf#)C{-~z*F9s<8#Q+4Uu zx>SscfFC!3?1z-XKLQ*@RZ;LU;54eM1zc2I0qRNt_m+_;SqUQmqX9So*#|xXd=`Z_ z1|9-#gB%9$2JVJTf)4^OLZ-lzz{M!X6!;kM285ulM2Wh*gxrDO58MFp!ru<8^bxXj Y`S=BkMf!!ES}dW1`TAMkl5TmS$7 delta 3389 zcmeHJeNa@_6~AxUU6;?@MOFd9EO-$O5_d!`9koJ4=56MgtgTMT1T$1|gDDA2+)Zg} zTx7-g@?5j#s!cn#A<=20PNIpOtQzVLu`OEZ>+jxuSo?4P z?wdL1_dDmFd(Zti_r2HdYxhMLOT)XCEDv@5@#w2JJ0@h0(%I1sdtho*;2tH~@f*>8 zqhl{{kFu?!PvEYO9)V2Yw>PY7;$slw@hvB$ahsKFI#J`B@FhsGJKba>BpV(sc%sZH z%}v>Ogs^2&d1|zhkd^SZu^&oLnX05+Mfoft*`%H9j#MgL?I|*SCb4eG@wz!TB&$sc zMQs@Nu8S*bTTIceD%xE+lG$8Dh<3qm54FDI)jm-V(=LgSctI*5qjtv*+6N1ym&QO4 zUWjnm7yYt*^I5;wzIiB~z!aBP#5zZ0?R{Borgiq64HgmQ`qC|M!N=|pdaJ#(m5-wK z(%LDD*bz0}A35%UONt0Jb=Pu=kOYwV$|)M2n4lz=@RDX5ggF`M_q=Vso% zn!KpeDN`A}NN-nEuX3)oHTBPOf0XWFD(>Df`U*syxqgi#LA?Z`T@9p3OM z$r~QDp`n?!LAwSEFsJZIc%HNz1P5+44$NtlQxeLear=(Caa~t5%vI3>R93WR>OtQH zTiDNRWh=d^nJOubv_aOeBtE)~@x0+%l31RiqRYFO1GWJDWSEtTx{3Pion`lQ9pfbH zLQ7T+mdmnJXSfwDd5{YH{9t7*dEhvj7JeXXb*g(UH;fatwi zv>j;w^+ryh>Sv3~C?zgw} zQV-_DPq#tL@i1*;YtlS<-<^i5v&}@vO=tLyv^fL!We#_3WWPvTWj&e?n)iD86V@f1 z4Y1YePg+mrfv#u0pigjWWs@^Hq^WFgMs0}X5~7!kPUZTV&=-Y1E%b4r4-5Tsp`$`~ z2;D67(?Tbvh;g9LovZqe9RA9EjNc#Kbqg+8J1uL&y6ZCMotI_Ra&RV?YWXR9D)Z%< z+a-i_#_T&|*x~B3LDljF92K#IVn0$o1{#39Z4nW;t8J3bOJF zPQlb&c_K?p*2V%}S<5^moMyH%tCXHcSKW0I8p&JG0B8kNTviKx+YXg-<1NE z@Lf}|Le?y)%S98!zltqChbMWavi1pf z)Q1M$^)@~i{4Is|ym$g6Wu9@)N3?9SFn#9+lXB5%JB06wCTFbNv&sz4ilTOPN ze#@st7)(=WmG1hdlaFf|C}Q)nTWmj?3@cI?UGm-Srx)%_)*rv!RvtahY={SIYe59y_zXX%R1G9dQdxT)U;28(+(=92eLV2O2Hx6e*sN{p zrI3}7CX~&<970yjB?MKG11YE=1SKc2xM(?aLzm zckIOXhJ(~@cap_z*<{wWhl%@q8F2*4iLLRG{~n_>jg%tay`e9!yV>{;py2Jmzd-826To}; zm1qPfsJx}9yxriu8rMN~fVUQs5K&=lg%Jf_fSd #include "mex.h" @@ -27,9 +26,9 @@ void Cii_constant(double C[], double ind_tr[], int Ntri, double XYZv[], int i, j, u, v, w, nze, lze[NR_NEIGH_TRI] ; /* 10 neighbouring triangles max for the ASA */ - printf("Nvert = %d\n",Nvert) ; - printf("Ntri = %d\n",Ntri) ; - printf("weight = %f , defl = %f \n",weight,defl) ; + /*printf("Nvert = %d\n",Nvert) ;*/ + /*printf("Ntri = %d\n",Ntri) ;*/ + /*printf("weight = %f , defl = %f \n",weight,defl) ;*/ epsi = .00000000000000001 ; pi = 4.*atan(1.) ; @@ -301,4 +300,3 @@ void mexFunction( mxSetPr(plhs[0],Cii_c) ; } - diff --git a/external/bemcp/bem_Cii_cst.mexa64 b/external/bemcp/bem_Cii_cst.mexa64 index 954ce47d2e923cd520b06a4dd460063bee0ae24f..9056cfff5e7d2093b42754e46232f12966a9736e 100755 GIT binary patch delta 3228 zcmZ8j4RBOf6@GVrlHJWFyDxvc*_7;36aE^q36O05HpxOl-gW|IhEh>uYGFiv>NLfq zbXsHsn@xFLmJ&`YfzH_CI2dtiQ+Mi6#%j_aBz9C99fzqhLY>;T0=kI`EmhWY?t71b z=gmFmeCM8f?zunj-uv$%_Wlq%;uf7Yfm53*ge${K1GaXbirRg{JFBc|gH|_u@`e0C zuL|ZRG_vn@Jo=ln&%bs4FW%=4_+ETwc<4rFSL2V!QN-fHl8>bTivvqGmRu}OEOsnJ zl!XW%tSDf`P-A##c_Fu|%&6&l8hMC|?y1j#VMDXlOihLaTo>CRd+JL4ty8z6*I=Rm5XRt5JQ$kKm`(EDHkw*i0082T%kyRR@ zPKe0EgE~#74@RPhmE zN+flW;|~ebtfa;{o*_)jpBm%%SA`c(Q(CPOnN#m#S5_yj37-e<^MYkq5=I{<;Di}W+6tJnV2|McZpnCziV@7#WBKQfEGjAAjzVt9&C+<9n-Ua#&he#$>e4fzkEy@p3 z2~h;p7oZ-NBj-6d$=mh$I4I|!zkq{pr~o70Q6p}ni2Kos)lOx*+Hfrg*RE4m{S6#c zsSPVRnB_HnUJkyGAS_eIP9@?-w=Tz<>2UN8;~76q@gG#r1qjqg_8LH)k)%P9OLTCtr^IT0aE?wH~z_ijU6F}sb?x#$&hr07zN5TVCHAOj z9HTpxMvQFb(GEbu13$kx4-qlg&Nxri9P1t{0a2y=)Z1$eUq@|Cpzk?ir*-nyl00S}WZ4Z({>VxjMtJ zg}lOV)$N)DN3&Ln^)>77G704_7)?Urp3ll2?)=>?O0$UZZ zTC~J15Ly+uI~sjd10b*R+w@seEb!i{I#JM4*QFDzwf?(LN&QJ#58+zBRVq`5Ey4cU zfVf#hx?Bd+wSL<@k4Zyaoo!TmV~%>0tLugsKFg*9eyjcx830xvfKLNXkm~E%LD*m4 z$_~Q>@{7P4TCJ})s2yVW4FT(=HWhsfeGzn8ET_yU=sU9jf;+i)@sL_Qh z7(!o*FbYp2vcO41HeowTSBX9!_qW771|MLpJ^}aF=HXsrO)j<>dC>z-K_B$}UZODS zg@>C?;pUoc!k1@LF_bkw%$%^Jc@L|GtIe*GgW8i!-{Sokfe9tT5fFne!4%t07#aasSQ?ekaRt(L_G#ghE6 z#lYZSt%WQNtkuN~u&~X=a*5Xz;;%ukT0vV`{m1fZ_WytFKE&GwIB(~C1Ls?kSKF>J J_`~Yg{s(!`@=E{! delta 3419 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 Wz8ZzlbqHKlpcKswD~p8FF#Zewm=;g~ literal 13504 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 F{u`Dn@)iI9 delta 3178 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 LE4jyY_*4H2(R^aT delta 3616 zcmd^Cdr(x@89#SnVG+q)9t*q3W5K%!;)9AB@e$d$*o#3!4OK|3Wg@JYp%KllGOcl$ zEHtba40y1$#*RALj!medsH2_4Em%22Y&s<#K2o zH_dQ*BYlyZHm0@pZceFdh@HdWjapoQ2`M$co zk~PPL1_L1_f%>4E_thP8yLjI|QBjl)y&8H6~cYsJ!#QyP)Q1VZ3k3#as@ zJXf;{U=8!;7NHrXK#mJ-8oA~c`K=$ji}|hn@^i=?cJXFM7|V9@=JP%|625$;sOh0g zQbg&I82C_V!{Uee3gb09Axot@{Ps>>b9@8`YIg{O$Z+#3FR`UI3WFRhuuh>(XLuv9 zrC|@3w3gk*n{^7OFk(q-$+tudbO-}5*g86e*JYg^S8Fn7qYz@%QSU>cj@4r%q!(@x z`oY9Ni*QIEh!|shY@=X82+L~}SW#A>LkQ~Q_6S{cnK6m3H&$^*`nhp>cSJ-g$E~MA zkYg&yCx5NF%2n3|&2?$i#hZKOv-Ap|w)!{Bg_m{-r5GQx z+VbBzJs7kqDF0k59kWOcY4y$x^Q&A!q5PAv1{^U23)oS(>FTq=(HF zbBnbBt6*pAx+I62=r(h@^=2ewp!SAm<-N>8sXkWVoZLnq znP1|P>7v+|(B$vN+PGWv_pzy|y%A$7{)rhye8s1%Y>#}B-i&qH#CWYxi?EBGVi8|{ z6?H2tCb}T*&)gCk9X~K>@4plUYtlN}C26+>$Gcwd4=~nmG%Dc*T9J@r6{S5wDVo2C zKl0G&e;O`I7q`?pTNl&a2@ZNDA*s3-FaIez#@Uau&Oxx^0kC2j{%0}OEql*6=RJKZ z)0O+ExYcz5mk{I3MDzzuqJN0f@?#4}yhCob2*R#07H9|397`50wb*Upv4qG9Ja=RL zkGZYmadoel;kriymX#4@jJ`|nSYD3!61PmAOXnq4L{u_*gYE_$dJc38eVn*5qKeUU zx+1CF@Wov^l=Lz!wFLeLs^3?2r>YM_U;fTh z_=@PiXFpAFdlbuFghi=Olm--w#CX#UF<>m1!0w@OGX2E*)}qE_LYjj7_8<+#1zXWmJu*2HWdgG@^1uE2buX!>NhqTlRVwm1= zY^ulC85v$J!wrzHB6QI>9a%VP()6&v8;P|{fi3zM%m)xp2CC(=GK_eB4?SH~~jQ%GEZ@wrQbEs!R z4Hu+;nJ^z8rsR}Nu8uB9S%#(CET! zysp=bJ-m;i#2cYl(&@?c48!es`c=Ba&>O$QZk^SEg^JQDAy2WigSw=F;`|$mrF9Gs zu$0ykVa{lztpis#~K|wp4Ud~(ea>$KJvcq=+g0&j+b@( ztB&_{9MLgCFPx}jnvQuozM$g@9Y+^juaB=)v24^$NVy(ZremRwGjtSmOw{qoY;9~v z$G_`1Fq`h@vbYf4FmYkw=IV88YdrP^c8A+O#a>nIt_5cXZWw!(c{Z+N(W+53*A-7zFe2$-Rp6}zg7$G)DS3V&bsKa;&QqSzeW^(w{1ak0D3fZ(P zmDJX!lQknrBu%!GgaI2F*PQm<{MiX)c3(1?iaD|$EFvkG$BKCp&Mzir%r%}CJL0)6 z`eR3WR2wEMoJhz3ZE~#7xRtAY9QIBkq%j+-fiV0v>}|k7YRSrtV_Ep_l3(Qz@&IC< zOqXZ9;2U*sM))A4OGhr8BjGP%$YLW|Jkx|FM5%UzzQ3qMUc(ufzK2~I<7S3kzLgmrixY0tF%zc>FYquca9Y<{{S`#`jd{It5hbmO`=JnruJoPTgR zqyKR1z}~Y~7?oz&Es!=QXszGUskv_+n_@EfSYwZEYS!HE*zrMwpJ6X#4miWNG13bD ztU1A1lWr2w4d5Z*4;^Se@Je7U+VkJwb-*KN(NFiO|`+zqgLGU`X_Xm&xaMtQqApPJWVEhz9M!@aB bI}kDpA7=x1z?5e&)bH<(opGOQ&x`yIFEOXb diff --git a/external/bemcp/bem_Cii_lin.c b/external/bemcp/bem_Cii_lin.c index 3592c78c..64f3ea99 100644 --- a/external/bemcp/bem_Cii_lin.c +++ b/external/bemcp/bem_Cii_lin.c @@ -1,11 +1,10 @@ /* -IN : ind_tr, XYZv, weight, defl, tri_pt4 -OUT : Cii_lin - - -weight = (sig1-sig2)/((sig1+sig2)*2*pi) + Input : ind_tr, XYZv, weight, defl, tri_pt4 + Output : Cii_lin + weight = (sig1-sig2)/((sig1+sig2)*2*pi) ; */ + #include #include "mex.h" @@ -27,9 +26,9 @@ void Cii_linear(double C[], double ind_tr[], int Ntri, double XYZv[], int Nvert, int i, j, u, v, w, nze, lze[NR_NEIGH_TRI] ; /* 10 neighbouring triangles max for the ASA */ - printf("Nvert = %d\n",Nvert) ; - printf("Ntri = %d\n",Ntri) ; - printf("weight = %f , defl = %f \n",weight,defl) ; + /*printf("Nvert = %d\n",Nvert) ;*/ + /*printf("Ntri = %d\n",Ntri) ;*/ + /*printf("weight = %f , defl = %f \n",weight,defl) ;*/ epsi = .000000000001 ; pi = 4.*atan(1.) ; @@ -403,4 +402,3 @@ void mexFunction( mxSetPr(plhs[0],Cii_l) ; } - diff --git a/external/bemcp/bem_Cii_lin.mexa64 b/external/bemcp/bem_Cii_lin.mexa64 index 7ebdaacb69f2ffba07050ad484cf379dd3600255..4ded6a806db30c8e63b0a6035625f14b2e28646b 100755 GIT binary patch delta 3228 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 literal 17640 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 PUV4U(H)@RVU##l?S1FZ= delta 2781 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 F{5Ro_s8#>~ diff --git a/external/bemcp/bem_Cij_cog.c b/external/bemcp/bem_Cij_cog.c index 8e78949d..e5039dba 100644 --- a/external/bemcp/bem_Cij_cog.c +++ b/external/bemcp/bem_Cij_cog.c @@ -1,10 +1,10 @@ /* -En entree : XYZva, ind_tra, XYZvb, ind_trb, weight, defl -En sortie : Cij_cog - -weight=(sig[0]-sig[1])/((sig[2]+sig[3])*2.*pi) ; + Input : XYZva, ind_tra, XYZvb, ind_trb, weight, defl + Output : Cij_cog + weight = (sig[0]-sig[1])/((sig[2]+sig[3])*2.*pi) ; */ + #include #include "mex.h" @@ -34,8 +34,8 @@ void Cij(double C[], double XYZva[], int Nverta, int i, j, u, v, w ; - printf("Ntria = %d\n",Ntria); - printf("Ntrib = %d\n",Ntrib); + /*printf("Ntria = %d\n",Ntria);*/ + /*printf("Ntrib = %d\n",Ntrib);*/ for (i=0;i7EKyj9{Cm-DtU} zh;X^g#R{OoR9lj7I8d6g>nRAEQFp-!(-xKwKQno(6juNjO+n{i4yqg41USte5Y0vG zNv`cQhZvB?`uO-eK90fL<{&%9^>6a=89sLMaS{$$f~*n7Ego1fXKmRmbc@;&|JD<_ ziZCCu+7I)Vy~(ZC5(c}n3cVD>^xw&cr|nd<`>^}qds$nC8yWev2si4)DPbQdeil!| zDl~2I{}Jtm-}MTW&LZsE;J>N+QRwr{>+^dhiOhmg8687*b}QSIjAS2R!}93O95sV6 z>MKa9F5x-IqgQjTWWMycM-nm>2XS=xcA`f3FtMc7dY-DOjSvzINn8= zjxIgP@pi%%!sj_|Bs^>-LxLM>$dE;NgyS;8wBd9w$HjzcE9s{>&L>Q_H@%nRT*7pZ z(mOde5vDtr4sm>^5Ha1mw8Zf$;_kzAq0%B6s1kC_8bPZZP4$~H3%n2sqdhXxx_~}G zR+hs1zA?}(kGA>=_vgv6)(fbqox~C^`M@O!UGa){P$1tg!Jq5f6GeYGQ*adxKSWh- zdGGn9S!)lf>_GV7{FNSu?<6LI?4zv-oG3hk%k&px_^WOV$9(K^y!A-(RPJLY<_0yd zXE+i~IZkz8fg>!{u0;Rxc_zbdC}-}Xj721tQleCr-SL7Z<;*_HOo=a}?|RgNfR>8I zZz5LW5Aw99dwI;XpQB?5S-C`I>WW7uyOd}Vw?^h0Y!hZ;kvME*dkh-!y&jnpWrCsX~Uq?T;E2k96Oq$ zei@apGRyV1ZWG%u(xIb?&+C^sm`Bga)PReFyBfI1_yIm9YN5s`s{cf{f~Ace71ch@ zNQ9!g#HVpWQ61Dch)`5t*MLqqj5)qZjMvbN{v!1pDq-3s>JsW5%5|>)l+WXgMQRlX zJjEjQaSb42M%%PPg#Bp6iIRFioA?zDKK>8iTMGyG-_8uvPU|?j#a;bA4t|9|TUk;! zAwiep!deF&5HD&E@w+vCzj{}jNBn;E^gVvR`j!TW-mjj~!ie6l$_P09FoNG8_yWI= z_}@TlyYg|na{EoX@M*`0J=+k$oe?wJPA}OTJQEzBq27#zv)4(KxB6UUs z69^>rJ4m(aa7NC{F$=E$1dO|yYL0x0Sty@(#2zYFe@)S&SNG%N9eyJGWcaE1EBGd% z$6AhCkHNC*K1We5KH8&enSL+6H8$nKmVz?dzqDyNSKzgR8}M|241?~FcRyO&aR-;M zVBbag{r_e%=TLqNF1xEtd7r>X?#hM^bWY)26~cCL_m54Rvj#@9f07lqp0b=an~#|D zvh}}#It=N@{(A@)23aE6S6Gz|=L;v`Y)QyTe>c?he;DCCm@jE-wCd2X(w`PJdYe)+ z{(I?VN^Qagou#D>2|NU9^pdAGL$7~q^pdBR(*5+(rnU!OE)BB1Fkk9(`svM&O&7u( ze2TshRQr7FFm&K3z_Y%WieJ-r^@c8Ib@}HUxZ``2^(Kd;3}feEs4QqR@=3r{S#!Rz zx*^vX+$jqNW^d<<0pCJ#|Aa3vj1Au>OT+e5v`Nr6QO+;o{|?Qa@kO5Mgx? zGhR5#>trMFSlto4B5&7uyn~X&ryDnY01*?s!U(W>50k)KzsI!bhVJ@+sn-QH zb(Jtvzs-b)uv#DRPU+7Be+qG8HnK2NkAx4xFIv62~t69JEROkbF< zj>ALi-l;&44JO|Ym>DaBL(IiiU?t#TcWG=eBN_kx)N5iqfp*>g|KF>{&=>NsNNc;#1i9?8EN)tK=#9+z`3R5y*3xh&ajg-)_669!+ z*ybQ7g;&>=;fOU%bfQ|dHr=K|y-pDoT2>e&)wH?Qn38JJU|OYT)}asvq-)FDIrqI6 z!j5#$Ip4YGe)sRad+*VnU-qPZuB=_)(yAF@>O`=);N>z6y&HsY zcr@_P!q?f)c8WtQ@9aB!_SMz4ryl>{hi|(6X`1S$L>Cq!E5TBT#ev0!r3i}?iy;N* zP%g=1n&H|5Vbk&@r3)hY=$oZSepq7O%w9v^%Z_k;h3k`CuY>dE5Ie^GZmwV8dOOz_AYuuzwa{nrLdQ}| zc?r(#jy|c!2o3atz3r!j8Sm;RJi+9I?ssK2MzqtV-&slB$}1ENTA!C0dK zn9keC3Nz)lT`Yb`uOv>|O+%!_XZeZ)yHMUH^#tyol(?LKNqu6GR}|Fh#i$*DR`dw( zr)Ih9DoS+;VQeGhvK$u>rWMPLb8I3^Tb(M_>p?g7k@&R%|HjzFjCkPkIGjtG=nQRMh%r) zU#M!bU&NR)ANvGjiHn~-P*uV4${yUE^-`!W$Hu(?aMlm`x z9;+aK0>eY&{UziV@_2t#dMYr_rVi~4Ii!2W_!Os!Sk*V++( zt+I}Te&VlHj%tADYn7;$M)bAH{k!_a;s~C{nn(D1h`%4BQTbL>zJG!LWY>5TOO+&F zRZbht*C?-`E6JP2kv3mBs(~>CP9>&+a|nFOa~gOHfvD6W^{m6S>8zBrVE>CxmNo^O zKF2}G589GztCXFToVeVD=R@S_$ezgF$xG=p9Sc&*dJ3K?UF>RN} zvb3`D9j#UVB|-Q`>~L?l*dkVcw}AW4YCarux4~Fx7P9U}zkumcoY_9yp6{XkHXayf z(6)o$Q)Bwge_(@Wne{e}6b^cP?lE(rO}}sIF)M~81E)P9HjtV0)YxF8ypc`Abou%X zcq?+zjX-w}iGk^AB%$+}#JK9|d?s1#hAkBp;Sv2#rh9{AiY^osx;IEB^m@7nNIKzk z1-%d^D*~<#x=c`XBh0|(Sl0!?K!By84Rsy#23`eG>Z$?CYY^ka2X>uY$t@5hFo>}1PogbeM>|3Eqf49Z zX&t2@hlmb(k{JkAHP6q@nB#uvs|wkTMI3|Cs^*fczEg%37|d2R%)cRxx8!~ZSBDB# zyES@T_XE{UE=h-m{U)5pqy^8&o7GMB3H^0BkqIt4#&Au~*M#iGvt$5rHO=-xQRKXX z5UgF#2B8=Ai!h3M0&=zM?IS_GTL=f6?b${R?Sj7G3v2{#1ihGdBj_<(g(+~=d2z=g zbsn=#=tAqo9tqiTP5SD*eq${(4o#c!eL4oOV{R6;$6O?2;iEcl*qH94xemdY@1t?2 za0bH5J!Y3Mf%Z+9Szc!L3xjZb`CjDhtp9<3M*lvHc0K4YfpTutd;Q1tRnRv?NMNlA zUzmr$wPLgBco}?WMS}_7#V@VcW5Nx%xuU_(^dDgsk7W`Y{x8hr69ypM5MpPbyTR)> z7FWvC55)ig diff --git a/external/bemcp/bem_Cij_cog.mexmaci64 b/external/bemcp/bem_Cij_cog.mexmaci64 index af076b472a4dbf039f8f79b7ac78653b24e95f9a..fd8c1116c7c352ea74cdd2439b6524bf7511629e 100755 GIT binary patch literal 13256 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 Hj1>GEh;G~J diff --git a/external/bemcp/bem_Cij_cog.mexw32 b/external/bemcp/bem_Cij_cog.mexw32 index 06843b422973cb2dfa823c4348838d583574c161..f22deeaffabd6ffef4854850756e6ade678cffc2 100755 GIT binary patch delta 2019 zcmc(geN0nV6u|E-=&PB+TX$;#5{ ztPc%%myEC(jibt9SQK31h)z`Ebm)eOA%#)H7@9K4BpXw*v32K_xe@=|KfCGge7$q; zJNLZX_nNYsvRm|cx|Lg7`1sIdnd2#4sj&___+6>#j)S1rJwRUFm73@{?9D56obp~* zI@-N@g@gC%1h3xoYL!`7t2IuMlxIRH2m7MVs0StJ?=gl%aRFF@PzVG9=Y#LkV4S+j za0nrhHy}p{eqQ0#^R7{Y&_;+(sb~#eCaT2roM<^cheL5+Yg{B9!xEfAC-Dm0N`pmj z;kF*T=yiNloPZl?qIenJLf3)R&{}buwapiy(LUZJsVH|Tw(|GOuHE`)6!KGiuHxOP z7P!^^n?XkcpeDX>@vz(F>r^5+f91-U*yn1#-85CiTO^0Yw}ndWCa2HU#C@f;2KqV{64ig4-p6858bu@F0^n&AHIMiQxfvF10cZIG)Zjx>BLOhm32) z<#ahOK#LJJO=Hs(HqF|0jNzdD+CM#>3fFMC%lXWnVe_zU+f9K$~+1e;rat}1)D{*`U9SBIqrSwUF5ob_Vn!?=g>r1BF?6{vM9-WkW%7Vl1+EZqC%A5r1u%2uCl9AR3kT=>2cW$ zqUkg`F54)m%)n$pZ3}!8x6q-$8;NICP|6NCC7#TJ)lg(+4lLmrDzTd;Y_lGV)MJr& zmekSyAPv^jxu6oJ7$#gUrdE06qN2?gDh00+ywl7em}ZWq1b4^f32P)2cxACyR)Vzc zi5M;IMo3!??}0iXe>0ZM@lfC^X% zL;!N&*|9Yo$u~vLzeMJ*NsQg$l{h#LI*b=&b9A>NRaPG{pZX%`BHE=0XD);FT?GAF z5rh5cq$09tPc)Jr1}4(~o!t(1h9iqc7sSp(3=S}AUJx6Cm>yzz3t}pv-OARuu>ZU9 zS^vH9^!bR7dhSM?5G6f*!M_2!659I|Gx)W@E+8)y-lz0fbXCt_bcWcP0y(<0#pz|~ zHR=87(HZp_cQUxlPcuu^+tgR=8oop=8?vaUCL&#T9&X|*b4SFb}!q+zR#XuPqAOHU$O)22>Xcrl@)8F zv|6oEYtpW_YV);a+MQZn+onCM^~q9ZHDo!miglH`ow_|btB&eAbv?QP-S@hmbP4)Z z`gQsZ`p5d;^)fD*BbV zJT}Z3L_|UYNeoFLD#8*2Swq&7jikJoRFG=2gVd3?iH-1tlH;V4bder%iCialh>MJq zpUD&Q2SKs(-#;JabIMrdN+p7$6c0_lr5sewq|K)3RYp~l>Y%Dw)uHNC-B3-a+$#7q Gp7;xE(pr`P delta 2078 zcmc(ge@s(X6vywad=AU z>I~%#g+j`ujB+?Jw!;DO;Y3|W9r*OS$mvB5w zd*|tnU0y%6L-cyB*Do$!ZI#w)>etA(o(sxs8i~TkNH|WE{c?iL#nEA9dW04sgp@jj z3c;fcgpT5-xL}`rgshkxlT8kdWe`e}=0*pNP*+o2q~GfmYbq-snL{4qsrWnzm%Wc$ z+M8shxQSMLBG=->BtbqI*OPRx?~t|f=9+FFgl?P@Es9lnF3n2uPHt!K%aJ7xZXRre z^|D2qCfoXiMr!vas245MGOTVXDuc-0rT%Dm{5GWwCgz9qxy3An%cmb^#qZDe%g3E} zSOy#9e@I((Se)a|FPYJ^RIHA5*!o3VltZ8O)L|KN%)jwqoH+l6nDx{p4|3je&z640 zDO!eH$dUU55{#6XKj^{^iw43eq{XKIhZ9W2$io}b5s9N>Vyop)ljU~FM5lAWT?!Et zi0Xm zOhW1h0rqMI-lVd2LExTF%6v1ay^_34dVH5qm6BXfrYM$B%Op98R4KA3T9OyY&x#^S zBgt$s+pma1lDtoj_>t&Se|bD&@Y2QZ0BDfC%d{%*#UXgKXP|{-g+CY92*RWN80^cF z@d}UjP4A3}9P~fszXh~7lA<&&m zgMH>+P@;F$);dzEnk7>+=>`dX{2}ja;g$8_^y&HR7d({FFjc+MYRy^r-ndUOUQ`& zcwDBmhIX0P=6G!(SbJ5x0^5S^JZ#`{P#7*DcZ00hL>5liKi%rBTI;oCURwdys8XaM zwN3VW=RIFIfnJZcio^svWg!gtGdNLR3nlGIA^UL60{COnKnQ?0rH2F*n35vYJj(x!>VdU8n5(*^}&9_A2XSZ?Vr=qTi$c zO5dhGtMAd@(LdA=>oFI`#c+CVAy>#1bERB8x1HO~wQ)ze6WkTp}59SX0RDH8tjG!LyO_Gq1(`J(52?59!UKuwa(aRY%v}*9x-+royOb7XT~5? zv?uoBXELQSRmvG1%g#rClpl(8->k6ov>ZlDSRgE6TTMOh0{W(a9MB)F5$ND zP#6}Vk+BFxN&Tc%^aOe`J(Yfq*3s#71`Y2Lc*5dg?h1X44q-G*4wKL9WezZhm@cN9 OaWitALI)q<=6?X!BzE)w diff --git a/external/bemcp/bem_Cij_cog.mexw64 b/external/bemcp/bem_Cij_cog.mexw64 index fa3f6e2c61175cfd60d7b63cc32725209b2f1e91..7e811dfc61eff914ca21b28774cc0ea8b9bf307e 100755 GIT binary patch delta 3018 zcmeHJZBSI#89sN}-7K){e&AjCW*0ACiU|rvO#E0zNbaT=Lku$&Wg1!-#Aq8cE*)AE z7eONHbelMe8ZO$kwqj%O>cuz!H>5u3pwGGhhz89iY1`o%!CU=st9V3Op|#eI{TIYPXF9aG-Go{7pp z{SB%91K}jJ%D|3sss6Ok%6P{EuRJ8m--z;KDX>#0vL42j;hvMQ4hrqCu$;WMB}@+X478~I)enjf$wdgX^K>eyy2>bTH{UM8IqHR%JP z7m_!ybyghuTE8(^65m*6_3!Rw?VfHHx}nn>_g!WExVUsw3iyP4wl+}=>=#-vP{L|G zB4k%%V~G6{8bg&Gcc!g2eJM>gWpPGYYU<4G7dqK2*pQ*ydP)9Xl;0Anym7Z)4i?^R z#IWfy3{dFTrot^(z-x!F%EAcCGBRzgy&?wn+r|2eV(^I2iDgY&?T0jCGqZqE1Qf7w zW9Zs1gwz)z> z)RR^BN(_8LYZI1RB)MO3sRQ~24?URRS|G~Dg(@hG);IbELI)Bu;!X=9jV7#1`9&Hb z(RWc6_wDVExxHpFXxYG|x9IxBYU5BUXg2Lh++tkK=%480#7)Mb6wue{E9OncGDaQr zLvxMsVlrr$nk+TOR~fCQ+bn0fDVnihn{&cRh>~+nZHLwN99r78AoqDmb-&})=UPNzmR5qNam#nGje}t#-@#-WIQJ(dAMcMMc zD$Y>OmX|Y(kqUnfE#`g=9e_GO@y$Snhq(tb$^=?zd&X~r=gStKAN8ebv;HGVomI4+ zS^Lk$nDzGkxH9>nZ1@6BN5p3y%);GAodz7kdNIh~Ws?Lg3Fod`6=AXA^2kZ+T#G?b0ZsNX%9j=X zSLi9{mOZzame_w>a3LE>t~DpE=Kl)ToQU<+3a)#X5#9cT^BLNo=$eZ~*-$|H?M+;S zW;oVx?R1MHn;WNZJAT5wNk4aNt6T0SJ(VP+{@cc~7_LAPWl8WT{Qa2H zPye2@%XAEHWHFd=gw`w+On2%i#m{aV8Y z4XZVLPQy$Mof^hQ5n|SSy@rog#d;<+9MjOIVX}sWG4zvlnjmSoS;IyRf2rYK4MQ59 z(D0mwb2l{e>>P{Xgyw&y;h2W!Ra{EQX-znxVVj068osV!9bKN1rw^qPTbDbDzL8=N zpG@iGYSQo!mKPJ^KHww=Iv0?AEmpFp$wq!&vV^=gmO!L|M3UEQCVaPrm}eFf6J9O) zhI}%P%9$I>6(*3vPjiTCIG3dR@+#VcImP84eVnakfe4A6S9InO9@1)?`GP zP)Q8Kuvx_XP)X3|R~xIkGJKtDp`+-@Ls&03!FSw@y6OYB0bfRaO@OnS+YP$`-kM4L zqzBG8oRh$>V6GAjM%n!ywg$Wp_!n3S_&6{Ms|B9|7Q67T7~BJFhxx#5sLLP04uP{8 qeG|4HJOm8GPJ>5)@8J8=UlP8m({ZOvxjJ3d@51){Z@I3br~V5E?gteB delta 3176 zcmd^BZBSI#89sMemgQsF<>MMa7I*O?5TH^~i;YB#n4ER4EgE9g&<+g*A+@bdcO7C< zm+%p}xvW`oFhh)OusRu>NoN!=BdI?iF+y8vNOTOTHX$Qz)~{wmOhh~F?Q`y49H#&J zyLaY2&+~qsbI*D2*=??Bt_rReCcDbk``bV0fAMP{6fnq9lKfvbYwbiZmezKHHh(4t|z4K1q<0bQc*c)3zKYDyva&PDlEwnYnUYo zOHC&~Vh;)5iY2QE*#!Fy_Kfhjsa)uCXRxqf75>5Q2)V+h0k`Q>fgKkdFPpnf%i`E8 z<`u#}*|@n-I5%*|{D>fQvbC1=!Y6E>#p9P1S#nXON^(#zD^<_X=WlEk2%*Z>S*kRI zsj@3Xm8L0Lds=FST~=x)srn^VugOZogskiuqXFCQEJDV<7XAmJu}(2>v08`X=v&{3%mAv9{X-tHfi2>1qB z@k-@TPfKCM@=4mHDKI&(T%ZMK`C?r>CXa6qrAlPI_4W0^Ioa4gJ!5y6i`it%A|Zy& z#&j$>Ep?!_N4-o(u9#)@8>)JxN>9|M-wzai&eLYrBH=cB!&A7OjLbN&ulg_N7*l8QzX6gT-ge#1|hQ45OUwuH017-N@?p^))%`d`If!& z!+&cURR^USzMtxI?Bm$n%uy=>te)1Jg1%w0vQsM7_m3)rEHm!g?1ypA#CrSBBRel6 z+r>KKoGF7+xnAW>iRySrs$_j}52kNfNJ!`a+T?mt>m6Zl0@|s7n_8F_S7kYt0h-6Q z#c#K`IUQp|@tZBj(m{8zq=e0ud`{C?W5PB|e;Viz8v}iS)9ozRc2YRb{%YI7suQK! zss)5-IS=b&sXpGXkE!}-(Z?Q<#~j2se(x!Nl(yb*4e>_O#FyZr>KIigHSt-_+b>Zi z+LHsOM1Pn4KJi!Ux+Q!D!}k5d*!Q&s?!GS`gKj*^PS|sEyl`n^Jr7W#?Qj4bfRam! zGrSn;KIfN<*}v>d{ln0_+4O-?Z-z1JZ&LJGsr^LR5jcHUu1Bp^zgDC7LunuOCJZgY z>O%{naV~3UKzyA~60mguDwLu|1ch#y_1A1~($FLU@ySTU7C`7cT%*xz5M@G@_HS1C zVz8Fg&}nO#3?N=Ns;%Q?9@fivlVtV1w|TTj9oNKscq)XVYuRkt@q>I{Hi~@cOIaoE z1M|h>{i-F`)p10(-W9yjt#?hn5~@ZEtS+fR=wW|OS}i=z;*zt4W>%E^Bf-r&lXuj7 z<|5?ki&2r2jhrb}KgO1Z;n2i~lKB2r@cy6GeDPHMlO~>Z;Prh&xTHzw31kKl{f-`; zdM{eF_30K9do)GL_#HBE3VUIqsw|aj;%gC09qUTjW&I^CdKz%7tW` z#k3ViZG7@-saO*agI1`Mo{~$N`0IK6RUQ(MrP4WPkd-Z1neV}M>$!biR-BK3(bhA0 z?`k=1h}Cj->tlmHZnq75W=a+O0h7j4A^gBIqZ33`2*3-3I>Fztva9fJQc ze5f@ggt)sLq^l#5>}#@Pbq zoQT5cb@;gR6bmf;iTi>(@?pP(Ch_7&yBESyfxZVg!O}Ael6e%aOtKF*$uz%BTx?6` zgW{Zd2i)C|UXJWo=0Z=Yu}OS0GO*L3V&u%TmBTgxTW|%Bh&mBUs!&-Qm_b1wXU zZ%&-x|Jck5UI;0M@E%#u zZo1C*XIoAFsbx5u`rHbL0sVXI*app?Z?~jdHmwH!9E3CkN*S{;FZ8? z^w}hM4e)jJn-yOo@4<&0<0j-a$RIfH*%8Q_;8VaT{48AncK|O!E-%LgX%dcDmzYdj4-X{e KeIaxe$NUF9EgfwD diff --git a/external/bemcp/bem_Cij_cst.c b/external/bemcp/bem_Cij_cst.c index 28fdbaa9..244813d5 100644 --- a/external/bemcp/bem_Cij_cst.c +++ b/external/bemcp/bem_Cij_cst.c @@ -1,12 +1,11 @@ /* -En entree : XYZva, XYZvb, trib, weight, defl -En sortie : Cii - - -siga==sig[0], sigb==sig[1], sigc==sig[2], sigd==sig[3] -weight=(sig[0]-sig[1])/((sig[2]+sig[3])*2.*pi) ; + Input : XYZva, XYZvb, trib, weight, defl + Output : Cii + siga==sig[0], sigb==sig[1], sigc==sig[2], sigd==sig[3] + weight = (sig[0]-sig[1])/((sig[2]+sig[3])*2.*pi) ; */ + #include #include "mex.h" @@ -20,8 +19,8 @@ void Cij_cst(double C[], double XYZva[], int Nverta, double XYZvb[], int Nvertb, double tmp[3], n[3], nn, beta, ideuxA ; int i, j, u, v, w ; - printf("Nverta = %d\n",Nverta); - printf("Ntrib = %d\n",Ntrib); + /*printf("Nverta = %d\n",Nverta);*/ + /*printf("Ntrib = %d\n",Ntrib);*/ for (i=0;i6u(~|Tf2?5x9w<$K(C{d?$rm0l&X^zSGmKfD4?cebIy3O{4l$s+rX|GLOUbTN z@*4lzz*Dy@WGnaPSKWLr+v=iDBDN}BmZPl1R*J0xn**CcWvDpeV2zu3AZluu%{%K( zGfKSzVFv1Od4n4|nbk@T7rbclS}EKE2TWnH$A;=9^ahA#FI&X<8sgAmjxgYOGv^<1 zz7xJQhuLFXzn$~@IbX*4e&R4@_OS&pVDZ*mizB$On20`y9eRBux_wxLPc4ajm9>Gv zl9HL#R1njD&u)FU(t~(5Ha~1Exh%DSkzb3bLfwhFgspql1GqU>Vc{kIFVJrI-Fs;% zEy9vZ{HJt33cbI1x__r6ky$X7NXJlG+RV!H$0A|CI5rWcGgyppd|@VH zI)_Dx<4MHpI_Q8EooJwyko&Dkw94BHT_$ymFGS9uRejB4=o943$;8SP-RtCZbC7UX zh1}o#4rv~k#U5VAB zhu1s&+prMKo^H-zM`0BX(=`jjU#Y@ytfx}WHgADlWh?8pA9w6(!G&bUGtX7vko`#~ zD`d7eqS~4{MAmjHB=asL%2VtR94x=wzYo`OvenV3^z*nx)>0}DPCA^HLz9lx)+h3; zqKUB)2+wF{Pr^pza{lcZKE^h|NM#Ls6@IBaojQV>t4y6&)nCQ5%C=TuL3iT*Dksq- z_g}4ij53iqO6n3++cHN;eIM0rg|4}z-@x^57wIWYFG-~THscazo1drjd(bNPKVnll zQAtn+)c=^GY^hH;=-~ajBo6*W&$dFhn}g7FMpetWkuu6!MyKLOC6oLdL!HViJR>D^ zD&C6;oyuDm6FQaeHGm~j!W7onN*T|g8GHJaAGp8kdJZ;g!Ep{=)j%T$TeL7g2lWWr zGBmPJ*@b$$E4eYW$?$h7GQH_T4ltT~2V?^%e}d7Q+kfs2D`+H8_!q zzf|=>l+VI$aw}~a85*|yO)S=Iihc2bk5?aRfmR^Zg3*HT8NB)B)VCMY|u8>AI;(3 z648Z6G)%=I(S=7;(EW6Q5iNy1bHi*ojL!9oLAnKzbRisr^XQ8}o!`$opbfbI5BOi0 z^}0T(_jGwwm*3dng8w$wneUZU#`ZyPP1tVKlY^m}n9CU5kW&mU)PzK%NJB1#_`I+< zU9(<$J@n2C+ao%Pz|g#yonPcwatBNxI;Q)MK{ODXo{llC<Pis6xo0^i~_w{coO1 zobUw3`jA(dok9Q~N?s--uY#Kzo?)HvV}ln?G|Ys`#$~Jz?r7YCoBw5_x4K7?cq-!v zcOzm#wa^Ew$;%|DZdz(O;f8fhA=8)$^^I4+aMPmdcKvMf?+SbTj?IKGJR8_UVH_5)bG5EJT7csxY2+Jlij`O%P>!FbrieuW7%pCums8$;=hHB4_vr0MSmzl{HT YdwD>NP_e|DIFILFj{MAEV8NsR0^bfo<^TWy delta 2931 zcmZ8jYiv|i5I$#j+p=xxKFhX^?OxihW&7CelIV(br7I#^Q%M^jsX{?sl^R9bY_$=! zYqq6bHzkD;EJmXyMkt97*oY09SmYrXVk$AF_^bH57mXGYrTDteoO^FYCpk0o&77HY z&YZ`+-)tN17%6g0TA83mO|YrG{&4QoZVf%{-upNr%t=_nUwzg4(+>gT|=0GktAJ~kV+9BlKk*|8aviwgB6%F~44g%C2; zEYyb-mU+m{*z`HE0@U4b(p2hYjQVkG+1Tuj$P!Wlxv&?)QB%+{PT@DvF}P~-@Vf=y z4hzjI`71)-CHPsv_d(PWgmdO1J}B@e!5E)j|koXT^0|tR9MQKxXR66?%WaY$Xv11a&TuCL4CHn&rgd$B4I*)xE0qZEQ~eG`8e~U zPF0k!^^|ntPG+&joBWs1ZungD(KFvfZ%Nl2q&y>KaeInU3O z=B(p=J9Q`Jq`fsLmi%d+Y{MbsBg6)9O0neWd8gFdN<0!%eYYUDc^gq9yq&_7X%)%m zB#bdknG`seFjY;N5ZFYRHePvGRr@gD_XTLMkl{7a;TqvA!XpA-AxtMhNeKKkVVbY9 zQ{b-%)8dqe1ina^E`!n{@TY|7Tq=zMe@vLprczJitG*LtphK-lqQf!5bg&h>z()wv z@l+UMs!S}M^=qNTVgnO#lR7C1Gh)!%L}Um9SSh%7(McR zlx4USToTJ`9`^O4#DwiIW%aI%V27ycK8=ROsK%B|b$@p@s|;1XF1r5wsScaBA7_H; zlaWRYWNUGpcnNl2txu>RHXNyfyK>iTOnr&!TUe=a3Xs?Rt*YrBJKElyv#ms1@|gs) z?YSR!AiW~NCsG6XIKT8-JHMFPUrXx1dgSD2rirKbQ&nQA{qR93kqKu}_lKSVYsy3z0kop{2`zPXMq-P1e$4PpVre{Z!f0?nu!x4JpVSeCA7hD}-ICm-#Zh`mzHq%yES2(0vQ4;pD8D3M z#FSWJ$}hhGp>L#5U^c{+xdAle?? z5Z!qG6ka$w{ITJzcAU^0UaeoyJM!@QBxlulG2XQrxZ6ioig$Nz)^zyD*$73>!~0zIj_Kc2wE-9R`yZ~MM9S1tKD z`m0)t{$^~u;h-zXr!(hWVJnQ5*7HknsdQPC(SwMj3q~*N&6qv_MDz*~8J{%e;;jdNGl7!DiqF`r5$n_3{yD zLS7A>-WNfVTKv1|^+Y=@ONARbgvFl0;P#;9sciCTP&SF#GsP^D~MXL+VIjjw(2S+4i#eMCn_7oeH&~j+pj6Y=K z@H+OLL|$l~&nDq>L_@%93e7e)iqgYBgb*SJn?`vEW@;9gi&+A$)@;P6*4ihFXY{={ zGIyZD8TGkb>nR@6*QghpCDCib-=v-3s9S03b;E;o0aJ?;p0C?b{IY&bOZ4OXi|AW` zXPpOvyca^q6R;`ZDIU?Y8e`rrZp&3Q0ei8}c;;ll%;AfG8!y|*pojkop9eggL2JDy ql!I47`%lw?jSJ<}?f?I;E2AhZE%C76%QMf_f6xE@!-I~+&-?=zd~odm diff --git a/external/bemcp/bem_Cij_cst.mexmaci64 b/external/bemcp/bem_Cij_cst.mexmaci64 index 882abc1ede893f44ae52529e6cd09ae0f69b432d..ace865d06dd39d9ca80b2f58419454cb003526aa 100755 GIT binary patch literal 9128 zcmeHNe{2)i9X|&{QW|;}N;|sIa!dt zS*q=i?Jqy&-S_kPzVG|I_rCY;V&D1QTc3PUDF}`^f*@3(N~rOlT!;W)jPoT z?DP?*b1+*`)o@ZzM00yyQpd`_+@$$7uwD{5HHrF`SDZ5B50koM^)A5 zZQbZ`d+lpXX3bOU<$Q>Xkxub`{<mTvU_>P)xrHTYiHi*rXU2T~E87a&2;Tv@6eF-H+iS;>v7WKA)cyYdnKK!?RB@Htko8U&Y}Y z7#CmOgw3DvNZF=^aCXD_Say++T_U)Q5ufpD8ji+KCq-$2f{RiyQp1QH$cZoCjc&dS zQ<-#$k`pmCo}sMsUgZGeCx{nPwQfSmc*a~= z=Nukx`^U&%>UN8D=aldXh>T9UMX3qFl4l68b7Eb#Nl?Nx?vYd;^ zsU3jxJtce;0yz?J9-+Ruby&X=9w$%rY4ZFY9&}`$I_A0R4WB_84?zVEvC~|abyi@? z)+9Qwfi7gU8guG=+a=Z_9h-Av?O$R3hP7T0Ymbr#@EC@8VhkZ5n{%)q*fGGzi-XQ_ zF4kVML&RDPFeP(=jpPzHllKV71y~CH&>C|D@Hi5V0|pjrKO{`!T@-6SCwv3=CfaVJ z?|08V+0+kWF6uko(m_@ns{ZcNDYf+MgIvG%kt!}h4(_}FLM zR5F|P`;BW#CN+#0Keqd2U&gZ!A~|fJQSptVjtM$1+bH?SkyL#WZKK$#)h7{C-tZ`DWF(sdKtr-yq>i?O~EBO;^{v-~Zxt-6u5$qYjPVak_uD>7d zab;W3o@*Re4x>3w|9q5XNA#wM7$0#rj*CmNAgTH+4jpHuh}b!bIu^m);HrU3=|AdJ z)|^hguNbG4HDme;CF?xvS~(V}7ni=kZY-E8lGBOPTq7v`xhhwFG<8LJ{utc{zVGUE zZFOyPsar>I@mcZH?-%`7n-$|Nukl&`t+}bY`tudf-J@i`^AaxfE0q9G1DHejcco+= zHFv^#jbj8g22T*A&(bgC^aluUXE?QxaKys%T>W3n(W{}gfwVf|RWi?3nfC*DjpGb| zg<+_{zmj#+Wkw`MQg<_Qk42^g?<2uG;YG7#zKz_{y@iqEAYOwMCG#vWCP<2s`6eSw zQ8GtBXnHAUlOsh_yaF-vFuaIeZ2r{hxPg%YtK%9*UbILZBfG4yrHuGMtbrGsYYB^Q zoKX62I9LXLPV!seMW}3k*Xl>|vblnh6v@lxDvOZ3Y%a9INM1HS!AZ5`W%JL3i{&Zf z=I8LbjmvK1?~UW;FIae`Vw^M&+dUsOUk9Z79~7(1*Fb#64@TiQ1czh}!r?dm;WsX_ zbB#REzM(t&Fq^_|FtK)&E&{{(pwIXWS6rhdjm&zkz#;$Q*ew(K3!!>Kb`km+p?*RK3B5w-6+%OVULy2sLO&w(79sj?3d_sH?<`Q&@`&v1ji>aa zyjBiu-m*Jb$4sbB#+M=-_h``_-Flte8rSQEM)~oSj$p*Dk46O+FZZO9x*XEvpxhHg zpEMddLA?w9Mw` z;RUmVe>qvfZ3DM!xpi~f%58w#5VtXIcXPXs+ZVYl3{(c?43sla&OkW>VzIRoVklr!*u%RtRCsgnj<)Pk33UDiwR5Z(*pCHND&gh64KRMVpNq}M03 zpsu<5QlXgUXU|X6Z>?^i_QkCIF-`XqlWo>Ytk!0238D=)ZMU9_z}3uL-sJkeo_I`4 zQ&bCgS%Z;B;hxr1kCupr$<@YP?eSnDsgWnZJnfopjkSFtrmdwtiG)A7qXWM@KuGtZ z7B#2`d%p=HIH(z~2VD!|J`gWOp&!dIycFVS67~ literal 13400 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 delta 2023 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 #include "mex.h" @@ -20,8 +19,8 @@ void Cij_lin(double C[], double XYZva[], int Nverta, double XYZvb[], int Nvertb, double tmp[3], n[3], nn, beta, ideuxA ; int i, j, u, v, w ; - printf("Nverta = %d\n",Nverta); - printf("Ntrib = %d\n",Ntrib); + /*printf("Nverta = %d\n",Nverta);*/ + /*printf("Ntrib = %d\n",Ntrib);*/ for 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 Uuj9HWdpPuWcIWX3d)oH>AI|2EiU0rr diff --git a/external/bemcp/bem_Cij_lin.mexmaci64 b/external/bemcp/bem_Cij_lin.mexmaci64 index 2c481ff6d5f0e5c8fc63cdf976cd747c7a0a507d..177dfa6ec5352646c4e702bae158cecd0f6eeb9b 100755 GIT binary patch literal 13272 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 delta 2328 zcmc(ge^3)w9>CuVA%vgVAR?y`f(0zpDVyC@kljsbC0DLvxSae@r(&t17aSDF2_8;W z=*9GmD-QVTjnmSz(|XmpD^nC^%6YZ|(n=7ke>69VO)@!$>xDy<@#+o7b=>>zqBHz| zf80(!-(THvVZo){T1}KE!rwUasxaB1X{Q{yBqzON#X~g7`W)+T+OLz$$>&{(4qF9eZ zWD2jw-NdN*6@IVZt7*ZfwTbQ3b(^Il)Mn>>8d0&dWQ3%8bG0+7cnCb!=N_dzve!On zIQ4M?jMkE4L znMTD0-3;1ridX8`Ow!HaziPAM#=Q1{&Xj=H-Z#B!I)(~|_|oMh_@ zqrhbBl;YV3!dMDKCWAL)N69tqp_17|SfPF_Y?}>%h=s-?!(rQ;qGEn^s3U9(C_{G^ zhN9}w719zvgTE&Ay3=?)nbj5Gbh0erIsAa|33XT^rxUhf3%L*WU9v%6k{29Ns`!G} zm34fU^5<;P&@J+zetAmptH^k8C~zzCkD!l?=zqjcaxJmD+VI)k z;7DX5=!;yB3wD|Uk(-jILYC#A&+yquWF+i42~|SlVUJqPG|8RpRj3$lZPNR93WSc8!fL(f2+SfvFNIm?z``2xQ|frt_0^r3!G$Kcv*^9EzzU@u}6iHHz6wwx{maWhmy$WE{*Nl|$tx z>(bg+u6_(H#%*@QU`vsElzU^ly1bk}1UY0Ptu+5#Fy#C$kc(QHkn=0mxS+~%l4BT6 zIu5opTPH8AATx&Cw11gll|x#DZfNriW@4g>a3gt@D#tWAPOZ^}AlrF|T%pXm3B?>E zQEEBn$bTpYWNb7R;u><$Sb!bm1EWd55mL6wOC4m`XiDe6VTa10*ZPqZw1;w5l845Z zae!FTH-S8sz6Ru_bQj)F3YLr&bTQD#UU+KdwKW@{#kDmsU;fKhuWiyjC%2}^t$KOs zVUm$if-A_zjIFv-m~gF>+|F2$ShsnwT=B}myP)d>(>X&9FTHHuqSVOWrpg9YIzhS* z=jn0l61Ny2Rhi514B4IO#8=7f%nOChYSMmHx>VT)l26r_BdS&N&+Ak0Fe13G9pv1y z0K6mGvS{rw$mqYM$;0g?c&|KJhtNIX8{i7?A#eh40gb?Gz>5F{=z<p(0#gatMtB zQD6W-5Z41)KoPJGr~ozrI{+7O7WfG00|wWkb~FM;2zaCvfa@&ilTYn7(EES}U=vUQ ztOJ$<6rcg-*oAqEWwHrT8uP+yw90j$X@^-f=Qk#ys)M@@xZZr~z=XzK+Kn#3GRvOGJlQCpL-u#J9u~;yLm6;($0IPKmSP<92ag zjI*X%v#q?f(%N9{w??hczf}7YbY({9JSaU)(b;q%T}*GFx6nK3x9D#AceJ0rOaGgG zLVsfUqvZ?Bcb12i$Cm9(BeRFu&m3V+FlU&{%o8S#UB;HNud>zb>+DXpg(d9!>?iD} z>}7V4{gVBL4Y51!u`%`m`vW`AVouK)xJ+&(m&d)pu^i8B;C{|+;p(}a++OY=_cqtb zo#sB`E^xhEKj-7_Z~+d%2~)nh-_ij(WQkhxnCF=W#>q4@$C%^HMP`&4W8nPv{1;+y B4D0{^ diff --git a/external/bemcp/bem_Cij_lin.mexw64 b/external/bemcp/bem_Cij_lin.mexw64 index dd5aab75f2203aaae1b875be4c49839c7e747a70..40bcb77d1403f3fb374afc117171f7f78e59c704 100755 GIT binary patch delta 3198 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 diff --git a/external/bemcp/bem_Gi_cog.c b/external/bemcp/bem_Gi_cog.c index d036ec0e..1a267fc9 100644 --- a/external/bemcp/bem_Gi_cog.c +++ b/external/bemcp/bem_Gi_cog.c @@ -1,13 +1,12 @@ /* -Direct potential for a COG approach + Direct potential for a COG approach -IN : XYZv, ind_tr, XYZd, weight - -OUT : Gi *transposed* !!!! - -weight=1./(2.*pi*(siga[0]+sigb[0])) ; + Input : XYZv, ind_tr, XYZd, weight + Output : Gi *transposed* !!!! + weight = 1./(2.*pi*(siga[0]+sigb[0])); */ + #include #include "mex.h" @@ -19,8 +18,8 @@ void Gi_cog(double Gi[], double ri[3], diff[3] ; int i, j, u, v, w ; - printf("Ndip = %d\n",Ndip); - printf("Ntri = %d\n",Ntri); + /*printf("Ndip = %d\n",Ndip);*/ + /*printf("Ntri = %d\n",Ntri);*/ for (i=0;il*mn#OK+3K1efko3mLdv{+owUtq}}g}c0zrmZ6CrGAc(^gpG; zK})dbPs_s$vQsj_my+3*Lq#JIGvWMEgVrhrk*6?9KTN3Ot_olR|#7P zcX7O$aGRABom{bs6!e4>?Hn&7OnXT*bNnP>+C<`6ju#N7)0L>_crIZ&iHQKmj}oTS znDB8tjW9jDgadT(n~YIdv?CmmOKG0h%0HspwvzA$Xzq`J64@bxjsOx99?fyH=qzy&Tv^kxmIbzbZ7|kxUh$V z5gfE;a4<~+_c9LAabJX5G>d8}3PGv~<->O<<5@0`;bAZSG*_P`{wC$Z0w>f zm^FxnmG$)+?~TsMxKMk^tXtFZOh;}d!#Vi6tWSrJodtF$uFPLJ$QSp)@6Jj%E>4k- z;VLt5U!8c8UPRsnOe#(Zqjtaq<&rCNzbS2m{vj(vdmWC4V2R{qcY74cnFifb7rc|_ zljw^`gtc+H2z_}oE0Q`gwDesiqOSsx@fV?g8Id1q^S!JKUdeZ}0KAK`ANum$lA!;{ zjQ?2|+(w%XO5EgE>vo$4t+2|yGk1kv>l&SJ(fLjr+;Pump`I2`lCj;;QqaZ*VW_|> zb0H~7~_=&={t#J@Nv*G#%s6H*AmGF2gX#{13C&o0#TQax}c=6YPevda6hyZ zdhNz`{cr$%>h;F3@dS70|#(E28nSqQ@56I zvv55HDodu=*ZDL!1zJk>;FFTZyK;;sX%=lZ-+Y=-USbi_}VUxm}&O!h5YD0i{TG*_tT lqg`{fDB~5msq6oLElToO2Q>IxESt}TJ)3+N7%Z*a@E<@#BtrlI delta 2834 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 I3{pV;3uke4=l}o! literal 9248 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 E4e|n4IsgCw diff --git a/external/bemcp/bem_Gi_cog.mexw32 b/external/bemcp/bem_Gi_cog.mexw32 index 2c52aa9b0b88c193cfc73d57f90de0657630bf04..7a782aea90a00da976e80bf94944cfeb0e30466a 100755 GIT binary patch delta 1818 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 Ml;V%2eH97+0j(niGXMYp delta 3204 zcmeHJeQZk(%#8pt`YbK=gH4_O=H~EPEED*Od!(b*P8wM_T zoJyxiA*B8LkUQQqzM}j?;bf zR3Le`Vo z!mXlH!euHcn2&}fu};FZYP!0HwZFR?EY{RGD>okb<^cmg=-w}>{4Z~$*-EGXo=T^0 z8@5FDd``S6pVH8IVT*i&Mv6bc4oF3U-8Yt`Zm_hiXAV=9;pZl{HO)97+2c%~qPWS~$X5(za>C@wC;}45XMJ&Aoz~#mpVSMk@1*$+(!5(kA*Od0gy9s*@?Fp_o8J(`IidW|mU^OrLBL z+x4uV#9wDcO_$}+)PEEOS>25ianNeXnO12DyYt%f!||r*3c{u3od-Rv#cr)^+@_b( zvRkjNWw%yuNj@c7)uqNor+(l{6;FvZDo%)XDjpLXIqr*7z}X8+9vWiq^diUgB0>^B zLkVx$LidHends{YZaTo8PH#1>JF{nxD3D8x74nrwER( z*tf$-gN&$&0 zaGf_=5QV~$!GG5U(r}bajA^K$7(o0ktd_%<*`zMxw@LE3_j$BezM$Cei`Yk~exGf$ z?5JwSVDNGv=W+XXus{ZG*Csk|UO;f@f#5fW9vA{1DjWB)xTRYtVAa-oVV3>C>K1$~ zVtvMN$IU*qcC}Bs3As6hjDKBLD*qK3jlrSV({p(Gn#4L9T2ulVRQ^!0{{-LqTY)Kj zU`gUR%p6Aa5jFZ6JX*Az)u&qiz@j#>FreCvEimzyyHT-sXqH-b$JT59jBgStnP)xO z)Ew0Y6KpDbT6m8AIOltwgH{}+Y)IAPs(we+$Dz@OmAG%fiX46$i;{pzu`3pqmg^MG zvC7ZnB#GNzA5 zbsW;MU&l5bC)Q~*Vme;dFi7Tf!@Q0UbWGPLX6q>GxJJj#IwlV?tk2u8W76KMkGpi- zq2p#1A0?z-H>}bzTSv2w57uf+EihMpg~94zoAXPZE&i8#oDI&h&UDS$(%I9ybR6x@ zHw(c&6#Uv6LR|0Vk@rrglkwvjWdCR;dG%lx>FrxaUg)-v?Q)H>~g0%wfFb8_y~^|6LJy4aSG#ifuw}(b*!}UFnk@!Z%PQsEhVIeO*z)v zlh&W2lj4wz99dRjk#|(j3Z{@(k*T>FLi(53#$cO)ZLyX|XwNCw8eu!V#P%)rQsMId zcj5ogg_A{ZXEc#r&-eLW?s?JQ72Q@mEmZRaC;!(Sz^lwlnUp?^_dxm~ygOcxHk5{h zlg?Db!v^Ke_9cEx#?Y)BYY{dKzNDGdruv`&e%P(}!45!bJy;fa2+dRvJ`DU5nrbIF zZ?w-Ko!|sr<$$z-JAuzbCOqVaq#vXL?KT5P4bTgTf%|~nkOX)yFbY`!j{#HAgaj=# w4EzvM0L~lp4#Wy>b>c@6QU~4$G`WDa(MyIx;cc^MF!+8EwUyr%MrzXj3lKIGr~m)} diff --git a/external/bemcp/bem_Gi_vert.c b/external/bemcp/bem_Gi_vert.c index afb71d45..dafd0e79 100644 --- a/external/bemcp/bem_Gi_vert.c +++ b/external/bemcp/bem_Gi_vert.c @@ -1,13 +1,12 @@ /* -Direct potential for a vertex approach + Direct potential for a vertex approach -IN : XYZ_v, XYZ_d, weight + Input : XYZ_v, XYZ_d, weight + Output : Gi *transposed* !!!! -OUT : Gi *transposed* !!!! - - -weight = 1/(2*pi*(siga+sigb)) + weight = 1/(2*pi*(siga+sigb)) ; */ + #include #include "mex.h" @@ -19,8 +18,8 @@ void G_vert(double Gi[], double XYZ_v[], int Nvert, double XYZ_d[], int i, j ; - printf("Nvert = %d\n",Nvert); - printf("Ndip = %d\n",Ndip); + /*printf("Nvert = %d\n",Nvert);*/ + /*printf("Ndip = %d\n",Ndip);*/ for (i=0;i~s?aa>3 z&hG8Lvuh8m?auW^olH>F6zo(_X_afY+eEwFJ?lcwA&ZIho_AgzcP85ewY1a-h;u z9H1z7l1zwY!c~hOnz;iOSZsOZ#j#O*PZU|Z(vDo@kOPM-VQRV{mk-W=CZJhmrm};wFYn#}F zWwf)%9dV`|57$FbDZU4Dh7igqJ+2cxJFZlplQa0;ntJ7LPv7!>$L!nCDEQsB*m zt%MH>yq+)>%jgw&9pO06$Bb^#v4%Qm*Nt|8ml3A57|jAdM3@#~tP=P^!gS({1p?0| zOsCU`3Ot=Kolqkp@D#$dp@xDOCDJll?q!GCW$&DzFtsz;YDo=>0(7ToaeIveM>18r z5L@(c+Zwf_rV)KvYo^*&^DAolYz(I+@(O$kYe*FNP++_tVaOSL;4s=_Dc^DI_?RY` zHnjf23Hx4D`J=JN297=H4sN47FpHYO9E`dcr)iyt?mv%5cg!bSP1Jl2vs|^&&eQIl z16Xi=THCV-r>xVGJgLpyp=zH}f$ASmstH?EJvwYvwN90C(hfJG=vus^j(@G~fg7%g z&Q5Z@=JqhiANwu;41OCs7{5R}pS+n$UGjFM_|{CEaXN0K{vmd$T{HAflrilDsV-FO zHC)aNJ&x+OWNSX@IYMt6NBRS%o)PP~X~h~PYTl#ptFc$@dd{I&qY|SCsDE{XqQy@N z5E0{A6#M}X@lz=$a`;uebNF(Z2Pzl6DU9{PIp?WXTE0S=p>T!3!VEhxYo z1oawC?9t=zBWQ3R7^%nAi;S00{6pAVr(K_unEAw)v_rZg#>~Zoa8m!{A31)8ZlJ1a zb5CI`hyH^Jl4f8WFjpH^yXGhBv}-e$ z#}+ljW-AX>-lsgXy0vM;T0A)SSZCl7!@Gg8Y8)^VWy8Oz)YB+OpvPTor)Bxzushdx ziD!89?UfHe zTE?KVAnZL)7aLMqmOx8E*y*9`4ao!h3aXr{L@F4F`XuUu(!#3Im8UCE4K0OXXS!}t z*oQt#WwL3B`4oo7jeZKql!t6Er6}agmG5*eG!<2OOC(Cm58zNy*mcL(z{R5bT_e(I zB)h-t-j_IUheO3-XZks51f#gh*{mpHMa@uJQp=m63Hb)thx`jLN@`uNlnOKZJp-nc z-tXKLF<}+7l)jA{?k)2N(j_u2Cb#0}g9l<|e%$6**?6my^+5~zrps}+?^qUvchGk! z^6}OzMBgFG1wMJa)y+y!`uQ1wym-*D7v@dg#T(%&+5@Z^19Il z$*-P5@t3%oYKGMzf1q7PHhmbII%@3+g)z6Ip-XT)?Bn0VcOgGNPrTAVAM<0x9F_hv e{UQ7R|M9|LVZ_ff1rG>b)c-={G>7F=p8pRpWZYi> delta 2790 zcmZ8jYiv|S6rS1LK6YvM(FfZW+g;i&^u1f6tvnjK+TvZTSkM|D_~2nwTsBv6!e86+!<{U%4Ck0T>My==Gerb9s0+_k8C&XXebz zxpQY{|C&>41`Aw$Rwkrb2R6Q^ve9;~6`nBe@!Ge0x&V@Q3AHr$)*zrlnCkr2$2`$EG7IIK#6CPdVLA`1A z%$#dH8Pb-MV%f-ZVFhhlceG6QA~50FMwa4AC=E)( zl^ADdky8b|_(Y1ju%Kyd-Zk+;w6Bj_u8V&s`y;U2SEJz+_ zIL$ZJEqD=eT3qT8!E=byo=mk1ZX-_nGSw`&i8$@&RDj0Ue3R4BLGL-`6%Ec4r>&WC zBBx3yiL_R9D*ef@NgEf17&N4#uW1}(Oo{&pakOfpS%g zTw5|#lSqac(B34nMZXYaQsfAG1=*@6%oQZ56U?aT8NZ>7KcN@HPW6!9agiV`dfT~z z?9@q(AdB^89ziZo(mH5hryAXWkv7Nv3n5&+n6Z`eZ$WQM{GVF~7OehMysw``pH|#V zU#K4#{pYK1qN&7N$1qo>`jSqPB5?>aw8l>>i93=l@$*U|GS(K?R1X%QEj|@WY-Q>@ z)Vw)%qyYC)@WJ3i!H16>rVXSFq-EnAjvY2OG9vl!k{iClfqN@t2D|lK&sU5I!I?Iih;L7Wtrb)p_3EEz$)k}^IHSb8-U@m zMyohou}vpTARCjhF_>B2c%>djUD~0m+;26i*$cziW>7BCz_XAl_vaY569Wsm|!+m0o#%F!bjL9iwz>W3yo!7pUIBvoWQmtsPk`dGGk@ew{o!| z2UJzR&AZ{-YD)ZVbv{g0FUG?&RMUfR`B06!&{(Ij!y}l3vqIJf=W5(0uMKRqi%bD0 zEUT?EJz|HVnprSXdo#!JYyFtmRp+m7lh?Cl@&Z;aa-GwR)W)m=(!UEf)X{X}b$-;J z)cpy+)#dTeVc75H6EK0XGoH}^*UFb5Q{i7=a$NAO! J6wH~k^*=q+33UJf diff --git a/external/bemcp/bem_Gi_vert.mexmaci64 b/external/bemcp/bem_Gi_vert.mexmaci64 index 7620f84577a6165261d1316442aa197cceeeb183..8a732dc09c1399bca8044886232876d29fa8db60 100755 GIT binary patch literal 9088 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 M-Xi~G1({>)-yUeRoB#j- diff --git a/external/bemcp/bem_Gi_vert.mexw32 b/external/bemcp/bem_Gi_vert.mexw32 index 167f88ecd1a00b2b438bd0a10296c7ca6f148816..3608939a52fce0bd65b403f323b3cf4e75f29086 100755 GIT binary patch delta 1812 zcmc(feN0nV6u|FoOL<^{0v0=ArhF*`GTXlQ%6qq<%ut6!4T4md7Pf40b;C%ORxuM{ zX*BB|81OomxF!3HGTjyhht1+9f>TUbf^JdcY-D~7g(z`^b%=R8?;)GnpZjMw?|05U z=bm@&eW&NPrLd*2y$}y~6fJKaJyBj6nx%dJbD?j*Zr@*|YF}Oa6FVn#RE?_$eW|2rpGiHxRD;i$@pYPdMX{p49=%_@gmIyJx$VV z#lG&KW*hFXGJAFU=5iFtaX2~@s`A4LxaX3@J6=AS{BG88e zy^QlR91nI(Xys*Du3cXz-S+ek{ynOsu{D7vqt+MgElo$p(K&%82JejX=7TYEp018s zt7nwy7TOtAp&zlpblzV5M*Wa7J3{OA)$>aq%d%8ukTmPcM`Gb{fiqckwd<8_=q@vA$vjASQj5?zU6zM#jn2c>^wa2K%+Z_C z`T9W!_MV|8#-i_4rYEVBnUAg1&6GpLAto1>(hJN&+(IKv8dD4*HL|INrp2TsS;1g? zi{VI~J_CB)=)FSAVxGrd+8R><@_I}@NJA{NLWc64&@M8+mW8wNrSPVFsV3;U6^O`w zgY0KyQv>aaEx;x8UTlqi019(zfNq|X8slCU8d9twu)fe+Ad|O3zdITtxM8UTmOS;tu7$qz1jJO0O#GK|13YD>C{uzxUr&8hlXB z_R*#BS8zQwCs=ij5CN_Gb8{{9b1{$w7=h_*gl+(XKo4*bXayR83V;L30A+B{S<8S7 z;6v>(cO%7@^D(2VF>#y@+efDhUcef*T~O(-9-bfl;J-$ix&x1!SR$scrE=I+zv z&i+?+!51lYoTU@&FM*?gB@v+?y2B}%nD%O{U1puG*#dESHo>;ncF*Rv57{r-ui0cU*UjIWh}!3SKB!Suk1fs31> zCcZ1aFMcK-5xd1x;!SZ>oD`=;4Pi(;SwQlMod{$JDIsNK4XGw|WFy&3eB><>AQGYE zBU0E&z9QY^J93s>AYpQYJS2aR$3*LV#%XcpI1#i9JZQjLZ)>m}w}ouuwuo)oX0~&7 J!48+P?=RYF0U-bY delta 1895 zcmc(fdrVVT7{JeMOJ5WzPnpH-@~8u4*!JFAZchtgnK;Zq5h!4^vN^zF)H!LDI1#jQ zQZE?rIEQgdrc3rV5t)xHW|l#wQ>IRhA#Nx$j@8Jrx~XdzdiUK<662ryXD9uAult?v zeD|Dl+vaF0-hk=LjUSusTp$kLN~(hw?~nkZ=+p+I+u6vye5TuSM&IzvYi0k5rocVG4gAv#8 z2pVyX#_sY%Eukn;c%<*tg#_=t{$CaHu)lQjj-0e9Ow>x!tKcfUDMHb>;0y|-A?VRp z6joEtd%k|k7f{#ig~&gNVy=0lPhUOoNqTtjCvg)#+7CQ9}X4WoW zDlH)zPe2+uujF$&zz~h?AS3HWglL=xewDioCW%RfU<;utG08!)RB17F(_w*=u*Ihp znJuJBH3v?0o2rm9kpWeX@**U=&yf2nS~)100b)?kpjcv6mqEr3bv9K(deyV2Vlu2w zRkuOP5;3WmOsZ4kS#X#@A++fFMu%4E-C;6Y^CHzwR%^;Zp3>xi9M`nXqSK*+H{e)B zu9AV?xDuEtUR~lZy5$RtUY+Pwi%A}`TboBY$XV?YWe~RKRFITL8#GnbCqj}J0`F60 zAyjg^$Yk^px=gBJtc=K-hbZ#n#EQy#! zxelZ~Mr}fRuk6o(+bY<-A<@`Oo|`sIb&&8hlVUSuz%~D}br;0qz@!nO zG2kk268Hev25bWA0BMwGf(V1I7%&K20mc9=%t-{&f!P2HEHt84v>qNx zg9e@W*hZiqWFQm-t^q^9*T6xb2iOU;0Z$KW0@6>#7S=Vcqv?FwSf@n`H`K59JhnI1 zH?DMh=r!IZ551zET-RUIjKVokFwaH$17d+EVh3TD5#61Z{C}ST{_kf%oC*7*H={N6 z&1LHw*LoWIeouHumOb^CdlTMJ+Se(D!T$*u1x#@W-S0b;oIxE)Q7BroAScFTFxkz; z=7Z)5bAx5nGG-aK{9y@O9$6HOmeDiGOe&MkSeOFlWu}aAGL4Lv>0)}A1I!mpKXaD3 z$xJY@Y$7{@$}$Xt-aQ7tv^_ATScob@1?xryp?&Y^OAW3{{sICU(46?=lLuA zHGY);ji2D7Z0WYOwkF#S+h?}pwgKBY+hyAgn;b{uWSolAaTdk|2) cAybFB%Y4N=Y}Q*+EU6aWQfaBN!1w&sKRAvX^Z)<= diff --git a/external/bemcp/bem_Gi_vert.mexw64 b/external/bemcp/bem_Gi_vert.mexw64 index 3ff16c8f19e03edba1c8ca8e7519fc335d37da98..587a21d28b3622d7207544fe5da2ba7feff2c1e6 100755 GIT binary patch delta 2888 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 diff --git a/external/eeprobe/read_eep_avr.mexa64 b/external/eeprobe/read_eep_avr.mexa64 index 811aa70a3873e4ea8eae53b8788b21c69fa79725..ec35cf37c214442761eb26899d407ce8fe0c3328 100755 GIT binary patch literal 167200 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 O!HU+^VMDzki2W}#>*pc> literal 152092 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�XI`D~qEBI^_aD7+!u;B)qUDU7zJYK!h{MWZ4 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

Welcome to SPM12

of the Licence, or (at your option) any later version.

diff --git a/man/Makefile b/man/Makefile index 72725c9e..8bb5cff7 100644 --- a/man/Makefile +++ b/man/Makefile @@ -1,18 +1,23 @@ #!/usr/bin/env make -f # Manual Makefile called by {SPM}/src/Makefile # -# Copyright (C) 2016 Wellcome Trust Centre for Neuroimaging +# Copyright (C) 2016-2017 Wellcome Trust Centre for Neuroimaging # -# $Id: Makefile 6761 2016-03-30 15:11:20Z guillaume $ +# $Id: Makefile 7019 2017-02-16 10:49:48Z guillaume $ include ../src/Makefile.var PDFLATEX = pdflatex -interaction=batchmode BIBTEX = bibtex +ifeq (octave,$(PLATFORM)) + SPMEXE = ../bin/spm12-octave +else + SPMEXE = ../bin/spm12-matlab +endif SPMPDF = manual.pdf ReleaseNotes.pdf -all: verb.pdf $(SPMPDF) verb.pdf.end +all: $(SPMPDF) @: clean: @@ -25,10 +30,18 @@ install: @: %.pdf: %.tex - @ $(PDFLATEX) $* && $(BIBTEX) $* && $(PDFLATEX) $* && $(PDFLATEX) $* + $(call makepdf, $*) -verb.pdf: - $(call verb, "Creating PDF files") +manual.pdf: manual.tex spm_manual.tex + $(call makepdf, "manual") -verb.pdf.end: - $(call verb, "PDF files: done") +spm_manual.tex: + $(call verb, "Creating TEX files") + @ ${SPMEXE} eval "spm_jobman('initcfg');spm_make_manual;" + $(call verb, "TEX files: done") + +define makepdf + $(call verb, "Building $(1).pdf") + @ $(PDFLATEX) $(1) && $(BIBTEX) $(1) && $(PDFLATEX) $(1) && $(PDFLATEX) $(1) + $(call verb, "$(1).pdf: done") +endef diff --git a/man/auditory/auditory.tex b/man/auditory/auditory.tex index d07bc66c..f861a0fc 100644 --- a/man/auditory/auditory.tex +++ b/man/auditory/auditory.tex @@ -78,7 +78,7 @@ \subsection{Coregistration} \subsection{Segmentation} -Press the \textsc{Segment} button. This will call up the specification of a segmentation job in the batch editor. Highlight the ``Volumes'' field and then select the subject's registered anatomical image eg. \texttt{sM00223\_002.img}. Highlight ``Save Bias Corrected'' and select ``Save Bias Corrected''. Highlight ``Deformation Fields'' \t the bottom of the list and select ``Forward''. Save the job file as \texttt{segment.mat} and then press \texttt{RUN}. SPM will segment the structural image using the default tissue probability maps as priors. +Press the \textsc{Segment} button. This will call up the specification of a segmentation job in the batch editor. Highlight the ``Volumes'' field and then select the subject's registered anatomical image eg. \texttt{sM00223\_002.img}. Highlight ``Save Bias Corrected'' and select ``Save Bias Corrected''. Highlight ``Deformation Fields'' \t the bottom of the list and select ``Forward''. Save the job file as \texttt{segment.mat} and then press \texttt{RUN}. SPM will segment the structural image using the default tissue probability maps as priors \cite{ashburner05}. SPM will create gray and white matter images and bias-field corrected structural image. These can be viewed using the \textsc{CheckReg} facility as described in the previous section. Figure~\ref{aud_gray} shows the gray matter image, \texttt{c1sM0023\_002.nii} along with the original structural. Figure~\ref{aud_bias} shows the structural and bias-corrected image, \texttt{msM0023\_002.nii}. diff --git a/man/dartelguide/dartelguide.tex b/man/dartelguide/dartelguide.tex index 751ea3a3..3959101d 100644 --- a/man/dartelguide/dartelguide.tex +++ b/man/dartelguide/dartelguide.tex @@ -19,7 +19,6 @@ \section{Using Dartel for VBM \label{Sec:dartel_vbm}} \end{itemize} } \end{itemize} -Segmentation can require quite a lot of memory, so if you have large images (typically greater than about $256\times256\times150$) and trying to run it on a 32 bit computer or have relatively little memory installed, then it may throw up an out of memory error. Further details of the steps are described next. @@ -27,7 +26,7 @@ \section{Using Dartel for VBM \label{Sec:dartel_vbm}} \subsection{Using Spatial$\rightarrow$Segment} \emph{Note: This subsection will be elaborated on later.} -The first step is to classify T1-weighted scans\footnote{Other types of scan may also work, but this would need some empirical exploration.} of a number of subjects into different tissue types via the Segmentation routine in SPM, which can be found under SPM$\rightarrow$Spatial$\rightarrow$Segment. +The first step is to classify T1-weighted scans\footnote{Other types of scan may also work, but this would need some empirical exploration.} of a number of subjects into different tissue types via the Segmentation routine in SPM \cite{ashburner05}, which can be found under SPM$\rightarrow$Spatial$\rightarrow$Segment. With this option, the ``imported'' tissue class images (usually rc1.nii and rc2.nii) would be generated directly. It is also suggested that \emph{Native Space} versions of the tissues in which you are interested are also generated. For VBM, these are usually the c1*.nii files, as it is these images that will eventually be warped to MNI space. @@ -38,7 +37,7 @@ \subsection{Using Spatial$\rightarrow$Segment} \subsection{Using Dartel Tools$\rightarrow$Run Dartel (create Template)} The output of the previous step(s) are a series of rigidly aligned tissue class images (grey matter is typically encoded by rc1*.nii and white matter by rc2*.nii -- see Fig \ref{Fig:VBM}). The headers of these files encode two affine transform matrices, so the Dartel tools are still able to relate their orientations to those of the original T1-weighted images. -The next step is to estimate the nonlinear deformations that best align them all together. +The next step is to estimate the nonlinear deformations that best align them all together \cite{ashburner07}. This is achieved by alternating between building a template, and registering the tissue class images with the template, and the whole procedure is very time consuming. Specify \emph{SPM$\rightarrow$Tools$\rightarrow$Dartel Tools$\rightarrow$Run Dartel (create Template)}. \begin{itemize} @@ -59,7 +58,7 @@ \subsection{Using Dartel Tools$\rightarrow$Run Dartel (create Template)} \end{itemize} The procedure begins by computing an initial template from all the imported data. If u\_rc1*.nii files exist for the images, then these are treated as starting estimates and used during the creation of the initial template. If any u\_rc1*.nii files exist from previous attempts, then it is usually recommended that they are removed first (this sets all the starting estimates to zero). -Template generation incorporates a smoothing procedure, which may take a while (several minutes). +Template generation incorporates a smoothing procedure \cite{john_averageshape}, which may take a while (several minutes). Once the original template has been generated, the algorithm will perform the first iteration of the registration on each of the subjects in turn. After the first round of registration, a new template is generated (incorporating the smoothing step), and the second round of registration begins. Note that the earlier iterations usually run faster than the later ones, because fewer ``time-steps'' are used to generate the deformations. @@ -141,7 +140,7 @@ \section{Spatially normalising functional data to MNI space} \end{itemize} The option for spatially normalising to MNI space automatically incorporates an affine transform that maps from the population average (Dartel Template space) to MNI space. -This transform is estimated by minimising the KL divergence between the final template image generated by Dartel and tissue probability maps that are released as part of SPM (in the new segmentation toolbox). MNI space is defined according to affine matched images, so an affine transform of the Dartel template to MNI space would appear to be a reasonable strategy. +This transform is estimated by minimising the KL divergence between the final template image generated by Dartel and tissue probability maps that are released as part of SPM's segmentation \cite{ashburner05}. MNI space is defined according to affine matched images, so an affine transform of the Dartel template to MNI space would appear to be a reasonable strategy. For GLM analyses, we usually do not wish to work with Jacobian scaled data. For this reason, warping is now combined with smoothing, in a way that may be a bit more diff --git a/man/example_scripts/DCM_example_MMC_BGC.m b/man/example_scripts/DCM_example_MMC_BGC.m new file mode 100644 index 00000000..11b80b43 --- /dev/null +++ b/man/example_scripts/DCM_example_MMC_BGC.m @@ -0,0 +1,80 @@ +% example script of an inversion of a MMC-BGC combined DCM with the generic DCM implementation +% using spectral densities as data feature +% 2 data channels: 1 beamformed MEG source, 1 LFP channel from STN +% 2 conditions: OFF and ON medication +% condition-related modulations allowed in all synaptic connections +% taking posteriors from grand average inversion as mean prior values for G, T, and A +% van Wijk et al. (submitted) + +clear all, close all + +DCM=[]; +DCM.name = 'example_inversion'; +DCM.xY.Dfile = 'filename'; + +DCM.Sname = {'cortex';'basal ganglia'}; + +DCM.options.model(1).source = 'MMC'; % specify name of the first model (in same order as data) +DCM.options.model(1).B = 1:14; % all intrinsic synaptic modulations can be modulated between conditions +DCM.options.model(2).source = 'BGC'; % specify name of the first model (in same order as data) +DCM.options.model(2).J = 5; % specify state that contributes to observed data: 1=Striatum, 3=GPe; 5=STN; 7=GPi; 9=Thalamus +DCM.options.model(2).B = [1:9]; % all intrinsic synaptic modulations can be modulated between conditions + +DCM.xY.modality = 'LFP'; +DCM.xY.Ic = 1:2; + +DCM.options.Fdcm = [4 48]; +DCM.options.trials = [1 2]; +DCM.options.Tdcm = [1 3000]; +DCM.options.D = 1; +DCM.options.spatial = 'LFP'; + +%modulation of individual extrinsic connections - only works if corresponding DCM.Bs are set +DCM.options.model(1).Zf{1,1} = [0 1;0 0]; %single forward modulation +DCM.options.model(1).Zb{1,1} = [0 0;1 0]; %split backward modulation: (in)direct connection +DCM.options.model(1).Zb{2,1} = [0 0;1 0]; %split backward modulation: hyperdirect connection + +DCM.A{1} = zeros(2,2); +DCM.A{1}(1,2) = 1; %thalamus -> cortex modeled as forward connection + +DCM.A{2} = zeros(2,2); +DCM.A{2}(2,1) = 1; %cortex -> Str / STN modeled as backward connection + +DCM.A{3} = zeros(2,2); + +DCM.B{1} = zeros(2,2); +DCM.B{1}(1,2) = 1; +DCM.B{1}(2,1) = 1; + +DCM.xU.X = [0; 1]; %(0 = condition 1, 1 = condition 2) +DCM.xU.name = {'ONvsOFF'}; + +DCM.M.nodelay = 2; %eliminates all delay self-connections + +%%%%%%%%% +%%% OPTIONAL: take priors means from posteriors of inversion grand average +%%% (omit to use defaults prior means) +load('priors_grandaverage_OFF.mat'); + +DCM.M.MMC_T = MMC_T; +DCM.M.MMC_G = MMC_G; +DCM.M.BGC_T = BGC_T; +DCM.M.BGC_G = BGC_G; +DCM.M.BGC_E = BGC_E; +DCM.M.MMC_E = MMC_E; + +%%%%%%%%%% + +DCM = spm_dcm_csd(DCM); + +%%%%%%%%% +%%% OPTIONAL: use multiple runs to get out of early convergence / local minima +cnt=1; +while cnt<=10; + + DCM.M.P=DCM.Ep; + DCM = spm_dcm_csd(DCM); + + cnt=cnt+1; + disp([fnames{fn},' rep ',num2str(cnt)]); +end \ No newline at end of file diff --git a/man/manual.pdf b/man/manual.pdf index 4b4559d21fde3c7b2ce98127aa282c8b8eaee4bf..bfe0bea7aee8fd1c9be14cd50dd0c3293ef28c65 100644 GIT binary patch delta 741113 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

xma2XsL=2_#V4BK@&-C0ufzXis3<_qW~ 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

W^g4U2~b5{yD0v4S6p(hLKrKO7$vs^kaNr zWK}0reCQCt3u2PRSBb?zp2U5ebMg`2PT-feq?9YZ9EiWE1DS3!Q=1uucH&vm6#a{WC8^Ts-4=?gd$Qy=PsN>_ouh%2vrus>JEe~iAk{*NB<52jgq?E#NoZZ~q~!3Ue%QX^ zjm~#yPJ#(0U(=gr*k*?N%aw)%C<5e9taSkIz;umh*8k1@{$*9i`U9;JC&OMF267fdR~y ziD8K$GmkUT28%>V{;>NV0i-oYlDU+5EJ;>{iUvfxK?S-r{`u=H%6lrCqL}VZ}mTx^IaJoLFD)Q z@hAGuxZ+*qNwO{4n|9-55kg(pvxOo~{Xa}3UbQ_~P^zU``$al@n^>JVzc{O;xx~UV z`5>cMIE(y&q{|`@bvQe3vM~^@=os9(9`Q^L>7n~4<^hsmxu-vV; z$@EgLAf?S9BJdY!`hA>RktTG*&zoL2{wZa}zGMYIzZ<3KH4nu)*WqxVFfJ4KGa$m0joN#8yt}HNUq&w4Smjrl!jcjvocI^X*wfpy<1rTy2xwT?t&*2k){E zCto`Ty2>FRJ~VUAxY@!VZ!)laXsMLtT6@dB=3-@+oC-dPtaT?j+n3@OslZKUs2JcQ z)ag{HGOu*k^F2G7_xUt2XD(&&(s2%k5~e;!JI~DqTKGb=TS(;V^#x#@=OQ&NxUq3j zmC5n;)0*vGHWcLA7DT~V74NPWd#ArAgtTQB$qas?dDz=r5se+YhZI(Iocw)tc_d`L z&%!52`30DCDwN{oom!EaY0uI5=hJ-}$+3-js~UN=f}3`J-@_+*O4p1*xtJ(dp;WvF zQ7ZICl=QHKF4)SJ?_Xn7SnJQibp~li`jCy+Hm=I{j)$m=1iEJXxq4DojT7_^`=;FP zH3-Rt3A=8sxU>sK^QHM|2}91DXtlD@Ws0c=UXFviJ_SZC8~P6u!sKvm=twDWraAKjWj0%~n=@O2w8wdg1GmQ<{;A7smz;wxG3m3E*#|R+FXVbdjK}>! z23QK<$sjC3C{cs+T0eDV~rMELz>(MKJ$v%2w&-1FdDaW=J`&(3-c7bfQid;X3OAKUk~e z$V=3sjP0%8_G|S5sg>)a7KgX;&YLZ7-x|~Sfvx4>Fq2c#i+x*Co_pepP2at2tA~0g z(HG&~AB5jylQO4% zpTS?u4vj178b=(iEta>N-ENv4j?R5=ULJln$|p_}K`C)kdPCRibt1`G>dgSj;_auE z26s}dM!_u0e$yKY;H-b0HC`xh4)1~UWvGP}#7bt9stpkDHL6*=3 z#YBNvSV+|KH21kCg;_OEYfYo1f^VrT8_HxNJCrYPnUd``6YMtW*6h^tDuCppmv7U> zD-TthmgbkR4mGP|Dbbpi`gD&2%?9?WEx{Z`+xKr4m~VY_X69$}6I~HX(+yA*Zawjb z!O4Umo`z{WIM4-cSx&Tsi$-SYOa_l+vfJ_eJ8Fdv`!!3HrSN#hd$TiE3sH5hY8l%q z%aX-PNWx+J%HWr!d1kyGtu}XT+!`N<#@-tH-r);t=B{QWnL1luV=FVo*KY$Z3c%eJ zd*nr`53zc4^1ZJUy90CT!4?;HYMD6KvrY;3-0{j>9q#Q@2+Ud^XtgyVHgzR!xi)wO z+`?>&9d82g-QFo4z8=_fvXzF9&wp-s(5YZFw@}YRF2L1O5GGJq#TQ7ZA;=oA0ME6_ zqWjWm!+B7mZd2gs-OAv6yyusWu2$1TUma;K^W=v7q^w52_$+LC;+Ci-Q6G=0CI3RfK(s` zJ%FX_@5n16d;!Qq575HQ*9FXZY@&vw_X0;iCYR&2;hA21EI2Uq~y z4^n^>^?+0%qys=4g<>!8&*%vzBBXf$$P(G>1%{{(0)s>QfTOEH;Of(U;3$3wSg*ey zSebViIIJi`q@YBIV;>Uq-j*b!F0>=a}#CQ~VwDHFy&=_#eVGBSJAX-y@Y9M@&F^d*_$l^Hgrf(X6 zL;BU%{Qs*Tt?M*^2^yz85o+aUK<_aiRF*(Y#^V|94di0@(qnL0A=rP=2+u@Il%}9hf1mO~B7WHsOE-8I6O6{hx+L5Y8D8 zer@6|2mu4~bsJ<3_osPiWd~&OuL*!?5U^AFW!DDH1@wo%?Z*ZI5D$X!9E%Bjpz*?e zffuEDTm8DK&#FivgITl3=EeM><^uD{bVm({daUO2_YUf8)0-<0LS+0B%|Yb=Ym*!e z!g^@ybGb2V!BErEVK1F8!YyHEnwWT+(L>Y8nk2bvoQYc>u)4=AYf4PPFjT1z)%Q0y z*&0d&G2BQKCMZVCBQHz!b&A=*CELi9QWWhsR3qwb7hR$H%Z+Zbokz!Ua4k)@>=7IM zuJ)b*uSckOw{EsLlYAVaOcDF_`C*aEk)&127!8H=JMD2`*|sS9il}d?7YRaiFj}@M zzK3(>912RRp$Na~vH4u&E9fEDgg!Td>rcrXKj2RrVnSe6U+Zlx7vF{o?(^sjV_+Wl z=WRMla#uz$9Vp1~$zN!QN}^}(RbsMw{~G5ltxX0*ts=j6iObdzO=e`n;N?KAmNPAu z%eGvv?=#hO(r@Cyg3c6ZdQGpY*0R+n_dr{7Ui750Pp@`J8jPueyGP92+j!B;oyMDEyPU|^>U^P%my=;N3j)lqhQvF{|6vk9D?_bCWs zC3)UdjFL@RsckzxT>KiGpYDEz{=xBi@^b+r%iJey7p=CEwibhO4zS(sgu8BED+MCz zyrqira1_$_;58zG`S&+hWfUs+<5A18)m~t~N8kOl9LHU1iICwPuA4uLA;c0d`-8ti z8=?4x z@fPt;us^~XDsi)6$3rM8^Ja+lr?@hfAW{Pc<-Oec;$nVtupKhhyV&qfeBx5Zg#Bu* z*b2rT88iahs10v~AiA*|fER+m8X{Qe1)tlKb(kAUicek=X@(?+SA}aIZ z+OOpHyV1YC{B%nN2Y&X2YGQhdoQ=omiS$&HZEgaB^yGYICR}K*Mq)EakRh8BpA3y1 zgSaP%Q)7zb2*y`*Z#A`Nw3lA~`~0>)@pY(teK0ff@)108t^WQl_=_Z#obDBMAiXS( zNc;I4oO9*@R+Vgu`u(1q3`!ZcTGqC#?C#lVDa(x%uE-9fCGepWI2K+kt5_Fn&^v!C7v~6fgTLgJ1cmLGe&D7>V zccv$Uf>CiroUM4#9u>66JDHIigtv6=?dMb&HWKQtWCTHyopZ*D{=V0ojPOBKAb3HR=sg3stDU7&sfFgc<3Xr&eWpb^Ki>kz^It z(heff8_L+xXs|b0=9nBB0K(Cr*`|j@<4*2Zp*!lvlxXv9N!UH)FOID~dP2`vxBB$r zSlFUthA)r#PS2>|#RNmh|f@XOuX{+_!!_=Fo>lVbF z;p203Sg^f=eL@GF%&Ey{inX@Fy!;*7{Rou)#QLgW+^Z4tjWAJ}n%i&OZuiThmXa*~ z9k4qOWO)M4mpO4SHlQtGZ$WuaT4}4P>iGLSb>6w-t82zn*X^wh*?E$t&*>g`Jts+z zZ%Z1`9TIkZ)*PrbB3H-NUI=Yh*z*nV-3Wwt69OjJYq^tvB5_ly05XnWotS`7nk~_Dc)ZVGCdD>x%T=@^C;;#CVGt-N=?dz{IKODYJT_)eP z@vb8$iQIVKWLvtzZcsjEk!4+lGmuySt<$ zr5QS;yBh@QPAP?TKu-RF6|_w)STFYgz{HEZp?XV2h1 z*8hJ5!0mymLD~qQq}M<>;$Z^9Ly`aw)HQ+Np{MbS+W*g<20zrS0S6BO$UOzv=Ye!o z_|W^m2SWrdi5;+I2^<5M>ms1vC&U8@2s{vpqEYdnz92xi3Y-Hdc>v1V2dX(9wC>Ls zE<7i|+M*GJ0z7nnpu6!PItBk9M5q57ALtL)Nah#U{2$4$Jy;;jKRpuxAlp?51?ZXR z>AM4tfBt|LRa4QDHLSL`i9RmpfJcQvJ$XCVCqP>6OUNVbptIw{Mxy*#R})s3@@cfj zMRxLc2|1=`2P+eMD_65%3IhKa=^2|E;?M^J78}9HpB%lim2PK)5x3J+s(E8`H*U8t z$iuQOPR4qU>7vXJ2RCOXZlJ5ekaH_ts?wzMW!h4)_pQTsukQF#50F)ZzNl6*6`?t!q!z`tP&*f8ZT-CtlkHkn+zi=ot@A_jf15Wv_!CvY*jFKHTGhb&UD7*F7;OICpvYj)mq}>VW@kP!XU=})*;({zH>DFbZd+pb zLLLH18{d?rsuRp$uZi;urubw?N)6q78QuKRtP`8$PJf@v@r)S--!~JSI`6eq1M;sg z%!HP;inJ{gei%$`d2Qlh(LwBE=-QC=Ih7NSNvxN9__+a^vPrx_152gShJC1X_z5MS zRcYZ4tbE_O?~Kn|JU70R#@L*#0x{y34jnhDx~wioH`Z@|sPa4yFoH8M@)(j=TXH|4 z(u#>tPrdYMDaq2Z+bZn-4x2_6jqjuUQE+Tr>`BfHAM*U$N~L!#?R$_{OF!oO2fhsw z-0)wza#8D)@K31eco=w`@boO&eC!nl9W2NX=Ax13U#NVuU54u2 z7I=+$y+R)n;}8o)l&^t2qVOU%zz$QvAOfQB%5}3{OEVk7$733|n9Sx%c-eQV!{jnu zL}$-Rqy)~L)G3%+rasI~^0)6{<7P`Qb$5O8BFYp-uMiPO8eP|S!X-o;dnOp;O+)7& zO+|U_&-EiXCwG``yEO{!F<l>d%LyD_BCDU+0(@BqJpefYUU zfNs*5_6boax&M7TBqM}1>`4u{ttJ)GPsFym1pQ3v65S^_MzD=#-tnleTAztU(RdhP zyG}|iYu#Oib1}b?dVT{`nFae&yUW7GPo?V(;VtevRWI&jW`QskZw&*;bfz(?((5JG zrxD_?@NBV`o^MdoWupX=^4k3~OD}g5Wbrm>D7)2RY9EWrL2Q1&T^or^$@(h58?$#S zYXn>cSU4f(I?SSbA|V8}W#xG?h85VylT9!OxXyn+EeSLus0ROYi~qpi#;e zG-ybqYLPRURBlpqH z%bi3h7$l2L4N=Ite&q#2FFeqXpV&4skfA+x%s&GU^27SUUvEpGTFf!Q8{5^!gF^|~ z&N%?>c^Jd@CUj)+n&-Gg50n! zp=Jr(UJjD2Ts?X1UG8{od z`-A3SoglDiPqpE{E`uvMWQa^Y5>aR-w{%pY8>>*uQ;M}Q?!#FY9jLzIxsVWDBl6W=r`h3Sv7*TmJkpThHSAfpL?zTg#y2>Y$tZ%V1CBMY7?<_P?%gsAZI z7CoBf1>3vC_Yl0pnTt>Ba&!W4&Kkwc<{6jlml_bPU}hC~EoOwybTaGHjuZZ#I+qJ1 ze6-*gIuG@_5%>;+`IPGAnF-3&f&r|ct^Qs-iyQ1fV}}}h&DHIkIAND+8409VPM8|A z%%W5QD>qc@%Mx{1Is3;Z$=YAO%=E645N0D1da`-GC^8r;B7d#L*l46N7%y!m@m@Gt zvM>-5jpz;uBtmCfdQu(o&4$T3O~Oi(gwmK53#U^tXV6!HqI zep;>(Q77N`M88yto{lkp@`&SS8ruL9T#)=w*6DSsNHCbQO$^JgqZQXX%)yjL?B|rY zoD0)q&%Wgd_KObEuYRq0_=eOcXIc`NNFATDOq!%c;`Nr=v;!zkOKmgGK6eG*1Y*is zt3E${X`Jl8e<)%#f0#1UbzjO-xc(O%!Q$XPg6HN3_Vz%}3gBftFlPP-9zFS=_-OvW z`b7S}`b7TU`b41j)vikLZ;}izps)KUNro422K*nA3^lOCRTJRV{KIYJKP&!_Wd5-N zAjwcbd*A>l@}L;}m)ppHR{bH#{A1N`eIhpKcOnsRt-m@+=MRX5+~IxuiSbkJo$Ao!44gwugT05!t>Jq18*fIJZxN0C>y zQ!Rv*F5E`PYS!_zgSO^mx0Y;v$xQK$y_cPd6nSLJ$Sp5SeZ=4w<0il3uh(6>XirRX zRT@roBYw<(IhABQA#&XlN>5>(yjtl-)%iNSyJ+$Z^etor%b4+T6&h~c0 z*A_{_6k%vIYPGY$-~I0HWS;=zE+k{*dTQcOarm_ObXT?aN9fl=m>W>8kS%B>u+MsNb;;}mppVIE~$4t~JXtnW26&o!~C^HFa>#`LHRem*|Hd&!7O1ykEM?=Fj zIdP_~jhI@JJxq_G1lrpEn4t$rD>ewVpg2G0(S}3XTKA)oskt!hW1I0T?BsopvKxTK z!_WHiYsH;Quo|JyZsq~nbO;Z+gyrIKbAXn=fI6e=rycadwj)|?lWcd5q8P6V+c%Oa z5zp928QjNZ2}DL)hjy6bIvY5Y=XE@!&;@^J%$i|A!nPvmpMsci zJC`sn=?LW<)-#$x^*p7P?NC4X?);h}vgS%`J+rEcNkeVFEcvHwTVwqiGnu{<2U5Xd zFjUEXJJ|*cS#+S)YIt_WvIVw_eAm7BPUz*-Rl^>wjojFPQ)nl2FtX`i zBq%><7()Ynl9G2&M2?{c>6%=pP$q?K81szW<2m;1MrSoU;C(_nwS+rKnhdFnK|B5! zT-kr~j)`Fi9u*787@rKFt!t|fuo}gLmW;D1MN0-7$?Xfp6xls>M7Mo39);#tQqg}6 z16UQWVnm_@5}Q9~%~LOb?#KG1jKe9TBM zpi`dLyf)`qu6s3&!(d4<ypwHLchej9Zxf!ra(Dt3=WGSvJ1rG>2|*@5zwO1UwF8XGQK)aE4iD1nd1ftMh?d z6bTnk;pCR`h;He%qUi47t^)g@S`PXtuR$`ybz@wb-Qbi=K&hFn2*Pcjr#l8A; z=Y*S1z0BBAx#S~?)E8!U5a#$+6f5vjN&ZV&2+A}A9+A0HS(SG*p#lHGwjF!#X5}un z-{}kPpF_TnAvg5c5-`YU%&1VZ+)J5|0!hE_ztvf z8OFG5O?~@vV(3ifY4j@XYpjvGSoc<;3Y4)AWh#EgGSOyf+4DA$iH8$##R;N8gphD# z3I5f9C6qv__w$OOs5dqs6)2v!IAaP%raoBsjfUrSCnT!KLt6JEGpKUg?h*M8h37Ph z0h{J)lPn~dMW3eV=gdUmPOzt~i?3SWm~8q}tC z`x@)qg#DS}oncgs1Z)c*zB%mtKB^_QtvA`1M$(>zQuU6K2&}M;ic7F9!+VW5Ys%aH zPF0A=a2*f*UZcHjCAoYHtY+J@XWyO)iovNaMwrRyMq9^E#n9U#^M`Ao`t4!NFWaP1 z4oJN;$ct{8A5})2#mnuP`Xu3+o@WhLcl7$WzN70ld`RT&s54??pQb)4zs}5bxDyQR znMg+xlh7$Ds%&N@n*Sic_Ns z?aN6dtSVl>aXu@dgW6;Qmf|hD1eWB_05JLKmFpggM>&!Igs!467CqDa+p<7;|LjEw zuF6qv9K&SaOIV8J330T=IQQG70WZp zvwX7O$Sd8sRnVvWk!{?nsK}>0g95LyFU<;U%y(uLHei9VHJ0xnr302sWVC%;HMDn+ zaOzj-fBZ~`*bDwISZ(is{nL^C<-+jq1W^FPX1S{Z5g&g#vd|&~(C>(khga@#SfMcw z*z1cH!Ef+KNCEt-U5fw@fe-ME0OBYg@{_bFfYux^hz}3w{h(&j5qQwphj}sS#eiu9 z-vfym;44E%{*J)`esnIy#RO1H%0EYg=LB;=+nD3=p-O*;5IG-`LwP>XAmG6P*Wzka zO-Av5sLuV%1dbm7mq6sm1IVQD0!T!wcr|+op zQ_GEP&Ww;{sm5qccQ@2`Be!{0Jn=34#*6*jYBq`grQf-m`}xmD@2pw8s?ifF2X6;1 zX!$X%Gt4x8%g)1Q3d@NhC|zV*93y*`2Pwwf3_ zPwGOQH>vnrMO%;JV&-}c>yNo$OIW$ug{;%3kAFTox5^ZFmjJt9GQAtY@#3j7?=OgM@*Hc`b6c=ILS7()`V4 zj0V*cdG_3E*8N^Tw|0G^116~<(j~Y$r^0+{JLnXVeJHr&QtW%uYSfi^NT<8J0ZW_S3l}$HrW@PS5C3u}tif zeu>d@4^P4s_FLE{udI#phKPg_O(tL~>+CDO)ikTucC^G*3rB`Hy_jO^3#zGKmdz6L zHp@4VuG_whnz6nQol`{6A#U1zvMlZF)%(>TrNvTk89)6ZDNyT0;@39!17EWuGJz^) z=R$=EgmokmQkK9adT51)^R9yW*j8qsjMIM4Uyt` zc9pRe2cPG;qdRo|1C~CKlYrWSN23PXb+ZNzM8C3hh>5|>Lw;_yo&T(Gz^ z(6m>6Pux3^ve+>3gduZHqVVM{wW;VN)M;WqWFhoXSS>z%wOl@JA1Jx~I^U3lk0fOJ z`Ua5c+na~J;?t3%nn=7vuxu6}w1lXy>%Q+)^PSp%g;2sVI|eDfeH&$o6j_RvM)iF^ zSKjPC0B&R5bkrnlO; z_;^xatC*NM=9vsB`aoBs?@aJolU!dYd3(4GQoagE#h;>M% ztBQZnv3j?$3|jQ2F~lqanXpu_cN~)<4V4^tzRHRPk3|%^HW6$-GH3jf+2b@@{G169 z(JjhquTJMVq<|oVnD?lhk?Xy@1~v_ON^DfyM;02=3A^~v%~;r(GG#fMGTLCrm=JFB zb=#WIXZE2fi0LB`i`a%WBFwP4%>1!}ZK0>D!2=a}d?gDzf-F~#Rr-{lwkPvYlBzpH z=6g?Dc%Slc%TIOU^nEUG{~(mwnrQlk(N?pD4hNlF38GNBzKY;;R{OZhI9tmq_6ctT z*e0OW`jgSX{@r|`2oIV5L~g4U)HCVxe$Cqx#vHm~2l((^&-z+(oWhH;&F^=j?Pqb0 zYn@8(J_Z_X;VuCN=B;5a%~`JYLS{&m&}&Vgb)@IU43@32y@3Yt{p6#hm&4cA z2Nu$m!@4Pz5Lm}P=h9zKP$&}BLlMP&5a5N3!J-rJ|F#_ZH?IkLRE5Yc%+3E-`Tvg! z5dU9V6aR0&exPjho7VJS>=f6JKyAlG91EA^!KsQDuts`_nfS|A=H=lAdRl)4Q`FE; z^dRNG9OeJa{liiI$J}34AZZ3*?jL&c-?@M3$^V%9M<4}+S^rl<51Lhj$O?T+2^4{7 zi?DvX5bi@)jvpX&N8J>U;Suv`OAw4giZDILJmYi zhR?R0gRHgA2gcKSwCzu04%IFs5Tv^JvVBt5e6TrT0}5f)(3ny_E*I2uloX(~Y0FXG zRg6Z6&{gu>A97rhYRFu3cAcm(@WVv3aLdF9;V<$*_p7n(xy1((dKaqHAlN-@}Mp@q> z%oZ@@wKr~l*MgB4ZgL$G9UU|dZ91Fr66Qm5OYGH5Y4oO4lrw*o(3Pqvn7G*QuRp2o zbp=}kNeqJ|W`_skJjzA-IynngV;3sCY|pJ;Wg=P^4oVV6%PI`b6uwuYWhtg6@6*z8 zw#QZLLa9Bew56*TegrRTdfd=xV{m9K_Y#_)>*03{*FyXQZT~f0??{h9t*>R~TP7iH z+1Mag;&U`sL-U%+LY|rIk6XSigQ2KWF2wcmkdg1Th8j7JzG4^zQz~(aNVFi6AP18# zALUJ51B6_1uKPVeL)4@=xOCSSwhZF94(54ZLbuD~Vx@9<>|2d9`G}-=*g2Nv_gxON zeS#4CmZHBAAZ?5qYeqjKk{%o4cO!k|HMk?l5k=g2$&R6;?7<37?rMwRm)l_F3a;MstD1%kDVuFZ=d~L@~1%+)?BlXN2wq4_6pjW(+fn~PJxVgbC*4I zZD|NHrwAOkgTACDD)gW;PN_SWOcB}_#*DfY%m<{{*v0B71=<$uhPtjaKR&`2gO*+} z8D-ohYtVgpqWp9It>@IGFDphw-fs9&-N%hCOXJMv$Rn(-FcM$LU*TVWPtUOk@Y{s2 zBDU7(CgCyGT|KvTEfO`?g1wJ(!T6>UT@9Z&bE6HD+@ddjMxOA*OV4b-&@Cj{;K(wp zj2kWI!{pxMjRk3)>l`G+)u8w936W+`lZBpb=hJ_*${#-n;0`Wj5!2e}ly}UZ7X;xK z3tdkQv0D$m4x0^atZio>I6MqFdWccmLl)FFx8r1hLEB#A}dtjm=f3>ZT4%aFG{6zJcT>9>6NnGXLwi1 z>V$Od=p()Ay)ZrW)ydcv6@H7^y|$v16xm+3`G=QTtO8_A0}J-1~QS8g_x{kZjV{nvDpHZuc)-vh_aNWRo{@;Klq=kZF-wf7>B zlP{JagrKn~FY*_`pD*v^j5VWk#dEK|fE^y}-cesJ=kYzrL$+=(%uyA5Ipx1HS~A?2 za-4^xX&7rLHZ$p`HBiC&o;&8LFZKY(YAj}sm`qmHEt#u3{Kaov;0@fe2OCRlLNLd# zXZ*h)0kEHSy+r{6to}Dl@XNVI17J7V&3~2E{C}0z{J)jeP-iZX1$4?0U@sRa z06stuRA+p^wHCSZpX66Y!Ay+zAk`N5lywaUN_jfn)Om@+x3|&I5F4mXBab z<6Lksp%MJRbO&Z&`h!wCfdW?&xDpN^h3P-JP=LEUpez0aTnPjhAQ6LsSSoaGkTxL? zAK*2~4FpI5$|x`ZNq8RgSb(s+29^?9$_D_8LT-=-0S^z5M+GE8aS3p;bMS$I;3~l1 z6MD=EPZXDl55yqx1LXx-9*`CR4OT0AGlM3kcZ);1qD3f9#t{H)^MMcN&n@TS;D%yl!P3Q*5rE=8<0C=`1wd%fc0Q069yieS z11$3YbGx~LT<7u{ZxY}gU_t$bfg5Pb58M#I>XaP}Xw?7SXMia6kbZ^31EK|@w?+`4 z)FQAL3E+pBKmrvvAc^~XkGX*s9Pnn;mw{ld1`*)Rq=WxlBrZ3QVhw!Ze!pXGo`+0p z2|*A;95x{$R6!W{RtO1zgrRDZSU?6BQ0)P}44lBn3|v!G}B3VVtg&9>ef_1Q z&+)e400SB%MrPaMiU*~mGeb6xH3Fb&F@Bv`D}sW?4!??t8uy$obU!w{^hpRLZrnUM z{roIJ_hL++yvJlk)mlH{CDiLem%kPZ0>*-4hif6ATX%_RP3%ynw%f26T$y_xjIg*9 z?hj52HRHKBSdSa8V4~|C#yzYdw3ipeh{s~6bXg9!mBCF&8C9}YC-*(5otH~5!!;#t zPqhhe4B>1vD7}20{fy0CosWmF#71!f`Bq_ZG04YMi*2?dAuRWf8$)E8!q<)zvcBNH zO85TECe%c+#l$u}?ne!73GYa9h}=hu*a@;yG%?)K;gkwVwUrQyl~i>h`s@$aE9gbcXbn&7^jm19(W;A#Q1a1bMR8zskfL+a3`kD9*Pgo0US(1>W8rpe zO1;}KcCxPKAZ4QT(1i@@wCR7V>-;KRxQ>rdr`X+&yoHi_ZpiFPj%LJCjcuFp(E_Oz{flVJ0VHxuOgV>i9BUus`%8FT)L zM1hg1Nf)J?;8pp`2qF{PyPxOH2+F-+5SHgt00 zr2UNZV#>`ctvHS|H7VZa}l0<4fP4 zRiABsR%1OQ-nxxgpv+RXq9}NXvQ3Oex%@w^DE-#u5)(2mkHyb zO1{tGq@$73VllEY2u?Oe>+bE#j{~vo#yqPp);a`sD9wgyqa33#9bUuS9U{)=ceOd- zeSA5&lIWs%)7kwb!myvU3l@i1wg`9OO<0D3y4CE5VxkaFud57?uWio$x^C>97`Ss1 z7b(Zm#IIkCi5g%nwL$_sZ*y*%4NQJwfw9+Ye?!SY1Xx-kZt!p6+rMGt?+A9G{|!ch zIsb&6f&ozX3r2zg#PR2cUo{VE;FthA+8cQOUT^|`ltsM~AO#@T0~?7KfC=D-N)rJ0 z_ymBzfvomr84x8D#Q-Rtd=tk~qyT)of4P$L0Bs#EKvTsHBp`9}K17s07=eGg2P`N5 zJoL$-aLcg54=f{~d<8@+{awKW92{8n&lSJK_Gz*}8RlCgrUDtj!3Hh|I3@t_xB!hm zCvaJO0I=Wz`Z#J$4Zp0}5uj`~fONjs4)8xem<4ow57t5?0Q3Uz(BE|rzCi-~-2b(1 z&;~?=^GinfPewVEQ$LvvIx7O;cX$0{LZ}Np6o^EX2f&A$elpP60@U?9P#PkDvt%z1 z+_m3>+`Ir{%$o4SgBJW}koR|UOAQt9I0yd{DgNs;uKLON@VuO0XgRMH0Wjm2dhuT~ zXpEByKwMk^)&XqQ9}WU|bp9I~K_3o+0Jt#$CZE5|H5K(hf2`Yo9i9t-i$}oWp(_f1 zE)|{&5S@v4V-Y~975`p6ClHzXr_N^bcMzVF0|3+jT?-z#cBm^cDw*K_wZHZ+zB{o0 zc=)0{k@?H2`URtk%7IVl!A>0(_|{!LX9hx;6#p8kUzKGQ%AitZK3*q$*;6`Gyg&Yq zxl}6_o>dap{H+#jd{1So{|!R)xQ)Z+Be+PJoNx1&4X|Bt^K|J=^}h8j*T*jsRCP`# z9vLf5&dSH;`=qP9eU!#{>{h|f2$8Z&AN*9Attaz&VR62xzWLeW+$~RehQWR(a}%_Ni9{7`W-R3uGoc zrVV~V2ubRFA@9ekUQ^cJmVM^aB>rx$E1j01MR7LtdgnXpx9yH{KAWr2VZKP{8??l- zRwTn06j+7%xD10C71!KDT;^uP8y*9zQNHHA#j27pvsHoV7QAgXkge^I)Yo5q(6;;Kylb@sB0Oq1xqxeYoohIX_nIM z&+znlhH!SpBe-vkh2MDN+9A11Qe|aD4gC?og_?6OE(i7#FsT&R5r3T)@6|3v`!dTm zX3y4GMA0iJ)#lrv6;rZP2)jCFwQ|hoL}og&=*WTh5i+-e)7( zu^Gobf2M~*q1y)*Gx_yPmj!_z!TkOC&7XCP+ zZ_e(cM)kgC;vJ05paX=Y*YDZi|Cwj7WOK}KcF z1X9AgyXR9_Mrhs;(Y{6;{ZTnb$NDA$!b2NM^7WJiQvQ4o;I1dHtOc$})i8H2*l;>A zVD^uEKZq5UI7^zMHOT;mR zGzaq@{yQW+wp9fQ>na!rtkfWS1zYQ^S}hAvi$}1VO-~*zIuU;RRK?9IUWDJGfU@N3ALIQ*Z<_!UZt(uh zC@*1^db9H74VI_@2iQX3xg3sdj})_DG_$~H{f;>s9&+RI?k=+h%ZpD;pFe&JFP!D> zkl0hA7_*61Gl_WDj0{h`sPAXWgvoV|I5B;S(o2i~K~2F?6-J3jgF;?`Ak5fMle;IE zQA)*ou2kU805XZfWCY(HqOK?K;hS_tRf)S97D6%R0KTF;#}A?Nrl>6h0^D zRzG=L))UCtx|WBvpbW0ZO*!J@BWv3*Rc1TzbrU6w$=G;zRCe!%is#g~Jk)IH=B(sa znGwDmx=5MjCK3F-E~a%LfU_8;tK%b^lgH|3QY|SrJ}bzm(CvXQx&k19iD%%0eI79H zV?l(Qy3n$9F)i|Tdoy~KwW~QyqxKuI4oSfJXTlB3ov*ddS{G>;-c!}IRfLwNi{x?` zM5alo?_jZAIZdAN^|lbZcncFs{Ybdb{HEF>r-SW&&u8dY*q8}-Xcf?}e-?Zzu@~Eu zNXT6+XBiC97afkfV}7SQ1dcM1ASe$OoY$*EEn4Sl2u!AEih9e6+JN|kaQV6KH#b|s zCmQACD{>P95Rsqx)70JXb%njbUJk0#Usk4C>PJGR$FjOqx zwKrYj5axY%aFswfOP$@6%5&709oh;TA>u0$5F}g55%{8zuD5P%C@+L7Pm2O<1^eHc zUDxu~uJBAfIeH-3f>vM(Db~BpGvC)H zc3U9)cb~~7pG=*t7tc%B+Q=Z`xK&%=6L602wn4u15>;HuWdC@Tp$*^S+md^)|2CiJ z!j`0;FSy7YeyZ(Bb8gkLB$bK)HYwebrZUb2oXm{ZWHqo!Iw^@j@0R+n!Gl|I8qcD|2OFIXNOQ2!Y9)2EPoES(Z{;@8!*Iy%5>S zF|)_1rFj$$HDcDWH=$As9oOwDcdG-e<}>0*s`YY?w^`4XuJ4g!k4Rg)Qpj3+inbE= zAV1Qu=xw_XJuWSGt>w$SHx?VijK0_7>A%UV`dPh^$w^$kf4OFR)9Y7=Y1q3+K#=(O zM_dos|CwFW8n=ib#u3}sF-ufi#8OGUbK|;_m<7FXlko7L-%~|aZhA=xESSeXc0j*X z`uboO@zmcGX87`dT*-Uc>J}6HKF@mr=UfowzEyu4E4_N|V=H~P`qbg(p zqPW*_|5AelPK4?B70b?yrT7;|QRb_k7gl~hATOB6(0{YXz)-Uki$}oLg!>oX`}fv_ z`|oT&aR;NbuaMuEEIKNkGz zebdMZb|3bN)mB`+=F(j#{Zq_Pg52B>?OMfco;^Y9}`b z7a&P+eUC{Fy_W%YBneq<*Z_Lwh91MivO?1ofgQv#79!p+tBef*r~k5-0RI|8-~+7d zxu99VUI7}W|DTs|0-pg?HJ}tNgGT^$wEEBZ!(k8}+)Fv3>ga8NE*1=2`@eSvzmAI! z57?SP+e?A`B}2e)|KU{l@H~8gL+HbalKu?g0rs7IP|it20_fD=AvggZ=<+>?5V~Im zB1ECdXPa;_|zlS0h66m#Sgq$@e}lqS1?a;ntW;cn}~Lie_*c|4nS1S>qR z)$orSF|iV7$~=faP*3Gbxz?{aDm|ofI?%~b$3!iKd&z8L&?Zr7iOLwrytsX`+Qo{Q za6Yat9P!DYSf;>h@t_WFUVo>g&~}S6`lX@wQnC`+6?QYR_R;5P4**hd^`g!WUXQRkUIq0z;9 zG}EMHcs-J}_N486{@ILF9laS|&6i3{IcFg5a+~|E=d0W27Tg9g?6xPh8nAK%j+b_E zw4hl6D`ZiK@SJhr4>Rm2E+nZ%HjibuJrDB1AZmtBhg6^Lgpd7?ng~?Kz$YV8ZOfhw zsV|Mw$TWwZ62&Hjb85Kbc^vJb+{dlsUEBYzO==KjFRZWxebnnR42A~rR5v=fwc`=- zL<26;l2CdvP}pcjK@(UdQ6)Pw=0xLa+O zq-5c_e;jJOGk0Llsu7%wL@?@={yMAOT#SKTXOd%4&PlYdV zZV3}n-c*s5P1Qh!(mf*BN?TKKm#k9xy8&cmZKakP!*`t78*Lam&RZmlBnTh*h>O$N z7)%~nQBgG~k1s!J#I^1_MdSLk@9Q0{mO-6nJMYxYj*)9#AXI^cQ_7OJ|9fs~3z*A( zO;sQ63(SsX+LSMJGwu0RMCGjD@J!hRcvNdM%eb96XK1q{GoXnSE(D`lrU;4`G~AB_8R?^4#>!<^%ExYqpthi5H447PPiYa z6VzcuXB8LN9`y(o`JsN@$)QmUk!N1`GGb=p?i0O99h^I@pEpWJvlA#_)4_C6 zaxN?3J^)AAm{5a`9YBGEOfGA!!eBqdB7(RT)0=F5oFxBpSo*zQvUQmJCh zsiJJd(Vkqm-F3ispM#(|g9$LXgfefu=K5#7i?ULr7y*WiZ*&60Vd1NuVkWo{1gs53 z!-1Ei`?oK{X3E#Y-RsO>>0bJUNe+-%DehZ%`mdRWIvvNOn{;}HFOC*))UGbpGxC%; zCnDTxzL!V>gCY9<5gF&CXIsf!`FsqK*p)jBMz8LOQXo83HwWca?QV zgUsYLRyyh&L_{21j9IJ8Vs0by&ayzsVxa@Rx^{L+GVQ*o>jhFwb})D2 zoegg0`Ho#q77C+noiy?Z3%84BPHK|vpHhC1;R>L5h&H9tP~{{}oWpKvLgH*il{d1& zrS(Q+Q?Rg#NcIgKWYpZweKK4A)2ZZ?D@RsG8R_TjZ4ee){ zx9p6{f)+O(ZE2rXwoe!9wL`p%di{4JkX!V~2bV2~5iq?S!CCscY|{djOWl0pR=Ja( zj^?~lk}sJmm*M>zLbmR^+La}=*po>ng|g;<>b;(elIUs0z~|UoV}~pw8qIMxC*@nr zXx}{3y(W0fpyTNzad^)E&YEL9icZ1v#j=vX@X{y$aet z#<#RCcxo9s5d`duDAE(EgMe=`k!J6ru5hXK|ZTDWXl z|0@my%te3WFrL4)VxVjNXXJ0K7znleGxCrD1ke(|zpdMVAD~%gczDo!YmhROMFxa| z5A@ghA1DETYQ}s3Y6Dn_!vH)J|AdGLMSUn8E7*V(N&i%iAEc(7Kt1?x?Sk6i^c-05pmcx*$HJC<&1Lt{eYd`L}NT-z$O2F)=jO;&)LS zi~J8fbUJ z@IHUF*#98Z|19|fQU9^zH$@W+)Lj2xP!OG(6-r|d|clDE-nKJpO$z)!TZ7L723`m|9~?A(&>L6{9zKbtlk?02QUtn9DqX?SpKKQ z54;E2Vm;2({cj|O+cM^2atv|+5xZp8sq{v z3Ba{H0NR`X3~~b70Kmys0T&NCZvfB%9A9H$G5>!rR{z7CrQRMO^D0N8A;AGb2Z3!G z%#ctmW#?25?B>JIOXI{$*llIv&dLheTFM5NF>W@#E^Uo7c? z9BxVSakg?<+DmP#*Edcmim*=x*Jpgrsn&E#<9K&V=Qhf7(n0Os|NTn(dB$}qG>@eI z`dDpl&Z&Q8xpG%sLB5>H`LLyqgx)eRT@~UjjGuB?TS^pL^ySvrzp)N;EST9f`le5i zm%I!HVSu@;7#%DI^OE~}PLgUcx%ok&KhEue)Jfa1B>VvDjiO1py8Bc_PHHb(I%$67 za4D2-4eK-FnWr0eg&04Sj-lEc_3`@K3#WLT2yBX3*GN9i=y=3jf+sM``$%`3a>5WY z!~%i{c!P+|NkmvxFz@d9mZIDs;>J_>M<t*?S(7UdU!5F6CQ^~61W%Oq!mboV2iy4JFhEW+BA!qfgiZ!r}`f!z1p~joEE&T}oIn;Z(InpkX zA?_ekvy?!tLOU&ATiQx@LEPuzMVqAt=$PzDo}iKfEWJ*h%E8nPp`Lc9b^&Jy=d`K> z?mNG)Ke!%GllsFLF?)oqzPZva?r}CbZeAhv6rzW3IGDK=F!&O*koS`#@g2`rVd4hb zt8ARr9t8H&?Me4sN6S}D12Pg@vtHC<{z%!K!zakLCJ~dx?8OAU!xO5OD>gsx?k~)_ zA2;5N^QEgq#Kk1N`xY57KGn->A{5|B9xu*W?2NF&iiw@~q9lI*;{Z z4gS4fgEBjSsG-L@aIDZ555LK-7}WT`?V&3jKm@@5N3LP+c<>Lb?BiES09D)m_pjUU z%^}(EXUBhU4*$ym2@cE$JvIaAKIzm522z~g-eDY%dU5kfYuH#g6vc$}YEI3~Np{SL^-j!l6VqYx1bl_DV-W=8JP0rwNK{aXY$Jdd4(!cU z0i&mfC*i||!U2}kz^NW+cK`GCjD7#;*ML{bLtn9gfHw|!T?5`u|6|a|4dmeoa6#Lp zu~>lJI~XdVM}QCPS%3R88W_6I)e!hkeO|hxSs(HyF%f6KvSEDDlP(x%;C7OE8E7Ec zm|wp}O3k*rcrn-3ELfdq#|T)8`Q&&$%ls1uejX}^=cA>Z{E3FN#sq{%G;>c)j^!;%g!Gj6WAYkj44ys%+EiKGf zQcQO#&?TE69Azf=_RtAh$?uooe$TFj&-f<)uu(rDBzWV?a(o0JFnd)eXKF)E=dW3> zkd2UU;KW|K*d+n)_c;jMU&vLL6O$rNPwm*ZS7_&i2{NjsJ}~nd^5+z$zgCQW}lY zTh$-^_lsIiP8dISr6GPv=w#e)qN<|W*HzKyn3hg2sLEo@r79#b06^@n_SqETdPCDA z?J8!-$d5Yq!(AiQ*uJSqSG2xN?U4w_`|)`qW@n*}{K=-}1?(FG+(@Y(lz}B?75cb$ z(d^}ccC^*fr?`~?XJw{Q$H0yc6z%cUcq0XWT08eYtlu1)XbuNPG{?F>=CRpp7y1$> zpjHem&1-HT=n*##7XZtPi_JbP-^#O%^!@y^H)~kF2Cvj@Y?mK$++00ejgCHk#G2l^ zh+eqNP3>9bxoVzwo0Ur(y;d%mV@pdZ^+ zO5zs8NkI&{miAv=Mb>4{d+I%GcllCmYzbct0-_H`@n7tvy^(~52x&_#5*vMrnerKPh1Hdj#a z;M<3NOoK1+^wvb3z&j$ktM< z&z`@UAg5p>da>KFLg1Y1_In#F8mI{`Z)vTa#?l*WIdM=lmina7Owm=tTQ94%R=z7? zK_6l@9+(1daT4~kvmpaLD0N3?^@f3^PHsP_B;?VQAyDk=M14YjCp<=2&0NBjX`;E6 zA5g|p#b`ST%rX(U=nN+vES5Ve*utp!eijr2*5X6&hD;`YXZz0kE&NNi1~|~@B#nmS zPWj^VgL9M4pRB$hyBcFehVEXNa>jmYM6K9PC1oN&JixX2E1JV`MIZDHPrGgg)qQyj ztblxirpLk0iGdO99hWu+92M5Hz-em995;s2XJ@CPM0>JmOB4@N+qt|dX^Qia)KmpR zM*L?s) zv7`e)ag4R?O2XV-5p)%}MJ-@9Sjh&Ds{;aNTe39&x|UeC@H>3uj7rV$U6Wg!XQZ7y zC#iZVz29Oh@qOkHodWs&^(E048Io!Ue(57YW0=aY@y&C^m#C(K!VbzjK~GDKf}!Jj zO9(p~@E^lD^iC^dGv_TZGAheh6*~-S>pNorgmz!N#(D~{nm$0EGP5CHclRY#x0!!mUO-9Y;S3UJ}20HyJOFv$Y!-pq>b?-2^QbS@e{3>RQ7O zN-Qz1Lhk`HdaFJ1ph;RX;F_$Up5p*~+>pLoii7)`J_O)uO=+bY^Ve zBN)$#okbFmDQB**5t_#sVl9(ss%ts=yvyj0AiR0l*dIR)yqV> zRrf%|Uhj3kX#nuz7T97c;OSw?tugNP5X$pCrS$naasxkbIh(n~D>PRy2PH46s)P(Kt7IZ9ZPdriYl0^4b{{0s5ctoaS!+=nn8c z1)@cy3>+;8Hc@{LY&W-@9&Q#i5ShC%DUNv5A|-)+z)e#TbBX854*OM&HbxMGQB`JZ zvs#U&p>Nav+}w>OwvMoOX=NE9dQxC!epi_gusFmgj804Bq$5$^cqpI+AWU_F`r?&! zEdpF<8r~_4pCpPh6p@6`b=l-gcUWG(4SC{$G^5m(O4lMh?KJKY>4CMq!>RmruT3Ra z^j#j(mzk-Z8~9r(ZM62n;ibkF4-3tTO(E_V0w-;rIDI^)B_{KA%0A^h_W?W7!U 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®SnRzCqCfWVe|0ROfWIYb;A*T~`x?R^bi=P9@ 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 z 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�f=rw3qCSlO%7yu22t)a@H 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%0DxNO>iM!jh^5xb{sD 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 delta 743312 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

!#qm$NBy!4@QmqbN9hO^rs&*S*wpUj`d|erbum? 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%0Dl=mqcM0g^!+(nlI$v^+ypnfC7w=3KZ|(VPZ_hU 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

k^T)MaXE zvAXre^DnuEcY}B0n4+&a!h^TgAw+H(=@^MGws(rIj*ugyd62%a4(Q)bavNx4)^sML z$aq#45lf-NV!RQPCw>@dEU!Kd#x0z1i+I}u4Dh9nGYd81RQ7JWpcN7r)!dL+vGK1(y>B=Z^$E+(c2_;?*5!p?61!|tbv-`O`!`d zUvzeTzwoJ2gM;@3=TsCkCN|EUD>hq=L|p&(>tSqEOKiuNl=-VhDxHt4g}mCb;t7h= zfZy~kWwY=-_sh@Iyl^s}Ci(@{pEl{Sd^@TUmX>eI$1G{O|x?@Q>in}BSi>zZ0pQm zA%5NEBx1&Lt0~c4@aIn-?El zsbQ|Ozwms`z0t-(1122&EFhC~?!}Q2-rp9YCJK-X_v%aV^m=Zy!xhYNJPQvKIV2dz zz|jt{cH7nd9y?mMRC3yE z3}cPxI?=g;RY&D==Jcv6|ys_Uu;m=!!dc~A{&ez1|2Wz_D#4i%8+)RqF?Ir>{#uZjK>uv<>!H`Oq z?7(C5JP_z`XFqhjQ{$=gt6cC`zIV;6qwi(Vk99Xz&QdN&Fi|rwrT~fqTEtNleR=CJ z(4!6>qQiJAE6E20(i}V(<#W4=Oq03_?}zoqkPuYA2pv{$bKL;XN#i((Jn5gZgk!#l zp|t5tCk0V7hkqKFlXJf>rU-lh z%~76jElu-TVf6@Ay#Sa+EHa_O(icta!*`6dn<)-Oo2sRlVV7 zLHz1ELUmr}E9c-QnK`2x3s+$H(`4 zX!E|}kI37on*&T;uB! znx~Oh9|eheKG#^G%?tZPMU8<~YVSbXnYIim!(!~|E2Ukq24&)7_jr|$P-#r6E8wqC z8xkN?xH5c=A4d}WCM9aoD| z4*dx*E02oZGn=Feq}m_j;*E?fNp|q&u?*xv z{cUC5GZkR6`|!q0WR1Z{g38Elvx{)dH!-hs#DmUz?ITbQhovpf52-q2y1tyfBO`EG zdX@6k7>tce&Lw)XrF=L#7cA8cRH8D;+NAptNc}^ftf4`hu@Gp$Drl;PdHB3wt5jdR7d=?}xR0Kw!_;}1%O zodZme5=`!yzi`4g(uBL_@345~r1XrKLZxO>Sj3_b%GyqFzj%wq5_FB*Bs8F4wsc;; zH0=(1(GO`xaJ-AMwU3?fI(K}XGD`YVX}El_Bje)q$6IoCP~=^6YB)I1Kz;_OD)@<* zXN^auhEjNx(Y@3gq#6wRo;w#sdDN+?=?1vwu~crhfU!W$(-DQ~3(k(e`;gSs5m{m* z4h#PwFcW!`5FpD0F;}?jwHqTtoX1OljMC?k$ivNxrW~(5(;V{!^h>s*J&^H%GXr?H z01`8%x#4%IEnSw?sDs0Gy)rm0Fn^w^F=oGoqD9t|L}q6;X5efasIARVk#O2#nFlx< zuTCPHU{0QoM2iJ26f?csX&BhSHE%c>k*s<1T`G^LA?##u>9_~44LmJMJ$#?t3 zcCt3(Is?qMyE#v?Byb#5@@wzD(|I3yH|GxdLH*JkAfLTedU7{A53pWq;#~NuHmRFK zY+!@54s=o)QO*=GuyLPjN5F^-l?Ra8`@H5!7NvZE!3)iagUpBoi`mPee)oRL&zixE0_LGsf={koQaq7y#9c}gSq4ePrX=M;cg0P3nC z<1QsoXuT!QOG8s-XZ^V5Q}nw`wJpa-fZt^vhl~h!L{l^LZ1qz3gNwKcVYodU^K_f= zha?A6Y|yAfxQQ~KGi->lt|VH9iQc4Mwyl2(^?bSNx@T`#!rP<7;oyU-<5A)nM>btF zl3OMiwwVK((~!#!vVpvh4i4~9H+kY4<^5)pY|7W4glI>Sl0w$>9^CP9+$&WKaSV(R zRV=R`_wGMsc#53Q{&8rSXGZf${{-nS&{ZGoevn3UgUPy~K?7O2 z3Y6n-@9Kr0YwNWZH)54x2RoN2g8n@g&+^OWA`YpEypSla3@6vTeVSAu6i#D&hokb-5LXnxH;brE*IL@>Ig8gWJ>X0%~@JDh?1QEfHNQVFug>gEj zootNcTEY+Qb*nNaZQs)YXB&HuhLd-Wi~?xSoLa%D0h)648*ab~%>5;Y{WE=N9sIE* z=4?64KX)S?QyC@Z(wXPZiKW)lV$q z`@iIQOE5K&rd#mE)apkwTpsie^rP3v{2t-?s&PMadUIgWO_SaO2sdY(@y0TnAn95( zMUe&W7Dwo>m`0tW`}0jhk8;{9J_YM88`27$*e>Q~FLcK7V8Kcos!~(ORXRxH9d4I% z?L$C}H29AEh^6q`UKwp#{N?(IG#-b^R36etL5tYeya85aA-lI7dgzUxZQ}PeU9S)f ze3NT`1P!(2j74b@0QZ^Y>(9(Dtw?W^(BhWKO^@T}Xp6cer7alOhK^eBmhMvYbdudy z*#nvhREQ1KdIUmqDCjw-A|CehT@{oreM&5bt6E*%a}4KC`!jb3%=}|-k|$OV)@I$= z!YoE?Gi-li%pMXMDn?^DVwKG%c`2N=urU#%8R)I&1ziYQ0D(`-{>xPyEap^H!V{s} zNcvmznaQ_0w0umLKNY(ZbDF=W;?78@%5Fj?1+HkjZs5ECDq9j(8}I{oJA%o0zNUBV zo8Jg^x-H0|XroXq=--Dovr25pFBmRDK}Y@u^J0e18_P^a6hp@`&2!4}=8uxawFP{Y zQdwAsU9nJ?2GHPIj^+wm>Bf{&9pq&JB$w|wub#?N{8z0wfBQqw8WS0rlk75_EN1eV z`{=?Gd3P3m#a6WK#6LNd)@)@te}BvCel4s_fe;xkYYq}w*s`3Zrerre7U6vgLGAsj z7+JWeMVb2oh*ciKh@@kmc_gy)xwlgPtzL0p6s*Du07!HNQ=p9PvYj~l4XGYl?AZj9 zO!_AHcnZUy9saR3ZZsmWn%j-V`9S0?YT`2doLeBO$VXYZs06f~DiOB{u)6$_EQ3qT zl4*4WEd6{i5Fq=JwT|TFc-^#)HP@EiIxOw3zAxkJT;hqvxKpfcfS1yydn{GQ}~H7IZ5jp7s75g$y{?uzZP-q&AYFIt`0Wk5mRorRsb zvQ;Jv6-AE?5}5(2w$Y)I^_+Dkp(xZF@mYq-xZgs1{5x&K!?1;lN#1q|qDhcHVHQ*t zDu3}|B70zAG$FQe23cXkas|OV7K&Ki@4U!Di2%+KUm(JAC?o8tFJ*Y$!iVmbru+6i z2o_)i$j5F4pdr0K-)B*AwZ&RtTKGuC+7P1j>kEYV3{TCP(apX8IBR0(y z(li(o>vwz;N8QD;VnvJOOs!gHR15e}ty_Q(OZQ;C z%W$z$@+HI7-HG&9x0s?AEzE=@TdwE*umS|#~;?+?<5_NO+0`xoc4X`--~Yv2A39_tn$tm9T1sUns?4= ztRBLDj^>Q}BF`_{BWN_I`Q2 zTDs$W8V$bv@wp6c9ZHcx$v;NK{`Wq@RA_ry6YN|p$y2NT(<-G__}3O@_R-eFjm2U> z?I`DY4y)BP!f4=Djvs=m(Qwf#{)5TZxhlPGjDL6p&sI6N#8k-}r1R7z-jMD|cT=mj z`Ag;bM{pKtd&m@>JzCSY9L=Rhj=T3pmF-Bo|G*NuoLNX5>a#CA`2_(g6SJI+QeX78 z>g)D}EqfQLWuntJ!|y-%XQG?G3RklLEQ4Pd8U zDE-2u+Vu0ve!A}WG2}@X9C;agm~Nm>#D_Bc7GUfb#wAx>XwKZR+GsjJ4;*{xMrTQc zRH(X<@~BEFCg*6!+3!;NE#{&n*7v?Z=o*A14mpdgQ@f;8!Acs7+Pa2N!?-UEU{-@y ztG>jGLXGQzc%VM{j&Z*lGwschnb^|w^|UOJO#(wJw-XrQ+Jnd&mjo~Ao=;8ppFP^oO3gZ=9V?6u}!Png}3I^6J z)k<}-#bKoW&z6`NgyI_grNanc0Gl^}-2(3J?rNn!(VJx0*J$;txt)MAm_~ye8R^lb zGB+z3v5>sSu0z~%XmW*V7 znfeEJ`FD(QxU@?Xj~k!H(Qz3Qmc8h@=Ri`XhhITM zS@Oe}@9IoPnknL#XshH*tX3rMnTR?&hHW|gl5n>Z1>5gLFA~7;bteFI9_yRPXAeN% z6@?^P!<=xLZWg8$ii9YM@B8^Pigo#3pZSIvF^urm>Zgc3?(||fQ^09E-#0i*1#F8{ z*%l`Dnlsc+r38z$J%*8M^RW6K>m;NZAQM-XethV(uH&1h^(6v5^*Doq*{h?U2P`=R z+Ktd8F>b~QXwL&PIhTp?h4p4+oeRoSg|7H&N1r5 z49eQ`DMDQMWO}6 z1k@PL-XHlwoJP{yn2S!M#}b47{pwEZ61r+i8sOf5kv2#_7cg_@sF*{~diGODy>>By z_=rb)_UD*KXr?UR6~4sf*r3kkr3mX@BFho zuTb`44@Sn!g%C|A3|-{wMs5n0Y{t8yxPxyPd;b`J@r`OQ>BP}}x$QZ-+_c zQeE-tQi_DHqWxe8H14s{RnYc#r`_}<5SV*OxdVQ#M&lbl-VP$EaU&(x^p;OO+o%$L#TgUoqI2k;lsX@}9 ziesusygKQVrNhv&eWsB-&Gd>NM%OMR77vPC#g-^;N~GfNz`QgS6{t5fS|lq5+^SFu zigx3MRe+;jr}6ImPM>ZSyN4KLMHc|Z`DoF>hrTx3Kr=P4Ko>R(lixy2*`=2N&+90q zu;3R_j#I7Ol|tzw3wLHs4_u=?>4JCLi&)256&4o$!`a@fVYv5jq70(qFMH}EwIY7r z4ARgtBeH#TK1?FB9(Wtl3#>28ryibJI`W6Tg@E&uPg%1>ZL4?`K?a6TeFqsH&A4!zm#szO?|7vJFG*~ zX6R1gDH}x{pKN5rFD{RFdGFEOv9~pVmT7ImgP~(qY33CCDv$W4+~o5?5e6%RLC%u) zx(Tp6yhWTUofdlk$1T@C@7p993^`E*-|>8&@Ub-+^49zWJKM4lZ@91f8YWRPPPhPi zA!_hX(KeI?%#(Cwj(j-vA?L-kyM)J$(WVyBjxgKPVdp3N~_vm7f@9G+IzT z^=;4!Z#L?MS~ejp&p2O{5?8()TgeI4sw{-@Q|_C{tuuX#N-^%?D7f1R371(w^G}7a zj!1BeevOSR+vm_!?rPwn5O60n`aW= zl3;M#g!Xq#uz~?P0WqaPTHl6;_IZD4wpu>abV!>VDbkf96);enyX>p$`8Y+L_{c)Q{oK z^fgc2$946$pMbYtP^*UM=U@F3zi8d^a1j`}v{$BGkCkFhdP*0&k@*`?bjWj*^M)7P zF>fzV6O-Q(TC`MtH(%TSvXQ|A98-Gm1X5qk&>q0Qmg&Zhwx)|DBr;d;Fwk*XV7kpt znkZrYjCLE}V#0xWmDJ03`NTY1Dn*md;ofBFr_%7{nSwUrGe!sI>g(1x8yDfi~f{UGnl*5XY)8fWE+Be`itx z-|-l9#(DPuFB#$839+ckDD8ZD0Y+c(^oe2a#6E7-!BphPe#hv9CxmCM{f;5^*fJ0;ixRSs z_aQ}^nmoqplbEXa7fF`@34|Uz9g_Pd)Wg$x{VHq%?^0TpYS`!9lpea_#=|}u{)w&j zAGhNiiYC=fR3&ykIQ-m){U)VKPa*CrnmRBe8UwApJ|PWL5*|=ISO6NjSlg)>zre7- z;L18s?V^HHTsmc0+CaXWXQ_Zh;<-gB)8(|@f{R+tea&VpO-2oFZShM#2LkfsjrPRhYHp6z%#TbMIeaeng8fCi1}kq-$-8J5bW!s2bmfs3 zXb0D~2J)h)DJg8sMnGG(uMr{iDJSE>o5ld+=CG}eQRUP7G0PnB{J}-$d+^`@%yBI? zB`!9$0-<78k}}foIQR&G8mg^>LpAX#Mw{2zIW@c47xw;vUbmN$uC`N ziZL=2G^dyQ1qWs0=F^i18l=BA3F0L1NlJpcUpzPj;CSH)f5 z7>i0oOA&=r%gB=^9HYcp+(}QmR^q&PZV}4^P8%= z>~5qE@mj+sLbp_-O>TL&hi-7v?>B9FFV{bf+R|uC4xvIR_+n+T^f_`ZB`hrWrAd5+ z>)d9slIgNo3xFtG9%drqILG(&11a3=pJn9j{%&4Pci&CW&fBA#1BdHrmNo16#TDcQ z#d(-PQ~ZNzjDrnT^>67E7FU9q>IT0?ca4OoR?jT03l;*BZdQ``9fqqkk6sa2^2q?U zWeKxH)+e&3Q=<81VY(_ns>34K4;4}F+*mCbVKCA;r2w`_^b{mqe)FI7I{<`L0&{kf zjAqq8lwY+Tg{OG{=ZR2v1cBawRcObJs)F+Ps9s*S=dS|<-EQw+rHd%C(zwrlG|Y2v zxdlFaQcX5W(-t$lNf{;?)cWJUq1&tfy}Vwd3#K!jcQ;+t&gagv1qPdJyX=Qy>6TqV zk@>`1ngW1WN-Vjifjs`JN1H>a$=J0_m+7r{NrAhTf>X!?9p@!OS^(8W5elAryDa4D zR%R`7xRC&F_Dddzy-mHpr#M3hOu7hC7KS$3^Y!;gu~qa0XG_Ejvbu5X_+Cl=;S86C zxb9}EZlAS`FjI;WjFiB^A1UP+=yX&dtYdy;7FK{gy>N5-;wZdYQSg(W{UDxJz9WXA zGuj1fbmF*{5})Ec_E8cPvPj(hD~af(YFUZzCrq3PJCYpDY&K41`1l7@v3kt7{gQZ2 zq4Lj`IkkL%=!nO{&CRi&;&=p@t(5D{hy(R>{J6gQpIyUHyob$BTi9DhoE$><5F5TI zRY3rL8093w5va3TVD{PDxn&Yn-r=&NvGz$FI%U`z-pj)DzXu&7uMGk?;vG2b=JfkX%uqd zF7w6sP@gtUjr-6pVm@6TpU=NVZtE1QJE~aLyJ90c-Ln<55ettLe-=h`VwK{oTK+m} z6m(B_i6~wAV7cF^CrSZN!|pyj)OIFH80#%ykOGw{$vi{607N&Mq76xUHcRP74S(Qk2d^w9BH>B9paaP-&RGA*JB@x^}=8uNW{N+46;|? zK8Ewv$`}=66Be9n``cD03Ecn6`Xj7wz)pKryklaiN>-#n@M!4BQpZ2mY1x?5poS4G znqCA?#Lu0K68yBAPZel1zUqNt4A7H41`O%BchQN-pqQC-mGahaJw!tMtTe03k^gj4 zF^2Xy#S?i9s81Kh)w5+#@JdZ^_d)svX}=#NK;+kaKQB)lsCkI(>R`3-xkQtapt!;@ zlhc#X_o8GD$+#b_F<~*yEB!R&6*m3`(+xHB!$^gzzY71TKEc7!-I+{m)7Qu!xq$dL zBMmMFk7_7hydToVt^5nfSo`a>wU5kBq zZls09quD`gT((43d6k*8SLHeV7IVr;2CqA*(F7kX_`Z*HY;^hHXBIg8gJdDoM?S(baV1httnSMrx33_*6BCW&w#Ei_jKUjZ zvw3OTyeF~T8ue&~)?2AYSUc=c)G7J&kAVAdJIeGO7hkDqnQo9mc!kp*lO@qHQB?nu zO>ok*_bjQGEm=gz-^4u zv(A3(S&k$yjwOG(Oi<#%^*+46fHM3l@Oww0($*hEUG!(IrY|r{weSrX}O* zR-#i5JBc#0KWz6iKP>8>MF?79QqK-$sya!@eeoRA$Rdq>lP0rZK*aL{S~mc4A+refC#o1`U-g@b=v;&9O_~JbD4BKjt1NB zRaF^#{*1BH!A)rr4U*(*D*8R)Kz6T=YX0@Swx87j9(9E$-d?@{-RGkuCjg5vnlDPA zdyj&^PP*Ec#ku#sjQd+v0hMg_qFQB#FLrLm2d4<|9xwRj?hUz`y2@~v>od+2-u~Zm8 zwuYqJ(d&PAKF5?`r35+JiL`VTDz?ySn^SuDQRl8C01&PLHO^i9pQhb`G+sm#?g5?N z)%iYpjT!q%8j-p1=XiF2x(7P!ZIkQRvtr)@+w95}GO07ykXFM?=8or{V-HD0)rz0? z2=#ITzZ3l@a6`LD$8lvnLbb+y3ITR|RAE5MBM}7m#&-e=myYg~cQ*Bth@4+rzvfg_ zZfhL3m8DVu-*bH@CSo%n$FMFbio*vMtvpJZVHW@t^nL9uHU+02xZL3T1o}nVbpH_AHKvpeD3Ma4z&&mw}(u0}2 z{}vQC4`6ar_M`sd-Fi7~+d8dyB~G~j`>8b&Q(hg8bO~KDwV{lLmHe@sR&IYbMDCOizay_U-H*;-}_o1i!4M0lM)$hM)C#9jh8@5N@>O|-GBj}WX zvY`>8sq}l~gXhEhCqDx~ztEyu7&A5k?R948fE^dfNw!9{+t~Dm*GsbQ!TD7pMc?fn zF&5`Yp*>TiJnY!a0EP8EU%byDW+93NQ+wJ4o`QtV9@0mm^!iZQpC?luqDC6^(xWEU z(*X162ku2^W01YS&$7G)LL^YFEyH+Dy0GJHV0amDmFP}j+c!{5=@alJCXGO5W9Vqp z)I@R1vu^MtnHinQF$(Dh2Leyv;ibgp%esaC;D+^nK8|dvE5@)~_abZ13CW$n_wx_0 zSmU2x57D81PHx#^MikxRp5qaIh zahS%@PlhVkI{8q7-*2<}UyGwd(v zuNI@{^q1CDx11-E8Te^KLkuNVLY+#GVc#eM)gD7+#%{LlvQ9s1ZfG-;r3i}Gtr2F# zk7~4*NUN)0HH6#V*z(aZ-Q8=c3Vq{W@nS1%9}4cBL>vXoO=MlnEztqLtL>_v$CCtV5oOg@wqMb zi@Htp?G~nLz%nZU(90sjx`zPTpb=;tx*o|QFqQGb4L-|n7=-X-RFZu7rX@G04}Fol z<2Lh&c@tS#KkMnvEO?{CjaB#_;$*L5=X-SAvrr%fJh^LdC?Z*N(Wc2(t~~J5@fl9f zTn(>O*2Q`(^D2e*oGBRi0Y75DSkNhcJqotgv3^b^T^Vvj`*GCVddd(`m?2|+zFhBn zG?_=YQRR4uXpcRQDwj?qcH2|4r$itrRU7JZ3eAnlI#394dba>{JDV*?hnAm>1Od>X+YdiD>|-IiI#J-fS`_qNMf1E=YeA?@R{rT%O?aC|yPsCq-Kl$I^eJ znFnedha+jLx^6e3ccN2DhWL-3U=rRDp@MvDe2A|G2BAl_>1so(;>d5dMoh?9}swdUm&lJF6aeJsiV6B>Gq6_R`Ep(O>((5_iebNA36sT0!s>P zGVDrzxGzqald3Dnuwe&g%*!6q9k(uph$7pDF^SE+t^879TK8e- z)TLa=j)>FQZypVbEE#)z;R+9@vZ?>IbG>x3p|IEGRX)EIzEZDO2M?&aet!u*G~E;(qHGDpBoxHD(FbVUuRxeTm@}@l5u#|rn+N{~W7)ztHqpyyhEdQuc-oG_^ z`tCt5O%2S~_aASl?-N-2eZAV@KPEmIl{$B`G^3qQ*i)~VoQ_6eY1=cmd`=uXH|5%d z+;!zwme;r}i`=7cb2`0~VUq)j-(QRBq^+&k^{{Wz;J6`qjgNbV-_tm`Tx@aJt%mFE z+8;x?|58mX>lU>b^?Kl)&iV^8%b&cRRMA2?ICu2DMpjRk#$FnJ_GxY3DBpd#&-BWT z-;8K{c({SOe06GJZc5><9OI8;)6`teNg=O)_gg<^!B5%FU$6NIE9=~_aY@=Apt|WaZ`1bqqm+-mK>;8)fUTjgcH}mV*4kvy#GWj@$SZdIepk;;)&<8RWG@w9d>r8i{2*J>)5>0@97zP z)9N0Yac0!k^#;>!-&&u(`NMd}*VCdtr@h%c+sf(CnE7>A#$VsHYw4Bt#$D3dnKun&m*&jCtQ8}>(#4FIG%Lit+43m zg;!^M`gm_y?=LlDViF=2m3k&$u6yQ?U1+DxCZ`spcTanG-!8aR(d@nYzSYM4nM+Jh zeF~rYx%<4PE1Q1tJa});{2OY|&qL-eZ4^50d+@9r$6oStt20WsZ#b^_*}m=Br+pok z6!flfR{Em*rci(lH~sCaO~@7bRdcb@K=pS##jd2g|QR!2?~ zvvqy6eMX^GxoE|(`+i=1&VQ5~idglrh3EUM$T^F@+qAUY_iNIOkM4U_hhkOViyK}a zJ4JurnO>pa%L2CK4SMZ%O!l3VsubKigQ_`_FU_V3W?)X?AqE{P!%7h8CDv9|4B!)(n2J^z|+ z-CcWs=s7Rq*4Ravb*r%n3gt{=Rz<01;`Nb<}#p6N2=K}5ihDF^0p?PtbM`0v3^uSOf3 z?{a$E%x${@=0xwytg+GSK=7zd>knS zsEOC8IqSndy&UW|ru05CDK4IRYtekm+%?<#*PLi^!DV8i*_dBr+?B197bg4FH&ivr znlbUAh0ncyUwUyX`wy5td+=`GdWZIJ$(q)rnM+;wR`_l)%DnR?+P0D(u>HNb z*_S{1$=37B74J7aIdRUX!^}HI2kpi$d^>#n*S@=E|L1pLap<(U!!Iw`lHTU!stjAr z(2_c7Z3f7#uTI!ED5mj#@#prBTU=iCb#$Bb!Zl9%^_Cv`X~FlNnD`+eF0jo4uRA6Q zK5L8D$6WsI{M7i9+uCb88oxRn{51DKg2R9pZTnu^yF|~Xw%==q%#1}b$xC`JZ658a zDP8fi*TT|nH-|cge~?{Vb9nr_(`$hc6XoW0~%V|{qk(_#Ah#T zD75cqlk_IF&emqrQa1Fm2(lV}xG3U|Tz0)A*v>-Sa9yhtD%sT*-UH@5EpKeyznyZ! zpEK=Zor`X?-zraQn9(Hdd#9Xh56zBybXnIsA*b*^qmbgB`=&fyJvZFCXzz`h2{|2B z^fOd!-deZhXJFFYcV=fs9h+)eOM696P^&eXvs8!^B}rLZfX_u{*7OyJyU_@m=?>ZHIls zUe>#D@yE}@-7ZY~H85c3zysH(ov`oFGbq&$CR_$^^>h#iO*t5O4?Pk|3e80Hg zhpscPIq~!Ni^KYMRDD1Hb=jE1x7+Ra4cOVXw%l!h zyl6>);l7rh7RGZOO!s~aw%y&KhR z%p?ofP2Qe$_EuU>X~HD22+qlvH}#pVWUj^hPqe&OTL0w8Df(?u)|QXmm3OROm+d@!*s9ZW z2b0+W%SY_5(b=!*rXvH!G>ThLv!KQGmULAQ8CH+kBh8NJpu`8v%ur&Hql8uO;Sd$GsohTj*bx>@7u z4O(KBYuWY7hVkD5yaIB>b;HlB5327~)W7coBgc{n6+!h0K@;zN+3Dr*Z0@v-{rg|moUgXNVKh4A&6>+CzY7#*58Pqb?E=%Gcomw(-|Y@qZ& zk;1m#xLHTuJXpMBZKp|>#;p3e&cCm*>#W$%STT2jMW=;I5n-I`>VC#`5A%9f1J)|+!;UKFXmHCpYEM<)+}i~vv!}_ zbK^(XTs!pTsP$ipH@!r98HeppmTt_hePn5A^b?asBTt`N_Y&EQk6$yf4(xHrbjz+K zBbUt^HOE1-r<9v8P1JNq`&LbUFLDe%S|*!!y}U50;(i); zX!N@IJ-=>G_G);ozu}K8^fFZ?Hukt4-68OhX{gz4%SX?=P3`xzoxkA9r^?z-=1o4_ zE^d4KJ9R%r*7jatvE#!^QDFE~s|f~!YUIVnyxqI~=B+NRoQ_Ph3u@7)UCsR&t#f;M zJUf#eJJ|iEJigUn=MFdLv~{2Ani0~wjg|SAF+0G$T(U7HTe%w62L-QX0Z{nD(6 zrg^8=?chvHEsb-xr~X*GIPj}+uTaH`&0Xb-dk-6V^_r>M>agwB#oc-T(`g@FoG*7i z>3Z{X#2u@5DF@Onwo-MpnS9C<`R%Gb#pURdW+NhZe07^P=l8n?$%aweU)+fAvEr$1 zx_L=xSpU?G9 znYZ8S`1RGXBk5=J-?i@Gx_`5L#iQV~)QV9?s#^B%q~qVIUq1fkJhn?z$(yOu=PkAD z_vUWPVX@s7UYWYltHFyueUbx@*mPg~(MV);Lwxhw(KSn&u792P-{;r-lJ<#a&R%Ex zo?G+9)S||_F}bRSr>0Dci#|5a_S!gok>0k;b?>>>eIKS5?k9gc@#BaVyMO$8KlyCP z@vqY^rj@H3x+~?P8U1URq=(M<&-d3h-;X_K%{l+N5AU?SaMYyR;i9?MYL#2OoL=Vr zLvp|CtI=?p5{W*l+(RFx*Jgw}5JNy}n_Hik77x=wY+t zV$6oTRpJ*r2liR(J3_By`_0NsZgsl8f5Yj=4%T+9dDzAN^RJ+0zUAm=7wPw>t!vJ* z+jMcddz$;m4L{buIFOi)(jG)B9z2h=*}n0kZTzyIu7|xj^F|Mvhu-P9`kZ|2{S)_( z&%J5iXvhbbE+@wtw43RCP+?QnV9XKQp2|8iPfYGJ=)%RHjm!AM+i&l=l`n2C`P?}9 zy7~Fgh;8Pns^x)m60cSaPQ1B$QS0Bg{o+Ke=dE1V(zIy((-+pgi;wa1)md+I(yq;Y zS^s;*u-v9~$`;?_YfSmGccoHolrp`d*6BVk$8QPf?d*}%Xh-d?4_}2CYZlg8Ti+^2 zBzrEp+{St3vqocI*LO)U(v;npx_r{%>kaoiTh|NfvwCcs*)KATpQa2_=CvK4IQ9GB zBLgR??bAKjWn0;Ff`P?oL>9`00Xc(Y?1^`2GHK(TcrWeOoPFTD#TF=e4I7FMTX6x#C%S z{|8lzgPTvzygqbtn#1RSS}FJLM7^2N=k@LMCw5t73j0N!D?8jM%5U|y#@)J$j-GCL zW_{uLdY^WcA5bKiDT_MI2(7!kclR&0lRdrXUzi>okz~>_vw`8y53NqLN?m{U;3IE` zv0ESYpVrK~-Hko%qQirK8Fr07yzRrRj;5Y^(zopbAM|sS^jf>;W82?zLnF;wJX#+yd#*9;O10#O+{_-&>nEy1!Ry?-YB>TkWTHeS3dt-N4|P&0&m#+sKMxx}s>k}zw+D!h#O?JJ|MKc|H~LI@m!^5IyM3u+ z=;GJ@=H7n(fU4CBYTjb|khgKcC(j@9`LC*Rq zYvzr;UcTqzlC&`c_er0>jomeJ(23H1gF9L$1(&b;l~?13khFrhm3t1qU0gXT zXI}TGW0I_l{uEspWBzf*#@i=LUiUcP-h5W()Tys-Z}0JGOJqG`#neK}4_AEGd_37; z?A0Dwr#AJwHf_+v)pgcp+oZ49QE$xr>rY<%Xi+rT##hyD?83@E8ONJs3^f^hgu8fu zvG-%Eb3JT+MfTAj>bHBH=kG@?P0xHvTe+(6RBwaTcWETHm-?-LnE}uQ)x!w1^uM#JYy6mez`tX1u(|48LDXDlI^q^?s+h424 z1#X@%b+k;Vb-cB*OOs7!_*bz}D{Nz~xz!B66QwjV_pui`44&_#?)Pc!+HGMeIh8*)*i3xAW6u5fXxIJMdX=9F9&tWp zO|#y7z<5*9-alJX+$)we_wm|M**drXx9$a33qKAmF==gVetu2$Mo^waW;!1X12cQvWkBzr7F zvu`s#y)HQ4<4N`wmuL4Y7Vf;XZtjANu7$pX`22hQ(mHof&*>NbR#CZVe)ycIP;1M5 z7i(VFv}#!K?XxSs{#rc7rmf?wW&S>UQW`9pU;cCI(%FT}uRqv7qVwyQFWRXapS%BO z+oIbyUzhDg^C#G>S0AYN+F?oeDW+m~uPd?Vuh|)n<)+7FSRcv1dnIgN;DZ+Z&cyHQ zqbW8yyXfR&p8+phjY=yne-ZjIKlCCJ(osI+jaKRD1WEM zSta9h9G`!6o1AX>s72C7AD5!cH|ZABFO{c1`~2>8o>TT_(=&I9!rFJJ6_oaLRKlAf z+rv-2$ou8GvfJl#*N!fkv*yfZ{#0d7SoY3Ud#~lzKCrdh?gg`ac(`S3R;`z9wR=fM^mHkO8@>u-y#@!X;_H1ll??p(9A&R=AoLgNg zO8hkF_7Ks!xSdUHr{3=#+S$iucGmz0>l!NWEDqKc=3_{YP{EuXx&WRvo$)f%Ifi4ohobG`bNnb)6YZghI_ zf8N^$UrIf^_fC`c?f1R>uKa0yXniv?yRGTRdvbG%v);~c!^Qka%Wj})178Mq+|YfU ztWBes*7NQuD#T&ef4G&-**0PHE5*r8jSa74-8NXh_osVg@I^zTgrJ?J*}w94_@6QR z&@AW1lq7Gv-z)CMOz$3DHdQmD`;?B8OGb}3y=}7dKkId$i}R9h>`vT&anAafZJS5; zIorWOI7>P?B`Gdu1U^+71&%5*M3ME$NvY1}VQt&?>eR+3s!iuG_}HuG;0ulg`$Nye zInp)5&IkODqe|gxI`}M9I2^Qg!Pv0#%aYKSap%lY>0mu_7H&byljq0kSV!t<6>m&DL>l?xiQDz0f@gO9-0J+&4Eo#<>+09{5lK-NYR@VTW= z?d1O+SqdMl#RsUCjx0{|M(2f-Ncm`v9?m;wY4PzYM=QS%DYi$G{4bgoz`3^jJJO?B z3nHHv_t5)aClCk4``HKw+SWvG2VbaN@Zd%9uX^a*$YOF9F)}v4@Y_!D54UOsob(PS z?iTo2To`MKdM<PwSs3i3TJv~P<}{bmQR+77<3!&IT= z8eK8F0O$Yu`Ws=g3V^J(xyZ@lf*I6ZlR|BusJmH4z)QNgvEC9iWB z@2{4Z%+sr-JzN@<4gv%qBD;c3D@z9CAxRcBmjYFbi}m&4>rww48mm+lfCkFrQQ~NN zrZk$j>Eca0<-bfS@u9S$f}G74Ed$U8bA5Uq?bVkT*PAN;vZ>eNqCM)nahXxU%2yZP zH2r(#F52hF9YQuOc;Qt1#P3-)2p*_Yu-b_;wm{Mi4BqvI+T%&^2#@qpYRC#-n4a#f8IiNni+&bYzaD%2?V>q;4U=EdLo^(bTEx86LxhdzN zuU4bQO*tP!DgH5_zkxHF?5A&pEZcFO$k2}y>4{MTKh6h9=9$=__|%i2ZY6X^!cS6k z(2r}PCqcOqt`+hY!!0@LAm*A_%c}_z+$-H_44mp4%!$wuG3Rce(kPKz5a*7*i#dyb z>=VxFEkpC^^I;PFyc&&^a6bR*(M$fE43$ba4Yf+K8YJ}cufkYoC<^QiY+S1m5 z(t1XNImas5D&;JYo)#ykFv2kK z{nyaTdoc~I4uU7J@w(}2#K@!>=WhFt))nws3^?RmirNJOW$+0JjBZXaSEnI~S-Rv^ z4;*rp5?%47%D^*f>{KcXyW+4gpNh{{1)RV zpcUpBbmWGnwBqWZ;hMjUXVe5q=RXHYuWAmzzih>M5$>sn*KYCG+(ztRAQ!X-w&5EW zds~C0C#yJ{e?=sht58r=5Rs~l@T?m3ZUfJjDF1@XjHwO5#hh8=!#0>JgSK1~Cz|~K zhbY`v5K=?Sx{zn+Xy^(YKT2&>$%)DO* z&c}{cG*xjb)M%NZo;&*exRwzL4CS0!sYt2e7aAX%Eb1*)i*be!N!1dJ04|jDjz-EZ zNFR|*EW>yDpeeUOt^Wg@Osv5o70D!|`V`5eVr<@ULE*||5?mOGWHJ(M`=HMy`u`i8 zT#AiVB$Jb{E|Mu^giM)2O))9d><+=*2i;eLng!}YbeWYY#T2trLOUzTryWExrIg(v zpGFYw;G}~(PBU;p7TNZuNEFH0MOFt%>T-CTl&o-}q6{m^mrX=6_@a>DUvNRbInk#| zK9;Fa<@#KQ{|Q?~3Ula3{2VTnlu8we*l>qoQxSPogN?tnB8Z~13QNh9>RqNHUuXdU z8Y*J7gk4A}18O-j0GV2W<)#B0>bJ^x&L^ZAT(z3@(NI}y#1yVZjICNE(-1KT7evH; z@6>cbeZ6ZF6Rl3FMn>t;$QdLi7!5IbfTUtS{SPr{G$^tc=Tom5sTyXh8V#;EL~=0{ zUL(Ufdk45Aq*Y~EE=KsfvBa`;#3>h3tC3R|0RSWezy#~t2 z^`dIfH1tUcbrrdUnkQTkYnMw%gb~Rl!~**ui!KlvN~83cq0%ynI68dtiAYE;Q4z(+ zCDd``67u;O5qKNLD>&^rW)4!P*j`9Y4@tvXi+O~aX7Mnec( zFhGPhksOpoK+B2XbwI-hI^Yvz_S9!}#SDDXj^sNd0E!6*uINw9BIHC$y1>!u$;a6v)B_n-(iHK9->hi@!t<$(HSS&6XShN#Gpisl1&ic+bTG5}I4 z1~rqhnwf^0STg#)$I3;Rgdq{9RdtXgYXAi-^r%S$hC9plxD9QvTHFM&dV>FVG# z5*kuy))2`xj2;d1EDck>hJ=PbsJFc}s|9o!)+i~T8ZxE;a7@cAF(|}T-3l?uSZGU6 zYp{HiIKpr>87joo_Z4C}Aypx!oWljXLw!LZCixNl_P23Cz5_Uqf1uH*tYAq%AtB!? z7bzrUN(C+$d>Yiz{o!_?k===yKzr0Fj57~WNN9djNNL%lkW%ARNNG8xkW!5(q$Ge; zHAVOscp}Uv3R-EXP{?RLhYMmd3K>mK3K`hJGKqK; zVNZ!uQAbdym?Tux_Y^8-Au1Y;6)Kv4U-eZ$(G_Y+O+{d{m4ZbLsIDoMYGxs7n%fn$ z8Wh3Bzr=w!S6|h`5tdLF0`)lwBnmYXx|({LLQUhBLc^5J;y{%WS)oCaZb_Kox*-Y; ztp^kuG8hplG|bpEO#K=%7=)jQlk132gWku3TKzh67Of!tka86+D8DQUC|DFwiYaYy zfo-%ZG^JRAcJ%{r;?A7868*3t%p!Yqv zxNjcqQvW|F4{q(eNHcMER}?6P9>p}3!oNCk%S6RC8gF37g!>w z{KhOOjatAO;iFz$!(f$^#%Yz5*6J!L1y>)bvFloNh@Z*9uY&f!`=@ zIZY8NIW3=5F#M!|n1EmmCETfM>nd1GisgLKyJ!rJ`UzA3lq@+7hVaQ_hKLRlRCLs* z15Kfw+;GMqAtKN@4X7n3%L=AJ1x-^bHpYVsj25}SK`>jkg+)byIQWT?0=b$n2FZ_J zP;Z8rE#mPoO2QY2k6Z==*Qi>wJ`o@VLo}e=vGE>EgfU3eBUMTo)Kp*z{|F5wJ~N>U-&S-_y0^`#||NTp^zq^7fg z@KIw*x`v2TNBSC6_}jn%o$L>BOU1@Duu@5BV`Yk3Of5?-rlTRaAmX~zels2CV<0fE zOX>y~5E8swwCnvHK@ z{7a=EBg9wLoLVLn=BIjX<(WBxmhww<=9tl`OzygVrs@c2^Tu>YeT34x=+p1~a*I`6K z<{NemfG7u>EhxoMLKE~*h|&w{v1%oaqG~1e3YTFgz5+h^lQFPPOzSwfz*Or3+kKXJzBw$^tQyQY zHBv+Jq7ayZ=y*$5a>l@ktXI6e=!$lwa4yJgC>SxUl@Qy7 zJ5dUxHh~lm1@mf{a3F|b)_{l|rT`SEVhmRwoBY%wyzXZVZeZjSPqPkD1clo0H}%SkE~izGIc0rv}^&F zAr!!L0({w7;Mj2tr2vpn&w?_TumDR*6r_d?0yNZcz~+fjEE&T!6+~bG)RJCMdJ!a0 zKM^Z{5{R$_WegD^h(spf4SCB=9lu(1nD3B(l^iZn1uD#$K#9NtSa zDuHu0fI1UZPJo+c<6)Z-d~*F!BIhDzLjXv}6r7q4tlt|uc2Z10%&h_fEt?42 zl|=9(>>d%|n@j+tDh%F^WqJ6O0aI(pV>96~5zNN3S!}hMR;+MA^aK~^{RG%kq3*YB`zfg2K`{6DQi4c&DjfoA{(; z;X#<&@exSdQ2`TVyC-vUGxmhg0bNOhPuc4==WS3(8Yl9=I?@tCOj3(er9sJQFvE5> zjf=uK8&aHf;~%4qQO-zEA^)kcC!qNhPRjNOGFC~BL5HVsftJ{|wa8%V&orIu?7^sI zz(@~Mzm74OJtQ{cUGza_k)wHAG%X$WHkeH3M0FTR>@mGNAcNQGoXnoOr}9749-e~L)BlIlj2QFBlJsb$UC7M z(**P+0cz2cxP{tI=lngZ|3(HITKvEzn$86qz+>qCbgnub@&ifp@C&bt4~Dc4T9h`IGZ7v% zK~3gz7M{$+DcwqDM?{D4FOsYTVr$LeWOk&;W>SPX2!V1mXAUT_+E2`Yh~p?>|Hhp; zfZJy-H_)BY$1t*I2}YD(0aDAK3!7W=o^o}(q)K8dT17+5Cjz4sYEaohq28FsNgVz@ zOpJ*pHk3IJNMvy6Pb58P#iUT6(s@9lcs|z|V@BUHIV)>s`HWaFtGO?Mz?~JaLvP)D zP6{|l!K@VvF+@~9gA3GkZAfl}aw-+r2sb(dT>E?m7v)FF5G@d5p?{fXT`AKt^xm3x zM$I!hg&ypU$>i+JDNtIyZ_k88^)r);B)qsT;w-)XktDM<3KUGe(wcXIEnMkQ;Mda^ zaBdDT-$2Dp#YT!-^nL*spf4Cl7H6xKAtczqEHE{=KO>8a5!#ou4P8k7-vKRhUqodL zt1F~*`wM~wBr0#13D;3JVDL)<#D~^kv5N9cGSWPi6jPAUZT$h^P)10^NupGPvq z`aG~1yL>K6!1sO)=jO?nV6xOrwnAT=@8;w~zLPV3Q&G}%Yq|=;V6~rg)2*Jq%bkv>w0a_=jK6YcA&;1ufZF0I9O#v_ z7DT4)D{z2TujA}sEE);H2HCFTJUnQUB<#WXuc~#+!8JnGajl>}oV|`40L>fHbXt%9 z+YJr!+5nahc7nEUMdl^eW6gxEz`;A2*@mna{mD@R2Pev`{n%M&38YXzrNoOdb-frRK zc1*?;6-_fEwt{o&DuZP%5&~ckBRaMfD?@)97JnRR&XdMxJHD9-4f?a4iwa;7gy5lT z?97C;qF@xWx{gu|$R1b%#YsCjg{w|kP1m^?Ae5L0BK)(1lcV6Bf5R8c_JnqAw5Hg! zFsM~P-09OCe0={-p$w3+&XjVZV5HhrT|!bapk$=LQXHDK3rpzYE-Vbc-MCo<4Kmon zQn=;-)VxeOj3TB%LJ@?D6V5=;m_1NEjVR!(SpN93hx50RvKoRCC`WDfa;>VRKRPd> zB@RN=^1USeJ=#msS;#){_r3d|3?Es*S^DYfTgt)`qmUUdrBHz`zk_nJ;eJkLOcyxO zrv2a@0L#OjQOG*8%8GPG{hfGM^cA|=OPS&+FLd=_`~fKF|M^WP_eml56(4|X0goYz z0w~{83%FQM#s$O7vMMDTI^pR0p@7z<)>67a^jA_yc@XyNE6}Khpn`;hoYX=pVfqrt zL<GTvWy};hKB&_4*gS#!)$^OJ&@hu ze@byWMa;;QfVIUP24pbQ+j1Bb3a$AOP-yBAuB#uF6cMU~88ju6@xsW1;I{M_NEpu&?-`PmjiA^^&APD7fpE8;8-gbBq)MWD~$ z)-Yn7RR}SkX`J9@ntPJE%j>oDqyl%)Ee7LGmb^;? z3<h}u{fDMQb~}wi#8VjQ<>6z<;;1+Fs$b4Ck=SKYjr z4N=Jg5Nuwe5)Sqi>X;YHD3mEmXI1ke_2=Fau&%Na5Jo=CPrx!i9Us$vOw&xY3@jx8 zoD3p|GwON~DoG8q157;df_)X;xCpjY)%GPC=7|^yJg7kRInb#B4dtL#P#}&pVjlmO zO`6Z7>3Ip?JPHl+y$rFAQB1M2s7)w_G*dO!VO)trfZ|n`A;MSdsxyZIJqgi&Wd_k^ zwHZt$$geJ-7K-7US2(FL?TWfxg_;2aqjSU5 zPX6kH0n-WHuqkVan0G-NuL|O4NuLUW*0c?;aRIg2Pe37Bcoi0VW?$nZ27n8dUDu{) ziH3y|N-212nIXvP-ZcR{vqcJ?)+imXR|}tz=c~qO_*a8gT!+X}aUEi`fYK6BI#O9N z!WerJH0&1496-=EM+0ww@51v-Z*ZB^wD=}fiiGZm z*28xUvb{0`)R%u7hKR7N`qzQct~(I_-0wjAW4DRGV1*OK+<}Qb0Xo`# z4^Xgt%uwhIy#PhoOh9qw4wRW{W;{fNuq-TKM6K^u3;q%{b0UfqhE7ZF;+p>MU0lq! zya(R5;~wP_T?S&bbEb?A=3K;>)CwVPx*)InoYb7|Hl;HN5f6Y@uK*aqoVs6a{Xn8- zCP^uQa^k~%oQqWtfD#qTCCx9=^e+XvuD~C7Gl)o&QNxUqQX@l6g^9OT4`Il(>M2Z9 znZMx7v31UQ$hiSrD0^MdsfV1*j44168hZZ-Xk9n~g22E>oV%81B2c<3pP7RSX1fFt(21W#sBc0Kf7o4OfUN&oD#XHx8l~DzH_kweQD-g!Amk@Ql zUvhp95+(CdDhgsbXwyqBuujz+D^ZEjLTBC%{dx)W6B^X=6?TnPq%nAn{~JV_V$w8u z1LnE%4a|?ToIr5UcL>>B5^Tezf}=c0koi+c8CGw>9GTRFo=98{=D7Mc)c$MV!aNcc zCG5>tvOdKiyY(0RXlA&GByc?=m00X?U?;#$-US`4x z?Le#ysVlia(5LtVfX}D|$O2HZP6_W_=rYILhT)K+KOe!8D)hjw-c~{`(RN@&k)mk$ z2N=caf`X~;qaU~^k#69E9S1tnhNo~&7JY=F`$Idv4h+C_$`2(|CL@VaOeHJ`PAJ({ z0swmjiwlH01zEm8Zl9_TykYdLV-&DU9*y`!V%wfiB#7DlN7`|;y+>RB&*c7UXpz+y z&{D)VP+F%Su;NUK)GkvHA_eFW&z#ZBFPz*~M@b4A-M)OOp0wy&YApIHz^mJS#Yt=a zSL}-wr0M((|F@qsj^FWr6G>AF4GRCk4X8GmD1jGds;WT%j?2hXKVY#^P=mF0#+CMf+@h_vMUPu30Y6OULXh?CH&&-5ciXl>r6OG6s*D~U|{hAS^a{NBK8-Qx-8Wb zZB?83|J#)ckrn5+e?bIgB{%I#YxDNM!PH?#@gFetyx*LEbqp*N5@NIrP_4mI#gZMs z-8)0x0{#BY$qccoQ0gD9jW-$M!8Raj<*bixXoKa6B@zIES0^6-fx21{CQ_L5b>J;0 z-2|asC?WjGQH3?{x+IjB+QUmeRUMgbW?53g|DD3796bX#8X6x~=c0$eXy&mt6fuJG--m-dng}0ATFDoF<9|RMu&r8hdW`0`n zBpC4ah}Y+3x)GbcD9S7t)>)910WXY;x*6~T&^ZIXGsfvhcb)xxu$rJ)@xui5NLW&C zR+ERN6lTZN4oI>@M{0to*iTec5GZOJ5>Z*A?#6r_PnMvWDs?lh96CT~az)ePV5MoA zA@89(%PwJ?qALt}9AAx~in22SZMQPwg#VOUOvtuhughP1OTrdsP(F8cG_7jxrmra3))h4{ZK3GPX2_GZ0t!j~W zBeVkkE|?PS)CrM~cA18fL^oD3sm0m}`}Xuc`X#8M`uiI^)gtIY>m(&$EkLIRAg z&BMCAzr14UvEhJ< z0|vsofH>AiLL)rTw+PT!E8wB}PdW(}-cU#9tUz>5)_fN~hKfR|7VWePK9p23 zDqFxg>r14l>=T6Cwbr~xU7hqs-(+H*P1k79AM3xCLNS4zhTHI+tJyTH#-KtQK16$) zhyXTwAv;?>#J?K3Oy~3|7MrP{wM#pMdYElm-4ZN%oGmY}X3b$#lFaQfnnHfCs-%qYRI0W=SatoM$*f)!bm9Eu{* zi4XIVu>z9O#*k1bF!zE>q03IZG_cwRFggdw%vrk~jDceECZM2n6=J3f@|*|5syMiE zfEj*jGSut|F^G5m*G*YYpgcfmad&}G1N04afsg|2S!j{c6$1KBH^~3Y+$c3LHCMI9 zgB_%>xaWelxC6$m)H-2gYVw(g`I3oUx# z&JVO^oH6te`$;0Y56U4KFCMSM&A zJnCPMckp12&0y<#fdmO&fO18=1SHICjWR$?5jlDO4LL-j5>QXPCsYK#>x1wl%z_yT zX2L|5Fv^$(!n^1RMThoLih&H8kiQpT&=~_kT0)s#6a%c_=)_$uoeUuxdr^eY7bmC> zUcA&?+gCt|tUx4aKphyLX4mCC*fs;o6-<$ws!MRXdumB#NOUa}0=EPtbS+a@n)+OiSZ4G3#4_`sMHUVC0iIgQDFxcqD9R?a%4rR#eK?X0V1PrX zl7MmI*#^A3a6BDMf4CsMhP>DUUJ$18#$xep1Y*f($V*`eaIzuKcD}(IJ~DKvArzh} zWZMXeu^El{C@pxRLv1m{sAQp>P$@vbXumh&rAEXU(NJ#)gN#ZBMn}b3@)%U+b`+{o z7%VuWBi_6m3dQ%{yeos<3OGpy!LIOjE zgOM{jw4=2XDt_6ZJ zQU9jA8|1+^oLU;97%5LW6EA`7n&yU%@+TiKnP_^1nt#)29K3@t}C9q=-bdz_G={p|3)UQMCk} zYP%6)Nx_MBwX9~z^jsdQQ&_!0KU!i-Zs89iRiS01`AnLq0DN;7Y0Lxhe?v)g4jLp0 zqT+53?}(6+h>*>y2ue27Fd>^&#~}%$;RO|6iKNQTWjGBq3%q_$5bt6Pixs$dat!8! z9cl2@PT~_#Fv7wiBsQ4$6XaJ1O^oDWc?LpDPB0&5r(*L`SS;{<3I^CZq?)N~Uy8xh z!|Dvm3gH7$X$T+IRA*jUMBgoB>eY6{i++!`BsK52fEre_;`^8jgV+T#C4k%l8p<97JwEYdtBO;CG$GmkVsNYkSOzPTS7 zcHwGEG+H&21F)IkVK=}mq!TSY`T$YRD;q(`R2Ad4g@b`VBs5eJekK;wOq ztL8$IsO-eM3jOMY^Ug+uRMah;Z*Hk828f@l!y&XoYZd`yL67(0yr%;-NF}pof&tVg zjFh4yc(L$gW(2^d&Uhn&Z!X-kjs&8?OvBO2&b(a%65F-@L*z@}VyEE>te9*Oeig|} z*t9=U5)H9`(G9`S#9yShdZDaLNjCTtYw2^UkPt6z_*$ z9V5SCTrxIgfx*Fm4TVPW&N%qv?XvLlgr7M*K$A{iF6;u77p-i zQ%~N)mBFQ~>r@G7%12nOT-OEsi9LpiVG9s-x>k#Dy2}s3`arL);L4l2@|`d?cb1b0 zA*|dXxS=>$&d4Un>@2~y$&D6<=waJ65mhCg_B1l{Qd>^0~PS{8WpVXlC& zYTxdlSeg4^6@Uc^ua7P6&Wo8?hN72z;WjV zd9(Qm25{SHJ|CzL?>$--Kt4{G&zm}8Llrd&4C~P?urutXj7#!{Bc@9 zeBRlayt~;bWJt`YW^Ll*hR24*jDp9+Y6&WZ--Xw~CW9xw&Q zmtn0@qo6+=`vcaJ#XI(!xPfyFaK2}Z#wUZ~;Ml>cH{;?4 zH)|CV2KQl)0HebYm1gl?sP}v(U#EqFz?oz~gB16W3n zY~Iz0o<%~Sz+1xDli=-pCE;vMHeVn4Er8CCviVy5NZzKxN*aG$Pj_knyHKO#OQ896QCebApQQ1kFy-ZV`jbcPfDh}Bf-3_QSn zN=23XGT}Zw8l@^Sxp1Gp;a~N>0^g_Ns{%&}_my%zCE}OEbjGhG;Ob_Jv{b2tUztFw z^it#dxYpHSRfF&UBN>4SI60y^b5cPv^hBvu9FM|{&JB#-I<1x^)e<~@IT0WTLtUb07}%Xw3@0|BnH*_3}&j(B66e{>?% zpbEs>cM?<}Cj*bFh-APO947dWsAU3I8hS266~bi#LmDaKmV<%LTnYq?T}%lukqJz} z`Cy1!$~!pyBX1dK6|$WM{Stouhfo=)4^HBf!Yhd|yN2QSTgH2$)=R*5^Oo_(j{guT zm=7HAjE+GMr+$P{P?{A@!5=U)ZE7Zgsy52zxSH-dbHZNhRn!2S%dQTTG+(3wTsznv7I1UTDE zfkrO>UnmtIb2w)Oa+L5hIiaEoBMKlG&aA@7nxRVwcu;_-VS||%HC+Kj(tKG3p9%%S z4=7;;Z$ytJs|pYN0>+j9^b(v8BD%nn3p%-i_dpw$0#CnI@W%fVr3B%_aYQQQwh}1# z$C)6``N0pU?@He2UrSK}`7ku6;zKLJ%F>qc9wtg40q#TT0)77nPH=Si8P+QEcn8OS zoH~i5o$}DLs*f z-Vx#jJLQkvf_q8@I5D;hRX$XX;^p8ztBygzH6oukiKS*rV2VNU@HmZ7^qye0aIy;t zPxPK(vh=-XMvqwVHg+ftLoe7a6f6ssm+etSKJ4i-UO};UhG}^GBlSxP82E>MXw=H- zJzyU0={yI@23D!ZlgGgLB3JP?#)1>VX|TxZIAGei3UHP(oTzjaZ&F9MmkgCbuVBm& zsk#|M63h@iErl{9!3@!J%-B85hZ4n{f(88ktHDAKu7o@)hQ#Ap~F&nH%q#y-7!BLnf zW<77yP)Ck(%!aO70IHCeFlWD{m(9?z^}Hogtl?dT37G<9qys`BFs5QDoM04E2Hew8 zqe5T|4!x|ZZXtKTJ)H<6Bo8>$1Erq;2a4YSdVB|{#R`Ejc3>Eli$Y*bMbCy}_XK6Z zk(%hr24Gf41pomU)4hcmk`izA+z7}vtmR!yg!BOlm!X)AyiH5p9+(Y!{usrn#B9)W zkJvrT2E^Lk074i93IXV@fT15KaF`O4t{YpGm~`FPsuUCiXHQm@8gvCdbd;dNe9$wh zCad=79;U*|p(l*8XE9gw06KOLb48}hSZGjTuIPD$>^ZC%R^k%_ zP+|7qTW*39LpK9z9;3z_k~umpNX#J{1d;CW7}UBt9I7#gy177&In>PsYRnxJGg#mT zTLAT}4ZL$>HRez^VyH2P^mHo94GhjAx9~PiF;luJK#iHAN8+)^F-J<`n#Z<)dIL6s zjMbPadI%VO6mBVCE}^O>HJB+fam3`I!A#Nf_E=ZU6q$0%5Ujg-S z4Q7fB-ibUlSZ%tYR)aaDN3AhDm_uC`(O?dB%}s;ZgAemz+`ij@?VX!==b=C*d@ZG_ z+Y4z6xUTBqQZeRQC&C<7O6g#m5APN)uam=Ty( z(zlAJ-NErH_?`}D!gvy%)8R~tIn!}YIGq4LN1d~9C)jN0Hs0ApiZvu0Pq&M=3D@CC zij|_1zoodCU`Mx72}9V!BC+L zi1OC49$Y}cxpq|*FT*@Q0fK!(x*O0P+|E09#{)~cUdd!A!%XQ!64)z-NzhRgh!B|4 z5vv^A9L$>*?q){%TELaC1AHGB6l!|*I~5EbXtK{dv3poI)c|AN=u~}DTurETsy?Y4 z8y<)i^VwGp1;WlfuyeSq)jI#G$@X6Ahyh~?XQmA!<1}-VoWVMfp8L0#-K2J9Ye3E0cq7zs?k zhXHW~WV;Wr^Je!ES*M9Xn783evC%92|e8xSpUdSTdrNU~;fP31BeU^n#FW84R{%EIW{Dle#H@ zi5F(`O@bk9vzt)U8zp7a;69f$QYaBuL zzY6Szo1mKJQ0Pgej18)K>PW^0W!}`4p+T8P;fPV_84LLlBQG)*j{O?y=vE+ak*$Fd z;88eY6ne%&UbY7Ir>D3^j6#2oj~Inf_Tq?(RO2{g?=AQO{{A&ce%qI2Dj0p!sEKBPn*FhXXFl0-QW{j2b;WlW0=>rLQw-^Iu`n95tF^&wSM0X!7g_ zUVKrXp0SXZok5v5;uPWA^VlXkgKD8fZ~6w1{|e;uWol6D5jAFm=IvARV@9F3Psz*7 zpsh!t%nZuB0hgH}&?eH0zX|Bie6`fGXv_%oms439Y!HY`{bs4vQ{}+tARrCP9EVsE zDGkg+H)`+p4YN!7g&@80Yo+eh1(_Cfo2IfL(}I0Rns15^U-m7A(+KlyAReQz>gjn- zwrMLfJ=ozc`4(c^{B?A2L8b+L``8+3o~9xhvDHgYEpvOayrrpRXv4L>miav}~_rq@D4NVJ+)CQ6B)^U6eN&NICWa&u6Yp6|T!W@Ya3t1<9j z_%>7L;%^{P1(_h!O^ZN5CJ1F7RiMb-ERQIeifr)wG9xth8{6C{$N-_9_H3Q*Yu|zI zM|~6P<&p1{8a=zOAPa<@phvST5XwB7rNt@Z-Hq>-TH8Ff$@<{*Eu1*pzYCd9e6zH0 zp$rg;yI3d;F8ZL768ca$r+t3PO2tAnL4}OZA(5&dK&5`?<$W z*&d_lsPst6?x4&gM|KBg9!F$%P-YfrhdX#PG;a7dY6<2+kJntb2UR`diTA;XJbZ3me;Pd2J_CK>_W=DopxyP~E7ebU z)&(z&siwDnNtB_*Lxx&Ic^?;;KvA00Aji646RN|l`93`U@-6)D?C%5BGm|96v`sT# zLQGMbGRZJSX~HDJL%ckZqE&7=ilTM??(ak9dAF8&HcNgfPg5cB<+a5$M`b}%0LAh`O$(ZKFxHLy(OH-8Qi23Y_ZpNos zcdq(hfS&w)0To^G<1JBl3>Zae(P5yWD=jAGvg4RPHHPM~_8XJmQm&3tvlfTU{~P56Mdx*rnMFZ=*fWkK^!LK-R+ zd7vN-)EsrumE&mW%}>Ycj424_rc1(FOqrX9jG~fdz_0&dsplMX(nZ&+U z{_-m$nxZr}&0Xg&yE37vl^zE3)Dig*%F@|C0c_*{GH)Q2Go>`j=B&e)m7>CYb!?B) zMH(>d?{tv{i)RtiMH(!g012Ts{}iS4O`vWvM;*^SrmGrdVO(HDzl>*Er{&AMbV*Q# z@zb1iaW?+G_3KW2`AN)Z4#sR>d-G3;DB1EOoYIf{w6tI%9>Uk2xNh6Tu8qW$fL$aK zlqjv7umzIHnS5HZNzo5rK)GG2K|6>gfG-g3@%7{Ch+ zuKAAAkbCD(!meuFTka^$eQnGZI@r8r*RDyz#?bUJD=0l@=fvA6i=PQZUc{YJ1K zDV1iQ98tSr;%$@D<5N2#fV@~8v24S(3C4UZ4!GHHA?)D%E)wdEau)K`6DQ#TL3KIz zhJfBb@iTh=Tu@rDC!%KK#IC~lj%j1jSZu{oI8;F`30tF>f!n@oCl3RN^!QPWK7B|A zFM2Vq*GeZZ+Od^DLRAi3lyS6?8!ngn-8*h4rtasZ2Di7&ZJZb-q8N8g?p)Q+ku)|6 zue7;q%B7=QBUWwl;^w7JK3F`$Z*o>tc7AgY>OtXkY(O= zB0pKF?dXV+$v4C}e)Xa+DMSg3RrNCJ)|Uy;0dk|e<4*R#a~W)a&aYwOH~+lU_p%JO za`CcXi)1zKTzf2T=R^{el!7>=yb?89?sEHoPWN|(-8Z@t+}fV)8$HeAcGEO zrA3B**{FCWF=j@~OWfCf#ai$PU{8^a%JT);+Cn}#LytKtOO<_S7Dds*F4hhGx^$Mi z>F3xE*Z;b7QW7}2aSPFZFJ+=mO>^kOFz|3pOo)A&oZdRVZsV!amn^`MtiAlM(sK8X zU$A)W_)V#H?uipyC*_pF^cZxP+*MjaK+Tu#Ds?Z65m!&^rglzj2L?Rjpl8$_yo=yx zB7a}Fi<<^SP@Q>@?goED;Ow!#M2_fqA)$Tu{{}^L^>0dzbg94V<@*7R`+igEXq0P* zfEbdq{e~7RU*9pmmgkO%(pRIqe#`ye*BoS`pZeR<@|j~J8{9vCN$e&a*R@WcyJ7dv z?UOqx-Lg~BnS@BF)%LM5lqC;*#yUorZ(#MDnqt8r4lvD|4ZAm-%ShBlWg&--%w5-gQy z;WBC!-@W793E4HgE*0XjY~zmc$!$Bf?A$^;@HmmkF*ZqM_xig^E8V`kOSSW+rx{0h zYNO!Z{Hkjg)eV>*yf4t=OCSf+a{+m18^^lx=-Ch zpfl!-c+x1Cg5j>YhuL`=a(cw(om-eUa1@c@O|4kPh~Uk;w{JwyF>_;Ju}#uZ|DPjf(Ro zx1Yad`}EZILFOHS!)f5>O}_o@6Fbd#MH(X0H*B?S++x^wY=zIv*1WsvzS0WpFG%cI zF)@D5)+vNNX7hPd8>Y8R^ZfY;a=kq6aZXG}I zwuPVL^Bh@Z9C zw&kM9P44}_FRjdlzbyow2)2}%+lL)f)7S-DrX&z7kNWJ^%=>cJEKmz8yUYGiT3kEI zQHOi<{!-VH*kNF#Y@OV^d7QxXNtxY|8}4CfPX1%54aNE9KbDrfF0I9OOm09T3HnV>I|`-q zNh*|L;*Ri=LbB{gpm(r)nATwg)P-tGfLi8-I7DCFmU}_q$OlSYHE4mCJV2TS;tS7y zpwv?rj>2t&aFmKl2o z-D3}iR~ihDJr9=Zmd21meBu^cFlw1~TQ<56AJi;ZHr2kEu(vcvr*~`{-!L_016Le# z>mFj(hu__IA0m?gp)mJ6#ELgE;-2GMIQQDEtCk4ZuBnY7>N)q{_m@_-Pw(2j>D;NU z+a^s*^PZ+j^yQa)t+Nqz8~$p3b#2=jg~ZEe9N0CrZTzilU}W#}{zYnpcW<9&?JJnx z@|OGP!v-m|VYi;yxX^I%7BIGIAw{DO*z-xl;m_KvxD7_NBbt~Ji zsol0)W!b;^&+Pn&!~ON2iM=&|)?Wzd!Y%Au!;Q`K&U3bIbKm_VY_IuCX~DT^axUDt z<(zYOjlXpRYauT|#?ZFzmL7n3RDDGJ)V6IC+u?_v=!}cDZ`u;=nYfn|&zPz0=NZ>R zyQIw!Id{Y6{P@nz7fCaDCxH?D13n zTAH(z*}zUT!Zihj1(By{bM8BTtKH6rGzgGvoyr0vKJ50~27 zB5HwWm{_d{nTJ5;#fM7`d$d9lz#R?*eMMde%A)a#%3#58G2XC7WdP$L!wMm4Yj#+C z3>4MFuo;ftv`lkJUz=zG3c^pV$4G8kI(&tGaYId;;&|;;5o^ELpwT1!yBmL`)Hxn4 zx~b0^EFO5MP!u&2YuG6y<F|~V_Wi(w-KpnD>OCNJ1Mp((@`tUssV_u(QLlka(y>tC_w&97nu8n1``Cyi_T&TpUp z30dOdPlK7pG=)-C19#+KOUv8+ZV+{(Y0&-8V>lNlA1}2WG1Q;$XW{1lM`RYK8|3>X zR;)Pg)W^AtN&M2|rM3nUsY}E6KUP|@fF4tjhv9*%eYmuusnU(gxLimF?uN%pb@4m7 zsaB&Q=eSZ7&8O*$+N_YVp#k32^AxndhQL6mJUDNzD@7i!qUMNtB5iyq|ENiu~tNKzIkHXmaS}r zai&GgqGW3K^!U~Z_9pm63ht9nmAa3PnX&nz@oiI^bPtv|XDh72Dump(Ij-t@A7gOt ze5%x{%eW6cMf$Ulw{G3vN+h`>$}Q3&D5Ik`$TvJby=&qeF`dJ}7%jdrSn|SQE%Br_ zIo1A#!Bud%=S!`NX@?E7WeO`7visDNYHy$1y>nu#TktqqM`id<)i{nUvZAe17Yb19 z%v2c)OMp~0b~me-70@P0d?*-~u}LJVGev|ds%G>|ys^lA zp#}yqkWu&fCrc~lg;;1Y9ARb-{(9A!pTcXf=lN2-`};pjquuf32x}Au`!)Eu-HYy$ zr@6=FgVAS*;lag0iEd{rJw|L-|MuBU{jGH5mCu$MaAR84Y6x%|&w0T;3WU_~#$CW* z&Ic+Y8JELk&T5C;yPx5Raq#(4cPr=sBPLJaNss*Z5PX9e!a0z;R@JX~MyD#2pgxlk zjye`a$-XsW6@3Z&NYc_Eggo)mqQ9%fG;#|5kgNYk2>vughk8}~6LE>FqXNumi`_t# zVg`>lFo)dyXG>Woc*flBc|YGyT?om1Z|<;Y)vY-wTncTSQ$EKbF!+Mm*(t zcgC|Y=-tnj>f<ZW zd#+T!DkBYi)htLn!WGbYw-ln?9nX~-Iy176>(`KR7vbVVrS1g+;DIi<*F9ZYb2@9Q zYQ;N&O3%VQeu6xOu?8$ky_6Yc}&248i%7p)IeOJ)GQEsNg4XNvvF@SkRJixk|D6&f(cw|009A`!zv} zM72@a@Fn4XzJJ*L7HnpPmS2t&(Rb5eJR>c6@f*i{h6kn-xlNp@O|e*9h(j`Bq$n4Q z*(1iBNz0GEy6c~1{XlkfmHaD8wNQseZ+TLL9Y_Di;?D@!>wm!zVc6JAM*FFlo*~;Hpq$787__g6 z!#776IavWbZL8seW6V!7hO_OH+ka(7WcFR@=t*-UO(&E{4qfuftaR+GB znxU7^L!=`OIvZp`j4=lXX9gXe89Ilh$8=Bf;$zEQt%b191R7u6uU<4 z>ekN)*7TY|MDwa%8R`+;xt~!VbgaxMurX0i9^niZ#}M@$RBu2Cu|h+2)#966WBt6S zR}-u`XH0TW2u8d)ipG6RDwATr>msI-isPWJh)NZU%0lehNR_L;p6xxmffIBsydVO^ zm<2S=yJu^H)wB6av=-R+UP|3J`<&pbXf4EUkO~B53dQ~up|)r*#8GRN+9H;9mzmRz z6$Zc*BBSn(nIR&g9T%iKyD{i^i_e*2xQmaTC#Wbg9W)%%Gc8c3W?FE^>SXgl<}>LtB$>9v$)CZ;6!a+mC11csjnX87Hy(Xc*mzaKNpAoX zJox4|&JNa0jN15R_iYBhnB8R$}ML-W~h%K|5Jqi$bQ(56I>q0}3^7!6dj zE6xd4&l(d2MegXj?=%J7rzhOlnFL&6;U@rgrh)-!6ES0I=Y<>_Bk#$1$>uOt%pLqY zZpRazF4cx``Y3mGbA!YCw`|``o~_AE<0r|x%nD9)P}p1L3kgx|3rB%hH3v)TL*BcV zmY{86?8QuK69%?R-JpO@XbBb~_n&A9x|^f!`{H`;dL=D+09jub7mZuH_>_Q?y2+gc zGIC-~cZoXZ6nj#cw?+!_c4zAp(UX&#r`cBNxT<9VmMPzdIE?1+MI25Ffp*&TZJpk= zl@ouQg3=~yS%Cj*UU0a(y)|eegFKDKM!2s>2l50E`#qu`?e(V8hF!Bhm>xr*^npZ* z*nI{2+dQ$@N^Zs?l*v2Vg1I~nQVnv*T{J&}C_9g+_NckmEN-EM{cdliUt(E-L3F{v zV$eB@Eh{yKFpr*Z4SLX^37l5?5oOzVZ`&}r6RKoboYVxA^`pU@T7J?~8*TD#4gV}N z3gR<&zg59)iO`RaWa12|@$(Fw=O?Lk9Nq*%R5(&|(?^N3(kn*sA_9d(bzxXjcB`jPga z%Pr{$8eOg}Xq^>VCkhT~4O$!dX~XOW+k!TCYez7P;VXCX_q`oK18EsWWxFlNX(VV? zaNlnUR=Bel!cu+~-N6ood&oV{KQ@wMxM;1X1D*7QQ;lA0I7GRoGw3l1QofKC!J>|w znrDV=u-{#`An0>vEDmNhgvQXA>tz@qK!Y;IJyLZD!1-N4PY95;!T?^^WxEgk-5_p_ zacV6(+Cn48C&c|%YXpa`wKR_5nA_U}2M*DVjfF&JkT>Fju0{!u>bNtPGDZiwgITVw zn;9V)VlmgCv_p>!m^2uUPd?rjL0xu_+tm?vuXUX>8)4^uztDt5FaUL*`hnSe#+^o)Hp8kbVFt5M zf7m!IZKWHJ0zSKKox$MDe1E|mScH7o81s5LGU^^(6bo-?@QjgGZelTPVOqAjOBV-? zR|;>2Ak*ono9MDmxo5B#l@ao12utnu#X%Cvml`L)!z|J#xzm>f-T%iFHCu%WZdrG* zxXoNCX_$O=ukH>8W)`61opj-@Ut*%zvLdidQTVsfl>AVzY*QaNVee>w*qJ?fM9@|* zZ^_88>!tg4I`K)8AH$v86AaAeFJa0Vfc4gBrYUEqQQuh1OJSna2@&YcD}uI0yH3e2 z+G;e|B}zW+T^=lHQ&(v!=zP>2y)Xo0#v%+C(sdznGgbzzU|_c?mGsAmQnM67U(d(BXr@C`5i}?F0sBPwK_YI zw6v-ZA8GXdGLU9*d4x_vh8Dt(8w_1oEwKaG!4(YiEl0xSP@+tBI8TVWMw0xlIZ`|< z$XSxV8GqJ zGH7I36q4{DP*a;Th?h}eB8a}xk7dTO_^NM86XHh`j`-{auFaf`X=r?R`&U2>f0!_! zB5qlQO~qL}|17GuZbHu-w-blmS*wGdh1I4FHEi~huKb~5hd1bU9cf^=K=tl5fRSQg z8yt30T4S=T4sBG}0ow^URGxIB3PZl(215ZZV@GfncwfNL6m zN!=8!n-EYlP^q{}-8%Ykdk2F0_Gq`{4FXTH z^ZjU(w)j3*s)B8gvG%KR;EN3wTjFj*A~RO{?pCZ029Dw{iR@_XoAIy&8F5%t305iA0vz{0pI_xiQjTa2;!yf5+y6#{Yu}cxK%Rxu9G3S-~>e zp?ZKcO`}*ykI^I8fp^o?HRXePY@J1I=Kb}dkGcA_!N9E0jXR3k9n2$BIsMb-#%ahp zslQFNU?~jbu?>wTCb?C5kxJoMhmP44ZWI*V)AV1Q0HonE4R7cctl({0Q!$eiRCSXvD_`i)z{9nu@F*#}{qJ zsVl>Ij2U+WUzs!3{e4B|40BCm(-HQN<_;wor2~j6jtSw?ZHo_AKhS~8&HcbzA(4yD zBijaxDfr1D493Xw;#H6~)l)pCCe7{P10Hp^38gbruT7i9OIHj@GXZJt3VBm26(tH?;5BmN7 zr4|$nHKGM;*gZBJ^z=%0llu>Tb+Ks7)_Hs_h8s(v&7u&Dk3!yEnGXg=%=^RPNpv#h z^=PQY2mRicA$Ru(1EoIdUAsBdB==YCaDC+Io zHZgrZejy7C;v_P{EGi9S#GP?}M*yl)wz##N(n>>g6 zlT#ZlC>4EnVG(D-p|N0|EjzmMVZCVRbj`?qhzH!>3V&!o6vC-5toiefLRXw{6jP?) zK5|sBc!3nR2V}%;8j4|v7o1$HarbK? z8s3l2$4Np}v~hwMHsTs0FX;|~>SWh(WHl@<%+`>Eg>KduaLeOC-T9Kw0$21x^$~tn z;v+6jM_5E<^hBB0x3V5lEz+b>J%+1Ti~|UwGWbZDd*V$&$6Nu7&=_>T8^ft2JhqY} zNR{Fsrl=t-EhdQ%qB8gi9+B}7l|dTMWJls0m0^AmbM2KuLxEH$?#VX=?eh#`gh|fb za8$&R^GF$_mT@Rx*qbDX6E43ukOQWmWpQCpFpq@9k+M6J7c0XEwDR|fSU zlW+z6-g9(>3@M()f+S8nYAhCzOTz~nra2+sd9Gnuw}kM zjM#!@{JLWjzR0R&WTTZP>P|c$A|s88JOEs^^u$LybfS|zUMY7HVaa}fBG+9&&g76U zW=Th&hTW=T6S2*U2hl55u{B=v!mv~b`-URL^`+bXc)IyqXy6IcQo#2&;OxBWX zwhITd$s>f_6~_q&k&G?vwGqkDYiKdbpioE>l7v0zN-$|lqJ=Fg6Ul6_(%mU>4Q27H z5yXfOMYrzwVD(m=jZwklgRTja?Zod~G$%PyBY>hgNjVUeiRL5-HYyXH!~sWBS0EE4 z>Q4w(pQnsWXbKN=;1!1AZ9v$M(%MkXlTCRYNSxxA8PRbhT-4U+95FREFDHNz3S0sL zh0V%vL&6jv1<^bfAJ;|wh~^}tV^k)Z6C)-n6U~Xy7nO~<11}F2&jC~d{KA(&KYbQ> zF(^H7%5=m1ZI3Rcy5VxLCof8KL%tRdZ{@k6%x^3DaO~YUAvF%b2m_*vUK*_4qNFz@ zbMeGnS#QYQ;-dwrByaIVUrBGs-r^~BWsoFKi-#6Xk%7nG6m-tZ30{Q3h z0*5p%-sDpb9Fn$p1S^pwWqv&f=CY{|4T1?A_L!g?I7)gVCd|tTVuHg}FAG+mtBjIE zNnA}hXv&B)#NvRE8XKu=qWR=){HykyU;il4E(ps8o~OQ}>Wnh8)U9q8TZW2@*{&M`C&2!%2CBTzVB_dN-r^TbN` z{8`*R@l*22q0FkNd*&RXdNk|WHDx|tB9n8;J1>+#2x5Z6-jfgrU9RU+zb9>M~eS=Q_wQsItr;H_k??j&fUYO1_SjWKJM((f}`CL z7h25<8f^dm=M~ia^l8D+j9%Bhj!M6_N_G?x62=+C##d75P3v&Zc(Ooz7MNnz8usqa zb-}QEawnu(D(VOu4i$P%307_;j6;><^v+@5vNK4)<8fO#8Y%PmtrecTuzs0FkL=EA z*2$z8;_yQ%V7@_&u^4l~DZ#3j!CFFPJ$74uQBFnD{aAKR!s)y+4HdgPcjg&EYnumF zW(3y^LiH;fD}q{Z?>{wIy+~&fL&TeTy@|>Z&O@)Ex1-Zy%LLaaPuEz=XzmfDXRP>1 zIB%%#@`4dTExKb*3s!BF5y2IM^lTz!9%a5gKv0v)Je!O3cq;QW4N2Hk7Vi$j@v{VY ztk0pQAxU2fiGQ4?wO?c=8MvcH8cePnrrBY+@RD@aQ9TW2a^*HGgGv;HH&&JokI7)O z-11mQd>C@qu0zvUTD-A1vNq~QH2dp3x1FubL(4MbC23-!wi?ao&Q;8E`4UMl6yacJ zB~fL!`E(XwCCTHv-?xU@U&r%GlSeF?H)eEA1_+O2nGXa7N1<3DB$*GylGy^B7rclI z!*0nLtUIzK*hqL1ElXlJdfPjx&L|I)t0Fx(mNSpr?p_&a4G;QKV_EYC@yyyLE-#P? z5_f^bd6qygNrWBY4avhvhU%~k>^w^E8tTh+)OHXm^qq!~};|oCzB& zxgKw$r|F{!p-~=rmR>J;*f0cV`SnPiG$zG|)3g&?m#d&X^VF{~Q8$z3$tg{sq+&97DJaA%N_vG60 z?j?7bLli9WUXtB3Dig&?4$r7e6q7$bjg~!-q0l7;Vy@PPhzVnE$GXV+0Z%U2uJ`4pyG8rKiAoak_y$nNjfg zVtK8H3*K^Md98^!O;2d@T7!HccDxy)1$!+6L(J5p0ERrE+}$7IpmAq|;vpd}Fa^Cb zaiQRu;h2jmiw}|_fSS++p9|=w0s(9+%bj!OO^R^HxsSglSa}|KbZJ8DVj7&>I^6Y6 zD}jPtVd1$pubyZw#)nNI3i6rb(MZn-d`pzM2`r}h1}{co$i3>d8Vc>2SXn%h?d6Rm z&sNm8NM?KB;UJQEeK%c(h(fZ*Rhdg@a$^IVq=XIF6tiC!tb7B}s#d|nK_MIj347x# z6NAelX<4@v*p&GIMKcq{UGpZqS@`(6<^mz2oO$tmpyDghz$SMFLn`ep4&MkXXaZ5> zVFw}wJgaHKC1c#=@Q{-|#og0T9T~s~iGsW6^}*^!c~6MQ8FUxFIY?4!hnUE=!t(Rv zK*kQ?1D?FdMMJOv0S0e@*7v-*+%d0EamwhX!y8aKvaKM&r$Ka$##vEAr~rj7ubPY- z@+5c+mOaIV5f2gBQ(VUtyF2GrTry0-zktE(Wm*xe zvDO~x;8vr%_$=sNrmYV55t30R7U7MkI(wOeu+j8D!Nfw6x-ukNwiJOr9zC*V$PeHl zth~Yuu{S8PpK!@td;uN+%fcNE@sNAtn;2r5QoQlN5z2Vby51wzPGbE{I6FhC6RPVW z%-~Vx6T#r=Qfa8(1SA35`evCNBGPlduzR&8o_3J+G?Mc+9qbcS=9wYb+bZ*=(cbJJ zPC#4Txe~(&gJJhmFgRb<6Wa!lr}lhDKE9$F^4^~B@Q(O2`wBmR2HvZJy%+BQVNp7F?g?xuo0tbEAQ$61d=YsfnYjIQ-xQHu&m-Ah`zZPbggx~^K$uAR9X`@0v&TJju&uPG!Z#oIF9rt zvWzD@@o6;!21rbrSJJ@+g3(jJco16+;~WA;P|+R&A$-`p5!fQ}oaBT1)db!Mo&~3s ze+I>s3M)&ag;AoiIE7l&yV!tJ%ELkfKjg823uY?gN}Jq21~JqOx_Nf#29{pZm01nH zCozHx;pyI)tK87_I3b&fdrKZGWHWIp>X(U7V&$-bJLd^rgaf{xlQs$mi$uV9_uz@@ zVb9Pa6$+AAWy z_pc}q6(LF5HHCxcb5Lk79z=W$dP6&K^uQ;gJB zD)YQnJUL9+m@lh3^}-26`1g5)B#?6Kyr6S-0u*JrnI+1CWqr2;+CX9Bo(96owla@! zSvW-XdE#Rajo=7KixiZS^eRMP4x$v1U39cS9n7Cm3xXDWzDA-q4TrYM@}Z@M%R6Dju=^G$n1_n*p3unL;##`L2z!Sl?~k)g9&CSaEM#MmamHhg zY%Bu%B6+AdsEB}=J`Xm?-XbfJHyEgb5@@Z7i4bn*~41q7V5_1jLa>Zv7Vlg$wNXZj|;M~DD&%yN>0yA6V9#p zr@-L>a5!J?BA$Zu+Ry~z()I}F%2v%oOBT;4XH;pKk&T6B^t%(81Y<-f05H-AqwbSi zWvhwgB$0e5?XtHh^WhoE{<OBbVYesCSIH>@AYqd6Qly50^Xrwj$ZzX5(5=*{})2oC*`h+}!OllSD9E=`=HCZc*lA zAcFnV5l(wm=516s?Nym)G5~>vC-*jFk+bJ`6o%XnwqqJdbzujlDMPyGgKHltoH!k} zvh=JOl6^(J^k8vftTNAyg=AV;=p_`uP!1?}@0to$PV&%)DtL}&4v4KRJ;FTop|Uvt zph*me##ZJb2Cf_vdidwv{2!19pm#T_vErQ~+tSdEVC7~h-h#jBmfppxOiQ`cEu>d47Skq!CEi1EB8`!ym6)}M8gFv6ui2$F|q^esUJ5P;(g%j{@ZMq0LF*&_< z3<)-_*ARG^xORp#SD-@RoGN|(0!Wvt<#U<>XrpgBVDi}=wohtXRvZ3eemj5nxoROG)S{gDi(_}jiNLxmz&e1OUL0$OiQwqDwisv zqx!lzKnuZhF|2(W&P&6RYtjP->$wP>=CkxGMQKX4g~clMYKc-#-%xBjuEpdbIGY1fYZ#sBL6;uIi5ec-%@ME| z`rci^s!2r;U|yy46fFNrsCMl!(N;k|L54Zsw=4mIkGg&G$J16~ZP#(C%Q> zX6aI_%rxavr6g@li-Eld;Gh3Xk&@aoO{UZtDLvCjOL?-THG!KWSTXSX0e+$qY;*GO z;V&wE=dzS2(U!?jrf$JwExWO|2g~iCeU7@L|DC%CsQ=hoiE2Ij?Lqg+35Jw|;8-P! zfdbIuSSVeEK63b*VwO?|jChJc+qu?x{0tR_%H7K@432m?e}Nz;K2e*UlW!Gka`85r z9K&S4j&n`MY*lHJP7=kp?;TusVvydUYcTH!=1D=c)>+@~&Uc_IDV*j0eqpeDG4Ies zxgzaeyrs9?xXqHvay^qC)+o=t_4KxP26Inl1&W=TYPx0H#5vrY=TU%NmaRNlT=h{G z=*8{W^ikO^QqdB|>CSdRo3c$ROJxRfUs%t5_M+hM*6?ql!b$Y6%=AOFees<^$5|1B z_^$l2tGK@+(M(P}EVnMC5QG!pLM#U6{_Sl9*xulR zS$oJdMvGj0c9p6m5zfW_mQ=aqI2Ug=Q{|FiqOU@6NtH{CbFtD+l}na$4D^mymKQb) z3lGEEw?`PBBF6&WuSh3UI|nl(k!pWStDC(Kk#o5@n*2KELWy7+Jw|DLYH8uWEEF;lIK_;`6rl^gN#45*Yd zs`y>qvb%$>R;0r2$E3cxx4a`lVIiA80~t-&RHd9-dU4Qsh6zYK!&9G){MciaDmU_D zr)H|$#DF7(3tn07X%WyAQ@Bv`zIO&kx*hKg8tip-d?`eL0Dinm!Yv9nNx7Q>AXX$P zmn-Gq2`j2NDt`pk-HkT{JuNwTLsIw@+?(GO46wFYooK~Pbt#?@pWxQMhxBB1?+q3# z71cyOWQA5v3D&nkck_ElQo|KYgQk8xXhZJ~1{&p)!soslj-kxAUw|n=#kMw66wmd%Wd*6!&{0hy{ zCRS7>0NN8%b;xa}oxAZDp(x3d;r0Fyy*J9YK;02{6?I=)HD*8n=c+M~smxLzEsGWY z4&|==0E8Ns$r|@rjgTOu;1UzNml2Y!Ne|KDoa({G0~hus?+-fT$HP*ejkMSql`0=` zgFtozAK>!Z&(A0L!IuhHkQp?O(&bPBofZ~F9l4hM%a&8uE!9DpHt~}FNX2qtO zyS*QTa5H5K@h&&@*+vut@63+|o&8zmfzlw-EUSUE-at0*s?Y|qZ4ol#HtCn(SNDd0 z57y4Ih}R;w)m+mh{|D6;+KTm`)n*pnN;%d6&AO}b(te-Mq^WV}Gr1coa>n+;mw&ckrDA+R9a zRO?aqA0G|+yLI{k)G84nTH|Awl4z+iK)N-e$&0m>UJCguKL!eiK!FRLqO#e7%2GAl zIhV*B5pi;1EusGEtU1oh$o4tA@^Yr{ZWDl8KNi$?XBDD_0CSTr0xS?I_M#>)4F+UN zA-YxU(ZL5zi*EjYy8pm_j4p{H7aB5J*8+dJnwN72_Or5`d2O(;+0LjcBoI=#jiC%MtVBDeFedl|e_91%shWzvRM*U;`yZ_^>;0IT;PsUl}Y>w!R(o zkc4DZ=r{8Q7jqV}`RwFop5f5o+ zSfdyR-EFk$tkN20+rY1D&_|rxcyLGD`u(y{B#wA*vzVLTZWNE)vj2qQs{JPxw%S#z zF`a}^o^v<;CrPnJ-EB>gVrUkm6x}0k<$pl8x$MZ7?(V04J~@7^P>9qL4_2jX&A3s@ z(j6ZU+Pg=qjA?vvAVNU&E6UI=C@I)vJ-9+fiYx)LDrado&mD2*uKaOmud)=d+|@2V zDN3QLnKz~z@Ba^J#@k_vN>Du5zXNuojzFk8>*z1@o*F+;s%q{x_ z#(0&ynSYK;tI@v4B7sw|$J|X<%0|(o8>_PP^X9ixp0tbU{1sKIT9yZ=5LI*AF7qT| zYAIYHk@|*=yWtZ-t!1`PeRm&mLBIBP*gj+Kgii+TORKa}LB1h+3HJu>yPphBc1PSD zv|@65e8n&CHvVU@)-`=9NP-3uSVZ-zmnuG67%e9zOrTGppQQm7Sln)fX*j~&Q6CT1 zHfsM%1k9*=f~r+QQ;?&Ep0X3kB4;V*Uh`E<(d>xfh*mRq|8t>P+1TQ5v-$2?|6j0n znMKiZj+33^7ClQjxhSp*I(p&|gbL-d2KZidZ#)q6lR5Iv1E?TRxzqMxK)C-r5FE>0 zq@`EGV)yx=BjfKN49xxD6PSD4j8~Uc^P*sPg$AqU1@3FBpA{$zYvq(FD^LoY!0lXJ zY?2T;KMaY~C>7ktKS`1iagQ#uQ`+KDDX$tG!J<67ln}{n%MG#wsFPLbL;_lQm5}IoZzu`&sK~Wl{7J5Iq{>I! zw$I@*5>NH!tc{274*`{5UL6c9kzGKYDuywZ@Yh}QIh;pTTqdAv?dOBeB}Qtsx{^DD zK3$n<*6jO2ID7fhHHd+X1+2*`S(LFrc{Mtctz4WsphBq@bjqt_QK1c#XT2#nL99GP z&G(gn+WS8ZYV-)@Rb!*mKYFYh8`&2GN9eJ-sS#d1`|Sd95`ta9Or{E#v8&bsnJSc5F;HF_wjXQ~ZQlDn8hp{; z{e0x3p;DDNn;}!+9{Z(V3_4yOA0sEofC}%YW>JyWg-O{Vw%}Nqf;R;V7ZAjdW)k1r zmH!p2Ef8KHbgQ5#ztb3M2A=S1W|CLsvEg+s9uG&Sx$v~xIGejKC^J*oc!PT zFBGqE&$V(=SvS?)b7pWIyfGeB*-4yDgA}kh=%zAyX4ov9z3RpTq8kn(CA#1aHNiyL5Jfw|roM&B!ii+|1a0f`MIGu0kVylhrp zg#&BoV>hu`GE=k|$2nE_iy^Y)%Q)da^%Zg#M`sN<6+N~Lx!N0aq&DoX|FXGu?&Y6# zB96^g6%iti9aFX(-VvEyHBNF!QQghBUN$6^Qo}Lq?gnm;-8m;3ud2tqJMa}qGc%OU zK-Kr63;5n>wkCFyJML?osNk&$4@xam*n{@f8zbiwmn=uzc51u*UkzH97)8}f1)~l{ zBkn~ic2_Oi7M4qFX-Jvxkiu_%$xTpZwj*xJEaoJ6STE??zaG@L#Q{;3G2_H{FP|ID z9%ONMkA2-9SYb=QFyndx(&jHmt|u~(<=v8R(C>*~4;EX5KNuvpAV~$E>I- z*9641^LhMkcr3jE^q(X+PRvOJ`BH6NY5?7PDu2KpXYD;-_ea4#L*Q}C33s9~^TW*63x|%_v zf*Bv()nCV~KqshHmHQPJgUYKm4iWo&|OPs5yylR_>?oxSGSQL9Rcl>wp7QhZJw~e~%Z$=e7^$KDr z3`7ca-t~Qpb5`~}RAqeJy{h`l?-Gk5BaLlRcE)fo*OKWLDqC?}sK-r7GtT=Qmc)G0-hKa;b9rkcP@CWUT`&dfcEOE%vQU9WG@>s^0*m z5Gc4`e;Z{XPZr?G;X!rGxGKq$p@p$uHM+8BFn|YL?`JkuH2lpf@w``~vW z+pa!wHP4+uT~e24WtVFt*W4O(;DuA4RbF3Iv&yS{JVP>zD3260`ac8w?3>x2%0{A6 z)yU~8Ipv&7fYeDdwn1q|FZ-)Gb|oJPosZ`N?~x8PQM>@sV(BY=@Y#gnp7 zWz_IB3stTxjPERcGI1y-c8@CtL{FG;D*zQDIhgyafi-ftHGAL(LHkKn(VB9c(NmVO zYLt$s4I|#>D~GIrshBaJO&%VX&l%MD6U^Fl0&8rk3I=3~Y2* z23!8OLZW}pMs(Z%`yQN?6~e`dA$R=$LSmJlOJ9fM{BMcsmfb_6ELfR66yyJ)FV6Th zk(zxohqoiPeIKy0K)8ufbWJ}B+Rv)mSz16mPwQnw(+=3Gz4#UkU+u(~SBqUxG{U~k z1Cq!5KzJ~O)ERaM!6SY*GojN?+XkyvNuG+i?Z;?tCMmnAtmebudHl!0(q?sC5h+UN z{1AY4#x_V+h8uni;Z^%tizXVZS~6tsutCeJE}1(NXJ@Gbq?IMyS!M zV%3(D#=SQPIu{rU73B2B(z+i9tC#T*iB1oBez>XwDCYLqmA3~S1J%7lP&P_SU5Ox+ z+od!LxAe_F4;orS7-{IEZplwbN~b2s45m*8Ij%Q@i%pWzXWV~? zyDrri)N-DJ538%KKNmg-o&M^+{L^6VX5Mq5TEE8ddpr6M)^6vB?=$H@#Gl5d-3K<#AYy?y+j%D_a zDu!dp#pHx)dqDZ;}7 z++Z2Z_>lW^_Wl4}+KF>0s0OCO2R%PIa7VDl-Bace@cnlNt&2gAs}dOyd3#Hat}G^! zt{PiBhU&YkDFtf|<1ctdZt)BWl*2U2M_q7dRn%gC-jqUaFgpa43!xmlfwO}H@ObWp3{?gIR5{t|fJXmM#j@i1ErcWn@?*~6d0Ims)Vs)CepP?<%_rU{3W85Ko8Vp;aeKtJUO z8s!*JR78bnW*!AjgV*2w-;zhIgkZw zFVOJv>ae?tW|&#%@h-x+JY7LJ%8Xywn>T_%-Vj&%wLF{IF$rfq@7cN+>8w7)!EL&W zgZmF$6STJW=fj6vVw&`f-#x!T2mI$YM~I$Z&FA29H(4!g_Xoz`kSC*O_nu$*L)^AEz=IOz~z36Mi~4pS0T*1 z&UiJnhJX^0D##GH>{r2>TK>X%Qj4=`(VfM^9-StAao+8r&Om153ZY)eZi9FV&(J6K zOtIoZpha*}GR^*P^RI*c!>FlYW5bgn#HJRp-FbJy@2d4;!QOD@_&7TrCaHvabC6E6 zNMu?=C>83pyuIWud>JN~M1bRu{e87sEZB<1n<~U4@;T#k>MxkwatfT0TgstHr^B|k z(Thj9-iT`c4YS$aZ_4u&c7}8wiK01*GE;8TfmGdDnt9kr^|Q0QVCx@e+F91xOd!nm z{vQP0ZK5K*X3#3{{sMZ->`5H*Xk^hCQ+K+1?GsyDZJ1Y-sMg|MY^X~Y2gU(vD4t0C^k0>Ss zlZ(i-WRXFwprc1qm)*l*H_ytu7pXld!m_6!{oy zU>0*8ua72cOFxg$d&1x@_&o~yyY~f)7lz6$$?TEpfhQ~f2rgIsG2pq??BIt=DoMea zGz*o~2-Cdx0mx-9BytT%W$?$``wp^{hYD&0EZ09k7%`rdb008GbN>Tu)L(b4R_mfw zN}6itGJZd+b;pCj>FA^{JxER0U!E7PKEBC-#&e^8pz{3>24_(DqKBwVNNrn-sotd1 zQR=n)k$TrYWSze3Pf@+5@Ui-sxH0$VKL-8oqCW+%ptl)+<`%x#JFh>&k(brCPP%Ib z%kA!Vh~G1{d*{Z<@yVS#rr84%ZxPL_u=t$aTPWorny7Tgrj6UiPug-0V@&?Z*e?>7 zGJ2H8Gc7JD1J#gBVZCiFt_r9rbI*m@>bX?ng=)qvc zp6C~Ia3pziBdoHSr={ z2qBM+p`1dlEx`v2`liFG?$r;G(cpwb!EATaUxEp@`{AJ3^*+qog42J6_4N;PGYP*A z3{#7EkZ`-8Bwg>HxL0m%7dUpJu3qq& zJvpnq$f-d~rpsc#yXQ|4Hv69+(3`6lKN_^T0}qp<;0F)$0=8KyBz^4 z-lq(J2_~W6m;aTjHfe`+lW4K}+W%Cp)m{B(ZhRZQ?|KA+Kl4b?x_@4wp@tw#b+O{PAG<{xinvT|{54=V{{(olgpRlyYr%8hW5I0QbiVj;R0An89t#$^@?$}5NEBc7@cH=T!J=9T zq70W-cktiJO?p7P1uSYf#vge&>NkAx+B#e0K2}3~i8`nSuaS@q`Z<%O%bmFj%J@|W z%<(6Jh4z5EcJqzpg|6udpmJe`?un(#KN9v{TdQg0u6YIw)Ur+p@oe5>AU^B@b%I*w zfLFA1)CnkyF9RiJ)Y?yj%X~;cO#Dl%iQ{> zVCoM2PXaMZt|cuv?5rfTmwj)BNe_1WU&5b_H9YZn!{36A1~b!e?Ses<-p%AsBSSsb zu^wL9NHKM{oa4| ztLtjW)2G?z4$_aOUG2L$xrJ)=<)dZw=U|KuNNiO)YB%-_GHPI9GD+CT4&jq}o7a+kUh zmJK`=^tyBZ8SJbN?YaFk&T6mC$(0T^i|QD&{7TB&T<_mlc8-7ABxTRjOqzE;&8}}} zJ2HRi&ssv@=p9$4N}W;UZhaPH`X6j*Al99O zdOzVAdM9?_8M3jw>lt4EhM-%Y(ev)cA{x?1yL^vLYH*Ejt*+_0puP^b5PQ_y{>7WLCR6yro|si$(j9f{jV=Z-P@A6) z2IuHcL1p{rc1S+=Yl!zhtI*(-lm%Rne6x6)bl|*T0l(DMoA5XxBWB` zT~r@-xc~C4ZEnFc_6mKtH|N@oxHuc9S=fN}MNker54;~fA9Uxpc6`UOoQFe0i3iD2P+ z0RR#Qci@Gfu3jTTpplKJ>atLt@gmZ2`irnua?yhqtZLD=vSHWyECZ#_=vKrCy%GY{ z6$kdcWPX0Z_%DtWLiKX>i)bO?<8o`My}hfZ(Y@*rbgjRr4xZWsT+HIEKKGw+QJZUj zj!PZudTNkxy1<>e|IKe>261@WUT$@lEUd8~CL=c=VuV=z7P!))n#L>st=#3N7T2g- zo&c7JpVm{;=q;@B@UhS8dY)C}#m}}kTyaUcr%u=vUAey8cEzpbTHON6vH7~<@^XjC zFX!tpR-fu6DQsnpuQz|89TZ6%@?5aQ`f@jZp}p1hykM`&n>~S<=ytpiwC~^dZibc& zYvR|vYib&5bIL#^X1P6Ug)oQsHX`@VD9>{5Sq`D=YRYrmAASIBHtItdEa-#sciY?C z!WYr*+iJ>ND+-=<+xL9Aoj$}F0jr&)_Ow|{22b&eW|L-xqp%yQ>U{&r7jnL0SLT(^Jkhgf8=+l)oW zpVxu@AjnR%?Z58>(5-klDNos0(w=vIpzVsqD022&BOe-%_FcA34tEr*$Kr15unL~`^Gj;V zgLCxRuxAMFtSfim47#_RwkUs>_p9sXlW?7&BT#v(#K2U;W%RV zvF*CDq1@C$pB{;%E7GFXKeN0{?{>poS{v`%-M$8-<*N;__xgsAy{&U_v)V{<_UI;N zmE)C!*aP9S|Jsi+c5MB$=GWtsm8Y^r0D5c7Ic*KY#-^{_WsS(~R~yS6?)uiwI`q|E zvtwq#N$G;fTD?ra4Xse8>vy8Q3kH63K^IYI7}fAza<+ zsc^l(ecK!~k=hyGIL3p$A%~De-!iW znl@KEuRJiDaW+c;FUJK+A+fgwc$(%!HJrJi+};qbdZbY9LW_T@r93O-W2^gC3nEio zP!26Pl)_`+e-PO1Xbq1`I7<$B|tB7HzZiHH0_V1bF=va%`hS-_>oRjwxU|c;lgxF2OveVyR`#h zvM=EzLMrb+l2O0s>kaPt1yD5D$)tfPxbMSFQzxREb06)L@>Ovp^tc7YJASi@be4Ox z4PY|2x)-maRLF!j*tF8iug3rTZVeZzi5I$*HNW~bZt4Z1(nRvxI6GKDMMOu!x8Ou+r! z^etYo9b>o0f>F@);-@CPdyzV|{NgDX24^;B88#yP){u8wZ<+D1I_^+Aw4Bj{5`1kR zyXln+QK5L6I=hhYtfr>V{`{4lG?+J3+u%-FSf0i&*tCeL)A0t@LX~=sB#8mhu3fa) z_7eOk?t&ha=%tIwv+K<7=l0%S(@t(1R?{U6?ae=e z$$0$D5LIvcZ~RfKo7r9NpRKbNBbOXZD-kRGRFCWtUb2WjuMe;Z^-CSOOBW-4Xy!Ke z#l;MvS-$(0FlRJ!9ARO*b;UiV1()Ub#!)DUOavJ{-2?SVx{FGUBU9Q&a5+B;zoe?!jx7w?2} zPX3^!b^lv_9{vD)J2P1lVLO9RDM=yTvV=#*GyS%?#9{7jD-bei#muCqJ1l1R*F`|=U51%a zaO2Am>9dw0(ibl)cgmrXzv2QhN!`<&VLD-ve)lqiS-|*>%y9if(#R=JC;&^Tt@(J( zUzjkDEoM+oI1JWK9)=i>ABGx--Cf$85oV#GYNx$Gv4aqQ8LbgJK|&^$mOHS34HA?{ zJ-c3d$S%o{LM`{$l5&0~-at389I-!ZIY6!Z@O*%KOHkD=^HRXj-q$QIFT}Xg*v-!O z<9Sy($;n|@XXIAQ4AH22bZNQRV0#CM*Otw_`EVrly@!|aAsim9#&bCm3dLNZ?t?4f zC0*lVS_<>dUQw=X)SAJGQK-S{!JjVO!NbdKGX~ugy|OHhK#SVJUSz6|uRyS0wGx3; z2MpGM6%5u@D*y?RQR$FddqjCrt%fSxAl!FExvoRqc!aP3V1_)oEP|tCefc36vi^vK zAqGXhL(rD=?LX^L^d)h<8lpN|Rb2m(<*qsUQxlp1z;J*BvYj41h*rxzby#`Ob~F-~ z$X~qYNMuVR5;=_dJ;%N0QB0ao9vQ2Ey?sc{%|}9Nv5(D?YRmGKJTw%w-N~(VH>{f3 z=Kj7MgFw3rVHCMc)wn@Jt1L@XeTdM{pJ3QjESo1!f=e-Q|9ww4xco|)8Y|1n>ZRU$ zicx1CG2sT`?}wKM_h0)AQ=WW1CPOMWK%q8^eR^c=!JNVG+lc8RfT75_`Nf$HuCNM- zgR3A-%5(pho@sQSF3xOq|5{NV*uVIBG!3SujDZ8I*g%MH?gspY_S0rKCZdMKUA@Yz z-7l`f5`O&)*z_;FlXYNlHR|n0P36x0i=OxWena6Fs`1D&r|GL%V?MK*EkW-Zc>a&Z za;MG^#MX(I<70j9$a23MSwp3lufd0A_KzjyTil^)nZd?VaR2IK+OJwmiG+pM7wTt}Y+G+5S`riCU5#D?A5_N^!(e znuNpdn%Xf%!AL$%RQJ{?PR|g3i>FQGs_vwsx^OkeQ+;yt^*0J)M6?7in9!*QJ>e&Ht z-{#ynslDCWQP4j$R$kSo`W9o5u5TI9Cw4ML`sn_s9Xqy+y059pJC6z}#wDA3zSP>L zPeO!RyLV3ZD_m^YojOL%N8_68>7Fn3H07jW;%Xd!-Z@rY;m$c)Z00VZ8+^XREoG_R zq!Jc{JL4$2dXQRT8nGXA)wRHEfw&s$Zm!^NRlNPxCWmVu%>>S*fS zM?Lk2w~78bJNSa_(zkVb*Y@4pHcam9Uke$7?i;H6=3~P?aS0uPhc?%Pf4z7NsNcf} zb;80iV^OfE9o^^mfg;Mgn~tH6jmL#m$&`2T@?deBJyf592HE5VKbD$*qUKCGb-mre z;&#eq@1<&@#@r36c>eKG#RCJu(iT}F>1rdca9sIF_ZXGLT~-%xZ)cI!fTp?|#m@TH zadfxi1jCR>Wf8Lw4r@@i?cTa;%TW>lxN+R^<>l_l6UwV0nr+*a#|Ay~tUr54L7B~O zQ;jVzDX#`5;;W}6sUZr&Dn<9w6M%Ivs==Yvg+a%B!aI{1FzAP>^17EA;_#0LNvWc1 zGhru$x4C0qLX|tBDg~#9lIQ1*rv?YJ(0xT!Uiz}Imty#&Uiz7JG{vfyQso;-6~i|5 z=rqR>SF1+}AGE)WDxXcN==s!nsfSFtTKy5#=ze+F33^S)k{==N zgu5wj#)(w9EUJP#X(tccq#nI1x(ijI?xe5}ETZj#lHkGXOzsiYct=zN$Er{*Rvt;> zo~qmMa;iK*733>tPp;1$syrMs>VBi|n@;jk)-#h?*W z<2uzk<&`FggcC-&eI+4DHEn8FyaIZD@=B9y+neg1b0)UFzO+=8?D3c}-t@ugRd+DiRJ-fNFs7XVW;6@6qu2aw-wM6$8lm$nq(T=u`{)eTZcBC#82GPmS#f1Aou>@N>y6Y6wL>)KYB5pLurkFTQ50%GNFwgV^z&-?wx?Z_|#hs`B@b3`M`^WEx6@QoCg^CPF#gyiFA76hTwqh{n)6f0@*uMJ* z=hg^7Ch{$Fct$MVo6Fk1o4)P?wElHkvtab1MY#)zA^h%t_uu*3k4(>hfRVrdgEOw# z+lnh0FW4WPJ$sM*Aiw{8ephb}6ZQT*N-Wm*oIOEbQj;J3p&7;OSosFIif&iS{qYY% z!T&-7);}8Zf63>$e=Fv!jQL003YSCqS3U@5KlQ^)2PI*ZJuQJGd*S?t!1s@T`2O+V z%O$GiLN^EpY5 zKNc1JFMs&{b>A@Sm;codGqVqTcy74dyXM-~teU=IP&9WX>~gyO5Y+wmAHIM5VO{Z> zudCioU;7zm{h$3mzwvvdf-sLkWhkxY1@-#G)AO8`tJ+)}N8F*_ymmi|r4@YphiUuU zwABok(g%0Mk2&U=dcdaon`-*8ADNpjH>cIK&gS9dMGw4qn(gsFE=`wPuw1sTlaI0t zO%Ulc_>Z0j_51(${o~&V71zr=k*WU$;tj9ozT3a^4@s(?{Rqv!LUS?wW=@{uk6D2A zYErXY`rGR8FaPLF`eMWCI=AlSylxdxOUB~#2mUyXe|>4Z)KF4mg{$6JoBY()_@a9K zu^*eKu+)Aa-COaLil=>jEw@L0lvWRDCCZok$NX_Sef-Dozn$cXFX;F8{P;}hQmf;R zYQLqJ%-Y(LE_pFM`eXNReP}5Ptu~^sQnFtArLPL&rJX1nfu@W)?(;G?|AP|fA&v);!_{}(=w#XTz}{t z-~Y@f`Tuv+44KaU#Qk@?f!ADx;GuWD>rEg1)JHIbp@$M6pZXK`|MT??w}7#eu6fJ% z$+Pn(&d#3rgAcvq`#$}VcR%ylkG|`NpeBW!S-@cJ^2pX*`D&F+)N9lU0 zT8{oB+u~{cc%}Mv_9NE@rWfi*UDB~1m7(#feuTRCk=ab|`IvrGVWi&k>W*x~FX_j+ zB5yyc8uTk4V=m`sDuUp@qI19VC;646BP5jldPCpme-gy?NTdCDjdk?0e!NxjWBZYf zH9h%p{iqT%_9MlFrsqC>fA|)jK1u#k)a-it%EzIJm(H>?J*LM#0p=?`)?%2?+27CV zN9r=gk7qFW#ZQ3u_FR`VdRJc7yqF&TDg8=i`}kGS(5LIyONk8Yd*B1SpkFV~RgJ)Y zy}`Bds($5mU2y91n!fLO7Lx0Fu65-d^XW_VqiT)YkCZ-`UU{}gRdELU^@5Dvcm7HJ z$|aWgmFk<*^YgDt*SEfBU%kxo@Tb8%r>xtrlpdU( zo_|elU|<}k7wXq4-fDf73G}Ldy}Lfq_l%tE_x!8+^(KYIxe8)@seUD4-)TO-#l(DN z{#B(f`nW7%cJ60{x$c(RuQzP5=j&JeQPEd7OkVyB8}R0?Duh^PRjqpRPl1{*on-OR zr|0x5#j=9YEX}THi{jHtC`*VS#`b3eZ)zFR94s9+`MNhEc0sNO{u`m?aS#sKMh{q>I-?p&G4(~ zOZDqze%&*QZceYvzvkCH;}+BO&VNmqd27-crL%8(zJ8@JSNwX$I|DE4SIW3KRa~)< zWd1Ytt5k%>WZtvFkbACvy-~R+`}KhA{Yw3MP<WT5hEms&hyUgcX*= ztMy|D4SwVxde5I@Sjyq~u&6bM=}Yya^qW2=FFo8&ulzYS*coNUf@Gc#zMkIsoaPe; z5f{o?7|-j+(x?qF<@TnRpM#6%s8KO2FH=rW{w%*@j|UfdGyHOTu70iZWrkT%vakHC zXbMH(;#RuJV?QUFVkPs+IkS28=k9OcKy4adjdAs zLG|$Gz|DlJn7k&Hxqfv9=s&+{u`qonwZ4fMQzrF=y!slyp7_2v23P)d1Y zm4uWhKd-)3E}@frLsgRLx%pRF2KMWL4JmnVtV$^ zYr=IK);eSNPA}H4mnQ}$2sb_a7wCK7)^L!ex3Zp|f6a|>quT*5)UTY+(U(Zb^lJTD zVYE&aH!?YQ|8>Si*Nc5}eT$CrCH=}}^4KTnwO7+C`jrPpv+oTb>79SEn1vm0zt(fG)|VGTrdR9N3;8eXSDsLt-t$+48CPxmisd$aNxz~k#Ao77QUtVq zy}{!deb3oy@B9URy}M0`rqW;2^S^*}xD6E+(}Df}vVP<&a=g5g!WMp>&&$%t!-$g0 z1el*^ScFJ+*17N%{ff&rCWJwYg#N|)HN`05jPvQ)`t>g5C^yGZo%JiFabw|d0rPHp z_}}DLDrts*##Uns>sPG#?2Gy|y`W#Yu@XyzS2fwf`jscpV!nu3Oy0jL%ozL5N{$Vb zEB$(XoAZ^hoL>2>_jkuLIm`OG;eK@^lwWyxqsy*>-F4-cFLuji@mPm!k2bZr?`+^7 znRWRb1mvT)Sr)<@)f?Bp%{PI)Ay?oI<1hNEQmDgJcXEVbud`JL*ip_7d}LkYq6?Rd zx?VZMx&kZ$k)%0eLNmi4qJYX2{S2OA-_>QD5RwVe*i{6cb-k`S<23xA{_Xp>_y?XfT1znzzDIw9CSRl!{}?Ht8tV4R2GDoL}qt1+)tyLp7^)NLFshLVRpbNM)a zUJj1lnL%(;br?^~o+U>~xNlp!h^Yd#BQe6)7dz_{4(p zkh9Th(OS;yWGgr}&kOsH{SX_{T02q89f&X^Z(V~pKuIWEEtggl2jHY|iyt#2Hd zW*pXIyP7d!?hZSkE2JihG1a)h_Xi>Jt#=lzTXQ^=CJQ|lA;(kB_@=ij0<px$xK`XNrRrpxDPKe7F1hILenB(V^ylqRl2;>svKCs3D-_cB8QHbYepirM5 z0&h}5;Qi6ot`Od+wz&SSG8TNSixF1%7FQ_qUmHS=1rZ8i>aIb3e-PqhA3M(oT^EBuJP~8N8U(*$haIjlmwjKI-?1`#JMi5d$Hf3TxII6Hs6SWE zPy^oNUlDjh$KnuZ5~A>NhV+3CRQ*}FwW=qDuwE(~2Zoq>+RI>OYQe#qtEyAKw<~;{ zbA4d&p-zl2@n4#QtxOQ!hF*Std)IBex$jK~Xs+R!tT=FjcLh=e@_g#i8bS=#>PTS? zQg2x7v(t>xA{(m<;lWow`1p8%51Vp^E$T@jtQuPTAcYV?WgmB72Q+CVrtid@U-DQ4 zuBK!c?|_XB#nu}lR2>GwdJua=c+HK|l!PoJBL;jtDAUvvePcOA$3ZmXL%sH~4^qUK zQ*?%P1+VbkL{J2Uc9(>kdg8IbLWt*gBnE`HxPar65L}I2LVU2bD|{rm7``K}gOvRT zZV>c_u!}?AVTZGBwunG<^Tz7ppoIrS45hXpM)Gfy^8hjZ`XEBs&xk^3p8rCKDcSpi zuZm-hW5}64_??b(wgU}an^Wg>TO3lf^7yu%(%J_p0tqgUup;n;8-({MLoEei?_3Bu zECXTH$J+<4LF#3J5r&HvXWrPi@DXVM_6#l8W0o18SV(LMUxXmcPl7PZ8MD%-U;QPi zxi?+LiUd3nxuP(IM^bA_#Em-)bs)pv=Qq^8>+QHQ%#sAAWwuX~?`4C45Q}u|Tm;tR z7b7o0c;4+y5qMjVvX1RI0S@Eh(J`YLU#Dmy5Efiu%^NQ%^_q@WM50R^h#?#?PNWFr z?PVJTgl5bZfhXiHr=#^{5Id{S$cMN?x{m`FzKi()Vg3XAQJlwyMImpRcNhq7JF5#J zwnuLVG1qU$IHLj59v0uJ_+mV5LUxE&%OjHLB_1+Ge?@o+MxVN{%+jG~K zTj4|csa^X@9D3H7R3sjaaD*7J?Q0gou!5Av|tqPi`eoY_v5@f@CqLWK;XONmDl@6d1kr)f~`w{e1sK-%P!FLoe8P6b~8*Vj{3K5 z0PsQ52rGP5ft_ZnMZ%vt>#eh3{k&#jxm%(7A_+Rs1Av?qDkE;RQOQV17AIK zTl`;-N(Q+$#Z?IT&)B&T;>8?c#ld>q&+uliphtU?YpyQ_#gkPnf& z1b<%ROyM)%OwHI_>ym#=xNk9i5-i5HXA2>XM=s2L`&yV`=Fda^p564-FMLD^!XwSG zn4%RyZ{HY4Gjxx{6vBghsAz=hGqx)Nw{YX?k>+X*QlNdi8DZbs)w#!105OQ4fZ)5e z{D;C`qUZ3=M@4*V70qgc%T}ZwfBta_g(RM7Mopq)pqa0@ys;Yc8><-Ov;Q%OOGq`=2pAt5E!Vzh62eB0tEN=?ER(U%q~6M;ypap1ytYs#=px2t;02Q;fV71cbeJ9cIf z%A?b^SRuqfZ0*!HldynUJMfWpcIBp$+a zo9Tv^u@5YSr)FG_+|8YrJQ;a@`l=Qe@L08h!H0jgaTNlOXI$2AE3;;Ih-48m3oSw| zgm}ltL2AZ`q!Cv5I8*{w*ZaPp30R9|`v28(v> z9^0xfcp>C88#@<5^XwNwRP?dk46_{xKJq6=Vk#Yt^Q|9x)tQ^;fsnN41`|S)#6=+4 zlC7P%g)b{%1fm*H2=fFcxxBNr2*gj{`f8AyP@?dL^vzNP;vB2Kql$2C3UCeL$qgdV zGAIfmI${t**fwFEXsHO?FzqhnLP%~^biNI*yVARZgO_GP6h5w(2fn+D;|ZW8H$Wh% z8*O$%crb%Y+#&%hX3WxR3s@5-yKGrUyNaM#`iagd{BGQ%CxkcsEGq(UQqJ8FDQjH# zBcj?ouSFr3rpAUdLNmguFZGT-{j2wH`Ib8prP@TRi)tOc@T-K9>bX;Rv~G7yD=s25 zu~Z#w@fTMuOQT?65LWP}?asot9NtaNkZI8x7Q);)6v*h&|3Zi#a%9Zh*VdpIb7=W6 zjL(e87HsRS5ZXCd2nYY?dJdxEHue@ia{vk7iM$A$eB`wR)v0RYitW2@M%Xhri$Joi z0v|;U8jK0wo-MLxl{1C#goBnh&4R55?hgmTo4z{>UuQM+fy^QnI*I}I*|A#*Dn^Rz z8Dk_dL`E7h!skLy_;^)(Y*z$cUmn{^FJidyIW{cVWf#>V5UJeS6+)cm**6#AVcSic z7XeSRW%m_AmPjBxvF#3K?m{4*leW_3tt2vMlY{>_|4j=lm{DB_+Yvn@%;+zPWGB`P zxhicU!bkpLGetxp=>csk7W*So2+^Lw&W#S-Fm0t5zV(91D&RCZaw!&Kw!Ajop6y~D zge-+dbs@~`5mc8A;byXsDALy!_{gqk3s`w=ETpvN2&u$EV$XKzD1>lqWNQ%^fnVMw zB=2HuC$4g=oi$U0MML&YczpRxx$XQiXd%SE*ai{4+wKxA0*8#y%@nzX#@1OBk~7d? zAS8V#KM8T9)~@=RkSbVbKNEg}$Wmu(QHWjI5%SK_OOI%?up;_c&_tefuDcWAICx=b z!AF6fHWZ35B(!!SiKl)DIm71dq!uw`cP6aMB_@e{?O(7EqTWT{Ll=_uRmm4!+WpA9 zxKV`p4sEj(LXzkL;RzFiLchHo_{fW%ZvGo(w%m2GFAA8sEqtrwHwqtjibh!VZ7~ClFABNP z*&0IOm8DV@!iY-K*A`FV+s>QCs1v?J4>T3NBhTEofkjNFF5{Usfk!_!a9fOpkp6*> zlQUq;6$$3QQHVtDB0&hb%YCAAmoYVCSF$0{C34}zTo{Nc{=<9|-Qt3~Mk(Zg4cyj3 zAtc*tKsbNS6K9aJg<8A9ckHYwgx4v$NtEeANCe(>4UAQdGpz6D!bd($8(3K>s~2Nc z2O%4vS#^c5v8z-7JmUUIf-{BBT`I!I{j!l5g8F=8!Vn{H?%W417~!YZP6#uF6}>8q zH8|5%g~E4v{!RVc6+)^5{nl^DQZk3FSmgSiI#`yWX2k00l&UWpZlk_n#!BH^l0vqv zQ3yR)tIk|p4}=tGXfPpMviR1mHscHHiGiCBq_zgYZqRC#q3^YiSO{Z!qww zklzMdvfY&|6k8j0A_wu{wGcAr4dI+Uue`kmD+2Aht6+$M*a#r(GZ71^>=mDc?6lYi z1U=%DP++9BD}1=CA^Ou0F|hwST$mJV2=RS|Cf7Jq2(9>2&G@Fr6wc13U;7^(JbJw1 zNbcLPFi_TR3#>ktA-a|$kyQORonC`UNJTlTS-aigNVQrZUcl!=ZyNsJuATm z?YI)k*gT|Cwa!IhTHxH63F8Bp?Y+X+xls7FG}?We9Z4qH7Q^CQLt!>92w~>N<3!#U z(%#pEh`8X@9E1<26r2|SXKISVynI0CE`jQk%$>KstQipY1zh+zCgXE9AI7}@a1nGh zx)9pU!$O!LFZzZi%vbM9YT?ULhRi>6?dUu#kU44vtjmBIVY-abAKN+-x6pdp>Yrir z4wD~sH88nt-3KO`b4NC}?^*nE6rB9(-{XeHs^H>K+q{MFCYL-Vx?-hp>#PZK@DUvt`!aqZypAkjd_-aC z12b_YgvOb|cg0tM{_Wd{TNY>H$IDBuLo{|3g{H_CLQ;4FVb*LRQ?Q#Zh0iY46~3if z4)fnd2^wDx;{FcJxN1M|vnzyoaf=XUYO~n)ui3u~i3?Bktb0%=L91CII_8=H* z>qCR!TWEs_p&kB(&+_4F#+DnY{dalgs}+PdTudAXDTH{_M%di9o1!zUJNEd*7$;pD zEPR)D$2hD}SR1Pg;k6yiLP&MYk(ffb+=m+%HTimNEfl^j2(bkcgs{7)3LzPj;~>@9 zx0pCcmCe=;0zC#)_|ELp!GGMkUHPg(Jk_`mcJ>P)nq?nY_^kF%;q#q?YR?lzcg;6i z2zffI%>;xP3@2c=(hFf%1PdQ|B7tvDu-XC%NZancWznG4cUU2$%4;A*s3*)~gu;ja zeQZY{0Tz<=I0D5kUS`ih_{yzaA?&J65tx_Z!FPgaG@fof2%&{PW`yR?7lB0V8!-j5 zBN}{+(H3ywTY|{iC2Jr7gtlje&;y5suq$MRFoVeSHJw}dB3<$7NMOJN349Xl`IsF= zI|62gpVrJ3`)+Jk1iC9+#8eij*tE57F>UwV zG`;U1-2Z`NT2=JyqZTDMe$gCCNIV;-tJSMC-h_2?V#YU%RhY19@E|077oATSRW$1? zU{F#5+Q7vs?hOXMZdBDr;0n8aU=VUEtj(?vS^@l;aaJq@TSzGGHFj&i@Le3!8$tz@ zkgJs4i5XM;vF*b`=y45w5=-YRqSwUxRSDpmpr&+{wGd*a1q(egtU(SIK?WaDqu?OH z;&yb3|8!1IA% za;xy6Rxhw!2{_=F85lUfKVi4zDdJ)sb~)~VT9?nU9F9DLv#62ul4A~UuG ztm=FhxtiQqIfbx)x*~8q>J~o;OTj$Q9ZrMxx(igQo}FB*tUbUXtL^sgb6^{579z+-o-=p&5%0R zEzE1B>@Ti$3}0I5zt zqRUS2c!iLxIgG0Vh(;vUfvXq^v-1(l3qsqDE_@bHD14W*^Q`R(zGWX+2v@~uP)i9t zw?PV_J+BhA?Sk zs}P!Bu@KrJT*Rz}6$hJzdl-FDpqP^a*0@#pFh*+JP2JRt54rX3C_mH*6vFP{D1?@Y zUj&*yTrj(z#XTYr+MU`$c*2ECL6AN>{No_)FbrDEzWgM4C!fAIk-W;4-`<%RISBjd zUj*XoZJZG?eyx1&oiqJr$sMoi(Owo+F&MNAr7z`7}k)&Ro3SPP-KdW&0m z|3$fS>-JpKO%?}u03Y>!3aYm$=qqRw)!bbsgO>R6}@riU+ z7lkUz$sgNiDun6NBj>$OLYnFJuXMCx)QwthFSfne@kfB+Pw#$oVLMY5}R zH356@reK#>XcqjnEiHV{q?NT#Q3x%CcJ7=ah5g#OUicc9#3VG1)u8`lyXYZC*(7HT z;tC6y&o`E(R0#Dp>kI!U6%Q=oOYN;Hd9^oVzs90eQe%cVj$gaMbVa~!Bo@B)M)jbn z(b*(HA?(7QLz85-Pz$JubYe+(#-H#}vU(&C$21<($fAJdT=5P^( zw>_N1WL)NTM&*fi!45*dxGNU2YC~Y7;+%k4@;mtSp2<9sT~njHkoja_7tc@j1uB@A zP2^S};qtZ?iokpeg}(jMNt$ye7}Z!?UMQdt-sJk=HLoP_vhN^SZ)~*o-3uQPoY2%T zD-)q#q9TZb7pkrFLYTh2E9{>BIW^(^iK9hRqYNJ&&Sc^C3d_Fj@eC$HFJ=Qi+-|L1 z5g4AFBh;MGFL5EZ&dN3BI!jwzg)lSdcuX_QL||q@kPyL6yl&CKLYNtJR9^_o9hfQ4 zLP+_{aeE41`0-%BtgE%%^y{zQe;X+(ZC_VMHxa9&xw-`-?R7;~`DNrhU*hB)VTI2W z2FVj-W3_81G4id=0-rDOLrX!A}fgyapj zfyE)uMk-j>bBGG^^cUU6msqO zreFO3?%#N{w2zveJ@l%nVBp3oq%4K4U>xmstQJ0V>lMDmh4=8L8aN|c)Z6YS)*5k?%IIWiM7^{Yrwn{4$Les9^vI|k4cdxxa@`9 zyUeCGPqGH_fG7y5V&0aT2!zjVFNjO{0$aNoW*+P#A2o|vhzTiN@pL9aH{m&TQJ~|a zlV=jElr4NY{iEOY;LYDkA1mZolR_7tp8UE8Z$BC>2iCkj^i%E8EBq@_vAliFVuIy1 zl7fVwO!0ZWmRXzbzwW`Cj@MnoqZehV`cYL>`0=Gr!Tsi-%p(?@XRa$1zU6$KKK=D9 zS8nPxM3h}XUv5*ZPWWG2I}u@fu~^}$V8RzgE)dB}(o8$3+264q@S^pZavPm&m`02U z#B^&!ix{dWv~~sK5xHR^jL!=r?nWzwJbW=Uq%R05)DkeiicOq}pjhK-;p=z2W_%Zv z77c{{Kn8aHk~dGM{V;Z6R0L+Al6n@#8R1)#+E&e=D9p;xbT%m{F0i&6(S@*2r0`vK zpHmTNt|a&`gy!afgWUQFQHyrhBwzK-)FUNU_H`tDnKH)daBJdP#N>q^V74%Cxg@^V zM_m23x0p%!IW3Q&h~BFBtm0Y-t(1mXc$t?Ear^YeRS13O6uz$1&G<}&!++vZ{gf0! ze9iqE3n9{E{O*M?FCVfK({sSJz;W9Vnzt_=xb6`9OMeu*jF>=Vpf~n`Q`KvAAazL z4c)rUgEs^+;(-6K>Kop6R@5wzJb{4H8S{|GqIb%h0n$)VsM|f z-BLi@NsS9anE8sgqAyQOg+fZYc_T(g=M)sN`h*HAHiWj(3<4 zMtKEgv!|WKtKUX6z7;YiR%+&W6SZVW!*6GQ5r|(ih}ly3cjpfwt@b%_l&j!PTU)}1 zm;U-qKjE{>B30~U%gey8z+P^H6he34h=Y2w{`h+zy!l8UyRTGzPK{^ocSs~(#JNsN zr#TG@U)t{UMPTSy9zG)nesgaizCpNUwCp;G*E1_(tbRzr{93e9Scin`HM@*sqZ?0i z=e`3AHsq(5R7S_a)z{Wu%{Yq+Qw1SRXwqE>Pq+0WgjVUI5ON!}wG;c(;|a{1%fe^= z+`>m)RllH$rEP*pgZRT$((2;v1{N-H{~!>{AYp@TTNhNhwYxNYFVw<$y0uB2?KW#QEzxP00mh*L_6Hue`nzcL_h<%LE{9NRGfKC+iJ z5v~7yRpYN~@x$zh32s- zgs>($dqG4Ih`Xe1Y(E1iWu0Rd#ivM)(GpQNdt9e>joa${55bBOqgUx-ra#Jvr z;9+20Q0L~!P zn_|J{w-+%d4yOoY7ruVfD=5up3ZDb-z2}Uh9srbZr?M@s!j~D7XeV8MXu?!_va;zy zXr9tSNStkCYjsYe_ZnTPx6@@M^7qERg%9OzhV6)Ztwte+$ay;MSiY`FYErk%1 zZ5%{1CM!4*&N3ak_5+5zt3llIQ{mgh_onD_yE#lV+<0Ly12b`pD}Y<6ZIB}HI%U6# zLX8vA`GedtJyHnmHqngGPBB=>O~m-_q?dQ`O^yj+nUD*3MeK^95N7P2*p`|3LTES3 zia^UN)%s9*T0v2mVFYB^q>ipRh5b|yN0aGkAhjqc?Fo8hpD*|y*cFu^v zF~eqg@rpbbJENH~9`Lre3t{FM)3+ZwMWBZy3SZolKkx=`ZaXqu+Q34{V(t4~2<^-- z0#B%1Bmu@E#5C0y;{U3E2w@&3Bw9CVR>YVHE|@P?5~j!wk2Ry~{rftq@6YTkk#a`Z zIfE8U9)7oAYQ|ZiiiGjL-wPkvhWo%sBH=rlm0bwEWRKWyN$rJ@Lpl)JB_ZL%Xpe2o zt82vt=D*8ok^@`AqA;p73t@z2RNSOVxFXO}s)SD&O9RoB?$3#JsRr62T}2#w`(x5H8FI*5d>FDP=sY zOcBj;JDWc9?GLysWot*D^)i)QH0ib^3WeD=nj;xgabV)#k1vP?(wLZ;8&SNMBpcof%(Os0!bD?RPX2h;rvQwimYwVP4VWIdjuLwZy0= zJ5H`X30m3+I~GE_a9k7;I3F9T^9?F@z)V3Vo1GFeX?(FwgBYx!s6>K-VCsMn=Jhf% zgZfG@0<&%lk<+dkia;#lg_y-ms2SVpFNAKLiwhR2D1@ihjBU@t=Z|Hv|CF2Az z5lgY{Q(99IJ$sn~%JPw@4lfe;Bc{pwrD0FY;*M~=lMzQpRX6p z*qNsgWZw|g{Dd{3=fPrFPu5f{-|XD@dF(#JnsG+)se05oQ~0ir>qc8<2SQe2KV`J4 zI2gv6ROh_+fNssT&5?Vd~nB&`1axI zM>2?}=bn7<#CNs5Tm&gC=b7xK38wMNAeGqx*y@vJHQ#|)d>4gORD06B=|YRm|8g|Jf^tBM%Q^_pR( zui(!nh>^g!R&||wI&>k)k2MM({&J;dYaQIWX|J3#l2uaUQi;x1a zi7-<+@z$8KC474U#ND4tggDus*NSxA!uJ>{_TArJGtRelQIK3P;7^s`#aIZ!e(D!O zymDhZSV(BPOOP4X7ppkPb((&f=#$_+@_0HSo^W9T>*A*nqBxDj6oKbq9@4ifdqv+?hy%i1)ggpB^!sgEXkS>_t2q=7=7!k+?-Zln(j~HKlam@&uHI1TAy;EP9LP+9! z5XfDRfLXw(@Kshd2k9tBQP11zFJdfByI`iofe`O!Q&CGa;vw;EOl^~4jK!Y{FlG$G zp3YD#O!b9yxf5Kt?eUW$kc#djXM~T$nXZD=>}-n_%wp_?@WS@CK1r%CyX}Av7N=sj;&3+LkSR?V<30j;^AHvg0FbX4uu$^e_Ey zFFj60Es~AH4@9SaI#(w@YY9|fT(xZk6}UM2p02)_3qb^{xyfjzMNGf1szQkBmz__r z$xmZNUCk*{_(&;S@O^qU9eJVq#Eh-P0jwnDrkf;%Fw2)n*NW|NewbeKf4%f5fyQw< zg@It-2rHgt$q_u%W*kEi?}4_F3ZGRCDSWG~GFVucIsM~nikw4D^c2E$7IO1|1 z9*XR_ZYLH?2@ni@>r5bL!A@9Rakq!Zion!cDp7Di$QXQdvY$s7IaFkvgt>+n>DU#V zxpSVxq+sD=w_f_Wl5b;n5^>s%1Rbi3%;zjhQ9K6f7j3vJH+UL3yYI2!lN=V15@(`C~*)+x!fmvagzTJOOW7wKLLLqip z=YApN>T@h$j3I}O7m$_yS@`1VTE56d=clqkj@$2%tfh%Iqp&R+J%EwC|#7XK@t4IJ})(q%U>nm5Aor zSa9LU{>_<~x34;%Fu^Il5If?;Efp-vvEV!|Z?vme+H+@;b{I=D)F@qo>>I)tRJ7Tj{u=EefDP@?s$g zL*b7-!2NNt7XJzA_x-MciE)n&YbGd=3ClEQ1Zx|l`cfyu&lNIsEI&a5>q@)N7+-M0 z@|GjFCGs1?)F7Iqiup4QrzWsiG$`Q_5kf`ikp>Y>L?S*Dxle5^AS<}#-gD`d#*8Pu z+dx9dIn+8AEEOffm*aM#6@Ag8W3iHe6dWY?;)w)$Vy+P0PEWm?WFF3U|1#)lF&56% zp#8+vFH#J1j^uA--@AD!j+=$BZ7dTs=$It8QsZk82K@Wt~7hPaZ+{(-bTpTqQF<(sMXT!ZSs3Sx9Aale?K)V^Dk9S;$ShSn1fq zvC_FD6L~qj%-I!L4T7`R7d7>%R-*UdCEm?A^SMD0i%a*;0wMZG!uEuu)%#2KgGoU6 zkIe7Jxv195thUncP(b{<-^rkgc07R>uypdWjCk+M8&ZNLJ_!nl>jCKAp&M{eb=R3D zg8t#M54(HYVRP_O4c(e5nAiVMyY$7Od>dQU&cZ>$$6mCF9BF9xt!StugcK^~xhw)L z2~#j87oUU`7oU@FcW^6OH{1M(B)A#^gcXxp7NF@Q*vtE?9?K#GHsn3dmqBD$lL_9} z0o3scE)4(9w7R@#j>OC5_$OyF5bdJW2(Spsq2Yx10=76#hr<>izItaGuS^9o6gRY`Ltne6 zsyV7&wd3RZ!3dMEr=i_3DHy4t(K#+L($|v6)mPWAy|3;P28_owO|;P2?voV4*txWe z(rzS%uip0U%mWq|;(@Kl)_&LmkmP zBMVq$)B&@!6b($A%C{_m?!)Ex`|J=Fz9UFxayK{O8BY#pkjtCt%kM{~SvH`?M?3_B z$b<-*c%8=g0IS$lC~_jP$DMS=-v#^BZX_vr(iJ~G76f@`Dn8gg}eN>oD#&1zN)GvCz0K7`)(_*_by@rJFw-gYaaI!|<*JfrpFfYab}1 zFPle-3~QR?;y{ZEZ!ng0EF<(*SD96qY+e`b973NB(T_JMCXVUfzFEm0tD__sVe!_E z?}-1qeS|uPD2x~jofMKdc`5#!GiEFL*W#wSyDONky%r>5&JW)avO+gGeVL&9Prvp- zzE;=(gy*8vF))k9Xe^4?`br}J>jn<(?An-C38aGctnV`pt+@=;wQ29}xx;x#l0zB4Mi53Jk00i!Ntz~b%` z3n%WF=-fey@xMWq;qO_@`$21LwFa^wVj*#ax@kqQ2+y$1m@M*GM+$&b{b6z{u+W#v52Zh~AzEScD1b8~H)N_N0~7L`S%{ zygzLhV5zR4fQD&>$OZ9y^6(n8t13U_u$&0qu^vy86z7ST&~eehVV)eI^nsgZEtdu+^(w4!I$de(sT^h)o{c3oyq7*va=ldvW8mA% z>GdCzeRFwUax-U5!XgtOZ^UjkSRL&hrnrUg@Rf;S5qFxPV)?Nk;fz zcRBokp!ij6aW-W0ZE3+#&M+1xIhLVjlU|++6UowV^a>%l_whX`$KgtV0vJK`Qg(Gb z{Yat-TN5d=Dj&P9hVGH8mD|NJNIWwD(fA#*9aRZ^D~8{JV}h_tE;ttOxJ`=H94;=M zxu6n)lasi+FU3_V7zI~V#?FG`5({yjlFAkaEsrL}Aml5$DnzUz1ss)1Hf?v))o@wF zLQ-;k%$VE&hwG5R>4~G>hyVkk&O@&Y;-F!DuMN|v8_`mr8 z3Havgf&5QR#qXZ;SVqI=}1c4*TQ_G7a#|jbK%x*cj&uQZ!~6tz7RWte7Sv) z%7Lb@-31apN&|(10MnplG)nm3ImvHKK8bSyhkxkucvE8MD4|eX75{hkQ=B-sfJb~WK0BxD`*RAU_JY;AWEJhMr>8z6r)PLZa9KoR4(U!2b|c|&7l_Le z!=?yN9EN!){7UjH(i8x(1b|M0qD z7sX~FD=pSGj0vwSnet(=lCs;CHuz6CCF*D3r?rP!)DGp&Hw#iJ&M3Vv@1KOIap=cv zsoSG}6I|V~2r(GLF>=S+iqAyGPz+2-cwY-RjMg!BMH+J_2O&6}gJg7=6UFl?VX3`I zDh|q=YYY7c1x)t^p|x;e@eENCLn4-+0MrnfzWmdQiib6clO-gUig3n9$Y;O^6-Gs4 zF0Zi(+I*M}>#jb+C|by~3YC~#$U&o+4|`p{3Sv|kF9u1qo2A|Kv=S}2TvwZEJ1|IF z4~H!&oXxbU}1v+i@Wu}P^_GoTM``t7S-`p>BAnk6V=#si7;xq(T?Z$ zVi2UC!*u8cY|k}VZFHq9xz7cd6 z>ei`X`ECPJ#@`o(3+Sn_Fptzc@%?_zeVw-YiJ-vnjr~*5nzCr*?xQd zxcb@L=e$P$IST*StJr)*m^tvRG!bC&QVh8PRy&~j#v?8?Ba>|V4hudVq=F4<5eTiw zl@Ow~`H~0d8VjJv1OOBUJg{!SODr%hwfCJuqNXm~NplFfOI4%(4GUis_h$@CuCI2a zxCd(p^&~8uco-0o;|}Zu`w2w4fS}=Wn_y6jlo=i~_A|J)ftTyV$ASp+)s3Gvv>39= zyMh7#b)_|yH-X+z`gm5yRbK_2L*np+j++J)i`+6hR?QdK#kD630!&r|b6*MVQj4Lg zn)@JVXDPiL)7a>%cCx5NGqA@;3g)lEaIlg|=E9vEW={vET^PK;(Bj)d{{|3Voljr* z#61r^}@ z-_Jdtz_`{rv@21-Lp7m%@HArxFcObKd*(~#b8Q5o6 zFf8-2Gc#t11w!tj#K72F9s#9V)p`MZ5Cvp|HP(niTo&%(0e0oLl7K}v60o@1OKONY z=OhY9Yjd{)tO-X82&48Pu(;MImb+7lA*6~b->5?dZ{7PmgBM?0g zo{`Kqlg?^hoXm7aBKmwtQEOlD{BnBgZ|Rzo6u3~=SW=!YgyQxs@V=VA6go55i5`dX62!z+UE0|@mdsmK!^ibohax#wF%!Zqrb^J6z<@6n zZj9uN3C;V?CL9?43k*!Emf1|GXBe~Ns&$-0NUi=!N_CB-^@{_lrb~I^5lhgCvv%DI zBq)UTPv^=86UhL`NqFAX|OYY#-)R=Jk(^0 z^~LeV-R(F%@P>t2qnbrc1Ze5t78zmBN^9T>S14X6A#o_Hx{)sly~E-Ho9!4r8uA#Y z^Uq3w?LMN?1ygBJ49}T{W*Hv=ibB!ljEgOZe{MF|Muzj?PZ(1wz%nvO{81`E*T{h} zMQ=w+VpsdbTZ$f!eSfMDQpdoVrrQw-gFUvj&{gBZ5X|pipKceo)6f6%gGY}RhpJz2 zxQ|!`L;H)7hLRfV{!##B6g@Q?lm%b(IL2lJsPUUPaeP#i1z%HK_6Si%tlp#4d;@dC z=v(0u7>Oy_2r#r1;_V)v*7*?ISC>6p^k9>OHbdfg7iA*m?vfXIMpgqPGTT_*z<5)AQMBr0GUe*#su>K`+3xMmu&`u_ZiWyiu#qtIs78!FG1l@5+YAOpL4(!g zX~lQPurNu8YssEX)9ECqk#mru8^+b6d{r)dfMK}y&cGrASukJKRP>Gm09cgE1E#kT zB>#5x6ojG3&@dz+Fft;XK=K~@>_}@xOKfWf&frYhPqHPX0x+D93=%1@w2P#06|``v z2Q2hr`l2iw(S%gy{I`({7+WsqrLwr11`ONS5R$#=+fJ`jxvbCwQ~Gqp|5ZH&Xcd{o zF2;3Ma~k-)NZN(#gq0OpKETGi<8w%bnRLAmZeVCfOqR}3vk}-*9d%ttB^S^bj58IX zbQpEGlQpQnW{ByT1>a7^p7;ZU3s`o6kJOL&oJ!c%M4121eqs{7oph@#XA*aSxGEC25P)&L$GL^w zKTb~kry(8^YlsAKbCh;*GXWSW<uU`r?H6uF?3aK`_x17De1tz~JU=`Vap4gSY;!+pFoR z&ttk;R9Yk4=HUVzu4w3{qieD9tS1Ms7~)&P(OQ7xRw71}E1J07xb$nbXpX)&xhvXj za3+G?<2oX+en-Bx5`xT4QX0aC@f#IFDtiXZ-npoD5dr~U*n|o|9X;eq0!9Q8f#GrY zfw`UUf`@`MagcC}+*4=3$A1gox|M1Lat+T0QDsygm{fU>*VT4yTSQ#Q3O8IKU&8O} z*3?#F5Z73-+`|#Y@^D=Z`A(S>|0GhCofw`ZcY~6?66Jly0{ZNLMGO}LIiamDlFajy zamG+zGumx(e>0^RBsRMaNk8d87-_x0l0abY^r4-(CYe7#=pHF#EvQJb9g}M3`yCid zDf)($L%TR1xX-TQ>|7A#~ueM7Zk;3%uABWTNJT1_bdeZK>X(gVPv zn2=!ZXaW}1Y=EuV58J`?5dmGn2eu}rFAX`vNq6hVq>N1Taoe&=9rcwyec|gBBtf$9 z2DURCTi?znhPMaD#Bg?>uVdt<3th&bqKb`yEWNmTdjLbGiNNW5-u==e-(jy5X!_)5 zJDpco)7dXS_@-lQM1q^HW+08C6d6)AKRVG#*P$eRUDgV=cH4k$f63uCBDxt@_%PWMH`PY}<-SOQz#?tcr6eqkWIc-GM?h637>p zLpV5mLTswGMVp-Z>SDowPsb{OV>G(~STOwPE?87XB-`Pu^1e8j$3e)f;hZ&B2{2^M z(Uo`9Iy3m#PO8=!Ggg)97#KUG!-UV5o$xKrruA6WAhfg@(=aYp0*ieM3|FQPjC3`k zQFFKzJGR3kuK=nm17uTT){hNoCwGT^PhgRo4=i*=Du!H6U;Y)=J5FXpi*v;DN+8M8 zfFP67H;wjMvT+xK;UmXT1tMn6d|U6D54^Q6h$X^x2q%zLYs-#7;*Kx);`Xy(?JU%K z2e@3hSa*HFNGGs?aY?$ZO5eD$4UBtxV_&Upu4pxUf?eHl5zrfwOyCWX1nw%}eoNFV zgst&57Q{rHL*+RZU1?wM0OOvBU|sg%IlyhvJ+m{+!w3)nu3ra7JgA~H3-9*FfzSC-#0t>@RFyHmS;`+W|t0dUe zNPvX(gP3>}gLZMfl9+BhON4-pYuEH8DW#2ZgoT-b0W6dOV3Fl3SU(5FLBh#xQO_`s z6VeXXkExLygtm3mnX88;Oeq}_p+Aw=cTV*^@i}qmtb%=2BN-&TY}`5tbqbnU*Nue` z!fOVdt%Ak%AmMZ8*-;2Ro(n9F6kupBHZYDKck$DXayj0PCF2|4y#Uroh>|ERei?mE&anT&u32rS(>}_&r!cDTWK90)7 zbGD+IxMt7IfVedZEbJCwk$VU%+z*s>Do0B3e-kQ7#`47_b-?8U&b{u3VkRe&p@7Ae z5K7%~MR)s5-&^iq%%I3aW+9Qqvo)OCQT09vyf~je|JP6@$iDODm{PtZP=7sB1)9Py ze}lAl`y0m{w+ds7AU14kJdQtp?GkTG7r@bMz^Z!*O*Q7$4iI zRp%0hRC0bXVp}I$W>CtI9!G* zLFp2AQ`4D9tq+Xd9>n0D@m*h{J^FHT&9GgSV1v0cmw_V*U$gT(iW}~sKCb%#sduq;tI3tr?r`Ek!z# z8VT`6Ojb8}VtweEtjig)^H{8Plo8E z0F?XY>5O~JzdMyL5|+9SYdX1r8sdGAn4lg>W<$h1Szt)bAcitp2@8=<=qBtP6{TPS z7yq{{1~9gm@)-S-VDq`r%}%uZ86+m!VsH>;ao9}{&nf~bhS#^#lYf_+g8317jW9oA zUe06R6O%J`09&o5ZI+ah2%|}dRPAvXGBk`gGZ`eF3jk&gJ5622ffIv<9t3hdY}8Kl zK@g{LDH<4jaD+qx{Scr)POLKBHgXBZS8%@sA^F3jv7(S_)AxKqd9R^@QL6d`-ZZ4i zER4mAk06I)ce$LvV=-+q#euIr;RCS-#}La zJo*c4t>d$6nYPX4fTVqmtL@teL;3ILcD!eZ$Fq-JNIiD2#*02c9XVCMZV ze27=aM;@&$5=z%y9sK$!z*w@Xad!eC*{ePXeiS=(=o@+%L~m(Co0f?WC93?A#u+JP zz=&G-z=U;u#(JqP+xg=Q#EkH_H#u9&lZ;9esYJld<;wqO$uvn&X{DSO(U%C5e`3CR zJSPc4f}OK?yfX_UW{kZX zD-F#!W{gH2`1m~8m(pKBb=tNv@LjJ07Pc+0ux$l%^8nat+YU+|tm*EflCzQUrt69^ zJ4AkL1s-V%y$XL>=QRAs`5eJKRr!kViFbbxPo+T9j?kigI-PUAjyPI^3sm+FSEAlG zi%-HOMz>!8k)|F4bJfaW__KXC(RsD-cO?%)HBJZI11AttgwzJXJ&-WG2)=;X52l5p z|GqC;3GS#uMd)z z2Ca5c@^tIYw-_+Y#ONG1A+h}9o*@z?ltJ)q9{g=B97)x315WORU?H-{wFkTgr-%tP zh;~tJ2^efOS0X^X(l%o>UAMPbNBNBv0JLo<-%fCl<9&!w&q`kTI@GJ3mEQD1_s!3F%;zO^}eN0(IXKTh|k^~X#i6-Mr-K0AFT%J=#% z0Tx`Ppn%DK+yxXia*3pSkbWNESBTIO?IQCIgyBd7W&*C*znIU=f7^?CL&FXjqAX!& z1LMn&-xw~Oc$0&H<2gL~_6j$8kdrLTaBtC&fTRr~6Vq9ZX3!-e#9%YUM98srD}^!i zJU|RWQrift#YKLB!*nZoglS+n=(~xdGDI+!ua*pgUH?N(q~y6F#BuMb1|;f40a1Lu z@d5$FM8>`D$@cYjto^xCGi*C@K>Xl90K3hE9vfjs2(&^6aE87ixX>$Zk3M5cjC*td zX%sc)w2R|Bz)|69I(;ME2H5s`-J<_VsHkX!u^$eGOecLO781(FAk#}TMwz!8*Kh&d zzz(~A0U&Y9-~zEnUr1aTnI8WYLK-YGqm#n@n?|)B{k&J@3J^o_h?(`(8&)}dB*f5n zseUtx3=A#LIG|xD!@xLOePGHH1TiE-`thMuvJobcjY3MIZXk@Sh4@PGsCzq(@A%U4 z+(f&$un9h{7LL>uF>Jmd2F*OaAl|xQH9B+PLjwxVY^h&^$iSF(7tJ02%teED7_roe z5sXCLHeU??j18;Zc8zE`X4KA$r3>bP9bj0S9Uq^aRp>8j zsUW*~uhe<1#Ic@lf?+d`1eWXrWrIl#u^KZa9dJU=?M9Jt)xDNFDmwvDC%G^qPN5Hvl>(X-*ub zZy>?kswlMR#N$w65V4fLJ_Yk~n1bPgP~Tl}3P^6bBVc$@+v+P^mLlpRSLR&GfA?*}faAG)={nOz}F}+)T-GzqWU^jOXefI$V>}z9ST}bHP9jA#G z{a3rCc-}~~3M6=6E{WN0Ql%Z&5O@j}k7LZ3#EqB<&!F080-<{)ATS;T63kzy5Ueg` z6#rK>kjzC7`p{5$c0M~UWh9IX6W)%XRB~aAM0`?)nFjG#iD2wIM~FGz5Z3DV5*T9-(w<>EX3i1X?!8v?5~{|ay#1>qaDJ>JT|~w5i5M2uBdh%*A|RdD4c4% zi+<4J?8&c)6UFU02t+a)7Zl2DW0a&>BEQUkn=yw|H&--cQfFMK^V!YAp?0CLAtlHf zabh@iMj6BSbk=pbXvoR!Fx{UHnCB^gk3+}T2hoX;2I!|pyVtJHUW5mjF5>vW@xrFs zd2I~A{M|*t)`!&wF{EmLE;jHm1HTjyE=cit*94uovrw*T=S=|->DEjyD44! zJ&*QVoeaTh{6-1$sy+;IHT~v)s(Sg!a5i{+eU1fRo~Q<~WEJ<1zR14d_xhgPD86u0 zhh9l^4PyLdVD-H{Fn?KY`x(j&i77t?M ze5sv@C9xWP&$ytA(S8h)5g=!w=s=yyj1LuB`v2xfsrwZl8&?chz53+ISS9^!1#9^NaVQs#|`SI^zZR&Jk!)y9iHAU;DE%>sjsoZU8U}JO(p}RQpgB z3-RGOYrUQ7$|OE?``A<{#K81MXt;j51subB=5`^mK*EU?PjqchPQ|Hiy*ClhK@4sHTfwM%eo0*_VECBeYQ$L}hO1#V2%QP0b#`eG-zC8OrDq1_%&}dfg1;`{ zXt$Pl+KnpZV7dlRL$9Usls25Erd z${!I5AGfaJGjVv@Zlc}o*)b^8?Sw!Wh8CT}&|=2s{S-0e1=!XWY&APJqY7Xc$-w+x zm=J~n0t_3}iN@OZZHx^xI;7b^WKHs&x}Q$h@5tmcb^(jP9Tzz*@z3P7eO;*=&Y$;Wm9S6KEI92-fAO`Kc z90Gj_TUuYe%#9`EGf@G^fDtH9n0s^-aCW0xM7vrCOpi$F{MkjYfF2_NMy`PmjQter z17_Lm_?Ena>wVE@wokX{e+&{K6*`{>TcwiQ_N1NXx0Bc!*Ez(IUgf;zsryBbG zPQk)F6wGyeE-Zz*2Fz=12wzs*h1#(NP1Vaa&>N6LbTt>&_p5|POuQLcuO`RwdpX*{P%AxhWYm7Y5Hu( zddt3Em`A~wP%DoBBdrpcKPIEj5m^Ejo=I+7A>y2?TvQAKQLa53POou=B;@**8^3z0 zWnIDBch{H8K_VTU`=rA)*j0xC7-tz?hB&E##YxSH8H-g*#<>72K9d~t?z^OVg1_;L zB7t=5TL&1Yyh}%5v1U~A*iTB9n?!KeVYCK)^;5*8ome`sfVsH|%~U0{?@lsja+P(t zFX}~y(L&#Wl_3YhT){BL!)DOz@9&{bv9_ETMZ#RxsCU<2&j8ZBUIG7zFY{L$+HBJPc#7K87`;@tGPEZnG;G zI=p>P@T5tNwgx)P9O>O zMIiIv*^fmqux8;*FHNl zg^z(l_+Zk8HHU#QedZxvyz$b3LJ?`2WMqYlRWSE-DswAV1UbYZ#PNgAN7?uh0EYa+ zwHy0_J4GHalEKvHSh`NiNIpx`D(fTQ7Y-GHn7T*bx$B?WBCrr L$8an(0e9lUhY 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 diff --git a/man/meeg/eeg_imaging.tex b/man/meeg/eeg_imaging.tex index 65b7e7a3..c822967d 100644 --- a/man/meeg/eeg_imaging.tex +++ b/man/meeg/eeg_imaging.tex @@ -69,7 +69,7 @@ \section{Coregistration} \begin{itemize} \item \texttt{select} - locations of some points such as the commonly used nasion and preauricular points and also CTF recommended fiducials for MEG (as used at the FIL) are hard-coded in SPM. If your fiducial corresponds to one of these points you can select this option and then select the correct point from a list. -\item \texttt{type} - here you can enter the MNI coordinates for your fiducial ($1 \times 3$ vector). If your fiducial is not on SPM's hard-coded list, it is advised to carefully find the right point on either the template image or on your subject's own image normalized to the template. You can do it by just opening the image using SPM's Display/images functionality. You can then record the MNI coordinates and use them in all coregistrations you need to do using the ``type'' option. +\item \texttt{type} - here you can enter the MRI coordinates in mm for your fiducial ($1 \times 3$ vector). If your fiducial is not on SPM's hard-coded list, it is advised to carefully find the right point on either the template image or on your subject's own image normalized to the template. You can do it by just opening the image using SPM's Display/images functionality. You can then record the MNI coordinates and use them in all coregistrations you need to do using the ``type'' option. \item \texttt{click} - here you will be presented with a structural image where you can click on the right point. This option is good for ``quick and dirty'' coregistration or to try out different options. \end{itemize} diff --git a/man/meeg/eeg_preprocessing.tex b/man/meeg/eeg_preprocessing.tex index ef290228..abf25fc5 100644 --- a/man/meeg/eeg_preprocessing.tex +++ b/man/meeg/eeg_preprocessing.tex @@ -26,7 +26,7 @@ \section{Conversion of data} \item Event padding - usually when epoching at conversion only events occuring within trials are included with the trials. This option makes it possible to also include events occurring earlier and later within the specified time window. \item Block size - this is size of blocks used internally to read large files. Does not usually need to be modified unless you have an old system with memory limitations. \item Check trial boundaries - SPM will not usually read data as continuous if it is clear from the raw data file that it is not the case and will give an error. In some rare cases this might need to be circumvented (e.g. if truly continuous data are stored in chunks (pseudo-epoched) and SPM does not recognise it automatically). -\item Save original header - the generic fileio interface does not let through all the possible header fields abailable for specific formats. Sometimes those missing header fields are necessary for particular functionality and this option allows to keep the complete original header as a subfield of the converted header. A particular case where this is useful is processing of continuous head localisation data in CTF MEG system which requires some information from the original header to interpret it. +\item Save original header - the generic fileio interface does not let through all the possible header fields available for specific formats. Sometimes those missing header fields are necessary for particular functionality and this option allows to keep the complete original header as a subfield of the converted header. A particular case where this is useful is processing of continuous head localisation data in CTF MEG system which requires some information from the original header to interpret it. \item Input data format - this option allows to force a particular low-level reader to convert the data. It is not usually necessary. Power users can find possible values for this field in the code of \texttt{ft\_read\_header} function. \end{itemize} @@ -342,7 +342,7 @@ \subsection{Grand mean: \texttt{spm\_eeg\_grandmean}} You will need to specify the name of the output file. \subsection{Merge: \texttt{spm\_eeg\_merge}} -Merging several MEEG files can be useful for concatenating multiple sessions of a single subject. Another use is to merge files and then use the display tool on the concatenated file to be able to display in the same graph data coming from different files. This is the preferred way in SPM to display data together that is split up into several files. The merged file will be written into the same directory as the first selected file. The prepended output letter is \textit{'c'}. +Merging several MEEG files can be useful for concatenating multiple sessions of a single subject. Another use is to merge files and then use the display tool on the concatenated file to be able to display in the same graph data coming from different files. This is the preferred way in SPM to display data together that is split up into several files. The merged file will be written into the current working directory. The prepended output letter is \textit{'c'}. You should specify what to do with condition labels. The simplest option is to keep them the same. This might be useful for instance when you have several sessions for one subject with the same conditions in all files. In other cases, however, it might be helpful to rename the conditions like ``condition A'' to something like ``condition A, session 1'', etc. The simplest way to do it is to append the name of the original file to the condition labels. There is also a possibility to specify more sophisticated 'recoding rules' (see the documentation in the function header). This is mostly useful for writing scripts. diff --git a/man/meeg_artefact/meeg_artefact.tex b/man/meeg_artefact/meeg_artefact.tex index ff96fc41..ea6b09d4 100644 --- a/man/meeg_artefact/meeg_artefact.tex +++ b/man/meeg_artefact/meeg_artefact.tex @@ -83,7 +83,7 @@ \section{Topography-based artefact correction} Plot such as the one in Figure~\ref{artefact_fig3} will appear in the Graphics window. For averaged-referenced EEG eye-blink related activity appears at the frontal sensors. Thus only the first of the four components is clearly eye-blink related. We could, therefore, only keep that one for our correction. It is possible that with more accurate data preprocessing and removal of other artefacts additional eyeblink components could be extracted. Also for MEG data where head movement change the blink topography over time one component will usually not suffice. For now we will change the `Mode' to `Clear', run the tool again and then return `Mode' to `SVD', set `Number of components' to 1 and run once again. The tool does not produce a separate output file and appends the confound topographies to the same file. Thus clearing is necessary to remove the results of the first run. For your own analysis you might want to explore the typical numbers of eye-blink components for different subjects and runs and decide whether it is safe to always use the same number of check for each file separately. -The next step is to use the artefact topography we defined using SVD to correct the data we are actually interested in. For this we will need to use `Define spatial confounds' tool once again, but this time our data of interest will be the input, in this case the continuous data file \texttt{afdfMspmeeg\_subject1.mat}. Under `Mode' switch to `SPM M/EEG Dataset' and choose the \texttt{eyeblinkafdfMspmeeg\_subject1} for which we defined confounds above. Run the tool and the confound definition will be copied from \texttt{eyeblinkafdfMspmeeg\_subject1} to \texttt{eyeblinkafdfMspmeeg\_subject1}. +The next step is to use the artefact topography we defined using SVD to correct the data we are actually interested in. For this we will need to use `Define spatial confounds' tool once again, but this time our data of interest will be the input, in this case the continuous data file \texttt{afdfMspmeeg\_subject1.mat}. Under `Mode' switch to `SPM M/EEG Dataset' and choose the \texttt{eyeblinkafdfMspmeeg\_subject1} for which we defined confounds above. Run the tool and the confound definition will be copied from \texttt{eyeblinkafdfMspmeeg\_subject1} to \texttt{afdfMspmeeg\_subject1}. Another way to define spatial confounds is to use the `Eyes' options under `Mode'. The idea there is that three orthogonal dipoles are placed at each eye and their lead-fields are computed using the forward model (that�s one place where you would need one) and used as artefact topographies. If you want to try this option do not forget to clear the previously defined components first. A plot like the one in Figure~\ref{artefact_fig4} will appear. diff --git a/man/multi/figures/figure7.png b/man/multi/figures/figure7.png index 9c7f5d242b848583bd4c3fff5bc565a4a3769fe4..784fa5ff9f9ebebea59f9bde04224ce0d357c4a9 100644 GIT binary patch delta 1066 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 axc>ltSj`W$QH-7d0000 end; if job.saveasstruct - save(out.file{1}, 'svar'); + save(out.file{1}, 'svar','-v6'); else - save(out.file{1}, '-struct','svar'); -end; \ No newline at end of file + save(out.file{1}, '-struct','svar','-v6'); +end; diff --git a/matlabbatch/cfg_basicio/cfg_vout_dir_move.m b/matlabbatch/cfg_basicio/cfg_vout_dir_move.m new file mode 100644 index 00000000..9047f56c --- /dev/null +++ b/matlabbatch/cfg_basicio/cfg_vout_dir_move.m @@ -0,0 +1,24 @@ +function dep = cfg_vout_dir_move(job) + +% Define virtual output for cfg_run_dir_move. Output can be passed on to +% either a cfg_files or an evaluated cfg_entry. +% +% This code is part of a batch job configuration system for MATLAB. See +% help matlabbatch +% for a general overview. +%_______________________________________________________________________ +% Copyright (C) 2007 Freiburg Brain Imaging + +% Volkmar Glauche +% $Id: cfg_vout_dir_move.m 6920 2016-11-02 14:48:01Z guillaume $ + +rev = '$Rev: 6920 $'; %#ok + +if ~isfield(job.action,'delete') + dep = cfg_dep; + dep.sname = 'Moved/Copied Directory'; + dep.src_output = substruct('.','dir'); + dep.tgt_spec = cfg_findspec({{'filter','dir','strtype','e'}}); +else + dep = []; +end \ No newline at end of file diff --git a/matlabbatch/cfg_callbuiltin.m b/matlabbatch/cfg_callbuiltin.m index 3e8545c1..692ef133 100644 --- a/matlabbatch/cfg_callbuiltin.m +++ b/matlabbatch/cfg_callbuiltin.m @@ -1,4 +1,23 @@ function varargout = cfg_callbuiltin(varargin) + +if exist('OCTAVE_VERSION', 'builtin') && ismember(varargin{1}, {'subsref','subsasgn'}) + % Fix for inheritance in GNU Octave + % Many thanks to Stanislaw Adaszewski (http://algoholic.eu) + obj = varargin{2}; + subs = varargin{3}; + varargin{3} = struct('type', {}, 'subs', {}); + for i=1:numel(subs) + switch subs(i).type + case '.' + sub = findfield(obj, subs(i).subs); + otherwise + sub = subs(i); + end + try, obj = builtin('subsref', obj, sub); end + varargin{3} = [varargin{3} sub]; + end +end + if nargout == 0 try varargout{1} = builtin(varargin{:}); @@ -9,3 +28,22 @@ varargout = cell(1,nargout); [varargout{:}] = builtin(varargin{:}); end + + +function S = findfield(obj, field) +S = substruct('.', field); +if ~isobject(obj), return; end +fields = builtin('fieldnames', obj); +if ismember(field, fields), return; end +for i=1:numel(fields) + if strncmp(fields{i}, 'cfg_', 4) % to check fields{i} is a classname + sub1 = substruct('.', fields{i}); + val = builtin('subsref', obj, sub1); + sub2 = findfield(val, field); + if numel(sub2) > 0 + S = [sub1 sub2]; + return + end + end +end +S = []; diff --git a/matlabbatch/cfg_getfile.m b/matlabbatch/cfg_getfile.m index cfe3e081..a0b1909a 100644 --- a/matlabbatch/cfg_getfile.m +++ b/matlabbatch/cfg_getfile.m @@ -88,7 +88,7 @@ % Copyright (C) 2007 Freiburg Brain Imaging % John Ashburner and Volkmar Glauche -% $Id: cfg_getfile.m 6467 2015-06-03 14:47:41Z guillaume $ +% $Id: cfg_getfile.m 7067 2017-04-20 16:49:53Z guillaume $ t = {}; sts = false; @@ -165,7 +165,7 @@ end t = cat(1,t{:}); sts = cat(1,sts{:}); - case 'prevdirs', + case 'prevdirs' if nargin > 1 prevdirs(varargin{2}); end @@ -261,7 +261,7 @@ [col1,col2,col3,lf,bf] = colours; % delete old selector, if any -fg = findobj(0,'Tag',mfilename); +fg = findobj(0,'-depth',1,'Tag',mfilename); if ~isempty(fg) delete(fg); end @@ -507,7 +507,7 @@ updatedir_fun = @(ob,ev)(update(char(cpath(subsref(get(ob,'String'),substruct('()',{get(ob,'Value')})))))); % Drives -if strcmpi(computer,'PCWIN') || strcmpi(computer,'PCWIN64'), +if ispc % get fh for lists tmp=uicontrol('style','text','string','X',lf{:},... 'units','normalized','visible','off'); @@ -623,7 +623,7 @@ waitfor(dne); drawnow; -if ishandle(sel), +if ishandle(sel) t = get(sel,'String'); if isempty(t) t = {''}; @@ -696,9 +696,9 @@ function click_dir_box(lb,varargin) str = get(lb,'String'); pd = get(sib('edit'),'String'); sel = str{vl}; - if strcmp(sel,'..'), % Parent directory + if strcmp(sel,'..') % Parent directory [dr, odr] = fileparts(pd); - elseif strcmp(sel,'.'), % Current directory + elseif strcmp(sel,'.') % Current directory dr = pd; odr = ''; else @@ -726,7 +726,7 @@ function update(dr) dr = get(lb,'UserData'); end [f,d] = listfiles(dr,getfilt); -if isempty(d), +if isempty(d) dr = get(lb,'UserData'); [f,d] = listfiles(dr,getfilt); else @@ -739,10 +739,10 @@ function update(dr) set(sib('previous'),'String',ls,'Value',mch); set(sib('edit'),'String',dr); -if ispc && numel(dr)>1 && dr(2)==':', +if ispc && numel(dr)>1 && dr(2)==':' str = char(get(sib('drive'),'String')); mch = find(lower(str(:,1))==lower(dr(1))); - if isempty(mch), + if isempty(mch) str = listdrives(true); cstr = char(str); mch = find(lower(cstr(:,1))==lower(dr(1))); @@ -786,7 +786,7 @@ function checkdone(selmsg) nsel = numel(get(sib('selected'),'String')); fb = sib('files'); lim = get(fb,'Userdata'); -if nsel == 1, s = ''; else s = 's'; end +if nsel == 1, s = ''; else, s = 's'; end if isequal(lim,[0 inf]) msg('Selected %d file%s. (%s)',nsel,s,selmsg); elseif lim(2) == inf @@ -815,7 +815,7 @@ function click_file_box(lb,varargin) c = get_current_char; if isempty(c) || isequal(c, char(13)) vlo = get(lb,'Value'); - if isempty(vlo), + if isempty(vlo) msg('Nothing selected'); return; end @@ -841,7 +841,7 @@ function click_file_box(lb,varargin) nalready = numel(already); nsel = min(lim(2)-nalready,nnew); set(sib('selected'),'String',[already(:);new(1:nsel)],'Value',[]); -if nsel == 1, s = ''; else s = 's'; end +if nsel == 1, s = ''; else, s = 's'; end checkdone(sprintf('Added %d/%d file%s.',nsel,nnew,s)); return; %======================================================================= @@ -916,7 +916,7 @@ function unselect_all(varargin) if nargin<2, filt = ''; end if nargin<1, dr = '.'; end de = dir(dr); -if isempty(de), +if isempty(de) d = {'..'}; f = {}; if domsg @@ -1060,9 +1060,9 @@ function unselect_all(varargin) end % Assemble paths if ispc - t = cellfun(@(pt1)fullfile(pt1{:}),pt,'UniformOutput',false); + t = cellfun(@(pt1)fullfile(pt1{:}),pt,'UniformOutput',false); else - t = cellfun(@(pt1)fullfile(filesep,pt1{:}),pt,'UniformOutput',false); + t = cellfun(@(pt1)fullfile(filesep,pt1{:}),pt,'UniformOutput',false); end %======================================================================= @@ -1098,9 +1098,9 @@ function clearfilt(varargin) for k = 1:numel(filt.tfilt) [f1, ind1{k}] = do_filter(f,filt.tfilt(k).regex); if ~(isempty(f1) || isempty(filt.tfilt(k).fun)) - [unused,prms] = harvest(filt.tfilt(k).prms, filt.tfilt(k).prms, false, false); - [unused,ind2] = filt.tfilt(k).fun('filter',f1,prms); - ind1{k} = ind1{k}(ind2); + [unused,prms] = harvest(filt.tfilt(k).prms, filt.tfilt(k).prms, false, false); + [unused,ind2] = filt.tfilt(k).fun('filter',f1,prms); + ind1{k} = ind1{k}(ind2); end end sel = unique(cat(1,ind1{:})); @@ -1530,7 +1530,7 @@ function null(varargin) function obj = sib(tag) persistent fg; if isempty(fg) || ~ishandle(fg) - fg = findobj(0,'Tag',mfilename); + fg = findobj(0,'-depth',1,'Tag',mfilename); end obj = findobj(fg,'Tag',tag); return; diff --git a/matlabbatch/cfg_load_jobs.m b/matlabbatch/cfg_load_jobs.m index 5dd6f8ff..567d8732 100644 --- a/matlabbatch/cfg_load_jobs.m +++ b/matlabbatch/cfg_load_jobs.m @@ -11,15 +11,15 @@ % Copyright (C) 2007 Freiburg Brain Imaging % Volkmar Glauche -% $Id: cfg_load_jobs.m 5678 2013-10-11 14:58:04Z volkmar $ +% $Id: cfg_load_jobs.m 7024 2017-02-21 17:53:55Z guillaume $ -rev = '$Rev: 5678 $'; %#ok +rev = '$Rev: 7024 $'; %#ok if ischar(job) filenames = cellstr(job); else filenames = job; -end; +end [ufilenames, unused, uind] = unique(filenames); ujobs = cell(size(ufilenames)); usts = false(size(ufilenames)); @@ -33,37 +33,39 @@ function [matlabbatch, sts] = load_single_job(filename) [p,nam,ext] = fileparts(filename); switch ext - case '.xml', + case '.xml' try loadxml(filename,'matlabbatch'); catch cfg_message('matlabbatch:initialise:xml','LoadXML failed: ''%s''',filename); - end; + end case '.mat' try S=load(filename); matlabbatch = S.matlabbatch; catch cfg_message('matlabbatch:initialise:mat','Load failed: ''%s''',filename); - end; + end case '.m' try - fid = fopen(filename,'rt'); - str = fread(fid,'*char'); - fclose(fid); - eval(str); + str = fileread(filename); + if isdeployed && strncmp(str,'V1MCC',5) % mcc compiled script + eval(nam); + else + eval(str); + end catch cfg_message('matlabbatch:initialise:m','Eval failed: ''%s''',filename); - end; + end if ~exist('matlabbatch','var') cfg_message('matlabbatch:initialise:m','No matlabbatch job found in ''%s''', filename); - end; + end otherwise cfg_message('matlabbatch:initialise:unknown','Unknown extension: ''%s''', filename); -end; +end if exist('matlabbatch','var') sts = true; else sts = false; matlabbatch = []; -end; +end diff --git a/matlabbatch/cfg_util.m b/matlabbatch/cfg_util.m index e09c6467..baa06490 100644 --- a/matlabbatch/cfg_util.m +++ b/matlabbatch/cfg_util.m @@ -423,9 +423,9 @@ % Copyright (C) 2007 Freiburg Brain Imaging % Volkmar Glauche -% $Id: cfg_util.m 6460 2015-05-28 08:30:28Z volkmar $ +% $Id: cfg_util.m 6942 2016-11-21 13:17:44Z guillaume $ -rev = '$Rev: 6460 $'; +rev = '$Rev: 6942 $'; %% Initialisation of cfg variables % load persistent configuration data, initialise if necessary @@ -1440,7 +1440,7 @@ function local_gencode(c0, fname, tropts, preamble) cfg_mlbatch_appcfg_master; [c0, jobs] = cfg_util_persistent; else - appcfgs = which('cfg_mlbatch_appcfg','-all'); + appcfgs = cellstr(which('cfg_mlbatch_appcfg','-all')); cwd = pwd; dirs = cell(size(appcfgs)); for k = 1:numel(appcfgs) diff --git a/spm.m b/spm.m index bc095d8e..64cd244c 100644 --- a/spm.m +++ b/spm.m @@ -50,10 +50,10 @@ % FORMAT & help in the main body of spm.m % %_______________________________________________________________________ -% Copyright (C) 1991,1994-2015 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 1991,1994-2016 Wellcome Trust Centre for Neuroimaging % Andrew Holmes -% $Id: spm.m 6894 2016-09-30 16:48:46Z spm $ +% $Id: spm.m 7134 2017-07-18 09:46:25Z guillaume $ %======================================================================= @@ -430,6 +430,7 @@ case lower(Modalities) %-Initialise SPM in PET, fMRI, EEG modality global ft_default ft_default.trackcallinfo = 'no'; ft_default.showcallinfo = 'no'; + ft_warning('off','backtrace'); if ~isdeployed addpath(... fullfile(spm('Dir'),'external','bemcp'),... @@ -594,6 +595,9 @@ case lower(Modalities) %-Initialise SPM in PET, fMRI, EEG modality 'DefaultUicontrolInterruptible','on',... 'Renderer','painters',... 'Visible',Vis); +if spm_check_version('matlab','8.3') < 0 + set(Finter,'DoubleBuffer','on'); +end varargout = {Finter}; %======================================================================= @@ -1191,6 +1195,7 @@ case lower(Modalities) %-Initialise SPM in PET, fMRI, EEG modality end mscript = cellstr(mscript); for i=1:numel(mscript) + mscript{i} = spm_file(mscript{i},'local',pwd); if isdeployed [p,n,e] = fileparts(mscript{i}); if isempty(p), p = pwd; end @@ -1199,7 +1204,11 @@ case lower(Modalities) %-Initialise SPM in PET, fMRI, EEG modality S = fileread(mscript{i}); try assignin('base','mfilename',@(varargin) mscript{i}); - evalin('base',S); + if strncmp(S,'V1MCC',5) + evalin('base',n); % mcc compiled script + else + evalin('base',S); + end catch fprintf('Execution failed: %s\n',mscript{i}); rethrow(lasterror); diff --git a/spm_ADEM.m b/spm_ADEM.m index ccbc0217..e2c0204a 100644 --- a/spm_ADEM.m +++ b/spm_ADEM.m @@ -55,6 +55,9 @@ % G(i).V = precision (input noise) % G(i).W = precision (state noise) % +% G(1).R = restriction or rate matrix for action [default: 1]; +% G(i).aP = precision (action) [default: exp(-2)] +% % G(i).m = number of inputs v(i + 1); % G(i).n = number of states x(i) % G(i).l = number of output v(i) @@ -131,7 +134,7 @@ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_ADEM.m 6901 2016-10-08 13:21:41Z karl $ +% $Id: spm_ADEM.m 7145 2017-07-31 13:57:39Z karl $ % check model, data, priors and unpack %-------------------------------------------------------------------------- @@ -248,14 +251,14 @@ iR = [zeros(1,ny),ones(1,nv),ones(1,nx)]; % for empirical priors iR = kron(speye(n,n),diag(iR)); -% restriction matrices - in terms of precision +% restriction or rate matrices - in terms of precision %-------------------------------------------------------------------------- q0{1} = G(1).U; Q0 = kron(iG,spm_cat(q0)); R0 = kron(iG,spm_cat(r0)); iG = blkdiag(Q0,R0); -% restriction matrices – in terms of dE/da +% restriction or rate matrices – in terms of dE/da %-------------------------------------------------------------------------- try R = sparse(sum(spm_vec(G.l)),na); @@ -265,13 +268,20 @@ R = 1; end +% fixed priors on action (a) +%-------------------------------------------------------------------------- +try + aP = G(1).aP; +catch + aP = exp(-2); +end % fixed priors on states (u) %-------------------------------------------------------------------------- xP = spm_cat(spm_diag({M.xP})); Px = kron(iV(1:n,1:n),speye(nx,nx)*exp(-8) + xP); Pv = kron(iV(1:d,1:d),speye(nv,nv)*exp(-8)); -Pa = spm_speye(na,na)*exp(-2); +Pa = spm_speye(na,na)*aP; Pu = spm_cat(spm_diag({Px Pv})); % hyperpriors diff --git a/spm_BIDS.m b/spm_BIDS.m index eea0aab5..82bf00ba 100644 --- a/spm_BIDS.m +++ b/spm_BIDS.m @@ -1,279 +1,682 @@ -function BIDS = spm_BIDS(root) +function varargout = spm_BIDS(varargin) % Parse directory structure formated according to the BIDS standard % FORMAT BIDS = spm_BIDS(root) -% root - directory formated according to BIDS +% root - directory formated according to BIDS [Default: pwd] % BIDS - structure containing the BIDS file layout % -% BIDS (Brain Imaging Data Structure): -% http://bids.neuroimaging.io/ +% FORMAT result = spm_BIDS(BIDS,query,...) +% BIDS - BIDS directory name or structure containing the BIDS file layout +% query - type of query +% result - query's result +%__________________________________________________________________________ +% +% BIDS (Brain Imaging Data Structure): http://bids.neuroimaging.io/ % The brain imaging data structure, a format for organizing and % describing outputs of neuroimaging experiments. % K. J. Gorgolewski et al, Scientific Data, 2016. %__________________________________________________________________________ -% Copyright (C) 2016 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2016-2017 Wellcome Trust Centre for Neuroimaging % Guillaume Flandin -% $Id: spm_BIDS.m 6862 2016-08-25 14:42:19Z guillaume $ - +% $Id: spm_BIDS.m 7120 2017-06-20 11:30:30Z spm $ -if ~nargin, root = pwd; end +%-Validate input arguments %========================================================================== +if ~nargin + root = pwd; +elseif nargin == 1 + if ischar(varargin{1}) + root = spm_select('CPath',varargin{1}); + else + varargout = varargin(1); + return; + end +else + BIDS = spm_BIDS(varargin{1}); + varargout{1} = BIDS_query(BIDS,varargin{2:end}); + return; +end + %-BIDS structure %========================================================================== BIDS = struct(... - 'dir',root, ... % BIDS directory - 'descr',struct([]), ... % content of dataset_description.json - 'sessions',{{}},... % cellstr of sessions - 'subjects',struct([]), ... % structure array of subjects - 'tasks',{{}},... % content of task-_bold.json (to be merged with sub-/func/sub-_bold.json - 'scans',struct([]),... % content of sub-_scans.tsv (should go within subjects) - 'sess',struct([]),... % content of sub-participants_label>_sessions.tsv (should go within subjects) - 'participants',struct([])); % content of particpants.tsv + 'dir',root, ... % BIDS directory + 'description',struct([]), ... % content of dataset_description.json + 'sessions',{{}},... % cellstr of sessions + 'scans',struct([]),... % content of sub-_scans.tsv (should go within subjects) + 'sess',struct([]),... % content of sub-participants_label>_sessions.tsv (should go within subjects) + 'participants',struct([]),... % content of participants.tsv + 'subjects',struct([])); % structure array of subjects -%========================================================================== %-Validation of BIDS root directory %========================================================================== - if isempty(BIDS.dir) error('A BIDS directory has to be specified.'); elseif ~exist(BIDS.dir,'dir') error('BIDS directory does not exist.'); elseif ~exist(fullfile(BIDS.dir,'dataset_description.json'),'file') error('BIDS directory not valid: missing dataset_description.json.'); -else - try - BIDS.descr = spm_jsonread(fullfile(BIDS.dir,'dataset_description.json')); - if ~isfield(BIDS.descr,'BIDSVersion') || ~isfield(BIDS.descr,'Name') - error('BIDS dataset description not valid.'); - end - catch - error('BIDS dataset description could not be read.'); - end end +%-Dataset description +%========================================================================== +try + BIDS.description = spm_jsonread(fullfile(BIDS.dir,'dataset_description.json')); +catch + error('BIDS dataset description could not be read.'); +end +if ~isfield(BIDS.description,'BIDSVersion') || ~isfield(BIDS.description,'Name') + error('BIDS dataset description not valid.'); +end +% See also optional README and CHANGES files + +%-Optional directories %========================================================================== -%-Participants +% [code/] +% [derivatives/] +% [stimuli/] +% [sourcedata/] +% [phenotype] + +%-Scans key file +%========================================================================== + +% sub-/[ses-/] +% sub-_scans.tsv + +%-Participant key file %========================================================================== p = spm_select('FPList',BIDS.dir,'^participants\.tsv$'); if ~isempty(p) BIDS.participants = spm_load(p); end +p = spm_select('FPList',BIDS.dir,'^participants\.json$'); +if ~isempty(p) + BIDS.participants.meta = spm_jsonread(p); +end +%-Sessions file %========================================================================== -%-Tasks -%========================================================================== -t = spm_select('FPList',BIDS.dir,'^task-.*_bold\.json'); -if isempty(t), t = {}; else t = cellstr(t); end -for i=1:numel(t) - task = spm_file(t{i},'basename'); - BIDS.tasks.(task(6:end-5)) = spm_jsonread(t{i}); -end -% + scans key file, sessions file +% sub-/[ses-/] +% sub-[_ses-]_sessions.tsv +%-Tasks: JSON files are accessed through metadata %========================================================================== +%t = spm_select('FPList',BIDS.dir,... +% '^task-.*_(beh|bold|events|channels|physio|stim|meg)\.(json|tsv)$'); + %-Subjects %========================================================================== -sub = spm_select('List',BIDS.dir,'dir','^sub-.*$'); -if isempty(sub) +sub = cellstr(spm_select('List',BIDS.dir,'dir','^sub-.*$')); +if isequal(sub,{''}) error('No subjects found in BIDS directory.'); -else - sub = cellstr(sub); end -for s=1:numel(sub) - - sess = spm_select('List',fullfile(BIDS.dir,sub{s}),'dir','^ses-.*$'); - if ~isempty(sess) - error('Multiple sessions (visits) are not handlet yet.'); +for su=1:numel(sub) + sess = cellstr(spm_select('List',fullfile(BIDS.dir,sub{su}),'dir','^ses-.*$')); + for se=1:numel(sess) + if isempty(BIDS.subjects) + BIDS.subjects = parse_subject(BIDS.dir, sub{su}, sess{se}); + else + BIDS.subjects(end+1) = parse_subject(BIDS.dir, sub{su}, sess{se}); + end end +end + +varargout = { BIDS }; + + +%========================================================================== +%-Parse a subject's directory +%========================================================================== +function subject = parse_subject(p, subjname, sesname) + +subject.name = subjname; % subject name ('sub-') +subject.path = fullfile(p,subjname,sesname); % full path to subject directory +subject.session = sesname; % session name ('' or 'ses-

[a-zA-Z0-9]+)?' ... % dir- + '(?_run-[a-zA-Z0-9]+)?' ... % run- + '_epi\.nii(\.gz)?$'],'names'); % NIfTI file extension + if any(~cellfun(@isempty,labels)) + idx = find(~cellfun(@isempty,labels)); + for i=1:numel(idx) + fb = spm_file(spm_file(f{idx(i)},'basename'),'basename'); + metafile = fullfile(pth,spm_file(fb,'ext','json')); + subject.fmap(j).type = 'epi'; + subject.fmap(j).filename = f{idx(i)}; + subject.fmap(j).ses = regexprep(labels{idx(i)}.ses,'^_[a-zA-Z0-9]+-',''); + subject.fmap(j).acq = regexprep(labels{idx(i)}.acq,'^_[a-zA-Z0-9]+-',''); + subject.fmap(j).dir = labels{idx(i)}.dir; + subject.fmap(j).run = regexprep(labels{idx(i)}.run,'^_[a-zA-Z0-9]+-',''); + subject.fmap(j).meta = spm_jsonread(metafile); + j = j + 1; + end end +end + +%-------------------------------------------------------------------------- +%-MEG data +%-------------------------------------------------------------------------- +pth = fullfile(subject.path,'meg'); +if exist(pth,'dir') + %-MEG data file %---------------------------------------------------------------------- - %-Behavioral experiment data - %---------------------------------------------------------------------- - if exist(fullfile(BIDS.subjects(s).path,'beh'),'dir') + f = spm_select('List',pth,... + sprintf('^%s.*_task-.*_meg\\..*[^json]$',subject.name)); + if isempty(f), f = {}; else f = cellstr(f); end + for i=1:numel(f) + + p = parse_filename(f{i}, {'sub','ses','task','run','proc', 'meta'}); + subject.meg = [subject.meg p]; + subject.meg(end).meta = struct(); % ? + end + %-MEG events file %---------------------------------------------------------------------- - %-Diffusion imaging data + f = spm_select('List',pth,... + sprintf('^%s.*_task-.*_events\\.tsv$',subject.name)); + if isempty(f), f = {}; else f = cellstr(f); end + for i=1:numel(f) + + p = parse_filename(f{i}, {'sub','ses','task','run','proc', 'meta'}); + subject.meg = [subject.meg p]; + subject.meg(end).meta = spm_load(fullfile(pth,f{i})); % ? + + end + + %-Channel description table %---------------------------------------------------------------------- - pth = fullfile(BIDS.subjects(s).path,'dwi'); - if exist(pth,'dir') - d = spm_select('List',pth,... - sprintf('^%s.*_dwi\\.nii(\\.gz)$',BIDS.subjects(s).name)); - if isempty(d), d = {}; else d = cellstr(d); end - for i=1:numel(d) - - %-Diffusion imaging file - %-------------------------------------------------------------- - BIDS.subjects(s).dwi(i).filename = d{i}; % or full path? - labels = regexp(d{i},[... - '^sub-[a-zA-Z0-9]+' ... % sub- - '(?_acq-[a-zA-Z0-9]+)?' ... % acq-X}$J8(|wfs5(iSZl#N?y=o>=bM| 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 delta 11017 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 diff --git a/spm_add.mexw64 b/spm_add.mexw64 index eef09dbfa1f5164a5e14dd3068d7e38485d38f81..bd5c935da3efbf946213050102a93cf4b0991de9 100755 GIT binary patch delta 39 scmZp8!PfACZNdu{g=bGAC%*AvT3FU>#kk#yk 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 literal 212232 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 j@$Lctm=-tn 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 DxUJR1 delta 7612 zcmeHMeOOdgw?Ahba8i&-`4~|U6%kSK%$zxAzGu*Y@Cye<7>PhCtqILgLCMrXfdt1C z-F~E0;+xkjD}~Ygy5%SYij?H*ReAwG%JL|tq=Z9i^R9gcxTw$Vy>C6w{p-&2{La~X zt@T@b?X}n5dl>S{gn4Dc5~r~8;hm)Q4+aai?L&cNq@aHWnnVUaMSM*V2?Rl`LG#Js zf-#<`Tri9*Lx)L);N&iJhYTYV&_KarL4AMw2Ek%)!NPa#eZ`xEeGa`t5cyRiPWTS` z*!MmEoS_6^YqiCQL6+|%vwe-pTtYvT<~Lr@uOBM&^Ap_jMhE@E1S__nOMVi;fz7DH z@1Wqb&3y0sO{mU)vp}#J%?fA`4BNyDlQ-IDNX`lcQ6*?hP^ciV1SJNA>e|*3M01+6 z*(3Y}A?AMKd#%kLA<%1@?d1Lo1Whrmwj6QO2nooVgPUWVO}v^rybjreM(8$laYWcd zL6<**_t45MR(yv6VqB^ndBoFzDcO4^ZDxuRnwtN{2j z^1kA{z%B$lbov6X!UUTLgoA-BNwis$e4!x*xx^MDN=P(vZ!GL~mfs=#3sL3G?RK=H zqu_st%F0jiiLjoCDtmUfv-}RxUx;c>dbgt$9Yuuo-$~XJQLQs~JIn77|Cy+)ol6*I z?BOZuf4_cDgfw+xx1$vugpi-!AJmog4-4ys2|b;`8vcdAlGHtYi8=$b{<(^uDC_C0 z=+6gcg^HgV(bJjuU#091Ge!>U=_~4A1{Tv}FFvuBF@fFA5-b^TYPkG%ItX#TBg*LV z+l^aQUWZ87S*U)nA1WN7p781h%n%mqZLw{dnrts4XYQ0NZ?nZZ-J<9&k#j}$ZeZuP zkU1Zwr^5a>a^Z*!8{$)6Nr+9xniwZ&32p)!7Zwoi02!D1o67}*nmK>Bj{--w7nntX z+4Y0)Fmw0Nyf8^%!+JiBPBknxalMdNA4X+ie$Twut$qsFP^3glikVySh!md~Ezg*_ z*^fx^>DDsV%uPhjuwcnf9Fwi1Gp1S4Fc-(Pao#9$q{L?pA8?oQGD;d5Kc$GD7*}0_ zuNas}VY^R3HMmUXE;wDTWSf&a1#h3dPJH*cdfAqVvwclw?r#rWE=xA{cLLPFOXfwWIN+<{0GSn6xNK(jWl#C2V6GlanA!z<6e?JKjng(9F z++G#E#3SD&&W>sJ5TkcT1r2iIyQh9FL^oAzO5pb22lowFcCHBQ}UU96KEfxeu&Kv9EeG`gf#hkU><%0RzoIZP(3w`$LE%o5Ulz9AhFD@LLHGIeA zSA`cg`V<7g>`l!L90Lp}&3vaIyPt_0+12ZnGuXrp=<4+*vqzgak9K5>7!>@UIIjD@ z^3yhPm-z!xb$x4GUY)d+19`=-u)RYZnE|1 z8%70(@O3rFU033oSYHATOW436kkb|=F0onEDC>hNh{d;+kHxl3WSi<`X#>*Os>GSVSh@mC+}qfdGu*^^VoH(-r|kqDbrNRn$E?iTNG}bPQ$R3rwQoIY z)(@MNVY5g+IA7b;dUNsGoiJnW_dK*lI&8oapg^#Nt{iWR1zTRbg^o+ZdWYlokz44N zG}3w%@8H5)czQxx8bsmc-Y`Z^jR)*1&Mh!mGdJ07hbw)snNxK2$n0=4H_F}9#EN>9 zssPH$!ta)0yc$aN{?Bk0LiKgPJHHB*%2Iou!!hjn89kJpbhn#sqB>gRZg0DZ`pIJ> zI(Lj89KPK_xpz$1O+NU1C%)7&WT=QCD!j?(fC5ihKu9@zGqtAG;v=%B86`UM9XXwx8o5hf9Xs!afOda z`AbJ-;$D43%3nHALsK7-3J5|^w0K+iOK9tLevTG=pJtL=f3P&!S~-7s^NEDZWVyG6 zzmn#;O-#)GIQ#37}2 zhv60`?j3)&i?}^n0mKW@cQNsFtnqQ8$W5f4EhWh;R2P>B^dS=u;ZDP(2zd6IJQSWI zCXa?^!sL$4L@5>2fkpIy0khFFr4+KvF#4j!BW}X^)da+@!K}p0qBb z2kG8RJn7c#CrIILQpU@TIFVY*cpTpH%o#X|nMd$Q8|J1wJ`%-~DqiC`P4m>46P!C7 zsppRco@IVD=8ao8<#C?UJy^-YVw|$ToCFwhZq5Ii|`sSXtQEbgEIPT;|#2 zk%hF2hYrOmn~-X#Ep)&|+Zf~IRahAFprOu|CP(7J0JLfG)8pNi{@Ain=-+MTwYs6M z@Ko_s(Z%BzPc_Dfx)r_w7i$a87AJ|igy`C0mY)fp{o>qA9OU9FLGzR zxCdv;8lID}_6g1m_dt%dJn7w%NqC@Z8)m{l&mw+l1)H8&+6*@-YZFhJvZV*<-d3Je zQThbQ;wFW>OZFmj?ZdWLd3fi-3N;=7?! z0a2*fu@Xi~IU_mn-Fj7g2{ks~F@-;RxjDOvMC}Mg8rIeTu<8r83jkV#Jy`=pFlz zz9sNiSW3$)nIi5bbi&S(VW`7C_Nk$8H&lY`1{$|Nu(uPkdd&G1GVTxZB!GI1K-2aQ z64ce9wfl=CSs<~zwx1Bs+5u@IjPRq6DcQUu7eyX82Gh88ARw66x)`jsMTd%u=Z1>k z28_P!HXQ!BdNj;K+!Ge<0dSiOQ|25%%de7DCfRQ0-xP!6*`E(1m!hK2XK1nh-uYr? zDZJBXrk<*FjmU!uxkeQ5&m#W02A&#kY?>puTY0@VxT|xG*ocA-e&~gz#f1%UJN?}H`?0|_7T|~f^SIc**b#Q4|oSq0LTI)1EK&CfIz^k(*&^yPypBl*bVp+Pz|^W zAiyROzv1J5iXcJ&EFcb$4Cn`#2gn1g0c->81{^vCKkd{);}*aP@T>)6fCL}|2(bJl zLEHdb2Al`f0Zssp04f0KV1qxKp&i>9gcrPn0TBQt;5YDf7H|`A2=FoBeZYoVnjo^F zkq$@%!~v=R7Xiz`VHV(J!1I7a01F65(&Ga>vp*%o1?Bch$Nfor$%&=C{Bf3Bp@{H4 z>iWF4fBjJZFeq3TmehB?yZY<);jiWdkqYnE_o3z0{+_=;)4LpPs}2^ZD$tSYz~qnY zg!l_URShDCR5HD9RKE6{i)~6%Q5jl;@THsw=ADYO#jZysQb( zYPCzWrP^vOr|qK~ql?#N={D%Ld~T1Qeo0xr3zVrtXft<_mL}^mza@?m5MEjeTsDDETuwY&}`Oh z*BG=3+84Fi+F}@Xx3*r}qAk*u=q~6QbvJakbOJ+wfihe)Ts06;?g^I54$C}gA9^o+ zoIXomr90@pa*5m;B~O+ACKoWzGLxC-m~>_VyNWGi@3ZlW>5ASenQFQ!PqkZBtGcOr zTD?)dUEQvBskdv&H77LZG}krvH6ksgovdA`ZPPx~KC7Fodrp_GTcBU1FVn{xrW*(& z+@mnTXxTK`F4=*#qdD_ttzDZeMbFYm+jV}`K`*2wUUyF?)_mcJ=qEnh3&&g^HtW#+K+S?i}tyV6tT zqbgTbs?Mo?Qr%a1tAo^W>O}Q%^(l3LW{@UA6A8(luAQ&#t9x1(YnWo#Vkk4<(cXmt z$5SS17PW}7QSVWoQkSS(RFX7Z`k{1>^oaCJ=^5Eo8A(s1OX(eSGBbyHoB11ap5Yjh z^=GHDCU%#V-OEl>yr5X1C{S!w>`@$5{H%DOcv?AM`G&Gad0P1oPXE5%!_d!QHl!Ld4f6~TRUVw}@Ul`Hsd8$vG(lQU zAE7c}96fc}FQ! z4OER*X;c}i1+c-cs}yRDdXhR`&1$Ae=jrtH+$)CKAywNn}-8!nqC%Z3mtWK}YMdKeuoAFY%s=O`0ZGga1aR2Nij zDz$owdVxAuy-8iF{y_baI#M%U^PHvvN-SMBOP2||d8w{Yw^oOAAL{J7Z*=E%mtdQ@ zbRvC-UI~kksGp%-p-SCoOu3?d3 zm0_o$+;GZ(|G%@3AQ~X*!PG=*J@qA3Mb%RE5c_KB25A|TQMvRh=|7}DN*_uG$U`CI4%6-GWl|OzI==Ph`dJrcX^}y2l;LJ09flV zW(*@^l#HH&fbWh$W}8klD02j*v{9ctB^ z?avNlN3vsCnw^3+zcCnwZ73?AQOSXz790U;x n6N{F{NjEa@Fip&5CWH-V$FR|C9BW|q*s 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 diff --git a/spm_bsplins.mexw32 b/spm_bsplins.mexw32 index dec0528bda5db22f7cc329bc39ebe555f949a9f0..09abcccb0624f62206131d67a790eb283e1d50bc 100755 GIT binary patch delta 33 mcmZoDX(*ZSfu&XYS>(hoKFl>G44a)93-!PPn|J7YZ~*}K1r2oo delta 33 mcmZoDX(*ZSf#vAmPoWdP_%MqaGH!NeEYt%FY~G>o!36*kRSzHl diff --git a/spm_bsplins.mexw64 b/spm_bsplins.mexw64 index 033eb5a8ce4497e7fb42870dd3634e8746ef8626..2694504114ccbac5df8c827ab0741d31c3a75c3b 100755 GIT binary patch delta 35 ocmZqZU~K4MobZ4}?b*}FiBEi(xmg%D8#7L{1Pg3FVP(My0Q)=*ng9R* delta 35 ocmZqZU~K4MobZ6<*WQ@WiBEi(7p`L1Y|J>(5-hO!gp~y+02g%+5dZ)H diff --git a/spm_bwlabel.mexmaci64 b/spm_bwlabel.mexmaci64 index 4d69709345d59c0e171ace8cc5ab6d4de70b4386..5665b9ac4a9058bdd79cd2fe44e1624d7688b438 100755 GIT binary patch literal 13820 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 diff --git a/spm_bwlabel.mexw32 b/spm_bwlabel.mexw32 index 08f8286c09e075bee37ffc3eab7ce0476fa28eef..2dcc8df76d9208d66160116b797e7e09a6265702 100755 GIT binary patch delta 32 lcmZqhXz-Zufn}xiv&e~Ge3;rEZFXXGk^%EKcgR+-0RZho4TJyy delta 32 lcmZqhXz-Zuf#urYPoWdP_%QvNx7mr&Ne0Z{+#y@R1^^TI58?m- diff --git a/spm_bwlabel.mexw64 b/spm_bwlabel.mexw64 index c8cda6dd9db5cf683b724c1ff05446f26035dd4a..d66e69f4560c9cd37c1e4152068ca41896e973c5 100755 GIT binary patch delta 33 mcmZpOX^5HdfJOJ&)5wWWe3*ZyF>E$woTvmA*nC3Sf(rlyP!4hc delta 33 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 literal 19016 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 diff --git a/spm_cat.mexw32 b/spm_cat.mexw32 index 4d26dfb7af0b8687bd47564c83dd02f0b0c40681..9c6ac555e4674f98dff2a44051ff4b92ab64e540 100644 GIT binary patch delta 32 lcmZpuXsDR*f#s6)v&e~Ge3+IW+w8;`WCG@Io?)871^@u14toFq delta 32 lcmZpuXsDR*f#v<*PoWdP_%Qu$+U&#_WCG@Io?)871^^=q5Sah~ diff --git a/spm_cat.mexw64 b/spm_cat.mexw64 index 281c0dc08bc0d74201c00b781071b26b16a948df..7ad99d1c2a4e754af9b244a1fb09fd24dea03106 100644 GIT binary patch delta 35 ocmZqZVQlDOobZ9g?Ag=EiC=t}3%MCLJ2M*EfCV;J*miIL00kQk1ONa4 delta 35 ocmZqZVQlDOobZ8#XJ1U{#4kR~+?yCSJ2M*EfCV;J*miIL0POY*h5!Hn diff --git a/spm_cat_struct.m b/spm_cat_struct.m index 583cad8c..9850a3a8 100644 --- a/spm_cat_struct.m +++ b/spm_cat_struct.m @@ -1,22 +1,20 @@ -function s = spm_cat_struct(varargin) +function s = spm_cat_struct(s1, s2, varargin) % Concatenates structure arrays with possibly different fields % FORMAT s = spm_cat_struct(s1, s2, ...) %__________________________________________________________________________ -% Copyright (C) 2013 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2013-2017 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_cat_struct.m 6409 2015-04-16 16:19:38Z guillaume $ +% $Id: spm_cat_struct.m 7074 2017-05-05 10:51:08Z guillaume $ -if nargin < 2 - error('At least two arguments are required'); -end - -s1 = varargin{1}; -if nargin > 2 - s2 = spm_cat_struct(varargin{2:end}); -else - s2 = varargin{2}; +if ~nargin + s1 = struct([]); + s2 = struct([]); +elseif nargin == 1 + s2 = struct([]); +elseif nargin > 2 + s2 = spm_cat_struct(s2,varargin{:}); end if isempty(s1) diff --git a/spm_changepath.m b/spm_changepath.m index ed86f2fd..abc31ba1 100644 --- a/spm_changepath.m +++ b/spm_changepath.m @@ -1,4 +1,4 @@ -function varargout = spm_changepath(Sf, oldp, newp) +function varargout = spm_changepath(Sf, oldp, newp, verbose) % Recursively replace all occurences of a text pattern in a MATLAB variable. % FORMAT S = spm_changepath(Sf, oldp, newp) % @@ -15,10 +15,10 @@ % If MAT filenames are specified, they will be overwritten with the new % version. A backup of the initial version is made with a ".old" suffix. %__________________________________________________________________________ -% Copyright (C) 2009-2013 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2009-2016 Wellcome Trust Centre for Neuroimaging % Guillaume Flandin -% $Id: spm_changepath.m 6416 2015-04-21 15:34:10Z guillaume $ +% $Id: spm_changepath.m 6948 2016-11-24 10:34:01Z guillaume $ %-Input arguments @@ -35,6 +35,10 @@ newp = spm_input('New pattern','+1','s'); end +if nargin <= 3 + verbose = true; +end + %-Replace pattern in given MAT-files %-------------------------------------------------------------------------- if ischar(Sf) @@ -52,20 +56,20 @@ catch error('Cannot load "%s".',f); end - tmp = changepath(S,oldp,newp); + tmp = changepath(S,oldp,newp,verbose); if ~isequalwithequalnans(tmp,S) - fprintf('=> Fixing %s\n',f); + if verbose, fprintf('=> Fixing %s\n',f); end [sts, msg] = movefile(f,[f '.old']); if ~sts, error(msg); end save(f ,'-struct','tmp', spm_get_defaults('mat.format')); end end else - varargout = { changepath(Sf,oldp,newp) }; + varargout = { changepath(Sf,oldp,newp,verbose) }; end %========================================================================== -function S = changepath(S,oldp,newp) +function S = changepath(S,oldp,newp,verbose) check = false; @@ -75,14 +79,14 @@ case 'cell' for i=1:numel(S) - S{i} = changepath(S{i},oldp,newp); + S{i} = changepath(S{i},oldp,newp,verbose); end case 'struct' for i=1:numel(S) fn = fieldnames(S); for j=1:length(fn) - S(i).(fn{j}) = changepath(S(i).(fn{j}),oldp,newp); + S(i).(fn{j}) = changepath(S(i).(fn{j}),oldp,newp,verbose); end end @@ -103,7 +107,7 @@ else sts = ''; end - fprintf('%s%s\n',t,sts); + if verbose, fprintf('%s%s\n',t,sts); end end tmp{i} = t; end @@ -111,16 +115,16 @@ case 'nifti' for i=1:numel(S) - S(i).dat = changepath(S(i).dat,oldp,newp); + S(i).dat = changepath(S(i).dat,oldp,newp,verbose); end case 'file_array' - S.fname = changepath(S.fname,oldp,newp); + S.fname = changepath(S.fname,oldp,newp,verbose); case 'gifti' if isfield(S,'cdata') && isa(S.cdata,'file_array') fa = struct(S.cdata); - fa.fname = changepath(fa.fname,oldp,newp); + fa.fname = changepath(fa.fname,oldp,newp,verbose); S.cdata = file_array(fa); end diff --git a/spm_check_installation.m b/spm_check_installation.m index 0886d244..612392f6 100644 --- a/spm_check_installation.m +++ b/spm_check_installation.m @@ -13,10 +13,10 @@ % Build signature of SPM distribution as used by 'full' option. % (for developers) %__________________________________________________________________________ -% Copyright (C) 2009-2016 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2009-2017 Wellcome Trust Centre for Neuroimaging % Guillaume Flandin -% $Id: spm_check_installation.m 6675 2016-01-12 18:22:29Z guillaume $ +% $Id: spm_check_installation.m 7005 2017-02-03 17:32:23Z guillaume $ if isdeployed, return; end @@ -41,17 +41,26 @@ %========================================================================== function check_basic +%-Platform: MATLAB, GNU Octave +%-------------------------------------------------------------------------- +if exist('OCTAVE_VERSION','builtin') + platform = 'Octave'; +else + platform = 'MATLAB'; +end + %-Minimal MATLAB version required %-------------------------------------------------------------------------- +minVer = '7.4'; try - v = spm_check_version('matlab','7.4'); + v = spm_check_version('matlab',minVer); catch error('A problem occurred with spm_check_version.m.'); end if v < 0 error([... - 'SPM12 requires MATLAB 7.4 onwards in order to run.\n'... - 'This MATLAB version is %s\n'], version); + 'SPM12 requires MATLAB %s onwards in order to run.\n'... + 'This MATLAB version is %s.'], minVer, version); end %-Check installation @@ -64,23 +73,24 @@ p = textscan(path,'%s','delimiter',pathsep); p = p{1}; if ~ismember(lower(d),lower(p)) error(sprintf([... - 'You do not appear to have the MATLAB search path set up\n'... + 'You do not appear to have the function search path set up\n'... 'to include your SPM12 distribution. This means that you\n'... 'can start SPM in this directory, but if your change to\n'... - 'another directory then MATLAB will be unable to find the\n'... - 'SPM functions. You can use the pathtool command in MATLAB\n'... - 'to set it up.\n'... + 'another directory then %s will be unable to find the\n'... + 'SPM functions. You can use the addpath command in %s\n'... + 'to set it up:\n'... ' addpath %s\n'... - 'For more information, try typing the following:\n'... - ' help path\n help pathtool'],d)); + 'For more information, type the following:\n'... + ' help path\n' ... + ' help pathtool'],platform,platform,d)); end if ismember(lower(fullfile(d,'src')),lower(p)) warning(sprintf([... - 'You appear to have added all SPM subfolders to the MATLAB\n'... + 'You appear to have added all SPM subfolders to the function\n'... 'search path. This is not recommended.\n'... 'You only need to add SPM main directory; relevant subfolders '... 'will be\nautomatically added by SPM when needed.\n'... - 'You can clear the MATLAB search path by typing the following:\n'... + 'You can clear the function search path by typing the following:\n'... ' spm_rmpath\n'... ' addpath %s\n'... 'For more information, type the following:\n'... @@ -97,7 +107,9 @@ 'and the updates installed on top of this. Unix commands\n'... 'to do this are:\n'... ' unzip spm12.zip\n'... - ' unzip -o spm12_updates_r????.zip -d spm12'])); + ' unzip -o spm12_updates_r????.zip -d spm12\n'... + 'For more information, type the following:\n'... + ' help spm_update'])); else error(sprintf([... 'There appears to be some problem with the installation.\n'... @@ -140,14 +152,13 @@ error([... 'SPM uses a number of MEX files, which are compiled functions.\n'... 'These need to be compiled for the various platforms on which SPM\n'... - 'is run. At the FIL, where SPM is developed, the number of\n'... - 'computer platforms is limited. It is therefore not possible to\n'... - 'release a version of SPM that will run on all computers. See\n'... - ' %s%csrc%cMakefile and\n'... + 'is run. It seems that the compiled files for your computer platform\n'... + 'are missing. See\n'... ' http://en.wikibooks.org/wiki/SPM#Installation\n'... - 'for information about how to compile mex files for %s\n'... - 'in MATLAB %s.'],... - d,filesep,filesep,computer,version); + ' %s\n'... + 'for information about how to compile MEX files for %s\n'... + 'in %s %s.'],... + fullfile(d,'src','Makefile'),computer,platform,version); end %========================================================================== @@ -164,11 +175,19 @@ disp(['(___/(__) (_/\/\_) SPM - http://www.fil.ion.ucl.ac.uk/spm/ ']); fprintf('\n'); +%- +%------------------------------------------------------------------------------- +if exist('OCTAVE_VERSION','builtin') + software = 'Octave'; +else + software = 'MATLAB'; +end + %-Detect SPM directory %-------------------------------------------------------------------------- -SPMdir = which('spm.m','-ALL'); +SPMdir = cellstr(which('spm.m','-ALL')); if isempty(SPMdir) - fprintf('SPM is not in your MATLAB path.\n'); + fprintf('SPM is not in your %s path.\n',software); return; elseif numel(SPMdir) > 1 fprintf('SPM seems to appear in several different folders:\n'); @@ -222,9 +241,9 @@ %-Detect MATLAB & toolboxes %-------------------------------------------------------------------------- -fprintf('MATLAB is installed in: %s\n',matlabroot); -fprintf('MATLAB version is %s\n',version); -fprintf('MATLAB toolboxes: '); hastbx = false; +fprintf('%s is installed in: %s\n',software,matlabroot); +fprintf('%s version is %s\n',software,version); +fprintf('%s toolboxes: ',software); hastbx = false; if license('test','signal_toolbox') && ~isempty(ver('signal')) vtbx = ver('signal'); hastbx = true; fprintf('signal (v%s) ',vtbx.Version); @@ -257,8 +276,13 @@ else platform = system_dependent('getos'); end -else - platform = system_dependent('getos'); +else + try + platform = system_dependent('getos'); + catch + [dummy, platform] = system('uname -sr'); + platform = deblank(platform); + end end fprintf('OS: %s\n', platform); @@ -283,10 +307,12 @@ %-Detect OpenGL rendering %-------------------------------------------------------------------------- -S = opengl('data'); -fprintf('OpenGL version: %s',S.Version); -if S.Software, fprintf('(Software)\n'); else fprintf('(Hardware)\n'); end -fprintf('OpenGL renderer: %s (%s)\n',S.Vendor,S.Renderer); +if strcmpi(software,'matlab') + S = opengl('data'); + fprintf('OpenGL version: %s',S.Version); + if S.Software, fprintf('(Software)\n'); else fprintf('(Hardware)\n'); end + fprintf('OpenGL renderer: %s (%s)\n',S.Vendor,S.Renderer); +end %-Detect MEX setup %-------------------------------------------------------------------------- @@ -514,7 +540,7 @@ function compare_versions(l,r) else l(end+1) = info; end if isempty(r) && strcmp(ext,'.m') - w = which(f{i},'-ALL'); + w = cellstr(which(f{i},'-ALL')); if numel(w) > 1 && ~strcmpi(f{i},'Contents.m') if ~dispw, fprintf('\n'); end dispw = true; @@ -556,7 +582,7 @@ function compare_versions(l,r) r = regexp(str,['\$Id: (?\S+) (?[0-9]+) (?\S+) ' ... '(\S+Z) (?\S+) \$'],'names'); -if isempty(r) +if isempty(r) || isempty(r(1).file) %sts = false; %fprintf('\n%s has no SVN Id.\n',f); else diff --git a/spm_cli.m b/spm_cli.m new file mode 100644 index 00000000..9d25666e --- /dev/null +++ b/spm_cli.m @@ -0,0 +1,276 @@ +function spm_cli(varargin) +% Command line interface for SPM +%__________________________________________________________________________ +% Copyright (C) 2016 Wellcome Trust Centre for Neuroimaging + +% Guillaume Flandin +% $Id: spm_cli.m 6964 2016-12-07 16:50:41Z guillaume $ + + +%-Input arguments +%-------------------------------------------------------------------------- +if isempty(varargin), return; end +if nargin == 1 && ismember(varargin{1},{'help','--help'}) + cmd = lower(spm('Ver')); + fprintf([... + 'Usage: %s [NODE] [arg...]\n',... + ' %s [NODE] help\n',... + ' %s [ help | --help ]\n',... + ' %s help --verbose\n',... + '\n',... + '[NODE] Batch node name\n',... + '--verbose List all available batch nodes\n',... + '--help, help Print usage statement\n'],... + cmd, cmd, cmd, cmd); + return +end +if nargin == 2 ... + && all(ismember(strtok(varargin(1:2),'-'),{'help','verbose'})) + c0 = cfg_util('getcfg'); + nodes = find_all_modules(c0.values{1})'; + for i=1:numel(nodes) + [n, c] = find_module(strsplit(nodes{i},'.'), c0); + h = normalise_help_text(c.help); + if ~c.hidden, fprintf(' %s %s\n',nodes{i},h{1}); end + end + return +end +node = strsplit(varargin{1},'.'); +opts = varargin(2:end); + +%-Get the configuration tree +%-------------------------------------------------------------------------- +try + c0 = cfg_util('getcfg'); +catch + spm_jobman('initcfg'); + c0 = cfg_util('getcfg'); +end + +%-Search module in configuration tree and allow for node shortcut +% (use first matching module if ambiguity) +%-------------------------------------------------------------------------- +[n, c0, found] = find_module(node, c0); + +if ~found + error('Cannot find module %s.\n',strjoin(node,'.')); +else + n = n(2:end); % first is matlabbatch + if ~isequal(n,node) + node = n; + fprintf('Matching module %s.\n',strjoin(node,'.')); + end +end + +%-Help for a specific node +%-------------------------------------------------------------------------- +if numel(opts) == 1 && ismember(opts{1},{'help','--help'}) + cmd = lower(spm('Ver')); + fprintf([... + 'Usage: %s %s [OPTIONS]\n',... + '\n',... + 'Options:\n'],... + cmd,strjoin(node,'.')); + [flags, h1s, ms] = get_items(c0); + n = cellfun(@numel,flags); + for i=1:numel(flags) + if ms(i), m = '(*) '; else m = ''; end + fprintf(' --%s%s%s%s\n',flags{i},repmat(' ',1,3+max(n)-n(i)),m,h1s{i}); + end + fprintf([... + '\n',... + ' --help%sPrint usage statement\n'],repmat(' ',1,3+max(n)-4)); + return; +end + +%-Get options +%-------------------------------------------------------------------------- +i = 1; +params = {}; +values = {}; +while i <= numel(opts) + flag = strtok(opts{i},'-'); + opt = {}; + i = i + 1; + for j=i:numel(opts) + if opts{j}(1) == '-', break; end + opt{end+1} = opts{j}; + i = i + 1; + end + params{end+1} = flag; + values{end+1} = opt; +end + +%-Create batch job structure +%-------------------------------------------------------------------------- +job = struct(); +for i=1:numel(params) + prm = params{i}; + if ~any(prm == '.') + subs = substruct('.',prm); + else + clear subs + p = strsplit(prm,'.'); + for j=1:numel(p) + subs(j) = substruct('.',p{j}); + end + prm = p{end}; + end + job = subsasgn(job, subs, get_val(values{i},prm,c0)); +end + +%-Execute batch job +%-------------------------------------------------------------------------- +subs = reshape([repmat({'.'},1,numel(node));node],1,[]); +subs = substruct(subs{:}); +job = subsasgn(struct(),subs,job); +cfg_message('none','destination','^matlabbatch:run:jobstart$'); +cfg_message('none','destination','^matlabbatch:run:jobdone$'); +cfg_message('none','destination','^matlabbatch:run:jobfailed$'); +cfg_message('none','destination','^matlabbatch:run:modstart$'); +cfg_message('none','destination','^matlabbatch:run:moddone$'); +%cfg_message('none','destination','^matlabbatch:run:modfailed$'); +try + [out, job] = spm_jobman('run', {job}); +catch + err = lasterror; + switch err.identifier + case 'spm:spm_jobman:jobNotFilled' + error('Incomplete job.'); + case 'matlabbatch:run:jobfailederr' + error('Job failed.'); + otherwise + error('Unknown error during job execution.'); + end +end + + +%========================================================================== +function [node, c0, found] = find_module(node, c0, found) + +if nargin < 3, found = false; end +if found, return; end +if strcmp(node{1}, c0.tag) + if numel(node) == 1 + if isa(c0,'cfg_exbranch'), found = true; end + else + if ~isa(c0,'cfg_exbranch') + for i=1:numel(c0.values) + [n, c1 , found] = find_module(node(2:end), c0.values{i}); + if found, node = [c0.tag n]; c0 = c1; return; end + end + end + end +else + if ~isa(c0,'cfg_exbranch') + for i=1:numel(c0.values) + [n, c1, found] = find_module(node, c0.values{i}); + if found, node = [c0.tag n]; c0 = c1; return; end + end + end +end + + +%========================================================================== +function [nodes,n] = find_all_modules(c0,nodes,n) + +if nargin < 2, nodes = {}; end +if nargin < 3, n = {}; end +if isa(c0,'cfg_exbranch') + nodes = [nodes strjoin([n c0.tag],'.')]; +else + m = n; + for i=1:numel(c0.values) + [nodes, n] = find_all_modules(c0.values{i},nodes,[m c0.tag]); + end +end + + +%========================================================================== +function param = get_val(param,flag,c0) + +for i=1:numel(c0.val) + if strcmp(c0.val{i}.tag, flag) + switch class(c0.val{i}) + case 'cfg_files' + param = param(:); + case 'cfg_entry' + switch c0.val{i}.strtype + case {'n','w','r'} + param = str2num(char(param)); + case {'s'} + param = char(param); + end + case 'cfg_menu' + if numel(param) > 1 + error('Only one value accepted for "%s".',flag); + end + param = char(param); + labels = c0.val{i}.labels; + j = find(ismember(labels,param)); + if nnz(j) + param = c0.val{i}.values{j}; + else + opts = sprintf(' "%s"\n',labels{:}); + error(['Cannot translate option "%s": %s.\n',... + 'Options are:\n%s'],flag, param, opts); + end + otherwise + end + return; + end +end +for i=1:numel(c0.val) + switch class(c0.val{i}) + case 'cfg_branch' + param = get_val(param,flag,c0.val{i}); + case 'cfg_repeat' + case 'cfg_choice' + end +end + + +%========================================================================== +function [flags, h1s, ms] = get_items(c0) +flags = {}; h1s = {}; ms = []; +for i=1:numel(c0.val) % go recursive instead + flag = {}; h1 = {}; m = []; + if isa(c0.val{i},'cfg_repeat') + % if more than one, they are not stored yet + for j=1:numel(c0.val{i}.values) + [flag, h1, m] = get_items(c0.val{i}.values{j}); + flag = [{c0.val{i}.values{j}.tag} flag]; + h1 = [{char(c0.val{i}.values{j}.help{:})} h1]; + m = [is_mandatory(c0.val{i}.values{j}) m]; + end + elseif isa(c0.val{i},'cfg_branch') + [flag, h1, m] = get_items(c0.val{i}); + flag = [{c0.val{i}.tag} flag]; + h1 = [{char(c0.val{i}.help{:})} h1]; + m = [is_mandatory(c0.val{i}) m]; + else + flag = c0.val{i}.tag; + h1 = char(c0.val{i}.help{:}); + m = is_mandatory(c0.val{i}); + end + h1 = normalise_help_text(h1); + flags = [flags flag]; + h1s = [h1s h1]; + ms = [ms m]; +end + + +%========================================================================== +function m = is_mandatory(item) +m = isempty(item.val) && isempty(item.def); + + +%========================================================================== +function h1 = normalise_help_text(h1) +h1 = cellstr(h1); +for i=1:numel(h1) + if ~isempty(h1{i}) && h1{i}(end) == '.', h1{i} = h1{i}(1:end-1); end + if numel(h1{i}) > 70 % use "stty size" to get the number of columns + h1{i} = [h1{i}(1:70-3) '...']; + end +end diff --git a/spm_contrasts.m b/spm_contrasts.m index 1076a024..180ca8fe 100644 --- a/spm_contrasts.m +++ b/spm_contrasts.m @@ -8,10 +8,10 @@ % This function fills in SPM.xCon and writes con_????, ess_???? and % spm?_???? images. %__________________________________________________________________________ -% Copyright (C) 2002-2016 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2002-2017 Wellcome Trust Centre for Neuroimaging % Karl Friston, Will Penny & Guillaume Flandin -% $Id: spm_contrasts.m 6752 2016-03-24 16:17:25Z guillaume $ +% $Id: spm_contrasts.m 7029 2017-02-24 15:39:07Z guillaume $ % Temporary copy of the SPM variable, to avoid saving it in SPM.mat unless @@ -61,6 +61,8 @@ if any(ismember(name,'SurfaceID')) metadata = metadata(ismember(name,'SurfaceID')); metadata = {metadata.name, metadata.value}; + elseif isfield(g,'faces') && ~isempty(g.faces) + metadata = {'SurfaceID', SPM.xY.VY(1).fname}; else metadata = {}; end @@ -300,8 +302,13 @@ xCon(ic).Vspm = spm_data_write(xCon(ic).Vspm,tmp); clear tmp Z - fprintf('%s%30s\n',repmat(sprintf('\b'),1,30),sprintf(... - '...written %s',spm_file(xCon(ic).Vspm.fname,'filename'))); %-# + cmd = sprintf(['[hReg,xSPM,SPM] = spm_results_ui(''Setup'',',... + 'struct(''swd'',''%s'',''Ic'',%d));',... + 'TabDat = spm_list(''List'',xSPM,hReg);'],pwd,ic); + img = spm_file(spm_file(xCon(ic).Vspm.fname,'filename'),'link',cmd); + n = 30; if length(img)>n, n = length(img)+n-13; end + fprintf('%s%*s\n',repmat(sprintf('\b'),1,30),n,sprintf(... + '...written %s',img)); %-# end % (if isempty(xCon(ic)...) @@ -317,5 +324,7 @@ if spm_check_version('matlab','8.0') >= 0, my_isequaln = @isequaln; else my_isequaln = @isequalwithequalnans; end if ~my_isequaln(tmpSPM,SPM) + fprintf('\t%-32s: %30s','Saving SPM.mat','...writing'); %-# save('SPM.mat', 'SPM', spm_get_defaults('mat.format')); + fprintf('%s%30s\n',repmat(sprintf('\b'),1,30),'...SPM.mat saved') %-# end diff --git a/spm_conv_vol.mexmaci64 b/spm_conv_vol.mexmaci64 index 6e7cbecdc3c852e8eda2f7a84d0a5c6ef3cb8eab..c328fba493d493adaf49ed9140ba898d42e5cc2d 100755 GIT binary patch literal 186280 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 QT{^^BGbFIK4&USUU%=1~TL1t6 literal 207856 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 E0VR7aiU0rr diff --git a/spm_conv_vol.mexw32 b/spm_conv_vol.mexw32 index 42ce0ad4ae26ca4443e74e639c2ec925bc03312b..b1062b105a3550a31ed0203831064eb03e7e55bc 100755 GIT binary patch delta 11361 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 delta 11069 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 diff --git a/spm_conv_vol.mexw64 b/spm_conv_vol.mexw64 index 27873201a0838861ccfb78c3bbcb5d577df498a7..ad55762af29f49b27e232bb9a82c0405e87921fe 100755 GIT binary patch delta 39 scmZo@VQ*+*pYVW1@!8YJiBEi(5)U;SF>W_vWMtX|7Ta#InehZ407ME8%>V!Z delta 39 scmZo@VQ*+*pYVW1llgP##3w#X-CvrG7`GcSGBRxfi*2{q%y@zi04%-^hX4Qo diff --git a/spm_copy.m b/spm_copy.m new file mode 100644 index 00000000..e084d872 --- /dev/null +++ b/spm_copy.m @@ -0,0 +1,77 @@ +function spm_copy(source, dest, varargin) +% Copy file(s) +% FORMAT spm_copy(source, dest [,opts]) +%__________________________________________________________________________ +% Copyright (C) 2017 Wellcome Trust Centre for Neuroimaging + +% Guillaume Flandin +% $Id: spm_copy.m 7121 2017-06-21 16:35:40Z guillaume $ + + +%-Source and destination +%-------------------------------------------------------------------------- +source = cellstr(source); +if nargin < 2 + dest = pwd; +end +dest = cellstr(dest); +if numel(source) == 1 + source = repmat(source,numel(dest),1); +elseif numel(dest) == 1 + dest = repmat(dest,numel(source),1); +elseif numel(source) ~= numel(dest) + error('Number of elements in source and dest must be one or equal.'); +end + +%-Options (struct array or key/value pairs) +%-------------------------------------------------------------------------- +opts = struct('gzip', false, 'gunzip', false, 'nifti', false, 'mode', {{}}); +if nargin > 2 + if isstruct(varargin{1}) + opt = varargin{1}; + else + opt = struct; + for i=1:2:numel(varargin) + opt.(varargin{i}) = varargin{i+1}; + end + end +else + opt = struct([]); +end +fn = fieldnames(opt); +for i=1:numel(fn) + if ~isfield(opts,lower(fn{i})) + warning('Unknown option "%s".',fn{i}); + end + opts.(lower(fn{i})) = opt.(fn{i}); +end + +%-Actual copy +%-------------------------------------------------------------------------- +for i=1:numel(source) + protocol = source{i}(1:find(source{i}==':',1)-1); + if ismember(protocol,{'file','http','https','ftp'}) + urlwrite(source{i}, dest{i}); % dest{i} has to be a filename... + else + sts = copyfile(source{i}, dest{i}, opts.mode{:}); + end + if opts.nifti + if strcmp(spm_file(source{i},'ext'),'img') + s = copyfile(spm_file(source{i},'ext','hdr'), dest{i}, opts.mode{:}); + s = copyfile(spm_file(source{i},'ext','mat'), dest{i}, opts.mode{:}); + elseif strcmp(spm_file(source{i},'ext'),'hdr') + s = copyfile(spm_file(source{i},'ext','img'), dest{i}, opts.mode{:}); + s = copyfile(spm_file(source{i},'ext','mat'), dest{i}, opts.mode{:}); + elseif strcmp(spm_file(source{i},'ext'),'nii') + s = copyfile(spm_file(source{i},'ext','mat'), dest{i}, opts.mode{:}); + end + end + if opts.gzip && ~strcmp(spm_file(source{i},'ext'),'gz') + gzip(spm_file(source{i},'path',dest{i})); + spm_unlink(spm_file(source{i},'path',dest{i})); + end + if opts.gunzip && strcmp(spm_file(source{i},'ext'),'gz') + gunzip(spm_file(source{i},'path',dest{i})); + spm_unlink(spm_file(source{i},'path',dest{i})); + end +end diff --git a/spm_create_vol.m b/spm_create_vol.m index e3af9902..54974bb1 100644 --- a/spm_create_vol.m +++ b/spm_create_vol.m @@ -3,12 +3,16 @@ % FORMAT V = spm_create_vol(V) % V - image volume information (see spm_vol.m) %__________________________________________________________________________ -% Copyright (C) 2005-2014 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2016 Wellcome Trust Centre for Neuroimaging % John Ashburner -% $Id: spm_create_vol.m 6157 2014-09-05 18:17:54Z guillaume $ +% $Id: spm_create_vol.m 6908 2016-10-21 11:29:25Z guillaume $ +if ~isstruct(V) + error('Input argument V is not a structure.'); +end + for i=1:numel(V) v = create_vol(V(i)); @@ -24,15 +28,24 @@ %========================================================================== function V = create_vol(V) -if ~isstruct(V), error('Not a structure.'); end - -if ~isfield(V,'fname'), error('No "fname" field'); end +%-Field 'fname' +%-------------------------------------------------------------------------- +if ~isfield(V,'fname'), error('Missing field "fname".'); end +V.fname = deblank(V.fname); -if ~isfield(V,'dim'), error('No "dim" field'); end -if ~all(size(V.dim)==[1 3]) - error(['"dim" field is the wrong size (' num2str(size(V.dim)) ').']); +%-Field 'dim' +%-------------------------------------------------------------------------- +if ~isfield(V,'dim'), error('Missing field "dim".'); end +if ~isequal(size(V.dim),[1 3]) + error('Field "dim" has a wrong size (%s).',num2str(size(V.dim))); end +%-Field 'mat' +%-------------------------------------------------------------------------- +if ~isfield(V,'mat'), error('Missing field "mat".'); end + +%-Field 'n' +%-------------------------------------------------------------------------- if ~isfield(V,'n') V.n = [1 1]; else @@ -43,7 +56,9 @@ error('Can only do up to 4D data (%s).',V.fname); end -if ~isfield(V,'dt') +%-Field 'dt' +%-------------------------------------------------------------------------- +if ~isfield(V,'dt') || isempty(V.dt) V.dt = [spm_type('float64') spm_platform('bigend')]; end dt{1} = spm_type(V.dt(1)); @@ -52,27 +67,40 @@ end if V.dt(2), dt{2} = 'BE'; else dt{2} = 'LE'; end -if ~isfield(V,'pinfo'), V.pinfo = [Inf Inf 0]'; end -if size(V.pinfo,1)==2, V.pinfo(3,:) = 0; end - -V.fname = deblank(V.fname); -ext = spm_file(V.fname,'ext'); +%-Field 'pinfo' +%-------------------------------------------------------------------------- +if ~isfield(V,'pinfo') || isempty(V.pinfo) + V.pinfo = [Inf Inf 0]'; +end +if size(V.pinfo,1)==2, V.pinfo(3,:) = 0; end +ext = spm_file(V.fname,'ext'); switch ext case {'img'} minoff = 0; case {'nii'} minoff = 352; % or 544 for NIfTI-2 otherwise - error(['".' ext '" is not a recognised extension.']); + error('".%s" is not a recognised extension.',ext); end bits = spm_type(V.dt(1),'bits'); minoff = minoff + ceil(prod(V.dim(1:2))*bits/8)*V.dim(3)*(V.n(1)-1+V.n(2)-1); V.pinfo(3,1) = max(V.pinfo(3,:),minoff); -if ~isfield(V,'descrip'), V.descrip = ''; end -if ~isfield(V,'private'), V.private = struct; end +%-Field 'descrip' +%-------------------------------------------------------------------------- +if ~isfield(V,'descrip') || isempty(V.descrip) + V.descrip = ''; +end + +%-Field 'private' +%-------------------------------------------------------------------------- +if ~isfield(V,'private') || isempty(V.private) + V.private = struct; +end +%-Create image volume +%-------------------------------------------------------------------------- dim = [V.dim(1:3) V.n]; dat = file_array(V.fname,dim,[dt{1} '-' dt{2}],0,V.pinfo(1),V.pinfo(2)); N = nifti; diff --git a/spm_cva_ui.m b/spm_cva_ui.m index 9b60023f..d3ca571e 100644 --- a/spm_cva_ui.m +++ b/spm_cva_ui.m @@ -82,7 +82,7 @@ % Copyright (C) 2008-2014 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_cva_ui.m 6242 2014-10-14 11:16:02Z guillaume $ +% $Id: spm_cva_ui.m 7081 2017-05-27 19:36:09Z karl $ %-Get figure handles @@ -234,7 +234,7 @@ %-Show results %------------------------------------------------------------------ - spm_figure('GetWin','MVB'); + spm_figure('GetWin','CVA'); %-Unpack %------------------------------------------------------------------ diff --git a/spm_dcm_bma.m b/spm_dcm_bma.m index 5d7bc44b..53fee1da 100644 --- a/spm_dcm_bma.m +++ b/spm_dcm_bma.m @@ -12,7 +12,7 @@ % BMA - Baysian model average structure % --------------------------------------------------------------------- % BMA.Ep - BMA posterior mean -% BMA.Sp - BMA posterior variance +% BMA.Cp - BMA posterior VARIANCE % BMA.F - Accumulated free energy over subjects; % BMA.P - Posterior model probability over subjects; % @@ -88,7 +88,7 @@ % Copyright (C) 2009 Wellcome Trust Centre for Neuroimaging % Will Penny -% $Id: spm_dcm_bma.m 6879 2016-09-17 17:45:08Z peter $ +% $Id: spm_dcm_bma.m 7081 2017-05-27 19:36:09Z karl $ % defaults %-------------------------------------------------------------------------- diff --git a/spm_dcm_bmr.m b/spm_dcm_bmr.m index e32ab242..24a65c7e 100644 --- a/spm_dcm_bmr.m +++ b/spm_dcm_bmr.m @@ -39,7 +39,7 @@ % Copyright (C) 2015 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_dcm_bmr.m 6879 2016-09-17 17:45:08Z peter $ +% $Id: spm_dcm_bmr.m 6940 2016-11-20 18:08:06Z peter $ % get filenames and set up @@ -66,7 +66,7 @@ if Ns > 2 for i = 1:Ns [p,q,r] = spm_dcm_bmr(P(i,:),field); - RCM{i,:} = p; + RCM(i,:) = p; BMC(i) = q; BMA(i) = r; end diff --git a/spm_dcm_bmr_all.m b/spm_dcm_bmr_all.m index ef2cc8f9..7949d5fb 100644 --- a/spm_dcm_bmr_all.m +++ b/spm_dcm_bmr_all.m @@ -2,46 +2,58 @@ % Bayesian model reduction of all permutations of model parameters % FORMAT [RCM,BMR,BMA] = spm_dcm_bmr_all(DCM,field) % -% DCM - DCM structures: +% DCM - A single estimated DCM (or PEB) structure: % % DCM.M.pE - prior expectation % DCM.M.pC - prior covariance % DCM.Ep - posterior expectation % DCM.Cp - posterior covariances -% % DCM.beta - prior expectation of reduced parameters (default: 0) % DCM.gamma - prior variance of reduced parameters (default: 0) +% NB: beta = 'pE' uses full priors % % field - parameter fields in DCM{i}.Ep to optimise [default: {'A','B'}] % 'All' will invoke all fields (i.e. random effects) % If Ep is not a structure, all parameters will be considered % -% RCM - reduced DCM array -% RCM.M.pE - prior expectation (with parameters in pE.A, pE.B and pE.C) -% RCM.M.pC - prior covariance -% RCM.Ep - posterior expectation: Bayesian model average -% RCM.Cp - posterior covariances; Bayesian model average -% RCM.Pp - Model posterior (with and without each parameter) +% Returns: +% +% DCM - Bayesian Model Average (BMA) over models in the final iteration of +% the search: +% +% DCM.Ep - (BMA) posterior expectation +% DCM.Cp - (BMA) posterior covariance % -% BMR - (Nsub) summary structure -% BMR.name - character/cell array of DCM filenames -% BMR.F - their associated free energies +% BMR - (Nsub) summary structure reporting the model space from the last +% iteration of the search: +% +% BMR.name - character/cell array of parameter names +% BMR.F - free energies (relative to full model) % BMR.P - and posterior (model) probabilities +% BMR.K - [models x parameters] model space (1 = off, 0 = on) +% BMR.bma - cell array of each model's parameters and optimised +% model evidences used to calculate the BMA +% % BMA - Baysian model average (see spm_dcm_bma) % %-------------------------------------------------------------------------- -% This routine searches over all possible reduced models of a full model -% (DCM) and uses Bayesian model reduction to model average. Reduced -% models mean all permutations of free parameters (parameters with a non- -% zero prior covariance), where models are defined in terms of their prior -% covariance. The full model should be inverted prior to post hoc -% optimization. If there are more than 16 free-parameters, this routine -% will implement a greedy search: This entails searching over all -% permutations of the 8 parameters whose removal (shrinking the prior -% variance to zero) produces the smallest reduction (greatest increase) -% in model evidence. This procedure is repeated until all 8 parameters -% are retained in the best model or there are no more parameters to -% consider. +% This routine searches over reduced (nested) models of a full model (DCM) +% using Bayesian model reduction and performs Bayesian Model Averaging. +% 'Reduced' means some free parameters (parameters with a non- +% zero prior covariance) are switched off by fixing their prior variance +% to zero. +% +% If there are fewer than nmax = 8 free parameters, all permutations of +% switching off parameters will be tested. Otherwise, this routine +% implements the following greedy search procedure. The nmax parameters +% are identified which, when switched off individually, produce the least +% reduction (greatest increase) in model evidence. All permutations of +% switching off these parameters are then evaluated and the best +% permutation is retained. This procedure is repeated until all nmax +% parameters are retained or there are no more parameters to consider. +% Finally, BMA is performed on the models from the last iteration. +% +% NB: The full model should be estimated prior to running this function. % % See also: spm_dcm_post_hoc - this routine is essentially a simplified % version of spm_dcm_post_hoc @@ -49,7 +61,7 @@ % Copyright (C) 2010-2014 Wellcome Trust Centre for Neuroimaging % Karl Friston, Peter Zeidman -% $Id: spm_dcm_bmr_all.m 6879 2016-09-17 17:45:08Z peter $ +% $Id: spm_dcm_bmr_all.m 7081 2017-05-27 19:36:09Z karl $ %-Number of parameters to consider before invoking greedy search @@ -106,7 +118,11 @@ % Accumulated reduction vector (C) %-------------------------------------------------------------------------- q = diag(DCM.M.pC); -C = double(q > mean(q(q < 1024))/1024); +if sum(q < 1024) + C = double(q > mean(q(q < 1024))/1024); +else + C = double(q > 0); +end GS = 1; while GS @@ -128,17 +144,25 @@ %------------------------------------------------------------------ Z = zeros(1,nparam); for i = 1:nparam + % Identify parameters to retain r and to remove s + %-------------------------------------------------------------- r = C; r(k(i)) = 0; s = 1 - r; % Create reduced prior covariance matrix + %-------------------------------------------------------------- R = U'*diag(r + s*gamma)*U; rC = R*pC*R; % Create reduced prior means - S = U'*diag(r)*U; - rE = S*pE + U'*s*beta; - + %-------------------------------------------------------------- + if isnumeric(beta) + S = U'*diag(r)*U; + rE = S*pE + U'*s*beta; + else + rE = pE; + end + Z(i) = spm_log_evidence(qE,qC,pE,pC,rE,rC); end @@ -166,16 +190,24 @@ %---------------------------------------------------------------------- G = []; for i = 1:size(K,1) - % Identify parameters to retain r and to remove s + + % Identify parameters to retain (r) and to remove (s) + %------------------------------------------------------------------ r = C; r(k(K(i,:))) = 0; s = 1 - r; % Create reduced prior covariance matrix + %------------------------------------------------------------------ R = U'*diag(r + s*gamma)*U; rC = R*pC*R; % Create reduced prior means - S = U'*diag(r)*U; - rE = S*pE + U'*s*beta; + %------------------------------------------------------------------ + if isnumeric(beta) + S = U'*diag(r)*U; + rE = S*pE + U'*s*beta; + else + rE = pE; + end G(i) = spm_log_evidence(qE,qC,pE,pC,rE,rC); end @@ -239,26 +271,30 @@ Gmax = max(G); for i = 1:length(K) if G(i) > (Gmax - 8) + r = C; r(k(K(i,:))) = 0; s = 1 - r; - R = diag(r + s*gamma); rC = R*pC*R; - S = diag(r); - rE = S*spm_vec(pE) + s*beta; + if isnumeric(beta) + rE = S*spm_vec(pE) + s*beta; + else + rE = pE; + end [F,Ep,Cp] = spm_log_evidence_reduce(qE,qC,pE,pC,rE,rC); BMA{end + 1} = struct('Ep',Ep,'Cp',Cp,'F',F); end end -BMA = spm_dcm_bma(BMA); -Ep = BMA.Ep; -Cp = BMA.Cp; +BMR.bma = BMA; +BMA = spm_dcm_bma(BMA); +Ep = BMA.Ep; +Cp = BMA.Cp; -if isstruct(Cp) || (size(Cp,1) ~= size(Cp,2)) +if isstruct(Cp) || (spm_length(Cp) == spm_length(Ep)) Cp = diag(spm_vec(Cp)); end @@ -271,7 +307,6 @@ else i = 1:spm_length(DCM.Ep); end - qE = spm_vec(qE); Ep = spm_vec(Ep); @@ -280,7 +315,7 @@ % BMR summary and plotting %-------------------------------------------------------------------------- try - Pnames = spm_fieldindices(DCM.Ep,k); + Pnames = spm_fieldindices(DCM.Ep,k); catch try Np = numel(DCM.Pnames); @@ -293,6 +328,7 @@ BMR.F = G; BMR.P = p; BMR.K = K; +BMR.k = k; subplot(3,2,3), spm_plot_ci(qE(i),qC(i,i)) title('MAP (full)','FontSize',16) diff --git a/spm_dcm_bpa.m b/spm_dcm_bpa.m index 4df13e90..305ee277 100644 --- a/spm_dcm_bpa.m +++ b/spm_dcm_bpa.m @@ -38,12 +38,12 @@ % applied to each model (i.e., each row) - and BPA becomes a {1 x M} cell % array. % -% See also spm_dcm_bma.m, spm_dcm_bma.m and spm_dcm_peb.m +% See also spm_dcm_bma.m, spm_dcm_bmr.m and spm_dcm_peb.m %__________________________________________________________________________ % Copyright (C) 2015 Wellcome Trust Centre for Neuroimaging % Will Penny & Klaas Enno Stephan -% $Id: spm_dcm_bpa.m 6880 2016-09-17 18:00:38Z peter $ +% $Id: spm_dcm_bpa.m 7081 2017-05-27 19:36:09Z karl $ % Preiminaries diff --git a/spm_dcm_delay.m b/spm_dcm_delay.m index 31e2a40e..b6662634 100644 --- a/spm_dcm_delay.m +++ b/spm_dcm_delay.m @@ -28,7 +28,7 @@ % Copyright (C) 2011 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_dcm_delay.m 6900 2016-10-08 13:16:46Z karl $ +% $Id: spm_dcm_delay.m 7149 2017-08-08 13:14:36Z karl $ % order of Taylor approximation %-------------------------------------------------------------------------- @@ -109,8 +109,11 @@ % suppress delays between voltage and current %-------------------------------------------------------------------------- -if isfield(M,'nodelay'), D(J == 1) = 0; end - +if isfield(M,'nodelay') + if M.nodelay == 1; D(J == 1) = 0; + elseif M.nodelay == 2; D((J == 1) | (J' == 1)) = 0; + end +end % Jacobian and delay operator %========================================================================== @@ -167,4 +170,4 @@ if norm((QJ - Q),'inf') < TOL; break, end end -Q = Q*spm_inv(J); +Q = Q*spm_inv(J,exp(-16)); diff --git a/spm_dcm_fmri_check.m b/spm_dcm_fmri_check.m index 746062fa..5320a29f 100644 --- a/spm_dcm_fmri_check.m +++ b/spm_dcm_fmri_check.m @@ -47,7 +47,7 @@ % Copyright (C) 2012-2013 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_dcm_fmri_check.m 6800 2016-05-25 09:33:15Z peter $ +% $Id: spm_dcm_fmri_check.m 7042 2017-03-16 10:35:41Z peter $ %-Prepare inputs @@ -101,6 +101,11 @@ drawnow; end + % Load if filenames given + if ischar(DCM{1}) + DCM = spm_dcm_load(DCM); + end + % Call spm_dcm_fmri_check recursively to assemble diagnostics [stats,DCM] = get_diagnostics(DCM); diff --git a/spm_dcm_fmri_csd.m b/spm_dcm_fmri_csd.m index 4ba90e22..e78b00bb 100644 --- a/spm_dcm_fmri_csd.m +++ b/spm_dcm_fmri_csd.m @@ -36,9 +36,9 @@ % Copyright (C) 2013-2015 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_dcm_fmri_csd.m 6801 2016-05-29 19:18:06Z karl $ +% $Id: spm_dcm_fmri_csd.m 7196 2017-10-31 12:07:52Z adeel $ -SVNid = '$Rev: 6801 $'; +SVNid = '$Rev: 7196 $'; % Load DCM structure %-------------------------------------------------------------------------- @@ -57,7 +57,6 @@ try, DCM.options.two_state; catch, DCM.options.two_state = 0; end try, DCM.options.stochastic; catch, DCM.options.stochastic = 0; end try, DCM.options.centre; catch, DCM.options.centre = 0; end -try, DCM.options.nmax; catch, DCM.options.nmax = 8; end try, DCM.options.analysis; catch, DCM.options.analysis = 'CSD'; end try, DCM.options.Fdcm; catch, DCM.options.Fdcm = [1/128 0.1]; end try, DCM.options.nograph; catch, DCM.options.nograph = spm('CmdLine'); end @@ -66,7 +65,34 @@ % parameter initialisation %-------------------------------------------------------------------------- try, DCM.M.P = DCM.options.P; end -try, DCM.M.Nmax = DCM.options.Nmax; catch, DCM.M.Nmax = 128; end + +% check max iterations +%-------------------------------------------------------------------------- +try + DCM.options.maxit; +catch + if isfield(DCM.options,'nN') + DCM.options.maxit = DCM.options.nN; + warning('options.nN is deprecated. Please use options.maxit'); + else + DCM.options.maxit = 128; + end +end + +try DCM.M.Nmax; catch, DCM.M.Nmax = DCM.options.maxit; end + +% check max nodes +%-------------------------------------------------------------------------- +try + DCM.options.maxnodes; +catch + if isfield(DCM.options,'nmax') + DCM.options.maxnodes = DCM.options.nmax; + warning('options.nmax is deprecated. Please use options.maxnodes'); + else + DCM.options.maxnodes = 8; + end +end % sizes %-------------------------------------------------------------------------- @@ -102,7 +128,7 @@ DCM.b = DCM.b*0; DCM.d = DCM.d*0; if isempty(DCM.c) || isempty(DCM.U.u) - DCM.c = zeros(DCM.n,1); + DCM.c = zeros(DCM.n,0); DCM.b = zeros(DCM.n,DCM.n,0); DCM.U.u = zeros(DCM.v,1); DCM.U.name = {'null'}; @@ -114,9 +140,9 @@ % eigenvector constraints on pC for large models %-------------------------------------------------------------------------- -if n > DCM.options.nmax +if n > DCM.options.maxnodes - % remove confounds and find principal (nmax) modes + % remove confounds and find principal (maxnodes) modes %---------------------------------------------------------------------- try y = DCM.Y.y - DCM.Y.X0*(pinv(DCM.Y.X0)*DCM.Y.y); @@ -124,7 +150,7 @@ y = spm_detrend(DCM.Y.y); end V = spm_svd(y'); - V = V(:,1:DCM.options.nmax); + V = V(:,1:DCM.options.maxnodes); % remove minor modes from priors on A %---------------------------------------------------------------------- diff --git a/spm_dcm_fmri_nmm.m b/spm_dcm_fmri_nmm.m index 44910725..57502465 100644 --- a/spm_dcm_fmri_nmm.m +++ b/spm_dcm_fmri_nmm.m @@ -51,10 +51,10 @@ % Copyright (C) 2002-2012 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_dcm_fmri_nmm.m 6856 2016-08-10 17:55:05Z karl $ +% $Id: spm_dcm_fmri_nmm.m 6922 2016-11-02 17:28:23Z karl $ -SVNid = '$Rev: 6856 $'; +SVNid = '$Rev: 6922 $'; %-Load DCM structure %-------------------------------------------------------------------------- @@ -93,7 +93,7 @@ try, DCM.options.hC; catch, DCM.options.hC = 1/128; end try, DCM.options.maxit; catch, DCM.options.maxit = 32; end try, DCM.options.maxnodes; catch, DCM.options.maxnodes = 16; end - + try, DCM.n; catch, DCM.n = size(DCM.c,1); end try, DCM.v; catch, DCM.v = size(DCM.Y.y,1); end @@ -115,7 +115,7 @@ U.u = spm_detrend(U.u); end -% check scaling of Y (enforcing a maximum change of 4% +% check scaling of Y (enforcing a maximum change of 4%) %-------------------------------------------------------------------------- scale = max(max((Y.y))) - min(min((Y.y))); scale = 4/max(scale,4); @@ -140,7 +140,7 @@ %-------------------------------------------------------------------------- [nE,nC] = spm_dcm_neural_priors(DCM.a,DCM.b,DCM.c,DCM.options.nmm); [xn,fn] = spm_dcm_x_neural(nE,DCM.options.nmm); - + % fix some neuronal (neural mass) parameters %-------------------------------------------------------------------------- p = {'T','D','R','G'}; @@ -149,14 +149,14 @@ nC.(p{i}) = spm_zeros(nC.(p{i})); end end - + pE.N = rmfield(nE,{'M','N','E','F'}); pC.N = rmfield(nC,{'M','N','E','F'}); - + % add neurovascular parameters %-------------------------------------------------------------------------- pE.J = sparse(4,3); pC.J = sparse(4,3) + 1/16; - + % and hemodynamic priors %-------------------------------------------------------------------------- bE.transit = sparse(n,1); bC.transit = sparse(n,1) + 1/256; @@ -164,20 +164,20 @@ bE.epsilon = sparse(1,1); bC.epsilon = sparse(1,1) + 1/256; x.x = xn; x.h = sparse(n,4); - + pE.H = bE; pC.H = bC; - - + + % Using specified priors %-------------------------------------------------------------------------- str = 'Using specified priors'; try, M.P = DCM.options.P; end % initial parameters try, pE = DCM.options.pE; fprintf(str); end % prior expectation try, pC = DCM.options.pC; fprintf(str); end % prior covariance - - - + + + % hyperpriors over precision - expectation and covariance %-------------------------------------------------------------------------- hE = sparse(n,1) + DCM.options.hE; @@ -199,12 +199,12 @@ M.n = size(spm_vec(x),1); M.l = n; M.ns = v; - + -% nonlinear system identification (Variaitonal Laplace) +% nonlinear system identification (Variational Laplace) %========================================================================== [Ep,Cp,Eh,F] = spm_nlsi_GN(M,U,Y); - + % predicted responses (y) and residuals (R) %-------------------------------------------------------------------------- y = feval(M.IS,Ep,M,U); @@ -218,7 +218,7 @@ H.g = @spm_gx_hdm; H.x = M.x.h; H.m = M.m; - + [H0,H1] = spm_kernels(H,Ep.H,64,1/2); % and neuronal kernels @@ -226,11 +226,11 @@ N.f = M.fn; N.x = M.x.x; N.m = M.m; - + [K0,K1] = spm_kernels(N,Ep.N,64,8/1000); -% Bayesian inference and variance {threshold: prior mean plus T = 0} +% Bayesian inference and variance %-------------------------------------------------------------------------- T = full(spm_vec(pE)); sw = warning('off','SPM:negativeVariance'); @@ -282,11 +282,10 @@ [DCM.version.SPM.version, DCM.version.SPM.revision] = spm('Ver'); DCM.version.DCM.version = spm_dcm_ui('Version'); DCM.version.DCM.revision = SVNid; - + %-Save DCM %-------------------------------------------------------------------------- if ~isstruct(P) save(P,'DCM','F','Ep','Cp', spm_get_defaults('mat.format')); end - diff --git a/spm_dcm_loo.m b/spm_dcm_loo.m index 3bf9d680..cfd3ebb4 100644 --- a/spm_dcm_loo.m +++ b/spm_dcm_loo.m @@ -4,18 +4,18 @@ % % DCM - {N [x M]} structure DCM array of (M) DCMs from (N) subjects % ------------------------------------------------------------------- -% DCM{i}.M.pE - prior expectation of parameters -% DCM{i}.M.pC - prior covariances of parameters -% DCM{i}.Ep - posterior expectations -% DCM{i}.Cp - posterior covariance +% DCM{i}.M.pE - prior expectation of parameters +% DCM{i}.M.pC - prior covariances of parameters +% DCM{i}.Ep - posterior expectations +% DCM{i}.Cp - posterior covariance % -% M.X - second level design matrix, where X(:,1) = ones(N,1) [default] -% field - parameter fields in DCM{i}.Ep to optimise [default: {'A','B'}] +% M.X - second level design matrix, where X(:,1) = ones(N,1) [default] +% field - parameter fields in DCM{i}.Ep to optimise [default: {'A','B'}] % 'All' will invoke all fields % -% qE - posterior predictive expectation (group effect) -% qC - posterior predictive covariances (group effect) -% Q - posterior probability over unique levels of X(:,2) +% qE - posterior predictive expectation (group effect) +% qC - posterior predictive covariances (group effect) +% Q - posterior probability over unique levels of X(:,2) % % This routine uses the posterior predictive density over the coefficients % of between-subject effects encoded by a design matrix X. It is assumed @@ -30,10 +30,10 @@ % % See also: spm_dcm_peb.m and spm_dcm_ppd.m %__________________________________________________________________________ -% Copyright (C) 2015-2016 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2015-2017 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_dcm_loo.m 6894 2016-09-30 16:48:46Z spm $ +% $Id: spm_dcm_loo.m 7120 2017-06-20 11:30:30Z spm $ % Set up diff --git a/spm_dcm_mdp.m b/spm_dcm_mdp.m index 6728b13e..5d3e324e 100644 --- a/spm_dcm_mdp.m +++ b/spm_dcm_mdp.m @@ -4,17 +4,17 @@ % % Expects: %-------------------------------------------------------------------------- -% DCM.MDP % MDP structure specifying a generative model -% DCM.field % parameter (field) names to optimise -% DCM.U % cell array of outcomes (stimuli) -% DCM.Y % cell array of responses (action) +% DCM.MDP % MDP structure specifying a generative model +% DCM.field % parameter (field) names to optimise +% DCM.U % cell array of outcomes (stimuli) +% DCM.Y % cell array of responses (action) % % Returns: %-------------------------------------------------------------------------- -% DCM.M % generative model (DCM) -% DCM.Ep % Conditional means (structure) -% DCM.Cp % Conditional covariances -% DCM.F % (negative) Free-energy bound on log evidence +% DCM.M % generative model (DCM) +% DCM.Ep % Conditional means (structure) +% DCM.Cp % Conditional covariances +% DCM.F % (negative) Free-energy bound on log evidence % % This routine inverts (cell arrays of) trials specified in terms of the % stimuli or outcomes and subsequent choices or responses. It first @@ -35,7 +35,7 @@ % Copyright (C) 2005 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_dcm_mdp.m 6705 2016-01-31 13:06:48Z karl $ +% $Id: spm_dcm_mdp.m 7120 2017-06-20 11:30:30Z spm $ % OPTIONS %-------------------------------------------------------------------------- diff --git a/spm_dcm_peb.m b/spm_dcm_peb.m index b3f037e0..b21b80dd 100644 --- a/spm_dcm_peb.m +++ b/spm_dcm_peb.m @@ -5,18 +5,18 @@ % % DCM - {N [x M]} structure array of DCMs from N subjects % ------------------------------------------------------------------------- -% DCM{i}.M.pE - prior expectation of parameters -% DCM{i}.M.pC - prior covariances of parameters -% DCM{i}.Ep - posterior expectations -% DCM{i}.Cp - posterior covariance -% DCM{i}.F - free energy +% DCM{i}.M.pE - prior expectation of parameters +% DCM{i}.M.pC - prior covariances of parameters +% DCM{i}.Ep - posterior expectations +% DCM{i}.Cp - posterior covariance +% DCM{i}.F - free energy % -% M.X - 2nd-level design matrix: X(:,1) = ones(N,1) [default] -% M.bE - 3rd-level prior expectation [default: DCM{1}.M.pE] -% M.bC - 3rd-level prior covariance [default: DCM{1}.M.pC/M.alpha] +% M.X - 2nd-level design matrix: X(:,1) = ones(N,1) [default] +% M.bE - 3rd-level prior expectation [default: DCM{1}.M.pE] +% M.bC - 3rd-level prior covariance [default: DCM{1}.M.pC/M.alpha] % M.pC - 2nd-level prior covariance [default: DCM{1}.M.pC/M.beta] -% M.hE - 2nd-level prior expectation of log precisions [default: 0] -% M.hC - 2nd-level prior covariances of log precisions [default: 1/16] +% M.hE - 2nd-level prior expectation of log precisions [default: 0] +% M.hC - 2nd-level prior covariances of log precisions [default: 1/16] % % M.Q - covariance components: {'single','fields','all','none'} % M.alpha - optional scaling to specify M.bC [default = 1] @@ -25,34 +25,40 @@ % NB: the prior covariance of 2nd-level random effects is: % exp(M.hE)*DCM{1}.M.pC/M.beta [default DCM{1}.M.pC/16] % +% NB2: to manually specify which parameters should be assigned to +% which covariance components, M.Q can be set to a cell array of +% [nxn] binary matrices, where n is the number of DCM +% parameters. A value of M.Q{i}(n,n)==1 indicates that parameter +% n should be modelled with component i. +% % M.Xnames - cell array of names for second level parameters [default: {}] % % field - parameter fields in DCM{i}.Ep to optimise [default: {'A','B'}] -% 'All' will invoke all fields. This argument effectively allows -% one to specify the parameters that constitute random effects. +% 'All' will invoke all fields. This argument effectively allows +% one to specify the parameters that constitute random effects. % % PEB - hierarchical dynamic model % ------------------------------------------------------------------------- -% PEB.Snames - string array of first level model names -% PEB.Pnames - string array of parameters of interest -% PEB.Pind - indices of parameters in spm_vec(DCM{i}.Ep) +% PEB.Snames - string array of first level model names +% PEB.Pnames - string array of parameters of interest +% PEB.Pind - indices of parameters in spm_vec(DCM{i}.Ep) % PEB.Xnames - names of second level parameters % -% PEB.M.X - second level (between-subject) design matrix -% PEB.M.W - second level (within-subject) design matrix -% PEB.M.Q - precision [components] of second level random effects -% PEB.M.pE - prior expectation of second level parameters -% PEB.M.pC - prior covariance of second level parameters -% PEB.M.hE - prior expectation of second level log-precisions -% PEB.M.hC - prior covariance of second level log-precisions -% PEB.Ep - posterior expectation of second level parameters -% PEB.Eh - posterior expectation of second level log-precisions -% PEB.Cp - posterior covariance of second level parameters -% PEB.Ch - posterior covariance of second level log-precisions -% PEB.Ce - expected covariance of second level random effects -% PEB.F - free energy of second level model +% PEB.M.X - second level (between-subject) design matrix +% PEB.M.W - second level (within-subject) design matrix +% PEB.M.Q - precision [components] of second level random effects +% PEB.M.pE - prior expectation of second level parameters +% PEB.M.pC - prior covariance of second level parameters +% PEB.M.hE - prior expectation of second level log-precisions +% PEB.M.hC - prior covariance of second level log-precisions +% PEB.Ep - posterior expectation of second level parameters +% PEB.Eh - posterior expectation of second level log-precisions +% PEB.Cp - posterior covariance of second level parameters +% PEB.Ch - posterior covariance of second level log-precisions +% PEB.Ce - expected covariance of second level random effects +% PEB.F - free energy of second level model % -% DCM - 1st level (reduced) DCM structures with empirical priors +% DCM - 1st level (reduced) DCM structures with empirical priors % % If DCM is an an (N x M} array, hierarchical inversion will be % applied to each model (i.e., each row) - and PEB will be a @@ -82,7 +88,7 @@ % Copyright (C) 2015-2016 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_dcm_peb.m 6778 2016-04-22 11:51:29Z guillaume $ +% $Id: spm_dcm_peb.m 7160 2017-08-25 08:11:30Z karl $ % get filenames and set up @@ -132,10 +138,26 @@ Ns = numel(P); % number of subjects if isfield(M,'bC') && Ns > 1 q = spm_find_pC(M.bC,M.bE,field); % parameter indices +elseif isnumeric(field) + q = field; % parameter indices else q = spm_find_pC(DCM,field); % parameter indices end -Pstr = spm_fieldindices(DCM.M.pE,q); % field names +try + Pstr = spm_fieldindices(DCM.M.pE,q); % field names +catch + if isfield(DCM,'Pnames') + % PEB given as input. Field names have form covariate:fieldname + Pstr = []; + for i = 1:length(DCM.Xnames) + str = strcat(DCM.Xnames{i}, ': ', DCM.Pnames); + Pstr = [Pstr; str]; + end + else + % Generate field names + Pstr = strcat('P', cellstr(num2str(q))); + end +end Np = numel(q); % number of parameters if Np == 1 Pstr = {Pstr}; @@ -196,11 +218,21 @@ % second level model %-------------------------------------------------------------------------- -if isfield(M,'beta'), alpha = M.alpha; else, alpha = 1; end -if isfield(M,'beta'), beta = M.beta; else, beta = 16; end -if isfield(M,'Q'), OPTION = M.Q; else, OPTION = 'single'; end -if ~isfield(M,'W'), M.W = speye(Np,Np); end +if isfield(M,'alpha'), alpha = M.alpha; else, alpha = 1; end +if isfield(M,'beta'), beta = M.beta; else, beta = 16; end +if ~isfield(M,'W'), M.W = speye(Np,Np); end +% covariance component specification +%-------------------------------------------------------------------------- +Q = {}; +if ~isfield(M,'Q') + OPTION = 'single'; +elseif iscell(M.Q) && isnumeric(M.Q{1}) + OPTION = 'manual'; + Q = M.Q; +else + OPTION = M.Q; +end % design matrices %-------------------------------------------------------------------------- @@ -260,7 +292,6 @@ %-------------------------------------------------------------------------- pQ = spm_inv(U'*M.pC*U); rP = pQ; -Q = {}; switch OPTION case{'single'} @@ -271,23 +302,51 @@ case{'fields'} % between subject precision components (one for each field) %------------------------------------------------------------------ + pq = spm_inv(M.pC); for i = 1:length(field) j = spm_fieldindices(DCM.M.pE,field{i}); - j = find(ismember(q,j)); + j = find(ismember(q,j)); Q{i} = sparse(Np,Np); - Q{i}(j,j) = pQ(j,j); + Q{i}(j,j) = pq(j,j); Q{i} = U'*Q{i}*U; end case{'all'} % between subject precision components (one for each parameter) %------------------------------------------------------------------ + pq = spm_inv(M.pC); + k = 1; for i = 1:Np - Q{i} = sparse(i,i,pQ(i,i),Np,Np); - Q{i} = U'*Q{i}*U; + qk = sparse(i,i,pq(i,i),Np,Np); + qk = U'*qk*U; + if any(qk(:)) + Q{k} = qk; + k = k + 1; + end end + case {'manual'} + % manually provided cell array of (binary) precision components + %------------------------------------------------------------------ + pq = spm_inv(M.pC); + k = 1; + for i = 1:length(Q) + j = find(diag(Q{i})); + j = find(ismember(q,j)); + qk = sparse(Np,Np); + qk(j,j) = pq(j,j); + qk = U'*qk*U; + if any(qk(:)) + Q{k} = qk; + k = k + 1; + end + end + + case {'none'} + % Do nothing + otherwise + warning('Unknown covariance component specification'); end @@ -317,8 +376,8 @@ Xe = spm_speye(Nx,1); bE = kron(Xe,U'*M.bE); % prior expectation of group effects gE = zeros(Ng,1) + gE; % prior expectation of log precision -bC = kron(Xc,U'*M.bC*U); % prior covariance of group effects -gC = eye(Ng,Ng)*gC; % prior covariance of log precision +bC = kron(Xc,U'*M.bC*U); % prior covariance of group effects +gC = eye(Ng,Ng)*gC; % prior covariance of log precision bP = spm_inv(bC); gP = spm_inv(gC); @@ -337,12 +396,12 @@ % compute prior precision (with a lower bound of pQ/4096) %---------------------------------------------------------------------- if Ng > 0 - rP = pQ/4096; + rP = pQ*exp(-8); for i = 1:Ng rP = rP + exp(g(i))*Q{i}; end end - rC = spm_inv(rP); + rC = spm_inv(rP); % update model parameters %====================================================================== @@ -423,7 +482,7 @@ % otherwise, retrieve expansion point and increase regularisation %------------------------------------------------------------------ - t = t - 1; + t = max(t - 1,-4); load('tmp.mat'); end @@ -531,6 +590,10 @@ PEB.Ce = U*rC*U'; PEB.F = F; +for i = 1:length(Q) + PEB.M.Q{i} = U*Q{i}*U'; +end + spm_unlink('tmp.mat'); % check for DEM structures diff --git a/spm_dcm_peb_bmc.m b/spm_dcm_peb_bmc.m index 1a3d06ba..e3a2c436 100644 --- a/spm_dcm_peb_bmc.m +++ b/spm_dcm_peb_bmc.m @@ -1,4 +1,4 @@ -function [BMA] = spm_dcm_peb_bmc(PEB,models) +function [BMA,BMR] = spm_dcm_peb_bmc(PEB,models) % hierarchical (PEB) model comparison and averaging (2nd level) % FORMAT [BMA] = spm_dcm_peb_bmc(PEB,models) % FORMAT [BMA] = spm_dcm_peb_bmc(PEB) @@ -24,7 +24,7 @@ % will be tested. % % BMA - DCM structure of Bayesian model average -% ------------------------------------------------------------- +% ------------------------------------------------------------------------- % BMA.Snames - string array of first level model names % BMA.Pnames - string array of parameters of interest % @@ -37,11 +37,26 @@ % BMA.Px - posterior probability over parameters (differences) % BMA.Pw - posterior probability over parameters (common) % BMA.K - model space -% or -% BMA.K - posterior probability with and without each parameter +% +% or for automatic model search, see spm_dcm_bmr_all.m (output: DCM) +% +% BMR - Parameters and evidence of reduced models which produced the BMA +% ------------------------------------------------------------------------- +% BMR{i,j} - model i of commonalities and j of group differences +% BMR{i,j}.Ep - expectations of second level parameters +% BMR{i,j}.Cp - covariance of second level parameters +% BMR{i,j}.F - free energy relative to full model +% +% or for automatic model search: +% +% BMR.name - parameter names +% BMR.F - free energy relative to full model +% BMR.P - and posterior (model) probabilities +% BMR.K - [models x parameters] model space (1 = off, 2 = on) +% BMR.bma{i} - Model i which contributed to the BMA (Ep,Cp,F) % %-------------------------------------------------------------------------- -% This routine performs Bayesian model comparison averaging of second +% This routine performs Bayesian model comparison and averaging of second % level or hierarchical (PEB) models. The model space is defined either % in terms of fields (e.g. 'A' or 'B') or as a logical matrix, with one row % per model and a column per parameter (in PEB.Pnames). This induces @@ -76,7 +91,7 @@ % Copyright (C) 2005 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_dcm_peb_bmc.m 6882 2016-09-19 12:14:50Z peter $ +% $Id: spm_dcm_peb_bmc.m 7081 2017-05-27 19:36:09Z karl $ % checks %-------------------------------------------------------------------------- @@ -90,7 +105,7 @@ % greedy search and (second level) Bayesian model average %---------------------------------------------------------------------- - [BMA,x,bma] = spm_dcm_bmr_all(PEB); + [BMA,BMR,bma] = spm_dcm_bmr_all(PEB); % plot posteriors over parameters %====================================================================== @@ -195,10 +210,6 @@ % check number of models %-------------------------------------------------------------------------- i = find(any(~K),1); -if (Nm > 32 && Nx > 1) || (Nm > 1024 && Nx < 2) - warndlg('please reduce the size of your model space') - return -end if isempty(i) warndlg('your model space is empty') return @@ -301,15 +312,15 @@ % Bayesian model averaging (with an Occam's window of eight) %-------------------------------------------------------------------------- -i = G(:) > max(G(:) - 8); -BMA = spm_dcm_bma(BMR(i)'); +i = G(:) > max(G(:) - 8); +BMA = spm_dcm_bma(BMR(i)'); % assemble BMA output structure %-------------------------------------------------------------------------- BMA.Snames = PEB.Snames; BMA.Pnames = PEB.Pnames; -BMA.Pind = PEB.Pind; -BMA.Kname = Kname; +BMA.Pind = PEB.Pind; +BMA.Kname = Kname; try BMA.Xnames = PEB.Xnames; catch, BMA.Xnames = {}; end BMA.F = G; @@ -325,6 +336,9 @@ BMA.Ch = PEB.Ch; BMA.Eh = PEB.Eh; +% Show results +%========================================================================== + % get name of covariate 2 (differences) %-------------------------------------------------------------------------- if Nx > 1 && isfield(PEB,'Xnames') && ~isempty(PEB.Xnames) @@ -333,8 +347,6 @@ xname = 'Differences'; end -% Show results -%========================================================================== if spm_get_defaults('cmdline'), return; end spm_figure('Getwin','BMC'); clf diff --git a/spm_dcm_peb_bmc_fam.m b/spm_dcm_peb_bmc_fam.m new file mode 100644 index 00000000..2702977f --- /dev/null +++ b/spm_dcm_peb_bmc_fam.m @@ -0,0 +1,291 @@ +function [BMA,fam] = spm_dcm_peb_bmc_fam(BMA,BMR,families,bma_option) +% Bayesian model selection and averaging over families of PEB models +% +% BMA - Bayesian model average (see spm_dcm_peb_bmc) +% +% BMA.K - model space [models x parameters] +% BMA.Pnames - parameter names +% BMA.Ep - averaged parameters (for inferring #covariates) +% +% BMR - model space (see spm_dcm_peb_bmc) +% +% BMR{i,j} - model i of commonalities and j of differences +% BMR{i,j}.Ep - expectations of second level parameters +% BMR{i,j}.Cp - covariance of second level parameters +% BMR{i,j}.F - free energy relative to full model +% +% families - [1 x Nm] vector of family membership where families(i)=x, +% for model i and family x. For example, families=[1 1 2] +% means that models 1 and 2 are in family 1 and model 3 is in +% family 2. +% +% bma_option - String specifying option for Bayesian Model Averaging +% +% 'ALL' - average over all models (under family priors) +% 'WINNING' - average models in the best family only +% 'NONE' - don't average +% +% Returns: +% +% BMA - Bayesian Model Average over models (specified by bma_option) +% +% fam - Bayesian model selection results: +% +% .model.post - Posterior probability of each model +% .model.prior - Prior probability of each model +% .family.post - Posterior probability of each family +% .family.prior - Prior probability of each family +% .famdef - Input vector of family assignments +%__________________________________________________________________________ +% Copyright (C) 2010-2016 Wellcome Trust Centre for Neuroimaging + +% Peter Zeidman +% $Id: spm_dcm_peb_bmc_fam.m 6946 2016-11-23 15:26:29Z peter $ + +% Model space [models x parameters] +K = BMA.K; +Nm = size(K,1); + +% Number of models for between-subjects effects +Nmx = size(BMR,2); + +% Validate +if nargin < 4 + bma_option = 'ALL'; +end + +if ~iscell(BMR) + error('BMR should be a cell array of parameters and evidences'); +end + +if ~isvector(families) || length(families) ~= Nm + error('Families should be a vector with one element per model'); +end + +% Unpack +%-------------------------------------------------------------------------- +for i = 1:Nm + for j = 1:Nmx + F(i,j) = BMR{i,j}.F; + end +end + +Pnames = BMA.Pnames; % Parameter names +M = BMA.M; % Original PEB model +Nx = length(BMA.Ep) / length(BMA.Pnames); % Number of covariates +nK = length(unique(families)); % Number of families + +% Set model priors given family priors +%-------------------------------------------------------------------------- + +% Likelihood +L = exp(F(:) - max(F(:))); + +% Size of each family +sK = zeros(1,nK); +for i = 1:nK + sK(i) = sum(families==i); +end + +% Family prior +pF = repmat(1/nK, 1, nK); + +% Model prior (commonalities) +pMw = 1 ./ (sK(families) * nK); + +% Model prior (differences) +if Nmx > 1 + pMb = pMw; +else + pMb = 1; +end + +% Joint model prior over commonalities and differences +pMj = pMw' * pMb; + +% Calculate posteriors +%-------------------------------------------------------------------------- + +% Model posterior +pMj = pMj(:); +Pm = L .* pMj; +Pm = Pm ./ sum(Pm); +Pm = reshape(Pm,Nm,Nmx); + +% Group differences families (fx) +if Nmx > 1 + fx = families; + k = nK; +else + fx = 1; + k = 1; +end + +% Family posterior +Pf = zeros(nK,k); +for i = 1:nK + for j = 1:k + p = Pm(families == i, fx == j); + Pf(i,j) = sum(p(:)); + end +end + +% Compute BMA +%-------------------------------------------------------------------------- +bma_option = upper(bma_option); + +occ = 8; % Occam's window + +switch bma_option + case 'ALL' + i = F(:) > max(F(:) - occ); + m = reshape(i,Nm,Nmx); + BMA = spm_dcm_bma(BMR(i)'); + case 'WINNING' + % Identify winning family + [wF,i] = max(Pf(:)); + [wFi,wFj] = ind2sub([nK nK],i); + + % Identify models + i = (families == wFi); + j = (fx == wFj); + + % Matrix of included models for BMA + m = zeros(Nm,Nmx); + m(i,j) = 1; + m = m .* (F > max(F(:) - occ)); + + % Compute BMA + BMA = spm_dcm_bma(BMR(m(:)==1)'); + case 'NONE' + BMA = []; + otherwise + error('Unknown BMA option'); +end + +% Inference over models (commonalities and differences) +%-------------------------------------------------------------------------- +P = Pm; +P1 = sum(P,2); +P2 = sum(P,1); + +% Inference over parameters (present vs absent) +%-------------------------------------------------------------------------- +k = find(any(~K)); +Nb = length(k); +Kname = Pnames(k); +for i = 1:Nb + Pw(1,i) = mean(sum(P( ~K(:,k(i)),:),2)); + Pw(2,i) = mean(sum(P(~~K(:,k(i)),:),2)); + + if Nx > 1 + Px(1,i) = mean(sum(P(:, ~K(:,k(i))),1)); + Px(2,i) = mean(sum(P(:,~~K(:,k(i))),1)); + else + Px(1,i) = 1; + Px(2,i) = 0; + end + +end +Pw = Pw(2,:)./sum(Pw,1); +Px = Px(2,:)./sum(Px,1); + +% Pack +%-------------------------------------------------------------------------- +BMA.F = F; +BMA.P = P; +BMA.Px = Px; +BMA.Pw = Pw; +BMA.M = M; +BMA.K = K; +BMA.Pnames = Pnames; +BMA.Kname = Kname; + +fam = struct(); +fam.model.post = Pm; +fam.model.prior = reshape(pMj,Nm,Nmx); +fam.model.Pw = P1'; +fam.model.Px = P2; +fam.family.post = Pf; +fam.family.prior = pF; +fam.famdef = families; + +% Plot +%-------------------------------------------------------------------------- +if spm_get_defaults('cmdline'), return; end + +spm_figure('GetWin','Family analysis'); +clf; + +% Family posterior +subplot(3,2,1) +if Nmx > 1 + imagesc(Pf) + xlabel('Family (differences)','FontSize',12) + ylabel('Family (commonalities)','FontSize',12) + set(gca,'XTick',1:nK,'YTick',1:nK); +else + bar(Pf); + xlabel('Family','FontSize',12); + ylabel('Probability'); +end +title('Family posterior','FontSize',16) +axis square + +% Model posterior +subplot(3,2,2) +if Nmx > 1 + imagesc(Pm) + xlabel('Model (differences)','FontSize',12) + ylabel('Model (commonalities)','FontSize',12) +else + bar(Pm); + xlabel('Model','FontSize',12); +end +title('Model posterior | families','FontSize',16) +axis square + +sp = 3; % Subplot counter + +if Nmx > 1 + % Commonalities + subplot(3,2,sp) + [mm,i] = max(P1); bar(P1), + text(i - 1/4,mm/2,sprintf('%-2.0f%%',mm*100),'Color','w','FontSize',8) + title('Commonalities','FontSize',16) + xlabel('Model','FontSize',12) + ylabel('Probability','FontSize',12) + axis([0 (Nm + 1) 0 1]), axis square + sp = sp + 1; + + % Differences + subplot(3,2,sp) + [mm,i] = max(P2); bar(P2), + text(i - 1/4,mm/2,sprintf('%-2.0f%%',mm*100),'Color','w','FontSize',8) + title('Differences','FontSize',16) + xlabel('Model','FontSize',12) + ylabel('Probability','FontSize',12) + axis([0 (Nm + 1) 0 1]), axis square + sp = sp + 1; +end + +% Family allocations +subplot(3,2,sp), imagesc(families) +title('Families','FontSize',16) +xlabel('Model','FontSize',12) +set(gca,'YTick',[]); +axis square +sp = sp + 1; + +% BMA inclusion +if ~strcmp(bma_option,'NONE') + subplot(3,2,sp), imagesc(m) + title('Models in BMA','FontSize',16) + xlabel('Model (differences)','FontSize',12) + ylabel('Model (commonalities)','FontSize',12) + + if Nmx == 1 + set(gca,'XTick',1); + end +end +axis square \ No newline at end of file diff --git a/spm_dcm_peb_fit.m b/spm_dcm_peb_fit.m index f7dac591..9eed82d1 100644 --- a/spm_dcm_peb_fit.m +++ b/spm_dcm_peb_fit.m @@ -9,6 +9,8 @@ % DCM{i}.Ep - posterior expectations % DCM{i}.Cp - posterior covariance % DCM{i}.FEB - free energy over empirical Bayes iterations +% DCM{i}.EEB - second level log-precisions over iterations +% DCM{i}.HEB - conditional entropy (uncertainty) over iterations % % M.X - second level design matrix, where X(:,1) = ones(N,1) [default] % M.pE - second level prior expectation of parameters @@ -70,7 +72,7 @@ % Copyright (C) 2005 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_dcm_peb_fit.m 6532 2015-08-23 13:59:19Z karl $ +% $Id: spm_dcm_peb_fit.m 7049 2017-03-29 10:01:27Z peter $ % set up @@ -139,9 +141,9 @@ % convergence %---------------------------------------------------------------------- - E(k) = PEB.Eh; - F(k) = PEB.F; - H(k) = spm_logdet(PEB.Cp); + E(:,k) = PEB.Eh; + F(k) = PEB.F; + H(k) = spm_logdet(PEB.Cp); disp('log precision : ');disp(E); disp('free energy : ');disp(F); diff --git a/spm_dcm_peb_review.m b/spm_dcm_peb_review.m index 3b482dd2..4ebb6634 100644 --- a/spm_dcm_peb_review.m +++ b/spm_dcm_peb_review.m @@ -10,19 +10,29 @@ function spm_dcm_peb_review(PEB, DCM) % Copyright (C) 2016 Wellcome Trust Centre for Neuroimaging % Peter Zeidman -% $Id: spm_dcm_peb_review.m 6785 2016-04-27 14:23:12Z peter $ +% $Id: spm_dcm_peb_review.m 6946 2016-11-23 15:26:29Z peter $ % Prepare input % ------------------------------------------------------------------------- if nargin < 1 || isempty(PEB) - [PEB,sts] = spm_select(1,'mat','Select a PEB model',{},pwd,'^PEB_.*mat$'); + [PEB,sts] = spm_select(1,'mat','Select a PEB model',{},pwd,'^(PEB|BMA)_.*mat$'); if ~sts, return; end end +if nargin < 2 || isempty(DCM) + [DCM,sts] = spm_select(1,'mat','(Optional) Select DCM or GCM file',{},pwd,'^(DCM|GCM)_.*mat$'); +end + % Load / validate PEB if ischar(PEB) PEB = load(PEB); - PEB = PEB.PEB; + if isfield(PEB,'PEB') + PEB = PEB.PEB; + elseif isfield(PEB,'BMA') + PEB = PEB.BMA; + else + error('Not a valid PEB or BMA file'); + end end if length(PEB) > 1, PEB = PEB(1); end @@ -32,7 +42,7 @@ function spm_dcm_peb_review(PEB, DCM) end % Load / validate DCM -if nargin < 2 || isempty(DCM) || isempty(DCM{1}), DCM = {}; end +if isempty(DCM) || (iscell(DCM) && isempty(DCM{1})), DCM = {}; end if ~iscell(DCM), DCM = {DCM}; end if ~isempty(DCM) && ischar(DCM{1}) @@ -69,6 +79,7 @@ function spm_dcm_peb_review(PEB, DCM) xPEB.input_names = {}; % First level input names xPEB.mtx_fig = []; % Figure handle for connectivity matrix xPEB.threshold_idx = 1; % P-threshold following model comparison +xPEB.threshold_method_idx=1;% Method for thresholding parameters % Get first-level DCM metadata if ~isempty(DCM) @@ -107,6 +118,7 @@ function update_view() DCM = xPEB.DCM; view = xPEB.view; threshold_idx = xPEB.threshold_idx; +threshold_method_idx = xPEB.threshold_method_idx; % Unpack PEB metadata np = length(PEB.Pnames); % Parameters @@ -129,16 +141,34 @@ function update_view() has_Pp = isfield(PEB,'Pp') || isfield(PEB,'Pw') || isfield(PEB,'Px'); -display_threshold = (effect > 0 && effect <= nc && has_Pp); - -thresholds_str = {'No threshold (P >= 0)'; - 'Weak evidence (P > 0.5)'; - 'Positive evidence (P > 0.75)'; - 'Strong evidence (P > 0.95)'; - 'Very strong evidence (P > .99)'}; +display_threshold = (effect > 0 && effect <= nc); + +if xPEB.threshold_method_idx == 1 + % Thresholding based on posterior probability + thresholds_str = {'No threshold (Pp >= 0)'; + 'Pp > 0.5'; + 'Pp > 0.75'; + 'Pp > 0.95'; + 'Pp > .99'}; +else + % Thresholding based on free energy + thresholds_str = {'No threshold (Pp >= 0)'; + 'Weak evidence (Pp > 0.5)'; + 'Positive evidence (Pp > 0.75)'; + 'Strong evidence (Pp > 0.95)'; + 'Very strong evidence (Pp > .99)'}; +end + +threshold_methods_str = {'Probability that parameter > 0'; + 'Free energy (with vs without)'}; + +% If there's no BMA posterior probability, disable free energy thresholding +if ~has_Pp + xPEB.threshold_method_idx = 1; + threshold_methods_str = threshold_methods_str(1); +end thresholds = [0 0.5 0.75 0.95 0.99]; - threshold = thresholds(threshold_idx); % Get parameters / variance for the selected covariate @@ -159,10 +189,22 @@ function update_view() % ------------------------------------------------------------------------- if display_threshold - if isfield(PEB,'Pw') && effect == 1 - Pp = PEB.Pw; + % BMA from spm_dcm_peb_bmc only has probabilities for parameters which + % differed across models. Get the original indices of these parameters. + if isfield(PEB,'Pw') || isfield(PEB,'Px') && isfield(PEB.K) + k = find(any(~PEB.K)); + end + + if threshold_method_idx == 1 + % Threshold on posterior probability + T = 0; + Pp = 1 - spm_Ncdf(T,abs(Ep),Cp); + elseif isfield(PEB,'Pw') && effect == 1 + Pp = zeros(size(Ep,1),1); + Pp(k) = PEB.Pw(:); elseif isfield(PEB,'Px') && effect == 2 - Pp = PEB.Px; + Pp = zeros(size(Ep,1),1); + Pp(k) = PEB.Px; elseif isfield(PEB,'Pp') Pp = PEB.Pp(peb_param_idx); else @@ -274,8 +316,12 @@ function update_view() % Drop-down menu for selecting threshold if display_threshold - create_text('Threshold (model comparison with/without each parameter):',... - 'Position',[0.1 0.59 0.65 0.05],'HorizontalAlignment','left'); + create_text('Threshold (optional):',... + 'Position',[0.1 0.585 0.65 0.05],'HorizontalAlignment','left'); + + create_menu('Position',[0.28 0.54 0.33 0.1],'Tag','peb_threshold_method',... + 'Callback',@selected_threshold_method_changed, ... + 'String',threshold_methods_str,'Value',xPEB.threshold_method_idx); create_menu('Position',[0.62 0.54 0.33 0.1],'Tag','peb_threshold',... 'Callback',@selected_threshold_changed, ... @@ -416,9 +462,28 @@ function update_view() set(ax,'Position',p); end + % Colormap 1 (hot) + T = [1 0 0 % Red + 1 1 0]; % Yellow + x = [0 1]; + x = x(end:-1:1); + c1 = interp1(x,T,linspace(0,1,64)); + + % Colormap 2 (cold) + T = [0 1 1 % Turqoise + 0 0.0745 0.6078]; % Dark blue + x = [0 1]; + x = x(end:-1:1); + c2 = interp1(x,T,linspace(0,1,64)); + + % Combine and add white + c = [c2;c1]; + c(64:65,:) = 1; + % Plot - imagesc(xPEB.Eq); - colorbar; + imagesc(xPEB.Eq,[-1 1]); + colorbar; + colormap(c); % Style axis square; @@ -567,9 +632,18 @@ function selected_view_changed(varargin) update_view(); +% ========================================================================= +function selected_threshold_method_changed(varargin) +% Callback for change of threshold method click +xPEB = evalin('base','xPEB'); +xPEB.threshold_method_idx = get(varargin{1},'Value'); + +assignin('base','xPEB',xPEB); + +update_view(); % ========================================================================= function selected_threshold_changed(varargin) -% Callback for change of thershold click +% Callback for change of threshold click xPEB = evalin('base','xPEB'); xPEB.threshold_idx = get(varargin{1},'Value'); @@ -641,12 +715,16 @@ function selected_input_changed(varargin) pname1 = pname_to_string(Pnames{idx1}, region_names, input_names); - txt = {pname1; ' '; + Ep = full(xPEB.PEB.Ep(idx1, effect)); + + txt = {pname1; + sprintf('%3.3f', Ep); + ' '; sprintf('DCM parameter %d',idx1); sprintf('PEB parameter %d',peb_param_idx(idx1))}; if ~isempty(Pp) - txt = vertcat(txt,' ',sprintf('P(with > without): %2.2f',Pp(idx1))); + txt = vertcat(txt,' ',sprintf('Probability: %2.2f',Pp(idx1))); end case 'rfx' diff --git a/spm_dcm_review.m b/spm_dcm_review.m index 22143e0d..ae489b0f 100644 --- a/spm_dcm_review.m +++ b/spm_dcm_review.m @@ -19,7 +19,7 @@ function spm_dcm_review(DCM,action) % Copyright (C) 2008-2015 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_dcm_review.m 6755 2016-03-25 09:48:34Z karl $ +% $Id: spm_dcm_review.m 6931 2016-11-16 12:09:58Z karl $ %-Get DCM structure @@ -401,36 +401,41 @@ function spm_dcm_review(DCM,action) % input effects %------------------------------------------------------------------ - x = (1:DCM.M.N)*DCM.M.dt; + try + tn = (1:DCM.M.N)*DCM.M.dt; + th = (1:DCM.M.N)*DCM.M.dt; + catch + tn = (1:64)*8/1000; + th = (1:64)*1/2; + end for i = 1:m % input effects - neuronal %-------------------------------------------------------------- y = DCM.K1(:,:,i); subplot(m,2,2*(i - 1) + 1) - plot(x,y) - set(gca,'XLim',[0 8]) + plot(tn,y) + set(gca,'XLim',[0 min(max(tn),8)]) axis square title(['neuronal responses to ' DCM.U.name{i}],'FontSize',12) xlabel('time {seconds}') for j = 1:l - text(x(j),y(j,j),DCM.Y.name{j},... + text(tn(j),y(j,j),DCM.Y.name{j},... 'FontWeight','bold','FontSize',fs,... 'HorizontalAlignment','Center') end % input effects - haemodynamic %-------------------------------------------------------------- - y = DCM.K1(:,:,i); k = DCM.H1(:,:,i); subplot(m,2,2*(i - 1) + 2) - plot(x,k,x,y,':') - set(gca,'XLim',[0 24]) + plot(th,k) + set(gca,'XLim',[0 min(max(th),24)]) axis square title('hemodynamic responses','FontSize',12) xlabel('time {seconds}') for j = 1:l - text(x(j),k(j,j),DCM.Y.name{j},... + text(th(j),k(j,j),DCM.Y.name{j},... 'FontWeight','bold','FontSize',fs,... 'HorizontalAlignment','Center') end diff --git a/spm_dcm_simulate.m b/spm_dcm_simulate.m index b90797cd..161d887f 100644 --- a/spm_dcm_simulate.m +++ b/spm_dcm_simulate.m @@ -8,11 +8,14 @@ % connection strengths % % mode - zero-mean Gaussian noise is added, defined by one of: -% 'SNR_var' - signal-to-noise ratio based on the variance [default] +% 'SNR_var' - signal-to-noise ratio based on the variance % 'SNR_std' - signal-to-noise ratio based on the standard deviation % 'var' - variance of the observation noise to be added +% 'Ce' - picks up the log noise precision from GCM{x}.Ce +% [default] % % noise - real-valued added noise (interpretation depends on mode, above) +% if mode is set to 'hE' then this can be empty % % gen_idx - index of the generative model % @@ -27,13 +30,13 @@ % Copyright (C) 2016 Wellcome Trust Centre for Neuroimaging % Peter Zeidman, Vladimir Litvak -% $Id: spm_dcm_simulate.m 6874 2016-09-15 09:29:34Z peter $ +% $Id: spm_dcm_simulate.m 7069 2017-04-24 10:15:20Z peter $ % Check parameters and load specified DCM %-------------------------------------------------------------------------- GCM = spm_dcm_load(GCM); -if nargin < 2 || isempty(mode), mode = 'SNR_var'; end +if nargin < 2 || isempty(mode), mode = 'ce'; end if nargin < 3 || isempty(noise), noise = 1; end if nargin < 4 || isempty(gen_idx), gen_idx = 1; end @@ -87,11 +90,15 @@ e = sqrt(noise) .* randn(size(DCM_gen.Y.y)); DCM_gen.Y.y = DCM_gen.y + e; + case 'ce' + [Y,x,DCM_gen] = spm_dcm_generate(DCM,Inf,graphics); + + e = randn(size(DCM_gen.Y.y)) * sqrtm(diag(DCM.Ce)); + DCM_gen.Y.y = DCM_gen.y + e; otherwise error('Unknown noise definition'); end - - + for i = 1:nm % Store simulated timeseries GCM{s,i}.Y = DCM_gen.Y; @@ -122,8 +129,10 @@ if isfield(DCM, 'Eg') Eg = DCM.Eg; + Ce = DCM.Ce; elseif isfield(GCM{i, 1}, 'Eg') Eg = GCM{i, 1}.Eg; + Ce = GCM{i, 1}.Ce; M = DCM.M; DCM.M = GCM{i, 1}.M; @@ -146,24 +155,32 @@ % generate data %---------------------------------------------------------------------- G = feval(DCM.M.G, Eg, DCM.M); - x = feval(DCM.M.IS, DCM.Ep, DCM.M, DCM.xU); + U = DCM.M.U; + R = DCM.xY.R; + x = feval(DCM.M.IS, DCM.Ep, DCM.M, DCM.xU); for c = 1:length(x) - y{c} = x{c}*G'; - e = spm_conv(randn(size(y{c})),8,0); + y{c} = x{c}*G'*U; + + e = randn(size(y{c})); switch lower(mode) case 'snr_std' + e = spm_conv(e,8,0); e = e*noise*mean(std(y{c}))/mean(std(e)); case 'snr_var' + e = spm_conv(e,8,0); e = e*noise*mean(var(y{c}))/mean(var(e)); case 'var' + e = spm_conv(e,8,0); e = e*sqrt(noise); + case 'estimated' + e = sqrtm(full(Ce))*e; otherwise error('Unknown noise definition'); end y{c} = y{c} + e; - y{c} = DCM.M.R*y{c}; + y{c} = R*y{c}*spm_pinv(full(U)); end % specify models @@ -171,9 +188,9 @@ for j = 1:nm GCM{i,j} = rmfield(DCM,'M'); GCM{i,j}.M.dipfit = DCM.M.dipfit; + GCM{i,j}.M.U = U; GCM{i,j}.xY.y = y; - end - + end % Store generative model gen{i} = DCM; diff --git a/spm_dcm_sparse.m b/spm_dcm_sparse.m new file mode 100644 index 00000000..6a7e63fd --- /dev/null +++ b/spm_dcm_sparse.m @@ -0,0 +1,237 @@ +function [Ep,Cp] = spm_dcm_sparse(DCM,field) +% Bayesian model reduction of all permutations of model parameters +% FORMAT [RCM,BMR] = spm_dcm_sparse(DCM,field +% +% DCM - A single estimated DCM (or PEB) structure: +% +% DCM.M.pE - prior expectation +% DCM.M.pC - prior covariance +% DCM.Ep - posterior expectation +% DCM.Cp - posterior covariances +% DCM.gamma - prior variance of reduced parameters (default: 0) +% +% field - parameter fields in DCM{i}.Ep to optimise [default: {'A','B'}] +% 'All' will invoke all fields (i.e. random effects) +% If Ep is not a structure, all parameters will be considered +% +% Returns: +% Ep - (BMA) posterior expectation +% Cp - (BMA) posterior covariance +% +%-------------------------------------------------------------------------- +% This routine searches over reduced (nested) models of a full model (DCM) +% using Bayesian model reduction and performs Bayesian Model Averaging. +% 'Reduced' means some free parameters (parameters with a non- +% zero prior covariance) are switched off by fixing their prior variance +% to zero.This version incorporates a sparsity prior over models (with a +% Gaussian hyperprior). In other words, the free energy is taken to be the +% likelihood of some data under a given model. The prior on that model +% corresponds to a softmax function of the prior entropy. Finally, the +% softmax (Gibbs) parameter is equipped with a Gaussian prior. Using +% Bayesian model reduction, this routine evaluates the joint probability +% over model and softmax sparsity parameter. The marginals over model space +% are then used to form Bayesian model averaging. +% +% The greedy search in this version simply evaluates the log evidence of +% models with and without each parameter and then successively removes the +% parameters with the least evidence. +% +% See also: spm_dcm_bmr and spm_dcm_bmr_all +%__________________________________________________________________________ +% Copyright (C) 2010-2014 Wellcome Trust Centre for Neuroimaging + +% Karl Friston, Peter Zeidman +% $Id: spm_dcm_sparse.m 7082 2017-05-27 19:36:36Z karl $ + + +%-Number of parameters to consider before invoking greedy search +%-------------------------------------------------------------------------- +nmax = 8; + +%-specification of null prior covariance +%-------------------------------------------------------------------------- +if isfield(DCM,'beta'), beta = DCM.beta; else, beta = 0; end +if isfield(DCM,'gamma'), gamma = DCM.gamma; else, gamma = 0; end + +%-Check fields of parameter stucture +%-------------------------------------------------------------------------- +if nargin < 2 || isempty(field) + field = {'A','B'}; +end +if ischar(field) + field = {field}; +end + +%-dela with filenames stucture +%-------------------------------------------------------------------------- +if ischar(DCM) + DCM = load(DCM,'DCM'); + DCM = DCM.DCM; +end + +% Get prior covariances +%-------------------------------------------------------------------------- +if isstruct(DCM.M.pC), DCM.M.pC = diag(spm_vec(DCM.M.pC)); end +if spm_length(DCM.M.pE) ~= size(DCM.M.pC,1) + DCM.M.pC = diag(spm_vec(DCM.M.pC)); +end + +% Get priors and posteriors +%-------------------------------------------------------------------------- +qE = DCM.Ep; +qC = DCM.Cp; +pE = DCM.M.pE; +pC = DCM.M.pC; + +% Remove (a priori) null space +%-------------------------------------------------------------------------- +U = spm_svd(pC); +qE = U'*spm_vec(qE); +pE = U'*spm_vec(pE); +qC = U'*qC*U; +pC = U'*pC*U; + + +%-Greedy search (GS) - eliminating parameters in a top down fashion +%========================================================================== + +% Accumulated reduction vector (C) +%-------------------------------------------------------------------------- +q = diag(DCM.M.pC); +if sum(q < 1024) + C = double(q > mean(q(q < 1024))/1024); +else + C = double(q > 0); +end + +%-Find free coupling parameters +%---------------------------------------------------------------------- +if isstruct(DCM.Ep) + k = spm_fieldindices(DCM.Ep,field{:}); +else + k = 1:spm_length(DCM.Ep); +end +k = k(find(C(k))); %#ok + +% Model search over new prior without the i-th parameter +%------------------------------------------------------------------ +nparam = length(k); +for i = 1:nparam + + % Identify parameters to retain r and to remove s + %-------------------------------------------------------------- + r = C; r(k(i)) = 0; s = 1 - r; + + % Create reduced priors + %-------------------------------------------------------------- + R = U'*diag(r + s*gamma)*U; + rC = R*pC*R; + F(i) = spm_log_evidence(qE,qC,pE,pC,pE,rC); + +end + +% Find parameters with the least evidence +%-------------------------------------------------------------------------- +[F,i] = sort(-F); +k = k(i); +M = cell(0); +for i = 1:nparam + + + % parameters to retain (r) and to remove (s) + %---------------------------------------------------------------------- + r = C; r(k(1:i)) = 0; s = 1 - r; + + % Create reduced prior covariance matrix + %---------------------------------------------------------------------- + R = U'*diag(r + s*gamma)*U; + rC = R*pC*R; + + % record + %---------------------------------------------------------------------- + M(i).F = spm_log_evidence(qE,qC,pE,pC,pE,rC) + M(i).H = spm_logdet(rC); + M(i).rC = rC; + +end + +% Sparsity hyperpriors +%-------------------------------------------------------------------------- +s = (1:64)/64; +Ps = exp(-((1:64) - 32).^2/(2*16)); +Ps = Ps/sum(Ps); + +% model likelihood, model prior and sparsity hyperprior +%-------------------------------------------------------------------------- +Lm = spm_softmax(spm_vec(M.F)); +for i = 1:numel(s) + Pm = spm_softmax(-s(i)*spm_vec(M.H)); + Qm(:,i) = Lm.*Pm*Ps(i); +end + +% evidence and log evidence +%-------------------------------------------------------------------------- +Qm = Qm/sum(sum(Qm)); +G = log(sum(Qm,2)); + +%-Bayesian model average +%========================================================================== +qE = DCM.Ep; +qC = DCM.Cp; +pE = DCM.M.pE; +pC = DCM.M.pC; +pE = spm_vec(pE); +Gmax = max(G); +BMA = {}; +for i = 1:length(G) + if G(i) > (Gmax - 4) + [F,Ep,Cp] = spm_log_evidence_reduce(qE,qC,pE,pC,pE,M(i).rC); + BMA{end + 1} = struct('Ep',Ep,'Cp',Cp,'F',F); + end +end + +BMA = spm_dcm_bma(BMA); +Ep = BMA.Ep; +Cp = BMA.Cp; +if isstruct(Cp) || (spm_length(Cp) == spm_length(Ep)) + Cp = diag(spm_vec(Cp)); +end + +% Show results +% ------------------------------------------------------------------------- +GRAPHICS = 1; + +if ~GRAPHICS, return, end + +spm_figure('Getwin','BMR - all'); clf +subplot(3,2,1) +imagesc(log(Qm)') +title('Joint density','FontSize',16) +xlabel('model','FontSize',12) +ylabel('sparsity','FontSize',12) +axis square + +subplot(3,2,2) +plot(DCM.Ep,Ep,'.',DCM.Ep,DCM.Ep,':') +title('Full and reduced expectations','FontSize',16) +xlabel('Full expectations','FontSize',12) +ylabel('Reduced expectations','FontSize',12) +axis square + +subplot(3,2,3) +plot(s,sum(Qm,1)) +title('Marginal over sparsity','FontSize',16) +xlabel('sparsity parameter','FontSize',12) +ylabel('probability','FontSize',12) +axis square + +subplot(3,2,4) +plot(sum(Qm,2)) +title('Marginal over model','FontSize',16) +xlabel(' model','FontSize',12) +ylabel('probability','FontSize',12) +axis square +drawnow + + + diff --git a/spm_dcm_specify.m b/spm_dcm_specify.m index 91d47d25..e773f04d 100644 --- a/spm_dcm_specify.m +++ b/spm_dcm_specify.m @@ -7,17 +7,17 @@ % % DCM - DCM structure (see spm_dcm_ui) %__________________________________________________________________________ -% Copyright (C) 2002-2014 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2002-2017 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_dcm_specify.m 6031 2014-06-02 12:49:52Z guillaume $ +% $Id: spm_dcm_specify.m 7064 2017-04-19 14:44:31Z guillaume $ %-Interactive window %-------------------------------------------------------------------------- Finter = spm_figure('GetWin','Interactive'); spm_input('Specify DCM:... ',1,'d'); -% Get design and directory +%-Get design and directory %-------------------------------------------------------------------------- if ~nargin || isempty(SPM) [SPM, sts] = spm_select(1,'^SPM\.mat$','Select SPM.mat'); @@ -30,8 +30,9 @@ catch error('Cannot read %s.',fullfile(swd,'SPM.mat')); end + SPM.swd = swd; else - swd = pwd; + SPM.swd = pwd; end %-Name @@ -47,4 +48,4 @@ %-Save %-------------------------------------------------------------------------- -save(fullfile(swd,['DCM_' name '.mat']),'DCM', spm_get_defaults('mat.format')); +save(fullfile(SPM.swd,['DCM_' name '.mat']),'DCM', spm_get_defaults('mat.format')); diff --git a/spm_ddiff.m b/spm_ddiff.m new file mode 100644 index 00000000..33f42209 --- /dev/null +++ b/spm_ddiff.m @@ -0,0 +1,189 @@ +function [varargout] = spm_ddiff(varargin) +% matrix high-order numerical differentiation (double stencil) +% FORMAT [dfdx] = spm_diff(f,x,...,n) +% FORMAT [dfdx] = spm_diff(f,x,...,n,V) +% FORMAT [dfdx] = spm_diff(f,x,...,n,'q') +% +% f - [inline] function f(x{1},...) +% x - input argument[s] +% n - arguments to differentiate w.r.t. +% +% V - cell array of matrices that allow for differentiation w.r.t. +% to a linear transformation of the parameters: i.e., returns +% +% df/dy{i}; x = V{i}y{i}; V = dx(i)/dy(i) +% +% q - (char) flag to preclude default concatenation of dfdx +% +% dfdx - df/dx{i} ; n = i +% dfdx{p}...{q} - df/dx{i}dx{j}(q)...dx{k}(p) ; n = [i j ... k] +% +% +% This routine has the same functionality as spm_diff, however it +% uses two sample points to provide more accurate numerical (finite) +% differences that accommodate nonlinearities: +% +% dfdx = (4*f(x + dx) - f(x + 2*dx) - 3*f(x))/(2*dx) +%__________________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% Karl Friston +% $Id: spm_ddiff.m 7143 2017-07-29 18:50:38Z karl $ + +% step size for numerical derivatives +%-------------------------------------------------------------------------- +global GLOBAL_DX +if ~isempty(GLOBAL_DX) + dx = GLOBAL_DX; +else + dx = exp(-8); +end + +% create inline object +%-------------------------------------------------------------------------- +f = spm_funcheck(varargin{1}); + +% parse input arguments +%-------------------------------------------------------------------------- +if iscell(varargin{end}) + x = varargin(2:(end - 2)); + n = varargin{end - 1}; + V = varargin{end}; + q = 1; +elseif isnumeric(varargin{end}) + x = varargin(2:(end - 1)); + n = varargin{end}; + V = cell(1,length(x)); + q = 1; +elseif ischar(varargin{end}) + x = varargin(2:(end - 2)); + n = varargin{end - 1}; + V = cell(1,length(x)); + q = 0; +else + error('improper call') +end + +% check transform matrices V = dxdy +%-------------------------------------------------------------------------- +for i = 1:length(x) + try + V{i}; + catch + V{i} = []; + end + if isempty(V{i}) && any(n == i); + V{i} = speye(spm_length(x{i})); + end +end + +% initialise +%-------------------------------------------------------------------------- +m = n(end); +xm = spm_vec(x{m}); +J = cell(1,size(V{m},2)); + +% proceed to derivatives +%========================================================================== +if length(n) == 1 + + % dfdx + %---------------------------------------------------------------------- + f0 = f(x{:}); + for i = 1:length(J) + xi = x; + xii = x; + xi{m} = spm_unvec(xm + V{m}(:,i)*dx, x{m}); + xii{m} = spm_unvec(xm + V{m}(:,i)*2*dx,x{m}); + J{i} = spm_dfdx(f(xi{:}),f(xii{:}),f0,dx); + end + + + % return numeric array for first-order derivatives + %====================================================================== + + % vectorise f + %---------------------------------------------------------------------- + f = spm_vec(f0); + + % if there are no arguments to differentiate w.r.t. ... + %---------------------------------------------------------------------- + if isempty(xm) + J = sparse(length(f),0); + + % or there are no arguments to differentiate + %---------------------------------------------------------------------- + elseif isempty(f) + J = sparse(0,length(xm)); + end + + % differentiation of a scalar or vector + %---------------------------------------------------------------------- + if isnumeric(f0) && iscell(J) && q + J = spm_dfdx_cat(J); + end + + + % assign output argument and return + %---------------------------------------------------------------------- + varargout{1} = J; + varargout{2} = f0; + +else + + % dfdxdxdx.... + %---------------------------------------------------------------------- + f0 = cell(1,length(n)); + [f0{:}] = spm_diff(f,x{:},n(1:end - 1),V); + p = true; + + for i = 1:length(J) + xi = x; + xii = x; + xmi = xm + V{m}(:,i)*dx; + xmii = xm + V{m}(:,i)*2*dx; + xi{m} = spm_unvec(xmi, x{m}); + xii{m} = spm_unvec(xmii,x{m}); + fi = spm_diff(f,xi{:}, n(1:end - 1),V); + fii = spm_diff(f,xii{:},n(1:end - 1),V); + J{i} = spm_dfdx(fi,fii,f0{1},dx); + p = p & isnumeric(J{i}); + end + + % or differentiation of a scalar or vector + %---------------------------------------------------------------------- + if p && q + J = spm_dfdx_cat(J); + end + varargout = [{J} f0]; +end + + +function dfdx = spm_dfdx(f,ff,f0,dx) +% cell subtraction +%__________________________________________________________________________ +if iscell(f) + dfdx = f; + for i = 1:length(f(:)) + dfdx{i} = spm_dfdx(f{i},ff{i},f0{i},dx); + end +elseif isstruct(f) + dfdx = (4*spm_vec(f) - spm_vec(ff) - 3*spm_vec(f0))/(2*dx); +else + dfdx = (4*f - ff - 3*f0)/(2*dx); +end + +return + +function J = spm_dfdx_cat(J) +% concatenate into a matrix +%-------------------------------------------------------------------------- +if isvector(J{1}) + if size(J{1},2) == 1 + J = spm_cat(J); + else + J = spm_cat(J')'; + end +end + + diff --git a/spm_defaults.m b/spm_defaults.m index 0bc38124..bd76d424 100644 --- a/spm_defaults.m +++ b/spm_defaults.m @@ -23,7 +23,7 @@ % Copyright (C) 1994-2016 Wellcome Trust Centre for Neuroimaging % SPM -% $Id: spm_defaults.m 6753 2016-03-24 20:30:28Z guillaume $ +% $Id: spm_defaults.m 7173 2017-09-22 11:26:31Z guillaume $ global defaults @@ -70,7 +70,7 @@ % Stats defaults %========================================================================== -defaults.stats.maxmem = 2^28; +defaults.stats.maxmem = 2^29; defaults.stats.maxres = 64; defaults.stats.resmem = false; defaults.stats.fmri.ufp = 0.001; % Upper tail F-probability @@ -208,7 +208,7 @@ if isdeployed && exist(fullfile(spm('Dir'),user_defaults),'file') user_defaults_file = cellstr(fullfile(spm('Dir'),user_defaults)); else - user_defaults_file = which(user_defaults,'-ALL'); + user_defaults_file = cellstr(which(user_defaults,'-ALL')); end for i=1:numel(user_defaults_file) try diff --git a/spm_dicom_convert.m b/spm_dicom_convert.m index 7d665ec0..2fa09e9f 100644 --- a/spm_dicom_convert.m +++ b/spm_dicom_convert.m @@ -1,6 +1,6 @@ -function out = spm_dicom_convert(hdr,opts,root_dir,format,out_dir) +function out = spm_dicom_convert(hdr,opts,root_dir,format,out_dir,meta) % Convert DICOM images into something that SPM can use (e.g. NIfTI) -% FORMAT spm_dicom_convert(hdr,opts,root_dir,format,out_dir) +% FORMAT out = spm_dicom_convert(hdr,opts,root_dir,format,out_dir) % Inputs: % hdr - a cell array of DICOM headers from spm_dicom_headers % opts - options: @@ -10,7 +10,7 @@ % 'spect' - SIEMENS Spectroscopy DICOMs (some formats only) % This will write out a 5D NIFTI containing real % and imaginary part of the spectroscopy time -% points at the position of spectroscopy voxel(s). +% points at the position of spectroscopy voxel(s) % 'raw' - convert raw FIDs (not implemented) % root_dir - 'flat' - do not produce file tree [default] % With all other options, files will be sorted into @@ -26,17 +26,18 @@ % 'img' - Two file (hdr+img) NIfTI format % All images will contain a single 3D dataset, 4D images will % not be created. -% out_dir - output directory name. +% out_dir - output directory name [default: pwd] +% meta - save metadata as sidecar JSON file [default: false] % % Output: % out - a struct with a single field .files. out.files contains a % cellstring with filenames of created files. If no files are % created, a cell with an empty string {''} is returned. %__________________________________________________________________________ -% Copyright (C) 2002-2015 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2002-2017 Wellcome Trust Centre for Neuroimaging % John Ashburner -% $Id: spm_dicom_convert.m 6899 2016-10-07 08:23:34Z volkmar $ +% $Id: spm_dicom_convert.m 7201 2017-11-08 11:13:25Z guillaume $ %-Input parameters @@ -45,6 +46,7 @@ if nargin<3, root_dir = 'flat'; end if nargin<4, format = spm_get_defaults('images.format'); end if nargin<5, out_dir = pwd; end +if nargin<6, meta = false; end %-Select files %-------------------------------------------------------------------------- @@ -63,28 +65,29 @@ fmos = {}; fstd = {}; fspe = {}; +fmul = {}; if (strcmp(opts,'all') || strcmp(opts,'mosaic')) && ~isempty(mosaic) - fmos = convert_mosaic(mosaic,root_dir,format,out_dir); + fmos = convert_mosaic(mosaic,root_dir,format,out_dir,meta); end if (strcmp(opts,'all') || strcmp(opts,'standard')) && ~isempty(standard) - fstd = convert_standard(standard,root_dir,format,out_dir); + fstd = convert_standard(standard,root_dir,format,out_dir,meta); end if (strcmp(opts,'all') || strcmp(opts,'spect')) && ~isempty(spect) - fspe = convert_spectroscopy(spect,root_dir,format,out_dir); + fspe = convert_spectroscopy(spect,root_dir,format,out_dir,meta); end if (strcmp(opts,'all') || strcmp(opts,'multiframe')) && ~isempty(multiframe) - fspe = convert_multiframes(multiframe,root_dir,format,out_dir); + fmul = convert_multiframes(multiframe,root_dir,format,out_dir,meta); end -out.files = [fmos(:); fstd(:); fspe(:)]; +out.files = [fmos(:); fstd(:); fspe(:); fmul(:)]; if isempty(out.files) out.files = {''}; end %========================================================================== -% function fnames = convert_mosaic(hdr,root_dir,format,out_dir) +% function fnames = convert_mosaic(hdr,root_dir,format,out_dir,meta) %========================================================================== -function fnames = convert_mosaic(hdr,root_dir,format,out_dir) +function fnames = convert_mosaic(hdr,root_dir,format,out_dir,meta) spm_progress_bar('Init',length(hdr),'Writing Mosaic', 'Files written'); fnames = cell(length(hdr),1); @@ -216,7 +219,7 @@ RescaleSlope = 1; RescaleIntercept = 0; if isfield(hdr{i},'RescaleSlope') && hdr{i}.RescaleSlope ~= 1 - RescaleSlope = hdr{i}.RescaleSlope; + RescaleSlope = hdr{i}.RescaleSlope; end if isfield(hdr{i},'RescaleIntercept') && hdr{i}.RescaleIntercept ~= 0 RescaleIntercept = hdr{i}.RescaleIntercept; @@ -230,6 +233,10 @@ N.descrip = descrip; create(N); + if meta + N = spm_dicom_metadata(N,hdr{i}); + end + % Write the data unscaled dat = N.dat; dat.scl_slope = []; @@ -243,13 +250,13 @@ %========================================================================== -% function fnames = convert_standard(hdr,root_dir,format,out_dir) +% function fnames = convert_standard(hdr,root_dir,format,out_dir,meta) %========================================================================== -function fnames = convert_standard(hdr,root_dir,format,out_dir) +function fnames = convert_standard(hdr,root_dir,format,out_dir,meta) hdr = sort_into_volumes(hdr); fnames = cell(length(hdr),1); for i=1:length(hdr) - fnames{i} = write_volume(hdr{i},root_dir,format,out_dir); + fnames{i} = write_volume(hdr{i},root_dir,format,out_dir,meta); end @@ -510,9 +517,9 @@ %========================================================================== -% function fname = write_volume(hdr,root_dir,format,out_dir) +% function fname = write_volume(hdr,root_dir,format,out_dir,meta) %========================================================================== -function fname = write_volume(hdr,root_dir,format,out_dir) +function fname = write_volume(hdr,root_dir,format,out_dir,meta) % Output filename %-------------------------------------------------------------------------- @@ -682,24 +689,29 @@ N.mat0_intent = 'Scanner'; N.descrip = descrip; create(N); + +if meta + N = spm_dicom_metadata(N,hdr{1}); +end + N.dat(:,:,:) = volume; spm_progress_bar('Clear'); %========================================================================== -% function fnames = convert_spectroscopy(hdr,root_dir,format,out_dir) +% function fnames = convert_spectroscopy(hdr,root_dir,format,out_dir,meta) %========================================================================== -function fnames = convert_spectroscopy(hdr,root_dir,format,out_dir) +function fnames = convert_spectroscopy(hdr,root_dir,format,out_dir,meta) fnames = cell(length(hdr),1); for i=1:length(hdr) - fnames{i} = write_spectroscopy_volume(hdr(i),root_dir,format,out_dir); + fnames{i} = write_spectroscopy_volume(hdr(i),root_dir,format,out_dir,meta); end %========================================================================== -% function fname = write_spectroscopy_volume(hdr,root_dir,format,out_dir) +% function fname = write_spectroscopy_volume(hdr,root_dir,format,out_dir,meta) %========================================================================== -function fname = write_spectroscopy_volume(hdr,root_dir,format,out_dir) +function fname = write_spectroscopy_volume(hdr,root_dir,format,out_dir,meta) % Output filename %------------------------------------------------------------------- fname = getfilelocation(hdr{1}, root_dir,'S',format,out_dir); @@ -859,6 +871,10 @@ get_numaris4_numval(privdat,'RealDwellTime')); create(N); +if meta + N = spm_dicom_metadata(N,hdr{1}); +end + % Read data, swap dimensions data = permute(reshape(read_spect_data(hdr{1},ntp),dim([4 5 1 2 3])), ... [3 4 5 1 2]); @@ -1241,16 +1257,43 @@ end end +% To use ICE Dims systematically in file names in order to avoid +% overwriting uncombined coil images, which have identical file name +% otherwise) +try + ICE_Dims = get_numaris4_val(hdr.CSAImageHeaderInfo,'ICE_Dims'); + % extract ICE dims as an array of numbers (replace 'X' which is for + % combined images by '-1' first): + CHA = sscanf(strrep(ICE_Dims,'X','-1'), '%i_%i_%i_%i_%i_%i_%i_%i_%i')'; + if CHA(1)>0 + CHA = sprintf('%.3d',CHA(1)); + else + CHA = ''; + end +catch + CHA = ''; +end + if strcmp(root_dir, 'flat') % Standard SPM file conversion %---------------------------------------------------------------------- if checkfields(hdr,'SeriesNumber','AcquisitionNumber') if checkfields(hdr,'EchoNumbers') - fname = sprintf('%s%s-%.4d-%.5d-%.6d-%.2d%s.%s', prefix, strip_unwanted(PatientID),... - SeriesNumber, AcquisitionNumber, InstanceNumber, EchoNumbers, ImTyp, format); +if ~isempty(CHA) + fname = sprintf('%s%s-%.4d-%.5d-%.6d-%.2d-%s%s.%s', prefix, strip_unwanted(PatientID),... + SeriesNumber, AcquisitionNumber, InstanceNumber, EchoNumbers, CHA, ImTyp, format); + else + fname = sprintf('%s%s-%.4d-%.5d-%.6d-%.2d%s.%s', prefix, strip_unwanted(PatientID),... + SeriesNumber, AcquisitionNumber, InstanceNumber, EchoNumbers, ImTyp, format); + end else - fname = sprintf('%s%s-%.4d-%.5d-%.6d%s.%s', prefix, strip_unwanted(PatientID),... - SeriesNumber, AcquisitionNumber, InstanceNumber, ImTyp, format); + if ~isempty(CHA) + fname = sprintf('%s%s-%.4d-%.5d-%.6d-%s%s.%s', prefix, strip_unwanted(PatientID),... + SeriesNumber, AcquisitionNumber, InstanceNumber, CHA, ImTyp, format); + else + fname = sprintf('%s%s-%.4d-%.5d-%.6d%s.%s', prefix, strip_unwanted(PatientID),... + SeriesNumber, AcquisitionNumber, InstanceNumber, ImTyp, format); + end end else fname = sprintf('%s%s-%.6d%s.%s',prefix, ... @@ -1414,20 +1457,20 @@ end %========================================================================== -% function fspe = convert_multiframes(hdr,root_dir,format,out_dir) +% function fspe = convert_multiframes(hdr,root_dir,format,out_dir,meta) %========================================================================== -function fspe = convert_multiframes(hdr,root_dir,format,out_dir) +function fspe = convert_multiframes(hdr,root_dir,format,out_dir,meta) fspe = {}; dict = load('spm_dicom_dict.mat'); for i=1:numel(hdr) - out = convert_multiframe(hdr{i}, dict, root_dir, format,out_dir); + out = convert_multiframe(hdr{i}, dict, root_dir, format,out_dir,meta); fspe = [fspe(:); out(:)]; end %========================================================================== -% function out = convert_multiframe(H, dict, root_dir, format,out_dir) +% function out = convert_multiframe(H, dict, root_dir, format,out_dir,meta) %========================================================================== -function out = convert_multiframe(H, dict, root_dir, format,out_dir) +function out = convert_multiframe(H, dict, root_dir, format,out_dir,meta) out = {}; diminfo = read_DimOrg(H,dict); dat = read_FGS(H,diminfo); @@ -1506,7 +1549,7 @@ R = [reshape(ImageOrientationPatient,3,2)*diag(PixelSpacing); 0 0]; % Determine the order of the slices by sorting their positions according to where they project - % on a vector orthogonal to the iamge plane + % on a vector orthogonal to the image plane orient = reshape(this(1).ImageOrientationPatient,[3 2]); orient(:,3) = null(orient'); if det(orient)<0, orient(:,3) = -orient(:,3); end @@ -1673,6 +1716,11 @@ Nii.mat0_intent = 'Scanner'; Nii.descrip = descrip; create(Nii); + + if meta + Nii = spm_dicom_metadata(Nii,H); + end + Nii.dat(end,end,end,end,end) = 0; % Write the image volume @@ -1820,5 +1868,3 @@ else error('"%s" is not multiframe.', H.FileName); end - - diff --git a/spm_dicom_metadata.m b/spm_dicom_metadata.m new file mode 100644 index 00000000..8f702d3f --- /dev/null +++ b/spm_dicom_metadata.m @@ -0,0 +1,275 @@ +function N = spm_dicom_metadata(N,hdr) +% Export image metadata as side-car JSON file +% FORMAT N = spm_dicom_metadata(N,hdr) +% N(input) - nifti object +% hdr - a single header as output by spm_dicom_headers +% N(output) - unchanged nifti object (unless header extension is used) +% +% PURPOSE: To create JSON-encoded metadata during DICOM to NIfTI +% conversion, including all acquisition parameters, and saved as a JSON +% side-car file (or, in the future, as NIfTI header extension). +% +% See also: spm_dicom_convert +%__________________________________________________________________________ +% Copyright (C) 2017 Wellcome Trust Centre for Neuroimaging + +% Evelyne Balteau +% Cyclotron Research Centre, University of Liege, Belgium +% $Id: spm_dicom_metadata.m 7201 2017-11-08 11:13:25Z guillaume $ + + +%-Provenance and general description of the image +if ~isdeployed + version = sprintf('spm_dicom_convert.m - version %s - %s', spm('Ver','spm_dicom_convert.m',true), spm('Version')); +else + version = sprintf('spm_dicom_convert.m - %s', spm('Version')); +end +metadata.history.procstep = struct('descrip','dicom to nifti import', 'version', version, 'procpar', []); +metadata.history.input(1) = struct('filename','AnonymousFileName', 'history',[]); +if isfield(hdr,'ImageType') + metadata.history.output = struct('imtype',hdr.ImageType, 'units','a.u.'); +else + metadata.history.output = struct('imtype','Unprocessed MR image', 'units','a.u.'); +end + +%-Acquisition parameters with complete DICOM header +hdr = reformat_spm_dicom_header(hdr); +hdr = anonymise_metadata(hdr); % default is basic anonymisation +metadata.acqpar = hdr; + +%-Save metadata as side-car JSON file +spm_jsonwrite(spm_file(N.dat.fname,'ext','json'), metadata, struct('indent','\t')); + + +%========================================================================== +function hdr = reformat_spm_dicom_header(hdr) +% To tidy up and rearrange CSA fields in the header, including formatting +% the ASCII part into a proper Matlab structure (Note: this is specific to +% Siemens DICOM format but could be extended to other cases where needed) +% +% FORMAT hdr = reformat_spm_dicom_header(hdr) +% where hdr is a dicom header structure as output by spm_dicom_headers. + +% list of CSA-like fields: +CSAlist = {'CSAImageHeaderInfo', 'CSASeriesHeaderInfo','CSANonImageHeaderInfoVA','CSAMiscProtocolHeaderInfoVA','CSANonImageHeaderInfoVB','CSAMiscProtocolHeaderInfoVB'}; +% NB: might be necessary to add cases 'Private_0029_1110' and +% 'Private_0029_1210' for spectroscopic data (see spm_dicom_essentials.m) + +for ccsa = 1:length(CSAlist) + if isfield(hdr,CSAlist{ccsa}) + tdyhdr = tidy_CSA(hdr.(CSAlist{ccsa})); + if isfield(tdyhdr,'MrPhoenixProtocol') + % works for Siemens VB, VD & VE DICOM format: + tdyhdr.MrPhoenixProtocol = read_ASCII(tdyhdr.MrPhoenixProtocol); + elseif isfield(tdyhdr,'MrProtocol') + % works for Siemens VA DICOM format: + tdyhdr.MrProtocol = read_ASCII(tdyhdr.MrProtocol); + end + hdr.(CSAlist{ccsa}) = tdyhdr; + end +end + + +%========================================================================== +function hdrout = anonymise_metadata(hdr, opts) +% FORMAT hdrout = anonymise_metadata(hdr, opts) +% hdr is a DICOM header read with spm_dicom_header +% opts are anonymisation options: +% opts.anonym = 'none': no anonymisation, all patient data kept in +% the metadata. +% 'full': no patient information is kept at all +% 'basic': patient ID (presumably not containing his +% name), age (years at the time of the data +% acquisition), sex, size and weight are kept, +% patient name, date of birth and DICOM filename +% (often containing the patient name) are removed. +% +% !!! IMPORTANT WARNING: EFFECTIVE ANONYMISATION IS NOT GUARANTEED !!! +% The anonymisation implemented here depends on the structure and content +% of the DICOM header and might not be effective in many cases. + +if nargin<2 + opts.anonym = 'basic'; +end +if ~iscell(hdr) + hdrout{1} = hdr; +else + hdrout = hdr; +end + +if ~strcmp(opts.anonym,'none') + for i=1:length(hdrout) + if isfield(hdrout{i},'PatientName') + hdrout{i}.PatientName = 'Anonymous'; + end + if isfield(hdrout{i},'PatientBirthDate') + t1 = hdrout{i}.PatientBirthDate; + t2 = hdrout{i}.StudyDate; + hdrout{i}.PatientAge = round((t2-t1)*10/365.25)/10; + hdrout{i} = rmfield(hdrout{i},'PatientBirthDate'); + end + if isfield(hdrout{i},'Filename') + hdrout{i} = rmfield(hdrout{i},'Filename'); + end + + if strcmp(opts.anonym, 'full') + try, hdrout{i} = rmfield(hdrout{i},'PatientID'); end + try, hdrout{i} = rmfield(hdrout{i},'PatientSex'); end + try, hdrout{i} = rmfield(hdrout{i},'PatientAge'); end + try, hdrout{i} = rmfield(hdrout{i},'PatientSize'); end + try, hdrout{i} = rmfield(hdrout{i},'PatientWeight'); end + try, hdrout{i}.CSASeriesHeaderInfo = rmfield(hdrout{i}.CSASeriesHeaderInfo,'UsedPatientWeight'); end + end + end +end + + +%========================================================================== +function tdyhdr = tidy_CSA(csahdr) +% FORMAT tdyhdr = tidy_CSA(csahdr) +% DESCRIPTION: +% To rearrange CSAImageHeaderInfo, CSASeriesHeaderInfo, ... structures +% and make it a simplified, easier to browse structure (Siemens specific). +% USAGE: +% tdyhdr = tidy_CSA(csahdr) +% where csahdr is a structure, content of the CSA field. + +tdyhdr = []; +for ccsa = 1:length(csahdr) + val = get_numaris4_val(csahdr,csahdr(ccsa).name); + % if val is empty, let's not waste disk space with empty fields + if ~isempty(val) + % for elements having a value representation corresponding to a + % numerical value (or an array of numerical values), convert char + % into numbers. Here is a list of VR corresponding to numerical + % values: + % - DS (Decimal String) + % - FL (Floating Point Single) + % - FD (Floating Point Double) + % - IS (Integer String) + % - OD (Other Double String) + % - OF (Other Float String) + % - SL (Signed Long) + % - SS (Signed Short) + % - UL (Unsigned Long) + % - US (Unsigned Short) + switch deblank(csahdr(ccsa).vr) + case {'DS','FL','FD','IS','OD','OF','SL','SS','UL','US'} + try + tmp = zeros(size(val,1),1); + for k = 1:size(val,1) + tmp(k) = str2num(val(k,:)); + end + val = tmp; + catch + fprintf(1,'Trouble reading CSA header %s (%s) = %s\n',csahdr(ccsa).name, deblank(csahdr(ccsa).vr), val(1,:)); + val = []; + end + otherwise + val = deblank(val); + end + % make sure no "-" in field name (invalid otherwise) + csahdr(ccsa).name = strrep(csahdr(ccsa).name,'-',''); + tdyhdr.(csahdr(ccsa).name) = val; + end +end + + +%========================================================================== +function val = get_numaris4_val(str,name) +% copied from spm_dicom_convert +name = deblank(name); +val = {}; +for i=1:length(str) + if strcmp(deblank(str(i).name),name) + if isfield(str(i),'nitems') + for j=1:str(i).nitems + if str(i).item(j).xx(1) + val = [val {str(i).item(j).val}]; + end + end + % else + % fprintf(1,'Found empty CSA header with name %s\n',name); + end + break; + end +end +val = strvcat(val{:}); + + +%========================================================================== +function ascout = read_ASCII(ascin) +% FORMAT ascout = read_ASCII(ascin) +% +% DESCRIPTION: +% To parse the content of the ASCII part of the DICOM header (Siemens +% specific) and convert it into a matlab structure. Compatible with VA, VB, +% VD and also reading *.SR files (PhoenixProtocols). +% +% USAGE: +% ascout = read_ASCII(ascin) +% where ascin is the char content of either +% hdr.CSASeriesHeaderInfo.MrPhoenixProtocol or +% hdr.CSASeriesHeaderInfo.MrProtocol according to Siemens software version, +% and asc is a matlab structure containing the information contained in the +% ASCCONV BEGIN - ASCCONV END part of the DICOM header. +% +% NOTE: slightly different formatting from read_ascconv in spm_dicom_convert + +% only for debugging purpose +ENABLE_DEBUG = false; + +% extract the portion between ### ASCCONV BEGIN ### and ### ASCCONV END ### +ascin = regexprep(ascin,'^.*### ASCCONV BEGIN [^#]*###(.*)### ASCCONV END ###.*$','$1'); + +% split ascin into lines +% asclines = strsplit(ascin,'\n'); % ok for Matlab 2013 and later versions +% replaced by textscan (with delimiter '\n') for compatibility with +% Matlab 2012 and earlier :/... +tmp = textscan(ascin,'%s','delimiter','\n'); +asclines = tmp{1}; + +% do a first cleaning pass over the data: +% - replace indexes [] by () + increment index +1 (C>Matlab indexing) +% - replace double "" and single " by single ' +% - replace hexadecimal values (e.g. "0x01") by decimal value +% - delete lines where a field starts or ends by "_" +% - delete end of lines after "#" +asclines = regexprep(asclines,{'\[([0-9]*)\]','["]+','^([^"]*)0x([0-9a-fA-F]*)',' #.*','^.*\._.*$'},{'($1+1)','''','$1hex2dec(''$2'')','',''}); + +% initialise variables +ascout = []; +clinenum = 1; + +while clinenum + % first process the name of the parameter (hdrnam) + % split into fields + [hdrnam,tmp] = regexp(tlhrh{1}, '(?:\.)+', 'split', 'match'); + % check whether any field starts with a number and if so, + % replace it by "index..." + isfirstdigit = cellfun(@(x) isstrprop(x(1),'digit'),hdrnam); + if any(isfirstdigit) + for cfield=1:length(hdrnam) + if isfirstdigit(cfield) + hdrnam{cfield} = ['index' hdrnam{cfield}]; + end + end + end + % concatenate back the fields + hdrnam = sprintf('.%s', hdrnam{:}); + % now process the value (hdrval) + hdrval = strtrim(tlhrh{2}); + % and eval the whole line + eval(sprintf('ascout%s = %s;', hdrnam, hdrval)); + if ENABLE_DEBUG, fprintf('ascout%s = %s;\n', hdrnam, hdrval); end + catch + fprintf('AscConv: Error evaluating [ %s; ]\n', asclines{clinenum}); + end + end + clinenum = clinenum+1; +end diff --git a/spm_diff.m b/spm_diff.m index 5b35547b..9a30b2aa 100644 --- a/spm_diff.m +++ b/spm_diff.m @@ -19,12 +19,25 @@ % dfdx{p}...{q} - df/dx{i}dx{j}(q)...dx{k}(p) ; n = [i j ... k] % % -% - a cunning recursive routine +% This routine has the same functionality as spm_ddiff, however it +% uses one sample point to approximate gradients with numerical (finite) +% differences: +% +% dfdx = (f(x + dx)- f(x))/dx %__________________________________________________________________________ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_diff.m 6836 2016-07-15 09:43:30Z karl $ +% $Id: spm_diff.m 7143 2017-07-29 18:50:38Z karl $ + +% step size for numerical derivatives +%-------------------------------------------------------------------------- +global GLOBAL_DX +if ~isempty(GLOBAL_DX) + dx = GLOBAL_DX; +else + dx = exp(-8); +end % create inline object %-------------------------------------------------------------------------- @@ -68,7 +81,6 @@ %-------------------------------------------------------------------------- m = n(end); xm = spm_vec(x{m}); -dx = exp(-8); J = cell(1,size(V{m},2)); % proceed to derivatives diff --git a/spm_diff_dx.m b/spm_diff_dx.m new file mode 100644 index 00000000..c08487b4 --- /dev/null +++ b/spm_diff_dx.m @@ -0,0 +1,73 @@ +function [DX] = spm_diff_dx(varargin) +% optimisation of finite difference for numerical differentiation +% FORMAT [dx] = spm_diff_dx(f,x,...,n) +% FORMAT [dx] = spm_diff_dx(f,x,...,n,V) +% FORMAT [dx] = spm_diff_dx(f,x,...,n,'q') +% +% f - [inline] function f(x{1},...) +% x - input argument[s] +% n - arguments to differentiate w.r.t. +% +% dx - 'best' step size +%__________________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% Karl Friston +% $Id: spm_diff_dx.m 7143 2017-07-29 18:50:38Z karl $ + + +% Stability of numerical gradients +%========================================================================== +global GLOBAL_DX + +% line search of step sizes +%-------------------------------------------------------------------------- +dh = 1; +dx = -8:dh:0; +nd = numel(dx); +for i = 1:nd + GLOBAL_DX = exp(dx(i)); + dxdp{i} = spm_diff(varargin{:}); +end +np = size(dxdp{1},2); +for i = 1:(nd - 1) + for j = 1:np + dgdh = spm_vec(dxdp{i}{j}) - spm_vec(dxdp{i + 1}{j}); + ssd(i,j) = mean(abs(dgdh/dh).^2); + end +end + +% graphics +%-------------------------------------------------------------------------- +dx = dx(1:end - 1); +mss = mean(log(ssd),2); +[~,j] = min(mss); +DX = dx(j); + +% graphics +%-------------------------------------------------------------------------- +if nargout, return, end + +str = sprintf('Log stability: dx = exp(%.1f)',DX); + +subplot(2,2,1), plot(dx,mss,dx,log(ssd),':') +title('Log stability','Fontsize',16), xlabel('log(dx)') +axis square, spm_axis tight + +subplot(2,2,2), imagesc(1:np,dx,log(ssd)) +title('Log stability','Fontsize',16), xlabel('Paramter mode') +axis square, ylabel('log(dx)') + +subplot(2,2,3), plot(log(ssd(j,:))) +title(str,'Fontsize',16), xlabel('Paramter mode') +axis square, spm_axis tight + +if iscell(varargin{end}) + V = varargin{end}; + subplot(2,2,4), imagesc(V{1}) + title('Paramter modes','Fontsize',16), xlabel('Paramter mode') + axis square, ylabel('parameter') +end + + + diff --git a/spm_diffeo.mexa64 b/spm_diffeo.mexa64 index 9f8b3b15578bf4d080d2b11ac0c53f901b424f0c..3879411cdcbe33ee59db43b50744dd714c842c29 100755 GIT binary patch delta 48213 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 OT$%cv`11|=wEqJPICVMz delta 26033 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 Az5oCK delta 36483 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 Q(AK$N@98;*DoxVA0jv`{k^lez literal 13720 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 Q_MuRoI{s-7ek#WP4cvJEd;kCd diff --git a/spm_dilate_erode.mexw32 b/spm_dilate_erode.mexw32 index 3eb8d8159bfff4ae8202cd265b6d00947a672cbf..188950e405bd0ea43bec10e95c2e331b1002b80d 100755 GIT binary patch delta 32 lcmZp0X>ghFfn}-mv&e~Ge3+(~Zgyg1k_7WNdr0kI2LRqc43Gc- delta 32 lcmZp0X>ghFf#vewPoWdP_%LyP+U&&0Bnjqk_K@1a4gdr=4)Op1 diff --git a/spm_dilate_erode.mexw64 b/spm_dilate_erode.mexw64 index 008f6ad996cb4b06917bdbc639531c0e5cdf70ba..3b876f40ce0efc6c64a42ba35a55a4ae4d3ec2fe 100755 GIT binary patch delta 32 lcmZn&Xb70_fJOJ&)5wWWe3&dwZ#H6Vk^%EK?~wK20s!#i4c`C& delta 32 lcmZn&Xb70_fQ4aSOz6ZXK1^o{HybfF$$ exp(-16))) && SVD - U = spm_svd(dfdx,0); - dfdx = U'*dfdx*U; - f = U'*f; - end - % relative integration time %---------------------------------------------------------------------- t = t{:}; @@ -89,89 +78,295 @@ % use a [pseudo]inverse if all t > TOL %========================================================================== if min(t) > exp(16) - - dx = -spm_pinv(dfdx)*f; - -elseif n > nmax && max(t) < 2 && isscalar(t) - - % numerical approximation (removing very dissipative modes) - % fprintf('\nnumerical approximation: n = %i',length(f)); - %---------------------------------------------------------------------- - tol = 1e-6; - OPT.tol = tol*norm((dfdx),'inf'); - - n = 512; - [V,D] = eigs(dfdx,1,'SR',OPT); - N = max(-real(D)*2,n); - dt = 1/N; - s = 0; - x = f - f; - dx = f*dt; - df = dfdx*dx; - while s < t - - % while there are dissipative modes - %------------------------------------------------------------------ - while N > n; - - - % while principal mode dissipiates - %-------------------------------------------------------------- - while abs(df'*V) > tol && s < t - for i = 1:8 - df = dfdx*dx; - f = f + df; - dx = f*dt; - x = x + dx; - s = s + dt; - end - end - - % sliminate the principal mode - %-------------------------------------------------------------- - dfdx = dfdx - V*(pinv(V)*dfdx); - [V,D] = eigs(dfdx,1,'SR',OPT); - N = max(-real(D)*2,n); - dt = 1/N; - - end - - % continue integration until s > t - %------------------------------------------------------------------ - f = f + dfdx*dx; - dx = f*dt; - x = x + dx; - s = s + dt; - - end - - dx = U*x; + dx = -spm_pinv(dfdx)*f; else % ensure t is a scalar or matrix %---------------------------------------------------------------------- if isvector(t), t = diag(t); end - + % augment Jacobian and take matrix exponential %====================================================================== - J = full(spm_cat({0 []; - t*f t*dfdx})); - + J = spm_cat({0 [] ; + t*f t*dfdx}); + % solve using matrix expectation %---------------------------------------------------------------------- if n <= nmax - dx = expm(J); - else - [V,D] = eig(J,'nobalance'); - dx = V*diag(exp(diag(D)))/V; + dx = spm_expm(J); + dx = dx(:,1); + else + x = sparse(1,1,1,n + 1,1); + dx = expv(1,J,x); end % recover update %---------------------------------------------------------------------- - dx = dx(2:end,1); + dx = dx(2:end); end -dx = spm_unvec(U*real(dx),xf); +dx = spm_unvec(real(dx),xf); + +return + + +%========================================================================== +% Roger B. Sidje (rbs@maths.uq.edu.au) +% EXPOKIT: Software Package for Computing Matrix Exponentials. +% ACM - Transactions On Mathematical Software, 24(1):130-156, 1998 + +function [w, err, hump] = expv( t, A, v, tol, m ) +% FOTMAT [w, err, hump] = expv( t, A, v, tol, m ) +% EXPV computes an approximation of w = exp(t*A)*v for a +% general matrix A using Krylov subspace projection techniques. +% It does not compute the matrix exponential in isolation but instead, +% it computes directly the action of the exponential operator on the +% operand vector. This way of doing so allows for addressing large +% sparse problems. The matrix under consideration interacts only +% via matrix-vector products (matrix-free method). +% +% w = expv( t, A, v ) +% computes w = exp(t*A)*v using a default tol = 1.0e-7 and m = 30. +% +% [w, err] = expv( t, A, v ) +% renders an estimate of the error on the approximation. +% +% [w, err] = expv( t, A, v, tol ) +% overrides default tolerance. +% +% [w, err, hump] = expv( t, A, v, tol, m ) +% overrides default tolerance and dimension of the Krylov subspace, +% and renders an approximation of the `hump'. +% +% The hump is defined as: +% hump = max||exp(sA)||, s in [0,t] (or s in [t,0] if t < 0). +% It is used as a measure of the conditioning of the matrix exponential +% problem. The matrix exponential is well-conditioned if hump = 1, +% whereas it is poorly-conditioned if hump >> 1. However the solution +% can still be relatively fairly accurate even when the hump is large +% (the hump is an upper bound), especially when the hump and +% ||w(t)||/||v|| are of the same order of magnitude (further details in +% reference below). +% +% Example 1: +% ---------- +% n = 100; +% A = rand(n); +% v = eye(n,1); +% w = expv(1,A,v); +% +% Example 2: +% ---------- +% % generate a random sparse matrix +% n = 100; +% A = rand(n); +% for j = 1:n +% for i = 1:n +% if rand < 0.5, A(i,j) = 0; end; +% end; +% end; +% v = eye(n,1); +% A = sparse(A); % invaluable for a large and sparse matrix. +% +% tic +% [w,err] = expv(1,A,v); +% toc +% +% disp('w(1:10) ='); disp(w(1:10)); +% disp('err ='); disp(err); +% +% tic +% w_matlab = expm(full(A))*v; +% toc +% +% disp('w_matlab(1:10) ='); disp(w_matlab(1:10)); +% gap = norm(w-w_matlab)/norm(w_matlab); +% disp('||w-w_matlab|| / ||w_matlab|| ='); disp(gap); +% +% In the above example, n could have been set to a larger value, +% but the computation of w_matlab will be too long (feel free to +% discard this computation). +% +% See also MEXPV, EXPOKIT. + +% Roger B. Sidje (rbs@maths.uq.edu.au) +% EXPOKIT: Software Package for Computing Matrix Exponentials. +% ACM - Transactions On Mathematical Software, 24(1):130-156, 1998 +%__________________________________________________________________________ + +[n,n] = size(A); +if nargin == 3, + tol = 1.0e-7; + m = min(n,30); +end; +if nargin == 4, + m = min(n,30); +end; + +anorm = norm(A,'inf'); +mxrej = 10; btol = 1.0e-7; +gamma = 0.9; delta = 1.2; +mb = m; t_out = abs(t); +nstep = 0; t_new = 0; +t_now = 0; s_error = 0; +rndoff= anorm*eps; + +k1 = 2; xm = 1/m; normv = norm(v); beta = normv; +fact = (((m+1)/exp(1))^(m+1))*sqrt(2*pi*(m+1)); +t_new = (1/anorm)*((fact*tol)/(4*beta*anorm))^xm; +s = 10^(floor(log10(t_new))-1); t_new = ceil(t_new/s)*s; +sgn = sign(t); nstep = 0; + +w = v; +hump = normv; +while t_now < t_out + nstep = nstep + 1; + t_step = min( t_out-t_now,t_new ); + V = zeros(n,m+1); + H = zeros(m+2,m+2); + + V(:,1) = (1/beta)*w; + for j = 1:m + p = A*V(:,j); + for i = 1:j + H(i,j) = V(:,i)'*p; + p = p-H(i,j)*V(:,i); + end; + s = norm(p); + if s < btol, + k1 = 0; + mb = j; + t_step = t_out-t_now; + break; + end; + H(j+1,j) = s; + V(:,j+1) = (1/s)*p; + end; + if k1 ~= 0, + H(m+2,m+1) = 1; + avnorm = norm(A*V(:,m+1)); + end; + ireject = 0; + while ireject <= mxrej, + mx = mb + k1; + F = expm(sgn*t_step*H(1:mx,1:mx)); + if k1 == 0, + err_loc = btol; + break; + else + phi1 = abs( beta*F(m+1,1) ); + phi2 = abs( beta*F(m+2,1) * avnorm ); + if phi1 > 10*phi2, + err_loc = phi2; + xm = 1/m; + elseif phi1 > phi2, + err_loc = (phi1*phi2)/(phi1-phi2); + xm = 1/m; + else + err_loc = phi1; + xm = 1/(m-1); + end; + end; + if err_loc <= delta * t_step*tol, + break; + else + t_step = gamma * t_step * (t_step*tol/err_loc)^xm; + s = 10^(floor(log10(t_step))-1); + t_step = ceil(t_step/s) * s; + if ireject == mxrej, + error('The requested tolerance is too high.'); + end; + ireject = ireject + 1; + end; + end; + mx = mb + max( 0,k1-1 ); + w = V(:,1:mx)*(beta*F(1:mx,1)); + beta = norm( w ); + hump = max(hump,beta); + + t_now = t_now + t_step; + t_new = gamma * t_step * (t_step*tol/err_loc)^xm; + s = 10^(floor(log10(t_new))-1); + t_new = ceil(t_new/s) * s; + + err_loc = max(err_loc,rndoff); + s_error = s_error + err_loc; +end; +err = s_error; +hump = hump / normv; + +return + + +function E = padm( A, p ) +% FORMAT E = padm( A, p ) +% PADM computes the matrix exponential exp(A) using the irreducible +% (p,p)-degree rational Pade approximation to the exponential function. +% +% E = padm( A ) +% p is internally set to 6 (recommended and generally satisfactory). +% +% See also CHBV, EXPOKIT and the MATLAB supplied functions EXPM and EXPM1. + +% Roger B. Sidje (rbs@maths.uq.edu.au) +% EXPOKIT: Software Package for Computing Matrix Exponentials. +% ACM - Transactions On Mathematical Software, 24(1):130-156, 1998 +%__________________________________________________________________________ + +if nargin == 1, p = 6; end; +[n,n] = size(A); + +% Pade coefficients (1-based instead of 0-based as in the literature) +%-------------------------------------------------------------------------- +c(1) = 1; +for k = 1:p + c(k+1) = c(k)*((p+1-k)/(k*(2*p+1-k))); +end; + +% Scaling +%-------------------------------------------------------------------------- +s = norm(A,'inf'); +if s > 0.5, + s = max(0,fix(log(s)/log(2))+2); + A = 2^(-s)*A; +end; + +% Horner evaluation of the irreducible fraction (see ref. above) +%-------------------------------------------------------------------------- +I = eye(n); +A2 = A*A; +Q = c(p+1)*I; +P = c(p)*I; +odd = 1; +for k = p-1:-1:1, + if odd == 1, + Q = Q*A2 + c(k)*I; + else + P = P*A2 + c(k)*I; + end; + odd = 1-odd; +end; +if odd == 1 + Q = Q*A; + Q = Q - P; + E = -(I + 2*(Q\P)); +else + P = P*A; + Q = Q - P; + E = I + 2*(Q\P); +end; + +% Squaring +%-------------------------------------------------------------------------- +for k = 1:s, + E = E*E; +end; + +return + + + + diff --git a/spm_eeg_artefact.m b/spm_eeg_artefact.m index 56c799bf..4f1870ed 100644 --- a/spm_eeg_artefact.m +++ b/spm_eeg_artefact.m @@ -2,44 +2,47 @@ % Simple artefact detection, optionally with robust averaging % FORMAT D = spm_eeg_artefact(S) % -% S - input structure +% S - input structure % % fields of S: -% S.mode 'reject' (default) - reject bad channels and trials -% 'mark' - scan the data and create events marking -% the artefacts -% S.D - MEEG object or filename of M/EEG mat-file with -% S.badchanthresh - fraction of trials (or time) with artefacts above which a -% channel is declared as bad (default: 0.2) +% S.mode 'reject' [default]: reject bad channels and trials +% 'mark': scan the data and create events marking the +% artefacts +% S.D - MEEG object or filename of M/EEG mat-file +% S.badchanthresh - fraction of trials (or time) with artefacts above +% which a channel is declared as bad [default: 0.2] +% +% S.append - 1 [default]: append new markings to existing ones +% 0: overwrite existing markings +% S.methods - structure array with configuration parameters for +% artefact detection plugins +% S.prefix - prefix for the output file [default: 'a'] % -% S.append - 1 (default) append new markings to existing ones -% 0 overwrite existing markings -% S.methods - a structure array with configuration parameters -% for artefact detection plugins. -% S.prefix - prefix for the output file (default - 'a') % Output: -% D - MEEG object (also written on disk) +% D - MEEG object (also written on disk) %__________________________________________________________________________ +% % This is a modular function for which plugins can be developed to detect -% artefacts with any algorithm. There are 3 basic plugins presently -% implemented and they can be used as templates for new plugins. -% The name of a plugin function should start with 'spm_eeg_artefact_' +% artefacts with any algorithm. +% The name of a plugin function should start with 'spm_eeg_artefact_'. +% Several plugins are already implemented annd they can be used as +% templates for new plugins: % -% peak2peak (spm_eeg_artefact_peak2peak) - thresholds peak-to-peak -% amplitude +% peak2peak - thresholds peak-to-peak amplitude +% (spm_eeg_artefact_peak2peak) % -% jump (spm_eeg_artefact_jump) - thresholds the difference -% between adjacent samples. +% jump - thresholds the difference between adjacent samples +% (spm_eeg_artefact_jump) % -% flat (spm_eeg_artefact_flat) - detects flat segments in the -% data +% flat - detects flat segments in the data +% (spm_eeg_artefact_flat) %__________________________________________________________________________ -% Copyright (C) 2008-2012 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2008-2017 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_eeg_artefact.m 6035 2014-06-03 22:32:20Z vladimir $ +% $Id: spm_eeg_artefact.m 7132 2017-07-10 16:22:58Z guillaume $ -SVNrev = '$Rev: 6035 $'; +SVNrev = '$Rev: 7132 $'; %-Startup %-------------------------------------------------------------------------- @@ -58,15 +61,15 @@ if isequal(S.mode, 'reject') if isequal(D.type, 'continuous') - error('Artefact rejection can only be applied to epoched data'); + error('Artefact rejection can only be applied to epoched data.'); end %-Create a copy of the dataset - %-------------------------------------------------------------------------- + %---------------------------------------------------------------------- D = copy(D, [S.prefix D.fname]); %-Run the artefact detection routines - %-------------------------------------------------------------------------- + %---------------------------------------------------------------------- bad = zeros(D.nchannels, D.ntrials); for i = 1:numel(S.methods) @@ -91,18 +94,18 @@ end %-Classify MEEG channels as bad if the fraction of bad trials exceeds threshold - %------------------------------------------------------------------------------- + %------------------------------------------------------------------------------ badchanind = intersect(find(mean(bad, 2)>S.badchanthresh), indchantype(D, 'MEEG')); badchanind = union(badchanind, D.badchannels); goodchanind = setdiff(1:D.nchannels, badchanind); %-Classify trials as bad if they have artefacts in good M/EEG channels %-or in non-M/EEG channels - %-------------------------------------------------------------------------- + %---------------------------------------------------------------------- badtrialind = find(any(bad(goodchanind, :), 1)); %-Update and save new dataset - %-------------------------------------------------------------------------- + %---------------------------------------------------------------------- if ~S.append D = badtrials(D, ':', 0); D = badchannels(D, ':', 0); @@ -112,17 +115,17 @@ D = badchannels(D, badchanind, ones(size(badchanind))); %-Report on command line - %-------------------------------------------------------------------------- + %---------------------------------------------------------------------- fprintf('%d rejected trials: %s\n', length(badtrialind), num2str(badtrialind)); elseif isequal(S.mode, 'mark') %-Create a copy of the dataset - %-------------------------------------------------------------------------- + %---------------------------------------------------------------------- D = copy(D, [S.prefix D.fname]); %-Run the artefact detection routines - %-------------------------------------------------------------------------- + %---------------------------------------------------------------------- for i = 1:numel(S.methods) chanind = setdiff(D.selectchannels(S.methods(i).channels), D.badchannels); @@ -151,14 +154,14 @@ badchanind = meegind(bad); %-Update and save new dataset - %-------------------------------------------------------------------------- + %---------------------------------------------------------------------- D = badchannels(D, badchanind, 1); else - error('Invalid mode specification'); + error('Invalid mode specification.'); end if isempty(badchanind) - fprintf('There isn''t a bad channel.\n'); + fprintf('There are no bad channels.\n'); else lbl = D.chanlabels(badchanind); if ~iscell(lbl), lbl = {lbl}; end @@ -170,4 +173,5 @@ %-Cleanup %-------------------------------------------------------------------------- +fprintf('%-40s: %30s\n','Completed',spm('time')); %-# spm('FigName','M/EEG artefact detection: done'); spm('Pointer','Arrow'); diff --git a/spm_eeg_artefact_events.m b/spm_eeg_artefact_events.m index 994f212c..e0602c97 100644 --- a/spm_eeg_artefact_events.m +++ b/spm_eeg_artefact_events.m @@ -1,58 +1,62 @@ function res = spm_eeg_artefact_events(S) % Plugin for spm_eeg_artefact for rejection based on events -% S - input structure +% S - input structure % fields of S: -% S.D - M/EEG object -% S.chanind - vector of indices of channels that this plugin will look at. +% S.D - M/EEG object +% S.chanind - vector of indices of channels that this plugin will look at +% +% Additional parameters can be defined specific for each plugin. % -% Additional parameters can be defined specific for each plugin % Output: -% res - -% If no input is provided the plugin returns a cfg branch for itself +% res - +% If no input is provided the plugin returns a cfg branch for itself. % -% If input is provided the plugin returns a matrix of size D.nchannels x D.ntrials -% with zeros for clean channel/trials and ones for artefacts. -%______________________________________________________________________________________ -% Copyright (C) 2013 Wellcome Trust Centre for Neuroimaging +% If input is provided the plugin returns a matrix of size D.nchannels x D.ntrials +% with zeros for clean channel/trials and ones for artefacts. +%__________________________________________________________________________ +% Copyright (C) 2013-2017 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_eeg_artefact_events.m 5592 2013-07-24 16:25:55Z vladimir $ +% $Id: spm_eeg_artefact_events.m 7132 2017-07-10 16:22:58Z guillaume $ %-This part if for creating a config branch that plugs into spm_cfg_eeg_artefact % Any parameters can be specified and they are then passed to the plugin -% when it's called. +% when it is called. %-------------------------------------------------------------------------- if nargin == 0 - artefacts = cfg_const; - artefacts.tag = 'artefacts'; + artefacts = cfg_const; + artefacts.tag = 'artefacts'; artefacts.name = 'All artefact events'; artefacts.val = {1}; + artefacts.help = {''}; - eventlist = cfg_files; - eventlist.tag = 'eventlist'; - eventlist.name = 'Load event list'; + eventlist = cfg_files; + eventlist.tag = 'eventlist'; + eventlist.name = 'Load event list'; eventlist.filter = 'mat'; - eventlist.num = [1 1]; - eventlist.help = {'Select events list file'}; + eventlist.num = [1 1]; + eventlist.help = {'Select events list file.'}; - whatevents = cfg_choice; - whatevents.tag = 'whatevents'; - whatevents.name = 'What events to use?'; + whatevents = cfg_choice; + whatevents.tag = 'whatevents'; + whatevents.name = 'What events to use?'; whatevents.values = {artefacts, eventlist}; - whatevents.val = {artefacts}; + whatevents.val = {artefacts}; + whatevents.help = {''}; - events = cfg_branch; - events.tag = 'events'; + events = cfg_branch; + events.tag = 'events'; events.name = 'Reject based on events'; - events.val = {whatevents}; + events.val = {whatevents}; + events.help = {''}; res = events; return end -SVNrev = '$Rev: 5592 $'; +SVNrev = '$Rev: 7132 $'; %-Startup %-------------------------------------------------------------------------- @@ -60,7 +64,7 @@ spm('FigName','M/EEG event-based rejection'); if isequal(S.mode, 'mark') - error('Only reject mode is supported by this plug-in'); + error('Only reject mode is supported by this plug-in.'); end D = spm_eeg_load(S.D); @@ -119,4 +123,4 @@ spm_progress_bar('Clear'); -spm('FigName', 'M/EEG threshold channels: done'); \ No newline at end of file +spm('FigName', 'M/EEG threshold channels: done'); diff --git a/spm_eeg_artefact_eyeblink.m b/spm_eeg_artefact_eyeblink.m index 1506bacf..aa131a55 100644 --- a/spm_eeg_artefact_eyeblink.m +++ b/spm_eeg_artefact_eyeblink.m @@ -1,23 +1,24 @@ function res = spm_eeg_artefact_eyeblink(S) -% Detects eyeblinks in spm continuous data file -% S - input structure +% Detects eyeblinks in SPM continuous data file +% S - input structure % fields of S: -% S.D - M/EEG object -% S.chanind - vector of indices of channels that this plugin will look at. -% S.threshold - threshold parameter (in stdev) +% S.D - M/EEG object +% S.chanind - vector of indices of channels that this plugin will look at +% S.threshold - threshold parameter (in stdev) +% +% Additional parameters can be defined specific for each plugin. % -% Additional parameters can be defined specific for each plugin % Output: -% res - -% If no input is provided the plugin returns a cfg branch for itself +% res - +% If no input is provided the plugin returns a cfg branch for itself. % -% If input is provided the plugin returns a matrix of size D.nchannels x D.ntrials -% with zeros for clean channel/trials and ones for artefacts. -%______________________________________________________________________________________ -% Copyright (C) 2008-2013 Wellcome Trust Centre for Neuroimaging +% If input is provided the plugin returns a matrix of size D.nchannels x D.ntrials +% with zeros for clean channel/trials and ones for artefacts. +%__________________________________________________________________________ +% Copyright (C) 2008-2017 Wellcome Trust Centre for Neuroimaging % Laurence Hunt -% $Id: spm_eeg_artefact_eyeblink.m 6046 2014-06-16 10:58:27Z vladimir $ +% $Id: spm_eeg_artefact_eyeblink.m 7132 2017-07-10 16:22:58Z guillaume $ %-This part if for creating a config branch that plugs into spm_cfg_eeg_artefact @@ -25,33 +26,34 @@ % when it's called. %-------------------------------------------------------------------------- if nargin == 0 - threshold = cfg_entry; - threshold.tag = 'threshold'; - threshold.name = 'Threshold'; + threshold = cfg_entry; + threshold.tag = 'threshold'; + threshold.name = 'Threshold'; threshold.strtype = 'r'; - threshold.val = {4}; - threshold.num = [1 1]; - threshold.help = {'Threshold to reject things that look like eye-blinks but probably aren''t'}; + threshold.val = {4}; + threshold.num = [1 1]; + threshold.help = {'Threshold to reject things that look like eye-blinks but probably aren''t.'}; - excwin = cfg_entry; - excwin.tag = 'excwin'; - excwin.name = 'Excision window'; + excwin = cfg_entry; + excwin.tag = 'excwin'; + excwin.name = 'Excision window'; excwin.strtype = 'r'; - excwin.num = [1 1]; - excwin.val = {0}; - excwin.help = {'Window (in ms) to mark as bad around each eyeblink, 0 to not mark data as bad'}; + excwin.num = [1 1]; + excwin.val = {0}; + excwin.help = {'Window (in ms) to mark as bad around each eyeblink, 0 to not mark data as bad.'}; - eyeblink = cfg_branch; - eyeblink.tag = 'eyeblink'; + eyeblink = cfg_branch; + eyeblink.tag = 'eyeblink'; eyeblink.name = 'Eyeblinks'; - eyeblink.val = {threshold, excwin}; + eyeblink.val = {threshold, excwin}; + eyeblink.help = {''}; res = eyeblink; return end -SVNrev = '$Rev: 6046 $'; +SVNrev = '$Rev: 7132 $'; %-Startup %-------------------------------------------------------------------------- @@ -64,25 +66,27 @@ D = spm_eeg_load(S.D); -chanind = S.chanind; +chanind = S.chanind; if length(chanind)~=1 - error('More than one channel - not currently supported') + error('More than one channel - not currently supported.') end eog_data = reshape(squeeze(D(chanind,:,:)), 1, []); -%% filter data at 1-15Hz (eyeblink duration typically 100-300ms) and demean +%-Filter data at 1-15Hz (eyeblink duration typically 100-300ms) and demean +%-------------------------------------------------------------------------- eog_filt = detrend(abs(hilbert(ft_preproc_bandpassfilter(eog_data, D.fsample, [1 15], 4, 'but',[], 'split'))), 'constant'); -%% find eye-movements - -sd_eeg=(spm_percentile(eog_filt,85)-spm_percentile(eog_filt,15))/2; %robust estimate of standard deviation, suggested by Mark Woolrich +%-Find eye-movements +%-------------------------------------------------------------------------- +% robust estimate of standard deviation, suggested by Mark Woolrich +sd_eeg = (spm_percentile(eog_filt,85) - spm_percentile(eog_filt,15))/2; em_thresh = S.threshold*sd_eeg; -%% find 'spikes' (putative eyeblinks): - -eblength = round(D.fsample/5); %length of eyeblink(200 ms) in samples; +%-Find 'spikes' (putative eyeblinks) +%-------------------------------------------------------------------------- +eblength = round(D.fsample/5); %length of eyeblink(200 ms) in samples spikes = []; for i = eblength:length(eog_filt)-eblength; if abs(eog_filt(i))>em_thresh && ... %bigger than threshold @@ -100,8 +104,8 @@ spikemat(:,i) = eog_filt(spikes(i)-eblength+1:spikes(i)+eblength); end -%reject spikes whose peak is not within 1 s.d. of the mean (gets rid of most artefacts -% etc. not removed by filtering): +% reject spikes whose peak is not within 1 s.d. of the mean +% (gets rid of most artefact, etc, not removed by filtering) mn_spike = mean(spikemat(eblength,:)); sd_spike = std(spikemat(eblength,:)); spikes(spikemat(eblength,:)>mn_spike+sd_spike | ... @@ -120,29 +124,30 @@ error(['As many as ' num2str(num_eb_per_min) ' eye-blinks per minute detected by algorithm. Try a higher threshold.']) end -% plot -%---------------------------------------------------------------------- -Fgraph = spm_figure('GetWin','Graphics'); -colormap(gray) -figure(Fgraph) -clf -subplot(2, 1 , 1) -plot(spikes,ones(length(spikes),1)*5*sd_eeg,'r.'); -hold on; -plot(eog_filt); - -subplot(2, 1 , 2) -hold on; -plot(spikemat);plot(mean(spikemat,2),'Color','k','LineWidth',4); - +%-Plot +%-------------------------------------------------------------------------- +if ~spm('CmdLine') + Fgraph = spm_figure('GetWin','Graphics'); + colormap(gray) + figure(Fgraph) + clf + subplot(2, 1 , 1) + plot(spikes,ones(length(spikes),1)*5*sd_eeg,'r.'); + hold on; + plot(eog_filt); + + subplot(2, 1 , 2) + hold on; + plot(spikemat);plot(mean(spikemat,2),'Color','k','LineWidth',4); +end -% Update the event structure -%---------------------------------------------------------------------- +%-Update the event structure +%-------------------------------------------------------------------------- if ~isempty(spikes) for n = 1:D.ntrials - cspikes = spikes(spikes>(D.nsamples*(n-1)) & spikes<(D.nsamples*n)); - ctime = D.trialonset(n)+(cspikes - D.nsamples*(n-1)-1)/D.fsample; - ctime = num2cell(ctime); + cspikes = spikes(spikes>(D.nsamples*(n-1)) & spikes<(D.nsamples*n)); + ctime = D.trialonset(n)+(cspikes - D.nsamples*(n-1)-1)/D.fsample; + ctime = num2cell(ctime); ev = events(D, n); @@ -150,7 +155,6 @@ ev = ev{1}; end - if ~isempty(ev) && ~S.append ind1 = strmatch('artefact_eyeblink', {ev.type}, 'exact'); if ~isempty(ind1) @@ -166,8 +170,8 @@ if ctime{i} == 0 continue; %likely to be trial border falsely detected as eyeblink end - ev(Nevents+i).type = 'artefact_eyeblink'; - ev(Nevents+i).value = char(D.chanlabels(chanind)); + ev(Nevents+i).type = 'artefact_eyeblink'; + ev(Nevents+i).value = char(D.chanlabels(chanind)); if S.excwin == 0 ev(Nevents+i).duration = []; ev(Nevents+i).time = ctime{i}; @@ -185,9 +189,9 @@ end end else - warning(['No eye blinks events detected in the selected channel']); + warning('No eye blinks events detected in the selected channel.'); end res = D; -spm('FigName','M/EEG eyeblink detection: done'); \ No newline at end of file +spm('FigName','M/EEG eyeblink detection: done'); diff --git a/spm_eeg_artefact_flat.m b/spm_eeg_artefact_flat.m index 49fa53c5..b0d3598d 100644 --- a/spm_eeg_artefact_flat.m +++ b/spm_eeg_artefact_flat.m @@ -1,22 +1,23 @@ function res = spm_eeg_artefact_flat(S) -% Plugin for spm_eeg_artefact doing flat channel detection. -% S - input structure +% Plugin for spm_eeg_artefact doing flat channel detection +% S - input structure % fields of S: -% S.D - M/EEG object -% S.chanind - vector of indices of channels that this plugin will look at. +% S.D - M/EEG object +% S.chanind - vector of indices of channels that this plugin will look at +% +% Additional parameters can be defined specific for each plugin. % -% Additional parameters can be defined specific for each plugin % Output: -% res - -% If no input is provided the plugin returns a cfg branch for itself +% res - +% If no input is provided the plugin returns a cfg branch for itself. % -% If input is provided the plugin returns a matrix of size D.nchannels x D.ntrials -% with zeros for clean channel/trials and ones for artefacts. -%______________________________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +% If input is provided the plugin returns a matrix of size D.nchannels x D.ntrials +% with zeros for clean channel/trials and ones for artefacts. +%__________________________________________________________________________ +% Copyright (C) 2008-2017 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_eeg_artefact_flat.m 6060 2014-06-19 13:31:19Z vladimir $ +% $Id: spm_eeg_artefact_flat.m 7132 2017-07-10 16:22:58Z guillaume $ %-This part if for creating a config branch that plugs into spm_cfg_eeg_artefact @@ -24,34 +25,35 @@ % when it's called. %-------------------------------------------------------------------------- if nargin == 0 - threshold = cfg_entry; - threshold.tag = 'threshold'; - threshold.name = 'Threshold'; + threshold = cfg_entry; + threshold.tag = 'threshold'; + threshold.name = 'Threshold'; threshold.strtype = 'r'; - threshold.val = {0}; - threshold.num = [1 1]; - threshold.help = {'Threshold for difference between adjacent samples'}; + threshold.val = {0}; + threshold.num = [1 1]; + threshold.help = {'Threshold for difference between adjacent samples.'}; - seqlength = cfg_entry; - seqlength.tag = 'seqlength'; - seqlength.name = 'Flat segment length'; + seqlength = cfg_entry; + seqlength.tag = 'seqlength'; + seqlength.name = 'Flat segment length'; seqlength.strtype = 'r'; - seqlength.num = [1 1]; - seqlength.val = {4}; - seqlength.help = {'Minimal number of adjacent samples with the same value to reject.'}; + seqlength.num = [1 1]; + seqlength.val = {4}; + seqlength.help = {'Minimal number of adjacent samples with the same value to reject.'}; - flat = cfg_branch; - flat.tag = 'flat'; + flat = cfg_branch; + flat.tag = 'flat'; flat.name = 'Flat segments'; - flat.val = {threshold, seqlength}; + flat.val = {threshold, seqlength}; + flat.help = {''}; res = flat; - return + return; end -SVNrev = '$Rev: 6060 $'; +SVNrev = '$Rev: 7132 $'; %-Startup %-------------------------------------------------------------------------- @@ -60,16 +62,15 @@ D = spm_eeg_load(S.D); -chanind = S.chanind; +chanind = S.chanind; threshold = S.threshold; seqlength = S.seqlength; - if isequal(S.mode, 'reject') res = zeros(D.nchannels, D.ntrials); %-Artefact detection - %-------------------------------------------------------------------------- + %---------------------------------------------------------------------- spm_progress_bar('Init', D.ntrials, 'Trials checked'); if D.ntrials > 100, Ibar = floor(linspace(1, D.ntrials,100)); @@ -82,7 +83,7 @@ res(chanind(j), i) = 1; end end - if ismember(i, Ibar), spm_progress_bar('Set', i); end + if any(Ibar == i), spm_progress_bar('Set', i); end end spm_progress_bar('Clear'); @@ -167,7 +168,7 @@ end end if isequal(D.type, 'continuous') - if ismember(j, Ibar), spm_progress_bar('Set', j); end + if any(Ibar == j), spm_progress_bar('Set', j); end end end if ~isempty(res) @@ -184,7 +185,7 @@ end if ~isequal(D.type, 'continuous') - if ismember(i, Ibar), spm_progress_bar('Set', i); end + if any(Ibar == i), spm_progress_bar('Set', i); end end end @@ -193,4 +194,4 @@ res = D; end -spm('FigName','M/EEG flat data detection: done'); \ No newline at end of file +spm('FigName','M/EEG flat data detection: done'); diff --git a/spm_eeg_artefact_heartbeat.m b/spm_eeg_artefact_heartbeat.m index 421fcb8c..c5d6454e 100644 --- a/spm_eeg_artefact_heartbeat.m +++ b/spm_eeg_artefact_heartbeat.m @@ -1,23 +1,25 @@ function res = spm_eeg_artefact_heartbeat(S) -% Detects eyeblinks in spm continuous data file -% S - input structure +% Detects heart beats in SPM continuous data file +% S - input structure % fields of S: -% S.D - M/EEG object -% S.chanind - vector of indices of channels that this plugin will look at. +% S.D - M/EEG object +% S.chanind - vector of indices of channels that this plugin will look at +% +% Additional parameters can be defined specific for each plugin. % -% Additional parameters can be defined specific for each plugin % Output: -% res - -% If no input is provided the plugin returns a cfg branch for itself +% res - +% If no input is provided the plugin returns a cfg branch for itself. +% +% If input is provided the plugin returns a matrix of size D.nchannels x D.ntrials +% with zeros for clean channel/trials and ones for artefacts. % -% If input is provided the plugin returns a matrix of size D.nchannels x D.ntrials -% with zeros for clean channel/trials and ones for artefacts. -%______________________________________________________________________________________ -% Copyright (C) 2008-2013 Wellcome Trust Centre for Neuroimaging +% See http://fsl.fmrib.ox.ac.uk/eeglab/fmribplugin/ +%__________________________________________________________________________ +% Copyright (C) 2008-2017 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% see http://fsl.fmrib.ox.ac.uk/eeglab/fmribplugin/ -% $Id: spm_eeg_artefact_heartbeat.m 6686 2016-01-20 14:49:15Z vladimir $ +% $Id: spm_eeg_artefact_heartbeat.m 7132 2017-07-10 16:22:58Z guillaume $ %-This part if for creating a config branch that plugs into spm_cfg_eeg_artefact @@ -25,25 +27,26 @@ % when it's called. %-------------------------------------------------------------------------- if nargin == 0 - excwin = cfg_entry; - excwin.tag = 'excwin'; - excwin.name = 'Excision window'; + excwin = cfg_entry; + excwin.tag = 'excwin'; + excwin.name = 'Excision window'; excwin.strtype = 'r'; - excwin.num = [1 1]; - excwin.val = {0}; - excwin.help = {'Window (in ms) to mark as bad around each heart beat, 0 to not mark data as bad'}; + excwin.num = [1 1]; + excwin.val = {0}; + excwin.help = {'Window (in ms) to mark as bad around each heart beat, 0 to not mark data as bad.'}; - heartbeat = cfg_branch; - heartbeat.tag = 'heartbeat'; + heartbeat = cfg_branch; + heartbeat.tag = 'heartbeat'; heartbeat.name = 'Heart beats'; - heartbeat.val = {excwin}; + heartbeat.val = {excwin}; + heartbeat.help = {''}; res = heartbeat; return end -SVNrev = '$Rev: 6686 $'; +SVNrev = '$Rev: 7132 $'; %-Startup %-------------------------------------------------------------------------- @@ -54,17 +57,16 @@ error('This tool requires FMRIB plugin, see http://fsl.fmrib.ox.ac.uk/eeglab/fmribplugin/'); end - if isequal(S.mode, 'reject') error('Only mark mode is supported by this plug-in, use event-based rejection to reject.'); end D = spm_eeg_load(S.D); -chanind = S.chanind; +chanind = S.chanind; if length(chanind)~=1 - error('More than one channel - not currently supported') + error('More than one channel - not currently supported.') end % Detect QRS peaks using FMRIB plugin @@ -74,7 +76,6 @@ EEG.srate = D.fsample; spikes = fmrib_qrsdetect(EEG,1); - % Update the event structure %---------------------------------------------------------------------- if ~isempty(spikes) @@ -89,7 +90,6 @@ ev = ev{1}; end - if ~isempty(ev) && ~S.append ind1 = strmatch('artefact_heartbeat', {ev.type}, 'exact'); if ~isempty(ind1) @@ -103,10 +103,11 @@ Nevents = numel(ev); for i=1:numel(ctime) if ctime{i} == 0 - continue; %likely to be trial border falsely detected as heartbeat + %likely to be trial border falsely detected as heartbeat + continue; end - ev(Nevents+i).type = 'artefact_heartbeat'; - ev(Nevents+i).value = char(D.chanlabels(chanind)); + ev(Nevents+i).type = 'artefact_heartbeat'; + ev(Nevents+i).value = char(D.chanlabels(chanind)); if S.excwin == 0 ev(Nevents+i).duration = []; ev(Nevents+i).time = ctime{i}; @@ -124,9 +125,9 @@ end end else - warning(['No heartbeat events detected in the selected channel']); + warning('No heartbeat events detected in the selected channel.'); end res = D; -spm('FigName','M/EEG heartbeat detection: done'); \ No newline at end of file +spm('FigName','M/EEG heartbeat detection: done'); diff --git a/spm_eeg_artefact_jump.m b/spm_eeg_artefact_jump.m index 5d7c89cc..ccd2ecc9 100644 --- a/spm_eeg_artefact_jump.m +++ b/spm_eeg_artefact_jump.m @@ -1,22 +1,23 @@ function res = spm_eeg_artefact_jump(S) -% Plugin for spm_eeg_artefact doing jump detection. -% S - input structure +% Plugin for spm_eeg_artefact doing jump detection +% S - input structure % fields of S: -% S.D - M/EEG object -% S.chanind - vector of indices of channels that this plugin will look at. +% S.D - M/EEG object +% S.chanind - vector of indices of channels that this plugin will look at +% +% Additional parameters can be defined specific for each plugin. % -% Additional parameters can be defined specific for each plugin % Output: -% res - -% If no input is provided the plugin returns a cfg branch for itself +% res - +% If no input is provided the plugin returns a cfg branch for itself. % -% If input is provided the plugin returns a matrix of size D.nchannels x D.ntrials -% with zeros for clean channel/trials and ones for artefacts. -%______________________________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +% If input is provided the plugin returns a matrix of size D.nchannels x D.ntrials +% with zeros for clean channel/trials and ones for artefacts. +%__________________________________________________________________________ +% Copyright (C) 2008-2017 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_eeg_artefact_jump.m 6060 2014-06-19 13:31:19Z vladimir $ +% $Id: spm_eeg_artefact_jump.m 7132 2017-07-10 16:22:58Z guillaume $ %-This part if for creating a config branch that plugs into spm_cfg_eeg_artefact @@ -24,32 +25,33 @@ % when it's called. %-------------------------------------------------------------------------- if nargin == 0 - threshold = cfg_entry; - threshold.tag = 'threshold'; - threshold.name = 'Threshold'; + threshold = cfg_entry; + threshold.tag = 'threshold'; + threshold.name = 'Threshold'; threshold.strtype = 'r'; - threshold.num = [1 1]; - threshold.help = {'Threshold value to apply to all channels'}; + threshold.num = [1 1]; + threshold.help = {'Threshold value to apply to all channels'}; - excwin = cfg_entry; - excwin.tag = 'excwin'; - excwin.name = 'Excision window'; + excwin = cfg_entry; + excwin.tag = 'excwin'; + excwin.name = 'Excision window'; excwin.strtype = 'r'; - excwin.num = [1 1]; - excwin.val = {1000}; - excwin.help = {'Window (in ms) to mark as bad around each jump (for mark mode only), 0 - do not mark data as bad'}; + excwin.num = [1 1]; + excwin.val = {1000}; + excwin.help = {'Window (in ms) to mark as bad around each jump (for mark mode only), 0 - do not mark data as bad.'}; - jump = cfg_branch; - jump.tag = 'jump'; + jump = cfg_branch; + jump.tag = 'jump'; jump.name = 'Difference between adjacent samples'; - jump.val = {threshold, excwin}; + jump.val = {threshold, excwin}; + jump.help = {''}; res = jump; return end -SVNrev = '$Rev: 6060 $'; +SVNrev = '$Rev: 7132 $'; %-Startup %-------------------------------------------------------------------------- @@ -58,14 +60,14 @@ D = spm_eeg_load(S.D); -chanind = S.chanind; +chanind = S.chanind; threshold = S.threshold; if isequal(S.mode, 'reject') res = zeros(D.nchannels, D.ntrials); %-Artefact detection - %-------------------------------------------------------------------------- + %---------------------------------------------------------------------- spm_progress_bar('Init', D.ntrials, 'Trials checked'); if D.ntrials > 100, Ibar = floor(linspace(1, D.ntrials,100)); @@ -73,7 +75,7 @@ for i = 1:D.ntrials res(chanind, i) = max(abs(diff(squeeze(D(chanind, :, i)), [], 2)), [], 2)>threshold; - if ismember(i, Ibar), spm_progress_bar('Set', i); end + if any(Ibar == i), spm_progress_bar('Set', i); end end spm_progress_bar('Clear'); @@ -94,7 +96,7 @@ bad = [zeros(size(bad, 1), 1) bad]; if ~any(bad(:)) - if multitrial && ismember(i, Ibar), spm_progress_bar('Set', i); end + if multitrial && any(Ibar == i), spm_progress_bar('Set', i); end continue; end @@ -127,7 +129,7 @@ res(end).duration = (min(offsets(offsets>onsets(k)))-onsets(k))./D.fsample; end - if ~multitrial && ismember(j, Ibar), spm_progress_bar('Set', j); end + if ~multitrial && any(Ibar == j), spm_progress_bar('Set', j); end end if ~multitrial, spm_progress_bar('Clear'); end @@ -146,7 +148,7 @@ end - if multitrial && ismember(i, Ibar), spm_progress_bar('Set', i); end + if multitrial && any(Ibar == i), spm_progress_bar('Set', i); end end if multitrial, spm_progress_bar('Clear'); end @@ -154,4 +156,4 @@ res = D; end -spm('FigName','M/EEG jump detection: done'); \ No newline at end of file +spm('FigName','M/EEG jump detection: done'); diff --git a/spm_eeg_artefact_nans.m b/spm_eeg_artefact_nans.m index 797c737b..5f1cd411 100644 --- a/spm_eeg_artefact_nans.m +++ b/spm_eeg_artefact_nans.m @@ -1,22 +1,23 @@ function res = spm_eeg_artefact_nans(S) -% Plugin for spm_eeg_artefact doing NaN detection. -% S - input structure +% Plugin for spm_eeg_artefact doing NaN detection +% S - input structure % fields of S: -% S.D - M/EEG object -% S.chanind - vector of indices of channels that this plugin will look at. +% S.D - M/EEG object +% S.chanind - vector of indices of channels that this plugin will look at +% +% Additional parameters can be defined specific for each plugin. % -% Additional parameters can be defined specific for each plugin % Output: -% res - -% If no input is provided the plugin returns a cfg branch for itself +% res - +% If no input is provided the plugin returns a cfg branch for itself. % -% If input is provided the plugin returns a matrix of size D.nchannels x D.ntrials -% with zeros for clean channel/trials and ones for artefacts. -%______________________________________________________________________________________ -% Copyright (C) 2011-2013 Wellcome Trust Centre for Neuroimaging +% If input is provided the plugin returns a matrix of size D.nchannels x D.ntrials +% with zeros for clean channel/trials and ones for artefacts. +%__________________________________________________________________________ +% Copyright (C) 2011-2017 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_eeg_artefact_nans.m 6060 2014-06-19 13:31:19Z vladimir $ +% $Id: spm_eeg_artefact_nans.m 7132 2017-07-10 16:22:58Z guillaume $ %-This part if for creating a config branch that plugs into spm_cfg_eeg_artefact @@ -24,17 +25,18 @@ % when it's called. %-------------------------------------------------------------------------- if nargin == 0 - nans = cfg_branch; - nans.tag = 'nans'; + nans = cfg_branch; + nans.tag = 'nans'; nans.name = 'Detect NaNs'; - nans.val = {}; + nans.val = {}; + nans.help = {''}; res = nans; return end -SVNrev = '$Rev: 6060 $'; +SVNrev = '$Rev: 7132 $'; %-Startup %-------------------------------------------------------------------------- @@ -43,14 +45,14 @@ D = spm_eeg_load(S.D); -chanind = S.chanind; +chanind = S.chanind; res = zeros(D.nchannels, D.ntrials); if isequal(S.mode, 'reject') res = zeros(D.nchannels, D.ntrials); %-Artefact detection - %-------------------------------------------------------------------------- + %---------------------------------------------------------------------- spm_progress_bar('Init', D.ntrials, 'Trials checked'); if D.ntrials > 100, Ibar = floor(linspace(1, D.ntrials,100)); @@ -62,7 +64,7 @@ res(chanind(j), i) = 1; end end - if ismember(i, Ibar), spm_progress_bar('Set', i); end + if any(Ibar == i), spm_progress_bar('Set', i); end end spm_progress_bar('Clear'); @@ -148,7 +150,7 @@ end if isequal(D.type, 'continuous') - if ismember(j, Ibar), spm_progress_bar('Set', j); end + if any(Ibar == j), spm_progress_bar('Set', j); end end end if ~isempty(res) @@ -165,7 +167,7 @@ end if ~isequal(D.type, 'continuous') - if ismember(i, Ibar), spm_progress_bar('Set', i); end + if any(Ibar == i), spm_progress_bar('Set', i); end end end @@ -174,4 +176,4 @@ res = D; end -spm('FigName','M/EEG NaN detection: done'); \ No newline at end of file +spm('FigName','M/EEG NaN detection: done'); diff --git a/spm_eeg_artefact_peak2peak.m b/spm_eeg_artefact_peak2peak.m index aedb8430..8e330ae2 100644 --- a/spm_eeg_artefact_peak2peak.m +++ b/spm_eeg_artefact_peak2peak.m @@ -1,22 +1,23 @@ function res = spm_eeg_artefact_peak2peak(S) -% Plugin for spm_eeg_artefact doing artefact detection based on peak-to-peak amplitude. -% S - input structure +% Plugin for spm_eeg_artefact doing artefact detection based on peak-to-peak amplitude +% S - input structure % fields of S: -% S.D - M/EEG object -% S.chanind - vector of indices of channels that this plugin will look at. +% S.D - M/EEG object +% S.chanind - vector of indices of channels that this plugin will look at. % -% Additional parameters can be defined specific for each plugin +% Additional parameters can be defined specific for each plugin. +% % Output: -% res - -% If no input is provided the plugin returns a cfg branch for itself +% res - +% If no input is provided the plugin returns a cfg branch for itself. % -% If input is provided the plugin returns a matrix of size D.nchannels x D.ntrials -% with zeros for clean channel/trials and ones for artefacts. -%______________________________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +% If input is provided the plugin returns a matrix of size D.nchannels x D.ntrials +% with zeros for clean channel/trials and ones for artefacts. +%__________________________________________________________________________ +% Copyright (C) 2008-2017 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_eeg_artefact_peak2peak.m 5592 2013-07-24 16:25:55Z vladimir $ +% $Id: spm_eeg_artefact_peak2peak.m 7132 2017-07-10 16:22:58Z guillaume $ %-This part if for creating a config branch that plugs into spm_cfg_eeg_artefact @@ -24,24 +25,25 @@ % when it's called. %-------------------------------------------------------------------------- if nargin == 0 - threshold = cfg_entry; - threshold.tag = 'threshold'; - threshold.name = 'Threshold'; + threshold = cfg_entry; + threshold.tag = 'threshold'; + threshold.name = 'Threshold'; threshold.strtype = 'r'; - threshold.num = [1 1]; - threshold.help = {'Threshold value to apply to all channels'}; + threshold.num = [1 1]; + threshold.help = {'Threshold value to apply to all channels.'}; - peak2peak = cfg_branch; - peak2peak.tag = 'peak2peak'; + peak2peak = cfg_branch; + peak2peak.tag = 'peak2peak'; peak2peak.name = 'Peak to peak amplitude'; - peak2peak.val = {threshold}; + peak2peak.val = {threshold}; + peak2peak.help = {''}; res = peak2peak; return end -SVNrev = '$Rev: 5592 $'; +SVNrev = '$Rev: 7132 $'; %-Startup %-------------------------------------------------------------------------- @@ -49,12 +51,12 @@ spm('FigName','M/EEG peak to peak artefact detection'); if isequal(S.mode, 'mark') - error('Only reject mode is supported by this plug-in'); + error('Only reject mode is supported by this plug-in.'); end D = spm_eeg_load(S.D); -chanind = S.chanind; +chanind = S.chanind; threshold = S.threshold; res = zeros(D.nchannels, D.ntrials); @@ -67,9 +69,9 @@ for i = 1:D.ntrials res(chanind, i) = (squeeze(max(D(chanind, :, i), [], 2) - min(D(chanind, :, i), [], 2)))>threshold; - if ismember(i, Ibar), spm_progress_bar('Set', i); end + if any(Ibar == i), spm_progress_bar('Set', i); end end spm_progress_bar('Clear'); -spm('FigName','M/EEG peak to peak artefact detection: done'); \ No newline at end of file +spm('FigName','M/EEG peak to peak artefact detection: done'); diff --git a/spm_eeg_artefact_saccade.m b/spm_eeg_artefact_saccade.m index 11f57f9b..089f8092 100644 --- a/spm_eeg_artefact_saccade.m +++ b/spm_eeg_artefact_saccade.m @@ -1,27 +1,29 @@ function res = spm_eeg_artefact_saccade(S) -% Detects eyeblinks in spm continuous data file -% S - input structure +% Detects eyeblinks in SPM continuous data file +% S - input structure % fields of S: -% S.D - M/EEG object -% S.chanind - vector of indices of channels that this plugin will look at. -% S.threshold - threshold parameter (in stdev) +% S.D - M/EEG object +% S.chanind - vector of indices of channels that this plugin will look at +% S.threshold - threshold parameter (in stdev) +% +% Additional parameters can be defined specific for each plugin. % -% Additional parameters can be defined specific for each plugin % Output: -% res - -% If no input is provided the plugin returns a cfg branch for itself +% res - +% If no input is provided the plugin returns a cfg branch for itself. +% +% If input is provided the plugin returns a matrix of size D.nchannels x D.ntrials +% with zeros for clean channel/trials and ones for artefacts. % -% If input is provided the plugin returns a matrix of size D.nchannels x D.ntrials -% with zeros for clean channel/trials and ones for artefacts. -%______________________________________________________________________________________ -% Copyright (C) 2008-2013 Wellcome Trust Centre for Neuroimaging +% A simplified version of a method described by: +% Engbert, R., & Mergenthaler, K. (2006) Microsaccades are triggered by low +% retinal image slip. Proceedings of the National Academy of Sciences of +% the United States of America, 103: 7192-7197. +%__________________________________________________________________________ +% Copyright (C) 2008-2017 Wellcome Trust Centre for Neuroimaging % Markus Bauer, Laurence Hunt -% simplified version of a method described by -% Engbert, R., & Mergenthaler, K. (2006) Microsaccades -% are triggered by low retinal image slip. Proceedings of the National -% Academy of Sciences of the United States of America, 103: 7192-7197. -% $Id: spm_eeg_artefact_saccade.m 5592 2013-07-24 16:25:55Z vladimir $ +% $Id: spm_eeg_artefact_saccade.m 7132 2017-07-10 16:22:58Z guillaume $ %-This part if for creating a config branch that plugs into spm_cfg_eeg_artefact @@ -29,33 +31,34 @@ % when it's called. %-------------------------------------------------------------------------- if nargin == 0 - threshold = cfg_entry; - threshold.tag = 'threshold'; - threshold.name = 'Threshold'; + threshold = cfg_entry; + threshold.tag = 'threshold'; + threshold.name = 'Threshold'; threshold.strtype = 'r'; - threshold.val = {3}; - threshold.num = [1 1]; - threshold.help = {'Threshold to reject things that look like saccades but probably aren''t'}; + threshold.val = {3}; + threshold.num = [1 1]; + threshold.help = {'Threshold to reject things that look like saccades but probably aren''t.'}; - excwin = cfg_entry; - excwin.tag = 'excwin'; - excwin.name = 'Excision window'; + excwin = cfg_entry; + excwin.tag = 'excwin'; + excwin.name = 'Excision window'; excwin.strtype = 'r'; - excwin.num = [1 1]; - excwin.val = {0}; - excwin.help = {'Window (in ms) to mark as bad around each saccade, 0 to not mark data as bad'}; + excwin.num = [1 1]; + excwin.val = {0}; + excwin.help = {'Window (in ms) to mark as bad around each saccade, 0 to not mark data as bad.'}; - saccade = cfg_branch; - saccade.tag = 'saccade'; + saccade = cfg_branch; + saccade.tag = 'saccade'; saccade.name = 'Saccades'; - saccade.val = {threshold, excwin}; + saccade.val = {threshold, excwin}; + saccade.help = {''}; res = saccade; return end -SVNrev = '$Rev: 5592 $'; +SVNrev = '$Rev: 7132 $'; %-Startup %-------------------------------------------------------------------------- @@ -68,31 +71,32 @@ D = spm_eeg_load(S.D); -chanind = S.chanind; +chanind = S.chanind; threshold = S.threshold; if length(chanind)~=1 - error('More than one channel - not currently supported') + error('More than one channel - not currently supported.') end eog_data = reshape(squeeze(D(chanind,:,:)), 1, []); -%% SACCADE DETECTION: -% 1) filter the data, saccade duration ~40 ms, filtering at 30 Hz is fine even if it may weaken signal a tiny bit, -% it takes out quite some noise -% 2) calcuilate the velocity values +%-Saccade detection: +% 1) filter the data, saccade duration ~40 ms, filtering at 30 Hz is fine +% even if it may weaken signal a tiny bit, it takes out quite some noise +% 2) calculate the velocity values +%-------------------------------------------------------------------------- eog_data = ft_preproc_lowpassfilter(eog_data, D.fsample, 30); eog_filt = [eog_data(:,1),diff(eog_data,1,2)]; % eog_filt = ft_preproc_lowpassfilter(eog_filt, D.fsample, 20); - -%% find saccades by thresholding - -sd_eeg=(spm_percentile(eog_filt,85)-spm_percentile(eog_filt,15))/2; %robust estimate of standard deviation, suggested by Mark Woolrich +%-Find saccades by thresholding +%-------------------------------------------------------------------------- +% robust estimate of standard deviation, suggested by Mark Woolrich +sd_eeg = (spm_percentile(eog_filt,85)-spm_percentile(eog_filt,15))/2; em_thresh = S.threshold*sd_eeg; -%% find 'spikes' (putative saccades): - +%-Find 'spikes' (putative saccades) +%-------------------------------------------------------------------------- eblength = round(D.fsample/5); %length of saccade(200 ms) in samples; spikes = []; for i = eblength:length(eog_filt)-eblength; @@ -111,8 +115,9 @@ spikemat(:,i) = eog_filt(spikes(i)-eblength+1:spikes(i)+eblength); end -%reject spikes whose peak is not within 1 s.d. of the mean (gets rid of most artefacts -% etc. not removed by filtering): +% reject spikes whose peak is not within 1 s.d. of the mean +% (gets rid of most artefacts etc. not removed by filtering): +%-------------------------------------------------------------------------- mn_spike = mean(spikemat(eblength,:)); sd_spike = std(spikemat(eblength,:)); spikes(spikemat(eblength,:)>mn_spike+sd_spike | ... @@ -132,23 +137,24 @@ end % plot -%---------------------------------------------------------------------- -Fgraph = spm_figure('GetWin','Graphics'); -colormap(gray) -figure(Fgraph) -clf -subplot(2, 1 , 1) -plot(spikes,ones(length(spikes),1)*5*sd_eeg,'r.'); -hold on; -plot(eog_filt); - -subplot(2, 1 , 2) -hold on; -plot(spikemat);plot(mean(spikemat,2),'Color','k','LineWidth',4); - +%-------------------------------------------------------------------------- +if ~spm('CmdLine') + Fgraph = spm_figure('GetWin','Graphics'); + colormap(gray) + figure(Fgraph) + clf + subplot(2, 1 , 1) + plot(spikes,ones(length(spikes),1)*5*sd_eeg,'r.'); + hold on; + plot(eog_filt); + + subplot(2, 1 , 2) + hold on; + plot(spikemat);plot(mean(spikemat,2),'Color','k','LineWidth',4); +end % Update the event structure -%---------------------------------------------------------------------- +%-------------------------------------------------------------------------- if ~isempty(spikes) for n = 1:D.ntrials cspikes = spikes(spikes>(D.nsamples*(n-1)) & spikes<(D.nsamples*n)); @@ -161,7 +167,6 @@ ev = ev{1}; end - if ~isempty(ev) && ~S.append ind1 = strmatch('artefact_saccade', {ev.type}, 'exact'); if ~isempty(ind1) @@ -175,10 +180,11 @@ Nevents = numel(ev); for i=1:numel(ctime) if ctime{i} == 0 - continue; %likely to be trial border falsely detected as saccade + %likely to be trial border falsely detected as saccade + continue; end - ev(Nevents+i).type = 'artefact_saccade'; - ev(Nevents+i).value = char(D.chanlabels(chanind)); + ev(Nevents+i).type = 'artefact_saccade'; + ev(Nevents+i).value = char(D.chanlabels(chanind)); if S.excwin == 0 ev(Nevents+i).duration = []; ev(Nevents+i).time = ctime{i}; @@ -196,9 +202,9 @@ end end else - warning(['No saccade events detected in the selected channel']); + warning('No saccade events detected in the selected channel.'); end res = D; -spm('FigName','M/EEG saccade detection: done'); \ No newline at end of file +spm('FigName','M/EEG saccade detection: done'); diff --git a/spm_eeg_artefact_threshchan.m b/spm_eeg_artefact_threshchan.m index c7dcbce2..d880e924 100644 --- a/spm_eeg_artefact_threshchan.m +++ b/spm_eeg_artefact_threshchan.m @@ -1,22 +1,23 @@ function res = spm_eeg_artefact_threshchan(S) -% Plugin for spm_eeg_artefact doing artefact detection by chanel thresholding. -% S - input structure +% Plugin for spm_eeg_artefact doing artefact detection by chanel thresholding +% S - input structure % fields of S: -% S.D - M/EEG object -% S.chanind - vector of indices of channels that this plugin will look at. +% S.D - M/EEG object +% S.chanind - vector of indices of channels that this plugin will look at % -% Additional parameters can be defined specific for each plugin +% Additional parameters can be defined specific for each plugin. +% % Output: -% res - -% If no input is provided the plugin returns a cfg branch for itself +% res - +% If no input is provided the plugin returns a cfg branch for itself. % -% If input is provided the plugin returns a matrix of size D.nchannels x D.ntrials -% with zeros for clean channel/trials and ones for artefacts. -%______________________________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +% If input is provided the plugin returns a matrix of size D.nchannels x D.ntrials +% with zeros for clean channel/trials and ones for artefacts. +%__________________________________________________________________________ +% Copyright (C) 2008-2017 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_eeg_artefact_threshchan.m 6060 2014-06-19 13:31:19Z vladimir $ +% $Id: spm_eeg_artefact_threshchan.m 7132 2017-07-10 16:22:58Z guillaume $ %-This part if for creating a config branch that plugs into spm_cfg_eeg_artefact @@ -24,33 +25,34 @@ % when it's called. %-------------------------------------------------------------------------- if nargin == 0 - threshold = cfg_entry; - threshold.tag = 'threshold'; - threshold.name = 'Threshold'; + threshold = cfg_entry; + threshold.tag = 'threshold'; + threshold.name = 'Threshold'; threshold.strtype = 'r'; - threshold.num = [1 1]; - threshold.help = {'Threshold value to apply to all channels'}; + threshold.num = [1 1]; + threshold.help = {'Threshold value to apply to all channels.'}; - excwin = cfg_entry; - excwin.tag = 'excwin'; - excwin.name = 'Excision window'; + excwin = cfg_entry; + excwin.tag = 'excwin'; + excwin.name = 'Excision window'; excwin.strtype = 'r'; - excwin.num = [1 1]; - excwin.val = {1000}; - excwin.help = {'Window (in ms) to mark as bad around each jump (for mark mode only), 0 - do not mark data as bad'}; + excwin.num = [1 1]; + excwin.val = {1000}; + excwin.help = {'Window (in ms) to mark as bad around each jump (for mark mode only), 0 - do not mark data as bad.'}; - threshchan = cfg_branch; - threshchan.tag = 'threshchan'; + threshchan = cfg_branch; + threshchan.tag = 'threshchan'; threshchan.name = 'Threshold channels'; - threshchan.val = {threshold, excwin}; + threshchan.val = {threshold, excwin}; + threshchan.help = {''}; res = threshchan; return end -SVNrev = '$Rev: 6060 $'; +SVNrev = '$Rev: 7132 $'; %-Startup %-------------------------------------------------------------------------- @@ -59,26 +61,26 @@ D = spm_eeg_load(S.D); -chanind = S.chanind; +chanind = S.chanind; threshold = S.threshold; res = zeros(D.nchannels, D.ntrials); if isequal(S.mode, 'reject') - -%-Artefact detection -%-------------------------------------------------------------------------- - -spm_progress_bar('Init', D.ntrials, 'Trials checked'); -if D.ntrials > 100, Ibar = floor(linspace(1, D.ntrials,100)); -else Ibar = [1:D.ntrials]; end - -for i = 1:D.ntrials - res(chanind, i) = squeeze(max(abs(D(chanind, :, i)), [], 2))>threshold; - if ismember(i, Ibar), spm_progress_bar('Set', i); end -end - -spm_progress_bar('Clear'); - + + %-Artefact detection + %---------------------------------------------------------------------- + + spm_progress_bar('Init', D.ntrials, 'Trials checked'); + if D.ntrials > 100, Ibar = floor(linspace(1, D.ntrials,100)); + else Ibar = [1:D.ntrials]; end + + for i = 1:D.ntrials + res(chanind, i) = squeeze(max(abs(D(chanind, :, i)), [], 2))>threshold; + if any(Ibar == i), spm_progress_bar('Set', i); end + end + + spm_progress_bar('Clear'); + elseif isequal(S.mode, 'mark') multitrial = D.ntrials>1; @@ -90,10 +92,10 @@ for i = 1:D.ntrials - bad = abs(squeeze(D(chanind, :, i)))>threshold; + bad = abs(squeeze(D(chanind, :, i)))>threshold; if ~any(bad(:)) - if multitrial && ismember(i, Ibar), spm_progress_bar('Set', i); end + if multitrial && any(Ibar == i), spm_progress_bar('Set', i); end continue; end @@ -130,7 +132,7 @@ res(end).time = D.time(onsets(k)+1) - D.time(1) + D.trialonset(i); res(end).duration = (min(offsets(offsets>onsets(k)))-onsets(k))./D.fsample; end - if ~multitrial && ismember(j, Ibar), spm_progress_bar('Set', j); end + if ~multitrial && any(Ibar == j), spm_progress_bar('Set', j); end end if ~multitrial, spm_progress_bar('Clear'); end @@ -149,7 +151,7 @@ end - if multitrial && ismember(i, Ibar), spm_progress_bar('Set', i); end + if multitrial && any(Ibar == i), spm_progress_bar('Set', i); end end if multitrial, spm_progress_bar('Clear'); end @@ -157,4 +159,4 @@ res = D; end -spm('FigName', 'M/EEG threshold channels: done'); \ No newline at end of file +spm('FigName', 'M/EEG threshold channels: done'); diff --git a/spm_eeg_artefact_zscore.m b/spm_eeg_artefact_zscore.m index b8ddc716..955f87fd 100644 --- a/spm_eeg_artefact_zscore.m +++ b/spm_eeg_artefact_zscore.m @@ -1,22 +1,23 @@ function res = spm_eeg_artefact_zscore(S) % Plugin for spm_eeg_artefact doing z-score thresholding -% S - input structure +% S - input structure % fields of S: -% S.D - M/EEG object -% S.chanind - vector of indices of channels that this plugin will look at. +% S.D - M/EEG object +% S.chanind - vector of indices of channels that this plugin will look at +% +% Additional parameters can be defined specific for each plugin. % -% Additional parameters can be defined specific for each plugin % Output: -% res - -% If no input is provided the plugin returns a cfg branch for itself +% res - +% If no input is provided the plugin returns a cfg branch for itself. % -% If input is provided the plugin returns a matrix of size D.nchannels x D.ntrials -% with zeros for clean channel/trials and ones for artefacts. -%______________________________________________________________________________________ -% Copyright (C) 2013 Wellcome Trust Centre for Neuroimaging +% If input is provided the plugin returns a matrix of size D.nchannels x D.ntrials +% with zeros for clean channel/trials and ones for artefacts. +%__________________________________________________________________________ +% Copyright (C) 2013-2017 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_eeg_artefact_zscore.m 6060 2014-06-19 13:31:19Z vladimir $ +% $Id: spm_eeg_artefact_zscore.m 7132 2017-07-10 16:22:58Z guillaume $ %-This part if for creating a config branch that plugs into spm_cfg_eeg_artefact @@ -24,33 +25,34 @@ % when it's called. %-------------------------------------------------------------------------- if nargin == 0 - threshold = cfg_entry; - threshold.tag = 'threshold'; - threshold.name = 'Threshold'; + threshold = cfg_entry; + threshold.tag = 'threshold'; + threshold.name = 'Threshold'; threshold.strtype = 'r'; - threshold.num = [1 1]; - threshold.val = {3}; - threshold.help = {'Threshold value (in stdev)'}; + threshold.num = [1 1]; + threshold.val = {3}; + threshold.help = {'Threshold value (in stdev)'}; - excwin = cfg_entry; - excwin.tag = 'excwin'; - excwin.name = 'Excision window'; + excwin = cfg_entry; + excwin.tag = 'excwin'; + excwin.name = 'Excision window'; excwin.strtype = 'r'; - excwin.num = [1 1]; - excwin.val = {100}; - excwin.help = {'Window (in ms) to mark as bad around each event (for mark mode only), 0 - do not mark data as bad'}; + excwin.num = [1 1]; + excwin.val = {100}; + excwin.help = {'Window (in ms) to mark as bad around each event (for mark mode only), 0 - do not mark data as bad.'}; - zscore = cfg_branch; - zscore.tag = 'zscore'; + zscore = cfg_branch; + zscore.tag = 'zscore'; zscore.name = 'Threshold z-scored data'; - zscore.val = {threshold, excwin}; + zscore.val = {threshold, excwin}; + zscore.help = {''}; res = zscore; return end -SVNrev = '$Rev: 6060 $'; +SVNrev = '$Rev: 7132 $'; %-Startup %-------------------------------------------------------------------------- @@ -59,11 +61,11 @@ D = spm_eeg_load(S.D); -chanind = S.chanind; +chanind = S.chanind; threshold = S.threshold; if isequal(S.mode, 'reject') && isequal(D.type, 'continuous') - error('Rejection mode not for continuous data'); + error('Rejection mode not for continuous data.'); end res = zeros(D.nchannels, D.ntrials); @@ -86,16 +88,13 @@ zsdat = dat./repmat(std(dat), size(dat, 1), 1); - if isequal(S.mode, 'reject') res(chanind(j), :) = any(abs(zsdat)>threshold); elseif isequal(S.mode, 'mark') - - bad = abs(zsdat)>threshold; if ~any(bad(:)) if isequal(D.type, 'continuous') - if ismember(j, Ibar), spm_progress_bar('Set', j); end + if any(Ibar == j), spm_progress_bar('Set', j); end end continue; end @@ -141,7 +140,7 @@ end end - if ismember(j, Ibar), spm_progress_bar('Set', j); end + if any(Ibar == j), spm_progress_bar('Set', j); end end spm_progress_bar('Clear'); @@ -150,4 +149,4 @@ res = D; end -spm('FigName','M/EEG zscore thresholding: done'); \ No newline at end of file +spm('FigName','M/EEG zscore thresholding: done'); diff --git a/spm_eeg_artefact_zscorediff.m b/spm_eeg_artefact_zscorediff.m index 14ae8793..392f5939 100644 --- a/spm_eeg_artefact_zscorediff.m +++ b/spm_eeg_artefact_zscorediff.m @@ -1,22 +1,23 @@ function res = spm_eeg_artefact_zscorediff(S) % Plugin for spm_eeg_artefact doing z-score thresholding on the diff time series -% S - input structure +% S - input structure % fields of S: -% S.D - M/EEG object -% S.chanind - vector of indices of channels that this plugin will look at. +% S.D - M/EEG object +% S.chanind - vector of indices of channels that this plugin will look at +% +% Additional parameters can be defined specific for each plugin. % -% Additional parameters can be defined specific for each plugin % Output: -% res - -% If no input is provided the plugin returns a cfg branch for itself +% res - +% If no input is provided the plugin returns a cfg branch for itself. % -% If input is provided the plugin returns a matrix of size D.nchannels x D.ntrials -% with zeros for clean channel/trials and ones for artefacts. -%______________________________________________________________________________________ -% Copyright (C) 2013 Wellcome Trust Centre for Neuroimaging +% If input is provided the plugin returns a matrix of size D.nchannels x D.ntrials +% with zeros for clean channel/trials and ones for artefacts. +%__________________________________________________________________________ +% Copyright (C) 2013-2017 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_eeg_artefact_zscorediff.m 6060 2014-06-19 13:31:19Z vladimir $ +% $Id: spm_eeg_artefact_zscorediff.m 7132 2017-07-10 16:22:58Z guillaume $ %-This part if for creating a config branch that plugs into spm_cfg_eeg_artefact @@ -24,33 +25,34 @@ % when it's called. %-------------------------------------------------------------------------- if nargin == 0 - threshold = cfg_entry; - threshold.tag = 'threshold'; - threshold.name = 'Threshold'; + threshold = cfg_entry; + threshold.tag = 'threshold'; + threshold.name = 'Threshold'; threshold.strtype = 'r'; - threshold.num = [1 1]; - threshold.val = {5}; - threshold.help = {'Threshold value (in stdev)'}; + threshold.num = [1 1]; + threshold.val = {5}; + threshold.help = {'Threshold value (in stdev).'}; - excwin = cfg_entry; - excwin.tag = 'excwin'; - excwin.name = 'Excision window'; + excwin = cfg_entry; + excwin.tag = 'excwin'; + excwin.name = 'Excision window'; excwin.strtype = 'r'; - excwin.num = [1 1]; - excwin.val = {100}; - excwin.help = {'Window (in ms) to mark as bad around each event (for mark mode only), 0 - do not mark data as bad'}; + excwin.num = [1 1]; + excwin.val = {100}; + excwin.help = {'Window (in ms) to mark as bad around each event (for mark mode only), 0 - do not mark data as bad.'}; zscorediff = cfg_branch; zscorediff.tag = 'zscorediff'; zscorediff.name = 'Threshold z-scored difference data'; zscorediff.val = {threshold, excwin}; + zscorediff.help = {''}; res = zscorediff; return end -SVNrev = '$Rev: 6060 $'; +SVNrev = '$Rev: 7132 $'; %-Startup %-------------------------------------------------------------------------- @@ -59,11 +61,11 @@ D = spm_eeg_load(S.D); -chanind = S.chanind; +chanind = S.chanind; threshold = S.threshold; if isequal(S.mode, 'reject') && isequal(D.type, 'continuous') - error('Rejection mode not for continuous data'); + error('Rejection mode not for continuous data.'); end res = zeros(D.nchannels, D.ntrials); @@ -75,7 +77,6 @@ if length(chanind) > 100, Ibar = floor(linspace(1, length(chanind),100)); else Ibar = [1:length(chanind)]; end - for j = 1:length(chanind) dat = squeeze(D(chanind(j), :, :)); if size(dat, 1) == 1 @@ -86,17 +87,15 @@ zsdat = dat./repmat(std(dat), size(dat, 1), 1); - zsdat = [zeros(1, size(zsdat, 2)); zsdat]; + zsdat = [zeros(1, size(zsdat, 2)); zsdat]; if isequal(S.mode, 'reject') res(chanind(j), :) = any(abs(zsdat)>threshold); elseif isequal(S.mode, 'mark') - - bad = abs(zsdat)>threshold; if ~any(bad(:)) if isequal(D.type, 'continuous') - if ismember(j, Ibar), spm_progress_bar('Set', j); end + if any(Ibar == j), spm_progress_bar('Set', j); end end continue; end @@ -141,7 +140,7 @@ end end - if ismember(j, Ibar), spm_progress_bar('Set', j); end + if any(Ibar == j), spm_progress_bar('Set', j); end end spm_progress_bar('Clear'); @@ -150,4 +149,4 @@ res = D; end -spm('FigName','M/EEG zscore diff thresholding: done'); \ No newline at end of file +spm('FigName','M/EEG zscore diff thresholding: done'); diff --git a/spm_eeg_assemble_priors.m b/spm_eeg_assemble_priors.m index a66bbbfd..0ed430b0 100644 --- a/spm_eeg_assemble_priors.m +++ b/spm_eeg_assemble_priors.m @@ -1,153 +1,139 @@ -function [LCpL,Q,sumLCpL,QE,Cy,M,Cp,Cq,Lq]=spm_eeg_assemble_priors(L,Qp,Qe,ploton,h) -%% function [LCpL,Q,sumLCpL,QE,Cy,M,Cp,Cq,Lq]=spm_eeg_assemble_priors(L,Qp,Qe,ploton,h) -%% to predict sensor level impact of sources in Qp given sensor noise Qe -%% L are the lead fields -%% Qp are priors on source level dipole moment nAm/(mm2) per sample -%% Qe is sensor level variance in fT^2 per sample -%% h are optional hyperparameters that scale the variance components in Qe and Qp (assume sensor followed by source level parameters) - -% LCpL are the sensor level covariance components corresponding to the -% source priors Qp -%% Q is a sparse array over sources holding dipole moment density nAm/(mm2) -%% sumLCpL is predicted sensor level variance due to sources (in fT^2) -%% QE is predicted sensor level noise variance (in fT^2) -%% Cy = QE+sumLCpL is the total sensor noise covariance predicted -%% M is the MAP estimator : M = Cp*L'*inv(Qe + L*Cp*L')) -%% Cp is the total source covariance matrix -%% Cq is conditional source covariance- need to implement -%% Lq is cell array of the L*q (impact of each source component at sensor level) - -% Copyright (C) 2010 Wellcome Trust Centre for Neuroimaging +function [LCpL,Q,sumLCpL,QE,Cy,M,Cp,Cq,Lq] = spm_eeg_assemble_priors(L,Qp,Qe,ploton,h) +% Predict sensor level impact of sources in Qp given sensor noise Qe +% FORMAT [LCpL,Q,sumLCpL,QE,Cy,M,Cp,Cq,Lq] = spm_eeg_assemble_priors(L,Qp,Qe,ploton,h) +% L - lead fields +% Qp - priors on source level dipole moment nAm/(mm2) per sample +% Qe - sensor level variance in fT^2 per sample +% h - optional hyperparameters that scale the variance components in +% Qe and Qp (assume sensor followed by source level parameters) + +% LCpL - sensor level covariance components corresponding to the source +% priors Qp +% Q - sparse array over sources holding dipole moment density nAm/(mm2) +% sumLCpL - predicted sensor level variance due to sources (in fT^2) +% QE - predicted sensor level noise variance (in fT^2) +% Cy - total sensor noise covariance predicted : Cy = QE+sumLCpL +% M - MAP estimator : M = Cp*L'*inv(Qe + L*Cp*L')) +% Cp - total source covariance matrix +% Cq - conditional source covariance - need to implement +% Lq - cell array of the L*q (impact of each source component at sensor level) +%__________________________________________________________________________ +% Copyright (C) 2010-2017 Wellcome Trust Centre for Neuroimaging % Gareth Barnes -% $Id: spm_eeg_assemble_priors.m 6498 2015-07-15 19:13:31Z gareth $ +% $Id: spm_eeg_assemble_priors.m 7132 2017-07-10 16:22:58Z guillaume $ -if nargin<4, - ploton=[]; -end; +if nargin < 4 + ploton = ~spm('CmdLine'); +end -if nargin<5, +if nargin < 5 h=[]; -end; - +end -Ne=length(Qe); -if iscell(Qp), - Np = length(Qp); %% number of source components +Ne = length(Qe); +if iscell(Qp) + Np = length(Qp); % number of source components else - Np=size(Qp,2); -end; - - - -if isempty(h), - h=ones(Ne+Np,1); -end; - -if length(h)~=Ne+Np, - error('There must be as many hyperparameters as priors'); -end; - -he=h(1:Ne); %% sensor level -hp = h(Ne + (1:Np)); %% source level + Np = size(Qp,2); +end +if isempty(h) + h = ones(Ne+Np,1); +end +if length(h)~=Ne+Np + error('There must be as many hyperparameters as priors.'); +end -Ns=size(L,2); %% number sources +he = h(1:Ne); % sensor level +hp = h(Ne + (1:Np)); % source level -Q=sparse(Ns,Np); -Lq={}; +Ns = size(L,2); % number sources +Q = sparse(Ns,Np); +Lq = {}; fprintf('Assembling %d prior components\n',Np); for i = 1:Np - if iscell(Qp), - if isfield(Qp{i},'q'), - %Q(:,i) = Qp{i}.q; %% patch amplitudes can be positive or negative - q=Qp{i}.q; - v=1; - if isfield(Qp{i},'v'), - v=sqrt(Qp{i}.v); - end; + if iscell(Qp) + if isfield(Qp{i},'q') + %Q(:,i) = Qp{i}.q; % patch amplitudes can be positive or negative + q = Qp{i}.q; + v = 1; + if isfield(Qp{i},'v') + v = sqrt(Qp{i}.v); + end - Q(:,i)=q*v; + Q(:,i) = q*v; - %% Lq is the sensor level projection of the prior Q{i}.q - Lq{i}.q = L*Q(:,i); %% supply an eigen mode in q - else %% no .q field, check it is 2D - if size(Qp{i},1)~=size(Qp{i},2), + % Lq is the sensor level projection of the prior Q{i}.q + Lq{i}.q = L*Q(:,i); % supply an eigen mode in q + else % no .q field, check it is 2D + if size(Qp{i},1)~=size(Qp{i},2) disp('making Qp 2D'); - Qp{i}=diag(sparse(Qp{i})); - end; - end; - - end; % if iscell - + Qp{i} = diag(sparse(Qp{i})); + end + end + end end -% assemble empirical priors +%-Assemble empirical priors %========================================================================== LCpL = {}; -sumLCpL=zeros(size(L,1),size(L,1)); +sumLCpL = zeros(size(L,1),size(L,1)); +Cp = sparse(0); +LCp = sparse(0); -Cp=sparse(0); -LCp=sparse(0); - -for i = 1:Np, +for i = 1:Np - if isfield(Qp{i},'q'), %% sparse diagonbal representation + if isfield(Qp{i},'q') % sparse diagonbal representation - - Q(:,i)=Q(:,i)*sqrt(hp(i)); %% update moment by sqrt of variance scaling + Q(:,i) = Q(:,i)*sqrt(hp(i)); % update moment by sqrt of variance scaling LQp = L*Q(:,i); - LCpL{i}=LQp*LQp'; + LCpL{i} = LQp*LQp'; Cp = Cp + Q(:,i)*Q(:,i)'; %% Q is already scaled by root hp %LCp = LCp+LQp; LCp = LCp+L*Cp; else % full matrix version - Qtmp=Qp{i}*hp(i); - LCpL{i}=L*Qtmp*L'; + Qtmp = Qp{i}*hp(i); + LCpL{i} = L*Qtmp*L'; Cp = Cp + Qtmp; % Q(:,i)=diag(Qtmp); - end; - - sumLCpL=sumLCpL+LCpL{i}; + end + sumLCpL = sumLCpL + LCpL{i}; - -end; - - -QE=zeros(size(Qe{1})); -for i=1:length(Qe), - QE=QE+Qe{i}*he(i); -end; +end +QE = zeros(size(Qe{1})); +for i=1:length(Qe) + QE = QE + Qe{i}*he(i); +end -Cy=sumLCpL+QE; +Cy = sumLCpL + QE; % This is equivalent to M = Cp*UL'*inv(Qe + UL*Cp*UL')) % with Cp the posterior source covariance (with optimal h values) -%Qsum=sum(Q(:,i).^2); %% diagonal of posterior source cov matrix +%Qsum=sum(Q(:,i).^2); % diagonal of posterior source cov matrix %Cp=diag(Qsum); -M=Cp*L'/Cy; - +M = Cp*L'/Cy; % conditional variance (leading diagonal) % Cq = Cp - Cp*L'*iC*L*Cp; %---------------------------------------------------------------------- %Cq = Cp - sum(LCp.*M')'; in original -Cq = diag(Cp) - sum(LCp.*M')'; +Cq = diag(Cp) - sum(LCp.*M')'; disp('end assemble'); -if ploton, +if ploton subplot(3,1,1); imagesc(sumLCpL);colorbar; title('source prior'); @@ -157,6 +143,4 @@ subplot(3,1,3); imagesc(Cy);colorbar; title('Sensor covariance per sample (fT^2)'); -end; - - +end diff --git a/spm_eeg_average.m b/spm_eeg_average.m index dcbc2873..81279547 100644 --- a/spm_eeg_average.m +++ b/spm_eeg_average.m @@ -15,12 +15,12 @@ % Output: % D - MEEG object (also written on disk) %__________________________________________________________________________ -% Copyright (C) 2008-2012 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2008-2017 Wellcome Trust Centre for Neuroimaging % Stefan Kiebel -% $Id: spm_eeg_average.m 6802 2016-06-03 09:03:34Z vladimir $ +% $Id: spm_eeg_average.m 7125 2017-06-23 09:49:29Z guillaume $ -SVNrev = '$Rev: 6802 $'; +SVNrev = '$Rev: 7125 $'; %-Startup %-------------------------------------------------------------------------- @@ -228,20 +228,13 @@ %-Display averaging statistics %-------------------------------------------------------------------------- -disp(sprintf('%s: Number of replications per contrast:', Dnew.fname)); %-# -s = []; +fprintf('%s: Number of replications per contrast:\n', Dnew.fname); %-# for i = 1:D.nconditions - s = [s sprintf('average %s: %d trials', cl{i}, ni(i))]; - if i < D.nconditions - s = [s ', ']; - else - s = [s '.']; - end + fprintf(' average %s: %d trials\n', cl{i}, ni(i)); %-# end -disp(s); %-# if robust - disp('Robust averaging might have introduced high frequencies in the data. It is advised to re-apply low-pass filter'); + disp('Robust averaging might have introduced high frequencies in the data. It is advised to re-apply low-pass filter.'); end %-Save new evoked M/EEG dataset @@ -258,4 +251,5 @@ %-Cleanup %-------------------------------------------------------------------------- +fprintf('%-40s: %30s\n','Completed',spm('time')); %-# spm('FigName','M/EEG averaging: done'); spm('Pointer','Arrow'); diff --git a/spm_eeg_average_TF.m b/spm_eeg_average_TF.m index 291bdb17..6c2deb14 100644 --- a/spm_eeg_average_TF.m +++ b/spm_eeg_average_TF.m @@ -16,12 +16,12 @@ % Output: % D - MEEG object (also written to disk). %__________________________________________________________________________ -% Copyright (C) 2008-2012 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2008-2017 Wellcome Trust Centre for Neuroimaging % Stefan Kiebel -% $Id: spm_eeg_average_TF.m 6180 2014-09-17 15:45:11Z vladimir $ +% $Id: spm_eeg_average_TF.m 7125 2017-06-23 09:49:29Z guillaume $ -SVNrev = '$Rev: 6180 $'; +SVNrev = '$Rev: 7125 $'; %-Startup %-------------------------------------------------------------------------- @@ -150,7 +150,7 @@ end %-Vector average (eg PLV for phase) - %------------------------------------------------------------------ + %-------------------------------------------------------------- else tmp = D(:, :, j, w); tmp = exp(sqrt(-1)*tmp); @@ -175,18 +175,10 @@ %-Display averaging statistics %-------------------------------------------------------------------------- -fprintf('%s: Number of replications per contrast:', Dnew.fname); %-# - -s = []; +fprintf('%s: Number of replications per contrast:\n', Dnew.fname); %-# for i = 1:D.nconditions - s = [s sprintf('average %s: %d trials', cl{i}, ni(i))]; - if i < D.nconditions - s = [s ', ']; - else - s = [s '\n']; - end + fprintf(' average %s: %d trials\n', cl{i}, ni(i)); %-# end -fprintf(s); %-# %-Save new evoked M/EEG dataset %-------------------------------------------------------------------------- @@ -202,4 +194,5 @@ %-Cleanup %-------------------------------------------------------------------------- +fprintf('%-40s: %30s\n','Completed',spm('time')); %-# spm('FigName','M/EEG TF averaging: done'); spm('Pointer', 'Arrow'); diff --git a/spm_eeg_avgfreq.m b/spm_eeg_avgfreq.m index 92eaf821..f516f2ca 100644 --- a/spm_eeg_avgfreq.m +++ b/spm_eeg_avgfreq.m @@ -4,21 +4,19 @@ % % S - input struct % fields of S: -% D - MEEG object or filename of M/EEG mat-file with epoched data% -% freqwin - frequency window to average over -% prefix - prefix for the output file (default - 'P') -% +% D - MEEG object or filename of M/EEG mat-file with epoched data +% freqwin - frequency window to average over [default: [-Inf, Inf]] +% prefix - prefix for the output file [default: 'P'] % % Output: -% D - MEEG object -% +% D - MEEG object %__________________________________________________________________________ -% Copyright (C) 2012 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2012-2017 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_eeg_avgfreq.m 5190 2013-01-17 15:32:45Z vladimir $ +% $Id: spm_eeg_avgfreq.m 7132 2017-07-10 16:22:58Z guillaume $ -SVNrev = '$Rev: 5190 $'; +SVNrev = '$Rev: 7132 $'; %-Startup %-------------------------------------------------------------------------- @@ -30,11 +28,10 @@ D = spm_eeg_load(S.D); -if ~strncmpi(D.transformtype,'TF',2); - error('This function only works on TF datasets'); +if ~strncmpi(D.transformtype,'TF',2) + error('This function only works on TF datasets.'); end - freqind = D.indfrequency(min(S.freqwin)):D.indfrequency(max(S.freqwin)); if isempty(freqind) || any(isnan(freqind)) error('Selected frequency window is invalid.'); @@ -52,10 +49,10 @@ for i = 1:D.ntrials - Dnew(:, :, i) = spm_squeeze(mean(D(:, freqind, :, i), 2), 2); + Dnew(:, :, i) = spm_squeeze(mean(D(:, freqind, :, i), 2), 2); - if ismember(i, Ibar), spm_progress_bar('Set', i); end -end % + if any(Ibar == i), spm_progress_bar('Set', i); end +end spm_progress_bar('Clear'); @@ -68,4 +65,5 @@ %-Cleanup %-------------------------------------------------------------------------- +fprintf('%-40s: %30s\n','Completed',spm('time')); %-# spm('FigName','Average over frequency: done'); spm('Pointer','Arrow'); diff --git a/spm_eeg_avgtime.m b/spm_eeg_avgtime.m index 15135853..088ae7ca 100644 --- a/spm_eeg_avgtime.m +++ b/spm_eeg_avgtime.m @@ -5,20 +5,20 @@ % S - input struct % fields of S: % D - MEEG object or filename of M/EEG mat-file with epoched data -% timewin - time window to average over (in PST ms) -% prefix - prefix for the output file (default - 'S') +% timewin - time window to average over {in PST ms} [default: [-Inf,Inf]] +% prefix - prefix for the output file [default: 'S'] % % % Output: % D - MEEG object % %__________________________________________________________________________ -% Copyright (C) 2012 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2012-2017 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_eeg_avgtime.m 5190 2013-01-17 15:32:45Z vladimir $ +% $Id: spm_eeg_avgtime.m 7132 2017-07-10 16:22:58Z guillaume $ -SVNrev = '$Rev: 5190 $'; +SVNrev = '$Rev: 7132 $'; %-Startup %-------------------------------------------------------------------------- @@ -30,8 +30,8 @@ D = spm_eeg_load(S.D); -if ~strncmpi(D.transformtype,'TF',2); - error('This function only works on TF datasets'); +if ~strncmpi(D.transformtype,'TF',2) + error('This function only works on TF datasets.'); end timeind = D.indsample(1e-3*(min(S.timewin))):D.indsample(1e-3*(max(S.timewin))); @@ -57,8 +57,8 @@ Dnew = trialonset(Dnew, i, D.trialonset(i)+ mean(D.time([timeind(1) timeind(end)]))); end - if ismember(i, Ibar), spm_progress_bar('Set', i); end -end % + if any(Ibar == i), spm_progress_bar('Set', i); end +end Dnew = timeonset(Dnew, mean(D.time([timeind(1) timeind(end)]))); @@ -73,4 +73,5 @@ %-Cleanup %-------------------------------------------------------------------------- +fprintf('%-40s: %30s\n','Completed',spm('time')); %-# spm('FigName','Average over time: done'); spm('Pointer','Arrow'); diff --git a/spm_eeg_bc.m b/spm_eeg_bc.m index 988ae376..bb9274e0 100644 --- a/spm_eeg_bc.m +++ b/spm_eeg_bc.m @@ -5,24 +5,24 @@ % S - optional input struct % fields of S: % S.D - MEEG object or filename of M/EEG mat-file with epoched data -% S.timewin - 2-element vector with start and end of baseline period [ms] -% default: the negative times if present or the whole trial -% otherwise. +% S.timewin - 2-element vector with start and end of baseline period {ms} +% [default: the negative times if present or the whole trial +% otherwise] % S.save - save the baseline corrected data in a separate file [default: true] % S.updatehistory - update history information [default: true] -% S.prefix - prefix for the output file (default - 'b') +% S.prefix - prefix for the output file [default: 'b'] % % D - MEEG object (also saved on disk if requested) %__________________________________________________________________________ % % Subtract average baseline from all M/EEG and EOG channels %__________________________________________________________________________ -% Copyright (C) 2008-2012 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2008-2017 Wellcome Trust Centre for Neuroimaging % Stefan Kiebel -% $Id: spm_eeg_bc.m 5212 2013-01-26 13:16:36Z vladimir $ +% $Id: spm_eeg_bc.m 7132 2017-07-10 16:22:58Z guillaume $ -SVNrev = '$Rev: 5212 $'; +SVNrev = '$Rev: 7132 $'; %-Startup %-------------------------------------------------------------------------- @@ -49,7 +49,7 @@ end if strncmpi(D.transformtype,'TF',2) % TF and TFphase - error('Use spm_eeg_tf_rescale for TF data.') + error('Use spm_eeg_tf_rescale for TF data.'); end %-Baseline Correction @@ -76,7 +76,7 @@ tmp = mean(D(indchannels, t(1):t(2), k), 2); D(indchannels, :, k) = D(indchannels, :, k) - repmat(tmp, 1, D.nsamples); - if ismember(k, Ibar), spm_progress_bar('Set', k); end + if any(Ibar == k), spm_progress_bar('Set', k); end end spm_progress_bar('Clear'); diff --git a/spm_eeg_collapse_timefreq.m b/spm_eeg_collapse_timefreq.m index 086f9c30..85046566 100644 --- a/spm_eeg_collapse_timefreq.m +++ b/spm_eeg_collapse_timefreq.m @@ -2,19 +2,21 @@ % Compute within-peristimulus time (or frequency) averages (contrasts) of M/EEG data in voxel-space % FORMAT images = spm_eeg_collapse_timefreq(S) % -% S - input structure +% S - input structure % fields of S: % images - list of file names containing M/EEG data in voxel-space % timewin - C x 2 matrix of start(s) and end(s) of a window in peri-stimulus -% time [ms] (or frequency (Hz)) +% time {ms} (or frequency {Hz}) % prefix - prefix for the averaged images -%_____________________________________________________________________________________________ -% Copyright (C) 2006-2013 Wellcome Trust Centre for Neuroimaging +% +% images - cellstr of saved images file names +%__________________________________________________________________________ +% Copyright (C) 2006-2017 Wellcome Trust Centre for Neuroimaging % Stefan Kiebel -% $Id: spm_eeg_collapse_timefreq.m 5194 2013-01-18 15:04:19Z vladimir $ +% $Id: spm_eeg_collapse_timefreq.m 7132 2017-07-10 16:22:58Z guillaume $ -SVNrev = '$Rev: 5194 $'; +SVNrev = '$Rev: 7132 $'; %-Startup %-------------------------------------------------------------------------- @@ -31,11 +33,7 @@ Nf = size(S.images, 1); Nc = size(S.timewin, 1); -if ischar(S.images) - fnames = cellstr(S.images); -else - fnames = S.images; -end +fnames = cellstr(S.images); ind1 = find(S.timewin(:, 1) == -Inf); S.timewin(ind1, 1) = 0; @@ -86,7 +84,9 @@ Vcon = Vbeta; Vcon.mat(3,3:4) = [1.0 0.0]; Vcon.mat0 = Vcon.mat; - Vcon.dat.fname = spm_file(fnames{j}, 'basename', sprintf('%s%s_con_%04d', S.prefix, spm_file(fnames{j},'basename'), i), 'ext', spm_file_ext); + Vcon.dat.fname = spm_file(fnames{j}, ... + 'basename', sprintf('%s%s_con_%04d', S.prefix, spm_file(fnames{j},'basename'), i),... + 'ext', spm_file_ext); Vcon.dat.scl_slope = 1.0; Vcon.dat.scl_inter = 0.0; Vcon.dat.dtype = 'float32-le'; @@ -117,11 +117,12 @@ end - if ismember(j, Ibar), spm_progress_bar('Set', j); end + if any(Ibar == j), spm_progress_bar('Set', j); end end %-Cleanup %-------------------------------------------------------------------------- spm_progress_bar('Clear'); +fprintf('%-40s: %30s\n','Completed',spm('time')); %-# spm('FigName','M/EEG Collapse time: done'); spm('Pointer','Arrow'); diff --git a/spm_eeg_combineplanar.m b/spm_eeg_combineplanar.m index f1609b2e..f27fc943 100644 --- a/spm_eeg_combineplanar.m +++ b/spm_eeg_combineplanar.m @@ -1,5 +1,5 @@ function D = spm_eeg_combineplanar(S) -% Combines data from MEGPLANAR sensors +% Combine data from MEGPLANAR sensors % FORMAT D = spm_eeg_combineplanar(S) % % S - optional input struct @@ -7,24 +7,23 @@ % D - MEEG object or filename % mode - % 'append' - add combined channels to the origal channels -% 'replace' - replace MEGPLANAR with combined (default) +% 'replace' - replace MEGPLANAR with combined [default] % 'replacemeg' - replace all MEG channels with combined but % keep non-MEG % 'keep' - only write out the combined channels % -% prefix - prefix for the output file (default - 'P') -% +% prefix - prefix for the output file [default: 'P'] % % Output: % D - MEEG object (also written on disk) % %__________________________________________________________________________ -% Copyright (C) 2008-2013 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2008-2017 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_eeg_combineplanar.m 6904 2016-10-20 12:04:59Z vladimir $ +% $Id: spm_eeg_combineplanar.m 7132 2017-07-10 16:22:58Z guillaume $ -SVNrev = '$Rev: 6904 $'; +SVNrev = '$Rev: 7132 $'; %-Startup %-------------------------------------------------------------------------- @@ -46,7 +45,7 @@ cind = D.indchannel(chanset(i, 1:2)); if length(cind) == 2 chanind = [chanind cind]; - labelnew = [labelnew; chanset(i, 4)]; + labelnew = [labelnew; chanset(i, end)]; end end @@ -95,10 +94,11 @@ end if strcmp(D.type, 'continuous') + %-Continuous data + %---------------------------------------------------------------------- blksz = D.fsample; blknum = floor(D.nsamples/blksz); - %---------------------------------------------------------------------- spm_progress_bar('Init', blknum, 'Data blocks processed'); if blknum > 100, Ibar = floor(linspace(1, blknum,100)); else Ibar = 1:blknum; end @@ -140,7 +140,6 @@ break; end - planar1 = D(chanind(1, :), Iblock); planar2 = D(chanind(2, :), Iblock); @@ -155,7 +154,9 @@ i = i+1; end end -else %-------- Epoched data -------------------------------------------------- +else + %-Epoched data + %---------------------------------------------------------------------- spm_progress_bar('Init', D.ntrials, 'Trials processed'); if D.ntrials > 100, Ibar = floor(linspace(1, D.ntrials, 100)); else Ibar = 1:D.ntrials; end @@ -214,4 +215,5 @@ %-Cleanup %-------------------------------------------------------------------------- +fprintf('%-40s: %30s\n','Completed',spm('time')); %-# spm('FigName','MEG Combine planar: done'); spm('Pointer','Arrow'); diff --git a/spm_eeg_contrast.m b/spm_eeg_contrast.m index a0350f06..b48b2925 100644 --- a/spm_eeg_contrast.m +++ b/spm_eeg_contrast.m @@ -10,27 +10,26 @@ % number of rows in c % weighted - flag whether average should be weighted by number of % replications (yes (1), no (0)) -% prefix - prefix for the output file (default - 'w') +% prefix - prefix for the output file [default: 'w'] % % Output: % D - EEG data struct (also written to disk) %__________________________________________________________________________ % % spm_eeg_contrast computes contrasts of data, over epochs of data. The -% input is a single MEEG file. -% The argument c must have dimensions Ncontrasts X Nepochs, where Ncontrasts is -% the number of contrasts and Nepochs the number of epochs, i.e. each row of c -% contains one contrast vector. The output -% is a M/EEG file with Ncontrasts epochs. The typical use is to compute, -% for display purposes, contrasts like the difference or interaction -% between trial types in channel space. +% input is a single MEEG file. The argument c must have dimensions +% Ncontrasts X Nepochs, where Ncontrasts is the number of contrasts and +% Nepochs the number of epochs, i.e. each row of c contains one contrast +% vector. The output is a M/EEG file with Ncontrasts epochs. The typical +% use is to compute, for display purposes, contrasts like the difference or +% interaction between trial types in channel space. %__________________________________________________________________________ -% Copyright (C) 2008-2012 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2008-2017 Wellcome Trust Centre for Neuroimaging % Stefan Kiebel, Rik Henson -% $Id: spm_eeg_contrast.m 6526 2015-08-20 10:28:36Z vladimir $ +% $Id: spm_eeg_contrast.m 7132 2017-07-10 16:22:58Z guillaume $ -SVNrev = '$Rev: 6526 $'; +SVNrev = '$Rev: 7132 $'; %-Startup %-------------------------------------------------------------------------- @@ -48,17 +47,15 @@ D = spm_eeg_load(S.D); - +%-Compute contrasts %-------------------------------------------------------------------------- c = S.c; Ncontrasts = size(c, 1); % Pad with zeros as in the contrast manager -if size(c, 2) <= D.ntrials - c = [c zeros(Ncontrasts, D.ntrials - size(c, 2))]; -else - error('The number of columns in the contrast matrix exceeds the number of trials.'); +if size(c, 2) ~= D.ntrials + error('The number of columns in the contrast matrix does not match the number of trials.'); end if ~isempty(D.repl) @@ -119,7 +116,7 @@ newrepl(i) = sum(D.repl(find(c(i,:)~=0))); - if ismember(i, Ibar), spm_progress_bar('Set', i); end + if any(Ibar == i), spm_progress_bar('Set', i); end end diff --git a/spm_eeg_convert.m b/spm_eeg_convert.m index 25c40e92..ebb51b84 100644 --- a/spm_eeg_convert.m +++ b/spm_eeg_convert.m @@ -44,12 +44,12 @@ % % % D - MEEG object (also written on disk) %__________________________________________________________________________ -% Copyright (C) 2008-2012 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2008-2017 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_eeg_convert.m 6244 2014-10-15 11:15:09Z vladimir $ +% $Id: spm_eeg_convert.m 7125 2017-06-23 09:49:29Z guillaume $ -SVNrev = '$Rev: 6244 $'; +SVNrev = '$Rev: 7125 $'; %-Startup %-------------------------------------------------------------------------- @@ -572,6 +572,7 @@ %-Cleanup %-------------------------------------------------------------------------- +fprintf('%-40s: %30s\n','Completed',spm('time')); %-# spm('FigName','M/EEG convert: done'); spm('Pointer', 'Arrow'); diff --git a/spm_eeg_convert2images.m b/spm_eeg_convert2images.m index da1daed1..b82cab0a 100644 --- a/spm_eeg_convert2images.m +++ b/spm_eeg_convert2images.m @@ -1,6 +1,6 @@ function [images, outroot] = spm_eeg_convert2images(S) % Convert M/EEG data to images for statistical analysis -% FORMAT images = spm_eeg_convert2images(S) +% FORMAT [images, outroot] = spm_eeg_convert2images(S) % % S - input structure (optional) % fields of S: @@ -29,12 +29,12 @@ % output: % images - list of generated image files or objects %__________________________________________________________________________ -% Copyright (C) 2005-2015 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak, James Kilner, Stefan Kiebel -% $Id: spm_eeg_convert2images.m 6653 2015-12-22 09:32:06Z vladimir $ +% $Id: spm_eeg_convert2images.m 7125 2017-06-23 09:49:29Z guillaume $ -SVNrev = '$Rev: 6653 $'; +SVNrev = '$Rev: 7125 $'; %-Startup %-------------------------------------------------------------------------- @@ -340,4 +340,5 @@ %-Cleanup %-------------------------------------------------------------------------- spm_progress_bar('Clear'); +fprintf('%-40s: %30s\n','Completed',spm('time')); %-# spm('FigName','M/EEG conversion: done'); spm('Pointer','Arrow'); diff --git a/spm_eeg_copy.m b/spm_eeg_copy.m index ffeb4648..d29e973e 100644 --- a/spm_eeg_copy.m +++ b/spm_eeg_copy.m @@ -9,25 +9,25 @@ % % D - MEEG object of the new dataset %__________________________________________________________________________ -% Copyright (C) 2008-2012 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2008-2017 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_eeg_copy.m 5079 2012-11-25 18:38:18Z vladimir $ +% $Id: spm_eeg_copy.m 7132 2017-07-10 16:22:58Z guillaume $ -SVNrev = '$Rev: 5079 $'; +SVNrev = '$Rev: 7132 $'; %-Startup %-------------------------------------------------------------------------- spm('FnBanner', mfilename, SVNrev); spm('FigName','M/EEG copy'); -if ~isfield(S, 'updatehistory'), S.updatehistory = 1; end +if ~isfield(S, 'updatehistory'), S.updatehistory = 1; end -D = spm_eeg_load(S.D); +D = spm_eeg_load(S.D); -D = copy(D, S.outfile); +D = copy(D, S.outfile); if ~isfield(S, 'updatehistory') || S.updatehistory D = D.history('spm_eeg_copy', S); @@ -37,4 +37,4 @@ %-Cleanup %-------------------------------------------------------------------------- -spm('FigName','M/EEG copy: done'); \ No newline at end of file +spm('FigName','M/EEG copy: done'); diff --git a/spm_eeg_correct_sensor_data.m b/spm_eeg_correct_sensor_data.m index e7537c62..42fbcdcc 100644 --- a/spm_eeg_correct_sensor_data.m +++ b/spm_eeg_correct_sensor_data.m @@ -1,31 +1,26 @@ function D = spm_eeg_correct_sensor_data(S) -% Function for removing artefacts from the data based on their topography +% Remove artefacts from the data based on their topography % FORMAT D = spm_eeg_correct_sensor_data(S) % -% S - input structure (optional) +% S - input structure (optional) % (optional) fields of S: -% S.D - MEEG object or filename of M/EEG mat-file -% S.mode - 'SSP' - simple projection -% - 'Berg' - the method of Berg (see the reference below) +% S.D - MEEG object or filename of M/EEG mat-file +% S.mode - 'SSP': simple projection +% - 'Berg': the method of Berg (see the reference below) % Output: -% D - MEEG object (also written on disk) -% _______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging -% -% Disclaimer: this code is provided as an example and is not guaranteed to work -% with data on which it was not tested. If it does not work for you, feel -% free to improve it and contribute your improvements to the MEEGtools toolbox -% in SPM (http://www.fil.ion.ucl.ac.uk/spm) +% D - MEEG object (also written on disk) % % Implements: % Berg P, Scherg M. % A multiple source approach to the correction of eye artifacts. % Electroencephalogr Clin Neurophysiol. 1994 Mar;90(3):229-41. -% +%__________________________________________________________________________ +% Copyright (C) 2008-2017 Wellcome Trust Centre for Neuroimaging + % Vladimir Litvak -% $Id: spm_eeg_correct_sensor_data.m 6054 2014-06-18 10:34:09Z vladimir $ +% $Id: spm_eeg_correct_sensor_data.m 7132 2017-07-10 16:22:58Z guillaume $ -SVNrev = '$Rev: 6054 $'; +SVNrev = '$Rev: 7132 $'; %-Startup %-------------------------------------------------------------------------- @@ -34,6 +29,7 @@ if ~isfield(S, 'mode') && isfield(S, 'correction'), S.mode = S.correction; end if ~isfield(S, 'prefix'), S.prefix = 'T'; end + %-Get MEEG object %-------------------------------------------------------------------------- D = spm_eeg_load(S.D); @@ -84,7 +80,7 @@ montage.chanunitnew = montage.chanunitorg; if size(A{i}, 1)~=numel(label) - error('Spatial confound vector does not match the channels'); + error('Spatial confound vector does not match the channels.'); end if isequal(lower(S.mode), 'berg') @@ -99,7 +95,8 @@ end end - %% ============ Find or prepare head model + %-Find or prepare head model + %================================================================== if ~isfield(D, 'val') D.val = 1; @@ -154,7 +151,8 @@ D = Dnew; end -%% ============ Change the channel order to the original order +%-Change the channel order to the original order +%========================================================================== tra = eye(D.nchannels); montage = []; montage.labelorg = D.chanlabels'; @@ -193,4 +191,3 @@ %-Cleanup %-------------------------------------------------------------------------- spm('FigName', 'Correct sensor data: done'); - diff --git a/spm_eeg_crop.m b/spm_eeg_crop.m index 91f3cb9f..14d32964 100644 --- a/spm_eeg_crop.m +++ b/spm_eeg_crop.m @@ -1,26 +1,24 @@ function D = spm_eeg_crop(S) -% Reduce the data size by cutting in time and frequency. +% Reduce the data size by cutting in time and frequency % FORMAT D = spm_eeg_crop(S) % % S - optional input struct % fields of S: % D - MEEG object or filename of M/EEG mat-file with epoched data -% timewin - time window to retain (in PST ms) +% timewin - time window to retain {in PST ms} % freqwin - frequency window to retain -% channels - cell array of channel labels or 'all'. -% prefix - prefix for the output file (default - 'p') -% +% channels - cell array of channel labels or 'all' [default] +% prefix - prefix for the output file [default: 'p'] % % Output: % D - MEEG object (also written on disk) -% %__________________________________________________________________________ -% Copyright (C) 2008-2012 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2008-2017 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_eeg_crop.m 6437 2015-05-14 12:27:21Z vladimir $ +% $Id: spm_eeg_crop.m 7132 2017-07-10 16:22:58Z guillaume $ -SVNrev = '$Rev: 6437 $'; +SVNrev = '$Rev: 7132 $'; %-Startup %-------------------------------------------------------------------------- @@ -71,30 +69,37 @@ ev = Dnew.events; if ~isempty(ev) ev = ev([ev.time]>=Dnew.time(1) & [ev.time]<=Dnew.time(end)); - Dnew = events(Dnew, 1, ev); + Dnew = events(Dnew, 1, ev); end end %-Copy data %-------------------------------------------------------------------------- +fprintf('%-40s: %30s\n','Channels',sprintf('%d/%d',numel(chanind),D.nchannels));%-# +if isTF, fprintf('%-40s: %30s\n','Frequencies',sprintf('%d/%d',numel(freqind),D.nfrequencies)); end %-# +fprintf('%-40s: %30s\n','Samples',sprintf('%d/%d',numel(timeind),D.nsamples)); %-# spm_progress_bar('Init', D.ntrials, 'Trials copied'); if D.ntrials > 100, Ibar = floor(linspace(1, D.ntrials, 100)); else Ibar = 1:D.ntrials; end +onsets = zeros(1,D.ntrials); + for i = 1:D.ntrials if isTF - Dnew(:, :, :, i) = D(chanind, freqind, timeind, i); + Dnew(:, :, :, i) = D(chanind, freqind, timeind, i); else - Dnew(:, :, i) = D(chanind, timeind, i); + Dnew(:, :, i) = D(chanind, timeind, i); end if D.trialonset(i) ~= 0 - Dnew = trialonset(Dnew, i, D.trialonset(i)+ D.time(timeind(1))-D.time(1)); + onsets(i) = D.trialonset(i)+ D.time(timeind(1))-D.time(1); end - if ismember(i, Ibar), spm_progress_bar('Set', i); end -end % + if any(Ibar == i), spm_progress_bar('Set', i); end +end + +Dnew = trialonset(Dnew, ':', onsets); spm_progress_bar('Clear'); @@ -107,4 +112,5 @@ %-Cleanup %-------------------------------------------------------------------------- +fprintf('%-40s: %30s\n','Completed',spm('time')); %-# spm('FigName','Crop M/EEG data: done'); spm('Pointer','Arrow'); diff --git a/spm_eeg_definetrial.m b/spm_eeg_definetrial.m index ca7392bc..bd0bdf50 100644 --- a/spm_eeg_definetrial.m +++ b/spm_eeg_definetrial.m @@ -4,27 +4,28 @@ % S - input structure (optional) % (optional) fields of S: % S.D - MEEG object or filename of M/EEG mat-file -% S.timewin - time window (in PST ms) +% S.timewin - time window {in PST ms} % S.trialdef - structure array for trial definition with fields (optional) % S.trialdef.conditionlabel - string label for the condition % S.trialdef.eventtype - string % S.trialdef.eventvalue - string, numeric or empty -% S.trialdef.trlshift - shift the triggers by a fixed amount (ms) +% S.trialdef.trlshift - shift the triggers by a fixed amount {ms} % (e.g. projector delay). -% S.reviewtrials - review individual trials after selection (yes/no: 1/0) -% S.save - save trial definition (yes/no: 1/0) +% S.reviewtrials - review individual trials after selection [yes/no: 1/0] +% S.save - save trial definition [yes/no: 1/0] +% % OUTPUT: % trl - Nx3 matrix [start end offset] % conditionlabels - Nx1 cell array of strings, label for each trial % S - modified configuration structure (for history) %__________________________________________________________________________ -% Copyright (C) 2008-2014 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2008-2017 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak, Robert Oostenveld -% $Id: spm_eeg_definetrial.m 6182 2014-09-18 12:03:18Z guillaume $ +% $Id: spm_eeg_definetrial.m 7132 2017-07-10 16:22:58Z guillaume $ -SVNrev = '$Rev: 6182 $'; +SVNrev = '$Rev: 7132 $'; %-Startup %-------------------------------------------------------------------------- @@ -46,14 +47,14 @@ %-Get input parameters %-------------------------------------------------------------------------- if ~isequal(D.type, 'continuous') - error('Trial definition requires continuous dataset as input'); + error('Trial definition requires continuous dataset as input.'); end event = events(D, 1, 'samples'); fsample = D.fsample; if isempty(event) - error('No event information was found in the input'); + error('No event information was found in the input.'); end if ~isfield(S, 'timewin') diff --git a/spm_eeg_dipoles_ui.m b/spm_eeg_dipoles_ui.m index 45c7eca3..a3d4a778 100644 --- a/spm_eeg_dipoles_ui.m +++ b/spm_eeg_dipoles_ui.m @@ -1,35 +1,35 @@ -function dipoles = spm_eeg_dipoles_ui +function dipoles = spm_eeg_dipoles_ui % Get dipole locations and orientations from the user %__________________________________________________________________________ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak, Christophe Phillips -% $Id: spm_eeg_dipoles_ui.m 3120 2009-05-13 13:01:03Z vladimir $ +% $Id: spm_eeg_dipoles_ui.m 7132 2017-07-10 16:22:58Z guillaume $ -SVNrev = '$Rev: 3120 $'; +SVNrev = '$Rev: 7132 $'; %-Startup %-------------------------------------------------------------------------- spm('FnBanner', mfilename, SVNrev); spm('FnUIsetup','Specify dipole model',0); -label = {}; -pnt = []; -ori = []; +label = {}; +pnt = []; +ori = []; dip_q = 0; % number of dipole 'elements' added (single or pair) dip_c = 0; % total number of dipoles in the model adding_dips = 1; while adding_dips - if dip_q>0, + if dip_q > 0 msg_dip =['Add dipoles to ',num2str(dip_c),' or stop?']; - dip_ch = 'Single|Pair|Stop'; + dip_ch = 'Single|Pair|Stop'; dip_val = [1,2,0]; - def_opt=3; + def_opt = 3; else - msg_dip =['Add dipoles to model']; - def_opt=1; - dip_ch = 'Single|Pair'; + msg_dip = 'Add dipoles to model'; + def_opt = 1; + dip_ch = 'Single|Pair'; dip_val = [1,2]; end a_dip = spm_input(msg_dip,1+dip_q,'b',dip_ch,dip_val,def_opt); @@ -47,21 +47,20 @@ loc = spm_input(str, 1+dip_q+1,'e',[0 0 0]); % Moment prior - wpr_q = spm_input('Oriented dipole?',1+dip_q+1,'b', ... + wpr_q = spm_input('Oriented dipole?', 1+dip_q+1, 'b', ... 'Yes|No',[1,0],2); if wpr_q % informative moment prior - m = spm_input('Orientation', ... - 1+dip_q+1,'e',[0 0 0]); + m = spm_input('Orientation', 1+dip_q+1,'e',[0 0 0]); m = m/norm(m); - pnt = [pnt; loc]; - ori = [ori; m]; - label = [label; {clabel}]; + pnt = [pnt; loc]; + ori = [ori; m]; + label = [label; {clabel}]; else - pnt = [pnt; loc; loc; loc]; - ori = [ori; 1 0 0; 0 1 0; 0 0 1]; - label = [label; {[clabel '_X']; [clabel '_Y']; [clabel '_Z']}]; + pnt = [pnt; loc; loc; loc]; + ori = [ori; 1 0 0; 0 1 0; 0 0 1]; + label = [label; {[clabel '_X']; [clabel '_Y']; [clabel '_Z']}]; end dip_c = dip_c+1; else @@ -82,13 +81,13 @@ 1+dip_q+1,'e',[0 0 0]); m = m/norm(m); - pnt = [pnt; loc; -loc(1) loc(2:3)]; - ori = [ori; m; -m(1) m(2:3)]; - label = [label; {[clabel 'R']; [clabel 'L']}]; + pnt = [pnt; loc; -loc(1) loc(2:3)]; + ori = [ori; m; -m(1) m(2:3)]; + label = [label; {[clabel 'R']; [clabel 'L']}]; else - pnt = [pnt; repmat(loc, 3, 1); repmat([-loc(1) loc(2:3)], 3, 1)]; - ori = [ori; 1 0 0; 0 1 0; 0 0 1; 1 0 0; 0 1 0; 0 0 1]; - label = [label; {[clabel 'R_X']; [clabel 'R_Y']; [clabel 'R_Z']; [clabel 'L_X']; [clabel 'L_Y']; [clabel 'L_Z']}]; + pnt = [pnt; repmat(loc, 3, 1); repmat([-loc(1) loc(2:3)], 3, 1)]; + ori = [ori; 1 0 0; 0 1 0; 0 0 1; 1 0 0; 0 1 0; 0 0 1]; + label = [label; {[clabel 'R_X']; [clabel 'R_Y']; [clabel 'R_Z']; [clabel 'L_X']; [clabel 'L_Y']; [clabel 'L_Z']}]; end dip_c = dip_c+2; @@ -96,19 +95,24 @@ end end -spm_figure('GetWin','Graphics'); clf - -sdip= []; -sdip.n_seeds = 1; -sdip.n_dip = size(pnt, 1); -sdip.Mtb = 1; -sdip.j{1} = reshape(ori', [], 1); -sdip.loc{1} = pnt'; -spm_eeg_inv_ecd_DrawDip('Init', sdip) -spm_eeg_inv_ecd_DrawDip('drawdip', 1, size(pnt, 1)+1); - +%-Display +%-------------------------------------------------------------------------- +if ~spm('CmdLine') + spm_figure('GetWin','Graphics'); clf + + sdip = []; + sdip.n_seeds = 1; + sdip.n_dip = size(pnt, 1); + sdip.Mtb = 1; + sdip.j{1} = reshape(ori', [], 1); + sdip.loc{1} = pnt'; + spm_eeg_inv_ecd_DrawDip('Init', sdip) + spm_eeg_inv_ecd_DrawDip('drawdip', 1, size(pnt, 1)+1); +end -dipoles = []; -dipoles.pnt = pnt; -dipoles.ori = ori; -dipoles.label = label; +%-Output variable +%-------------------------------------------------------------------------- +dipoles = struct(... + 'pnt', pnt, .... + 'ori', ori, ... + 'label',label); diff --git a/spm_eeg_downsample.m b/spm_eeg_downsample.m index 3055c3ce..efe1d9b3 100644 --- a/spm_eeg_downsample.m +++ b/spm_eeg_downsample.m @@ -5,10 +5,10 @@ % S - optional input struct % (optional) fields of S: % S.D - MEEG object or filename of M/EEG mat-file -% S.method - resampling method. Can be 'resample' (default), 'decimate', -% 'downsample', 'fft' +% S.method - resampling method. Can be 'resample' [default], +% 'decimate', 'downsample', 'fft' % S.fsample_new - new sampling rate, must be lower than the original one -% S.prefix - prefix for the output file (default - 'd') +% S.prefix - prefix for the output file [default: 'd'] % % D - MEEG object (also written on disk) %__________________________________________________________________________ @@ -17,12 +17,12 @@ % http://www.mathworks.com/products/signal/ % (function resample.m) if present and spm_timeseries_resample.m otherwise. %__________________________________________________________________________ -% Copyright (C) 2005-2014 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % Stefan Kiebel -% $Id: spm_eeg_downsample.m 6614 2015-11-30 10:42:02Z vladimir $ +% $Id: spm_eeg_downsample.m 7125 2017-06-23 09:49:29Z guillaume $ -SVNrev = '$Rev: 6614 $'; +SVNrev = '$Rev: 7125 $'; %-Startup %-------------------------------------------------------------------------- @@ -59,7 +59,8 @@ fsample_new = round(10*fsample_new)/10; end -disp(['Resampling frequency is ',num2str(fsample_new), 'Hz']) +fprintf('%-40s: %30s\n','Sampling frequency',[num2str(D.fsample),'Hz']); %-# +fprintf('%-40s: %30s\n','Resampling frequency',[num2str(fsample_new),'Hz']); %-# %-Generate new meeg object with new filenames %-------------------------------------------------------------------------- @@ -81,13 +82,13 @@ blknum = ceil(nchannels(D)/blksz); % now downsample blocks of channels - chncnt=1; + chncnt = 1; for blk=1:blknum spm_progress_bar('Set','ylabel','reading...'); % load old meeg object blockwise into workspace - blkchan=chncnt:(min(nchannels(D), chncnt+blksz-1)); - Dtemp=D(blkchan,:,1); - chncnt=chncnt+blksz; + blkchan = chncnt:(min(nchannels(D), chncnt+blksz-1)); + Dtemp = D(blkchan,:,1); + chncnt = chncnt+blksz; spm_progress_bar('Set','ylabel','writing...'); @@ -104,10 +105,10 @@ for i = 1:D.ntrials Dnew(:, :, i) = ft_preproc_resample(spm_squeeze(D(:, :, i), 3), Q, P, S.method); - if ismember(i, Ibar), spm_progress_bar('Set', i); end + if any(Ibar == i), spm_progress_bar('Set', i); end end -end; +end spm_progress_bar('Clear'); @@ -120,4 +121,5 @@ %-Cleanup %-------------------------------------------------------------------------- +fprintf('%-40s: %30s\n','Completed',spm('time')); %-# spm('FigName','M/EEG downsampling: done'); spm('Pointer','Arrow'); diff --git a/spm_eeg_epochs.m b/spm_eeg_epochs.m index 58da7445..e7b51511 100644 --- a/spm_eeg_epochs.m +++ b/spm_eeg_epochs.m @@ -46,21 +46,18 @@ % Output: % D - MEEG object (also written on disk) %__________________________________________________________________________ -% Copyright (C) 2008-2015 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2008-2017 Wellcome Trust Centre for Neuroimaging % Stefan Kiebel -% $Id: spm_eeg_epochs.m 6596 2015-11-10 15:52:16Z vladimir $ +% $Id: spm_eeg_epochs.m 7125 2017-06-23 09:49:29Z guillaume $ -SVNrev = '$Rev: 6596 $'; +SVNrev = '$Rev: 7125 $'; %-Startup %-------------------------------------------------------------------------- spm('FnBanner', mfilename, SVNrev); spm('FigName','M/EEG epoching'); spm('Pointer','Watch'); -if ~isfield(S, 'prefix'), S.prefix = 'e'; end -if ~isfield(S, 'eventpadding'), S.eventpadding = 0; end - %-Get MEEG object %-------------------------------------------------------------------------- D = spm_eeg_load(S.D); @@ -69,11 +66,15 @@ if isTF && isfield(S, 'bc') && S.bc sw = warning('off','backtrace'); - warning('Automatic baseline correction is not done for TF data. Use TF rescaling'); + warning('Automatic baseline correction is not done for TF data. Use TF rescaling.'); warning(sw); - S.bc = 0; + S.bc = false; end - + +%-Input parameters +%-------------------------------------------------------------------------- +if ~isfield(S, 'prefix'), S.prefix = 'e'; end +if ~isfield(S, 'eventpadding'), S.eventpadding = 0; end if ~isfield(S, 'bc'), S.bc = ~isTF; end %-Check that the input file contains continuous data @@ -127,7 +128,7 @@ conditionlabels = 'Undefined'; end else - error('Invalid trial definition'); + error('Invalid trial definition.'); end if ischar(conditionlabels) @@ -167,7 +168,7 @@ if ~isempty(rejected) trl = trl(inbounds, :); conditionlabels = conditionlabels(inbounds); - warning([D.fname ': Events ' num2str(rejected) ' not extracted - out of bounds']); + warning([D.fname ': Events ' num2str(rejected) ' not extracted - out of bounds.']); end ntrial = size(trl, 1); @@ -193,13 +194,15 @@ bc = Dnew.nsamples; chanbc = D.indchantype('Filtered'); else - S.bc = 0; - warning('There was no baseline specified. The data is not baseline-corrected'); + S.bc = false; + warning('There was no baseline specified. The data is not baseline-corrected.'); end end %-Epoch data %-------------------------------------------------------------------------- +fprintf('%-40s: %30s\n','Baseline correction',num2str(S.bc)); %-# +fprintf('%-40s: %30s\n','Number of trials',num2str(ntrial)); %-# spm_progress_bar('Init', ntrial, 'Trials completed'); if ntrial > 100, Ibar = floor(linspace(1, ntrial, 100)); else Ibar = [1:ntrial]; end @@ -222,7 +225,7 @@ Dnew = events(Dnew, i, select_events(D.events, ... D.trialonset+[trl(i, 1)/D.fsample-S.eventpadding trl(i, 2)/D.fsample+S.eventpadding])); - if ismember(i, Ibar), spm_progress_bar('Set', i); end + if any(Ibar == i), spm_progress_bar('Set', i); end end Dnew = conditions(Dnew, ':', conditionlabels); @@ -246,6 +249,7 @@ %-Cleanup %-------------------------------------------------------------------------- spm_progress_bar('Clear'); +fprintf('%-40s: %30s\n','Completed',spm('time')); %-# spm('FigName','M/EEG epoching: done'); spm('Pointer','Arrow'); diff --git a/spm_eeg_filter.m b/spm_eeg_filter.m index 66e16bb9..c7dfb4b8 100644 --- a/spm_eeg_filter.m +++ b/spm_eeg_filter.m @@ -15,19 +15,19 @@ % 'fir': FIR filter (using MATLAB fir1 function) % S.order - filter order [default: 5 for Butterworth] % S.dir - filter direction [default: 'twopass'] -% 'onepass' forward filter only -% 'onepass-reverse' reverse filter only, i.e. backward in time -% 'twopass' zero-phase forward and reverse filter +% 'onepass': forward filter only +% 'onepass-reverse': reverse filter only, i.e. backward in time +% 'twopass': zero-phase forward and reverse filter % S.prefix - prefix for the output file [default: 'f'] % % D - MEEG object (also written to disk) %__________________________________________________________________________ -% Copyright (C) 2008-2013 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2008-2017 Wellcome Trust Centre for Neuroimaging % Stefan Kiebel -% $Id: spm_eeg_filter.m 5876 2014-02-11 15:53:28Z vladimir $ +% $Id: spm_eeg_filter.m 7125 2017-06-23 09:49:29Z guillaume $ -SVNrev = '$Rev: 5876 $'; +SVNrev = '$Rev: 7125 $'; %-Startup @@ -72,6 +72,10 @@ error('Incorrect filter band.') end +fprintf('%-40s: %30s\n',... + ['Filter ' S.band ' (' S.type ', ' S.dir ')'],... + ['[' num2str(S.freq) '] Hz']); %-# + %-Filter %========================================================================== @@ -114,20 +118,20 @@ blknum = ceil(nchannels(D)/blksz); % now filter blocks of channels - chncnt=1; + chncnt = 1; for blk=1:blknum % load meeg object blockwise into workspace - blkchan=chncnt:(min(length(Fchannels), chncnt+blksz-1)); + blkchan = chncnt:(min(length(Fchannels), chncnt+blksz-1)); if isempty(blkchan), break, end spm_progress_bar('Set','ylabel','reading...'); if isTF - Dtemp=D(Fchannels(blkchan), :, :, 1); + Dtemp = D(Fchannels(blkchan), :, :, 1); else - Dtemp=D(Fchannels(blkchan), :, 1); + Dtemp = D(Fchannels(blkchan), :, 1); end spm_progress_bar('Set','ylabel','filtering...'); - chncnt=chncnt+blksz; - %loop through channels + chncnt = chncnt + blksz; + % loop through channels for j = 1:numel(blkchan) if isTF Dtemp(j, :, :) = spm_eeg_preproc_filter(S, spm_squeeze(Dtemp(j, :, :), 1), Fs, ignoreWarnings); @@ -144,9 +148,9 @@ % write Dtemp to Dnew spm_progress_bar('Set','ylabel','writing...'); if isTF - Dnew(Fchannels(blkchan),:,:,1)=Dtemp; + Dnew(Fchannels(blkchan),:,:,1) = Dtemp; else - Dnew(Fchannels(blkchan),:,1)=Dtemp; + Dnew(Fchannels(blkchan),:,1) = Dtemp; end clear Dtemp; end @@ -187,6 +191,7 @@ %-Cleanup %-------------------------------------------------------------------------- +fprintf('%-40s: %30s\n','Completed',spm('time')); %-# spm('FigName',''); spm('Pointer', 'Arrow'); diff --git a/spm_eeg_ft2spm.m b/spm_eeg_ft2spm.m index d56b8da1..81d3adde 100644 --- a/spm_eeg_ft2spm.m +++ b/spm_eeg_ft2spm.m @@ -5,7 +5,7 @@ % Copyright (C) 2008-2013 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_eeg_ft2spm.m 5438 2013-04-24 10:38:47Z vladimir $ +% $Id: spm_eeg_ft2spm.m 7059 2017-04-18 10:59:54Z vladimir $ isTF = 0; @@ -153,8 +153,16 @@ D = type(D, 'single'); end -if isfield(ftdata, 'hdr') && isfield(ftdata.hdr, 'grad') - D = sensors(D, 'MEG', ft_convert_units(ftdata.hdr.grad, 'mm')); +if isfield(ftdata, 'hdr') && isfield(ftdata.hdr, 'grad') + grad = ftdata.hdr.grad; +elseif isfield(ftdata, 'grad') + grad = ftdata.grad; +else + grad = []; +end + +if ~isempty(grad) + D = sensors(D, 'MEG', ft_convert_units(grad, 'mm')); S = []; S.task = 'project3D'; diff --git a/spm_eeg_grandmean.m b/spm_eeg_grandmean.m index 6c5e218d..eaa73096 100644 --- a/spm_eeg_grandmean.m +++ b/spm_eeg_grandmean.m @@ -1,34 +1,34 @@ function Do = spm_eeg_grandmean(S) -% average over multiple data sets +% Average over multiple M/EEG data sets % FORMAT Do = spm_eeg_grandmean(S) % % S - struct (optional) % fields of S: -% D - filenames (char matrix) of EEG mat-file containing epoched -% data +% D - filenames (char matrix) of M/EEG MAT-files containing +% epoched data % weighted - average weighted by number of replications in inputs (1) -% or not (0). -% outfile - name of the output file (default - 'grand_mean') +% or not (0) [default: 0] +% outfile - name of the output file [default: 'grand_mean'] % % Output: % Do - EEG data struct, result files are saved in the same -% directory as first input file. +% directory as first input file. %__________________________________________________________________________ % % spm_eeg_grandmean averages data over multiple files. The data must have % the same trialtype numbering and sampling rate. This function can be used -% for grand mean averaging, i.e. computing the average over multiple subjects. -% Missing event types and bad channels are taken into account properly. -% The output is written to a user-specified new file. The default name is -% the same name as the first selected input file, but prefixed with a 'g'. -% The output file is written to the current working directory. +% for grand mean averaging, i.e. computing the average over multiple +% subjects. Missing event types and bad channels are taken into account +% properly. The output is written to a user-specified new file. The default +% name is the same name as the first selected input file, but prefixed with +% a 'g'. The output file is written to the current working directory. %__________________________________________________________________________ -% Copyright (C) 2008-2012 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2008-2017 Wellcome Trust Centre for Neuroimaging % Stefan Kiebel -% $Id: spm_eeg_grandmean.m 6625 2015-12-03 21:49:24Z vladimir $ +% $Id: spm_eeg_grandmean.m 7139 2017-07-24 10:54:11Z guillaume $ -SVNrev = '$Rev: 6625 $'; +SVNrev = '$Rev: 7139 $'; %-Startup %-------------------------------------------------------------------------- @@ -51,7 +51,7 @@ end D = F; catch - error('Trouble reading files'); + error('Trouble reading files.'); end end @@ -59,11 +59,11 @@ %-Check dimension of the data files %-------------------------------------------------------------------------- -estr = []; +estr = ''; for i = 1:Nfiles flist = []; - if ~strcmp(D{i}.type, 'evoked'); + if ~strcmp(D{i}.type, 'evoked') flist = [flist ' ' D{i}.fname]; end if ~isempty(flist) @@ -195,7 +195,6 @@ % send message error (if any) if ~isempty(estr) error(estr) - return else fprintf('Ok: All data files have the same dimensions.\n') end @@ -277,7 +276,7 @@ Do(1:Do.nchannels, 1:Do.nfrequencies, 1:Do.nsamples, i) = d; - if ismember(i, Ibar), spm_progress_bar('Set', i); end + if any(Ibar==i), spm_progress_bar('Set', i); end end @@ -306,7 +305,7 @@ Do(1:Do.nchannels, 1:Do.nsamples, i) = d; - if ismember(i, Ibar), spm_progress_bar('Set', i); end + if any(Ibar==i), spm_progress_bar('Set', i); end end end @@ -315,25 +314,27 @@ %-Average sensor locations %-------------------------------------------------------------------------- +nograph = spm('CmdLine'); +h = []; Ntrials = sum(nrepl, 2); if ~isempty(megsens) - spm_figure('GetWin','Graphics');clf; + if ~nograph, spm_figure('GetWin','Graphics');clf; end if ~isempty(eegsens) - h = subplot(2, 1, 1); + if ~nograph, h = subplot(2, 1, 1); end aeegsens = ft_average_sens(eegsens, 'weights', Ntrials, 'feedback', h); Do = sensors(Do, 'EEG', aeegsens); - - h = subplot(2, 1, 2); + if ~nograph, h = subplot(2, 1, 2); end else - h = axes; + if ~nograph, h = axes; end end - [amegsens,afid] = ft_average_sens(megsens, 'fiducials', fid, 'weights', Ntrials, 'feedback', h); Do = sensors(Do, 'MEG', amegsens); Do = fiducials(Do, afid); elseif ~isempty(eegsens) - spm_figure('GetWin','Graphics');clf; - h = axes; + if ~nograph + spm_figure('GetWin','Graphics');clf; + h = axes; + end [aeegsens,afid] = ft_average_sens(eegsens, 'fiducials', fid, 'weights', Ntrials, 'feedback', h); Do = sensors(Do, 'EEG', aeegsens); Do = fiducials(Do, afid); diff --git a/spm_eeg_inv_Mesh2Voxels.m b/spm_eeg_inv_Mesh2Voxels.m index 6e04781c..09c48414 100644 --- a/spm_eeg_inv_Mesh2Voxels.m +++ b/spm_eeg_inv_Mesh2Voxels.m @@ -25,13 +25,13 @@ % (using a graph Laplacian) and then in voxel-space using a conventional % Gaussian filter. %__________________________________________________________________________ -% Copyright (C) 2007-2013 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2007-2017 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_eeg_inv_Mesh2Voxels.m 6412 2015-04-20 10:14:50Z vladimir $ +% $Id: spm_eeg_inv_Mesh2Voxels.m 7094 2017-06-06 11:14:10Z guillaume $ -SVNrev = '$Rev: 6412 $'; +SVNrev = '$Rev: 7094 $'; %-Startup %-------------------------------------------------------------------------- @@ -137,6 +137,7 @@ %-Save mesh data %---------------------------------------------------------------------- spm_progress_bar('Init',numel(ssq),'Exporting as meshes',''); + fprintf('%-40s: %30s','Export as meshes','...please wait'); %-# for c = 1:numel(ssq) fprintf('%s%30s',repmat(sprintf('\b'),1,30),... @@ -206,7 +207,7 @@ sprintf('%s_%.0f_%s%.0f.nii', name, val, str, ucon(c))); %-Initialise image - %---------------------------------------------------------------------- + %------------------------------------------------------------------ N = nifti; N.dat = file_array(fname, [Vin.dim, length(ind)], 'FLOAT32-LE'); N.mat = Vin.mat; @@ -219,27 +220,27 @@ n = n+1; fprintf('%s%30s',repmat(sprintf('\b'),1,30),... - sprintf('...image %d/%d',n,numel(ssq))); %-# + sprintf('...image %d/%d',n,numel(ssq))); %-# %-Normalise - %---------------------------------------------------------------------- + %-------------------------------------------------------------- Contrast = ssq{ind(i)} / scale; %-Interpolate those values into voxels - %---------------------------------------------------------------------- + %-------------------------------------------------------------- RECimage = spm_mesh_to_grid(m, Vin, Contrast); %-3D smoothing and thresholding - %---------------------------------------------------------------------- + %-------------------------------------------------------------- spm_smooth(RECimage, RECimage, 1); RECimage = RECimage.*(RECimage > exp(-8)); %-Write (smoothed and scaled) image - %---------------------------------------------------------------------- + %-------------------------------------------------------------- N.dat(:, :, :, i) = RECimage; %-Store filename - %---------------------------------------------------------------------- + %-------------------------------------------------------------- D.inv{val}.contrast.fname{n} = fname; spm_progress_bar('Set', n); diff --git a/spm_eeg_inv_checkdatareg.m b/spm_eeg_inv_checkdatareg.m index fa03f8aa..79b5d103 100644 --- a/spm_eeg_inv_checkdatareg.m +++ b/spm_eeg_inv_checkdatareg.m @@ -8,7 +8,7 @@ function spm_eeg_inv_checkdatareg(varargin) % Copyright (C) 2005-2014 Wellcome Trust Centre for Neuroimaging % Jeremie Mattout -% $Id: spm_eeg_inv_checkdatareg.m 6884 2016-09-19 14:07:46Z vladimir $ +% $Id: spm_eeg_inv_checkdatareg.m 7010 2017-02-07 18:15:30Z vladimir $ % Inputs @@ -81,7 +81,11 @@ function spm_eeg_inv_checkdatareg(varargin) % Sensors (coreg.) %-------------------------------------------------------------------------- -ft_plot_sens(sensors, 'chantype', unique(lower(D.chantype(D.indchantype(modality)))), 'edgecolor', [0 1 0]); +try + ft_plot_sens(sensors, 'chantype', unique(lower(D.chantype(D.indchantype(modality)))), 'edgecolor', [0 1 0]); +catch + ft_plot_sens(sensors,'edgecolor', [0 1 0], 'coilshape', 'point', 'coil', true); +end axis normal; % @@ -101,7 +105,6 @@ function spm_eeg_inv_checkdatareg(varargin) view(-135,45) % cameratoolbar('setmode','orbit') hold off -zoom(5/3) %-Display channels %========================================================================== diff --git a/spm_eeg_inv_checkforward.m b/spm_eeg_inv_checkforward.m index defc5e25..74d4ba4c 100644 --- a/spm_eeg_inv_checkforward.m +++ b/spm_eeg_inv_checkforward.m @@ -5,7 +5,7 @@ function spm_eeg_inv_checkforward(varargin) % Copyright (C) 2008-2014 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_eeg_inv_checkforward.m 6182 2014-09-18 12:03:18Z guillaume $ +% $Id: spm_eeg_inv_checkforward.m 7169 2017-09-19 10:42:27Z vladimir $ %-SPM data structure @@ -69,10 +69,12 @@ function spm_eeg_inv_checkforward(varargin) ft_plot_vol(vol, 'edgecolor', [0 0 0], 'facealpha', 0); -if ft_senstype(sens, 'eeg') - ft_plot_sens(sens, 'style', '*g', 'coil', true); -else - ft_plot_sens(sens, 'style', '*g'); +hold on + +try + ft_plot_sens(sens, 'style', '*', 'edgecolor', 'g', 'elecsize', 20, 'coil', ft_senstype(sens, 'eeg')); +catch + ft_plot_sens(sens, 'edgecolor', 'g', 'coilshape', 'point', 'elecsize', 20, 'coil', true); end rotate3d on; diff --git a/spm_eeg_inv_datareg.m b/spm_eeg_inv_datareg.m index a8424f67..73d24e37 100644 --- a/spm_eeg_inv_datareg.m +++ b/spm_eeg_inv_datareg.m @@ -1,5 +1,5 @@ function M1 = spm_eeg_inv_datareg(S) -% Co-registration of two setse of fiducials according to sets of +% Co-registration of two sets of fiducials according to sets of % corresponding points and (optionally) headshapes. % rigid co-registration % 1: fiducials based (3 landmarks: nasion, left ear, right ear) @@ -30,16 +30,12 @@ % this is generalized to a full twelve parameter affine mapping (n.b. % this might not be appropriate for MEG data). %__________________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % Jeremie Mattout -% $Id: spm_eeg_inv_datareg.m 3833 2010-04-22 14:49:48Z vladimir $ +% $Id: spm_eeg_inv_datareg.m 7112 2017-06-16 11:30:37Z guillaume $ -if nargin == 0 || ~isstruct(S) - error('Input struct is required'); -end - if ~isfield(S, 'targetfid') error('Target fiducials are missing'); else @@ -71,7 +67,7 @@ if S.template - % constatined affine transform + % constrained affine transform %-------------------------------------------------------------------------- aff = S.template; for i = 1:64 @@ -102,10 +98,10 @@ end -% Surface matching between the scalp vertices in MRI space and -% the headshape positions in data space +% Surface matching between the scalp vertices in MRI space and the +% headshape positions in data space %-------------------------------------------------------------------------- -if ~isempty(sourcefid.pnt) && S.useheadshape +if ~isempty(sourcefid.pnt) && S.useheadshape headshape = sourcefid.pnt; scalpvert = targetfid.pnt; @@ -121,18 +117,23 @@ % intialise plot %---------------------------------------------------------------------- - h = spm_figure('GetWin','Graphics'); - clf(h); figure(h) - set(h,'DoubleBuffer','on','BackingStore','on'); - Fmri = plot3(scalpvert(:,1),scalpvert(:,2),scalpvert(:,3),'ro','MarkerFaceColor','r'); - hold on; - Fhsp = plot3(headshape(:,1),headshape(:,2),headshape(:,3),'bs','MarkerFaceColor','b'); - axis off image - drawnow + if ~spm('CmdLine') + h = spm_figure('GetWin','Graphics'); + spm_figure('Select',h); + spm_clf(h); + Fmri = plot3(scalpvert(:,1),scalpvert(:,2),scalpvert(:,3),'ro','MarkerFaceColor','r'); + hold on; + Fhsp = plot3(headshape(:,1),headshape(:,2),headshape(:,3),'bs','MarkerFaceColor','b'); + axis off image + drawnow + else + Fmri = []; + Fhsp = []; + end % nearest point registration %---------------------------------------------------------------------- - M = spm_eeg_inv_icp(scalpvert',headshape',targetfid.fid.pnt',sourcefid.fid.pnt',Fmri,Fhsp,aff); + M = spm_eeg_inv_icp(scalpvert',headshape',targetfid.fid.pnt',sourcefid.fid.pnt',Fmri,Fhsp,aff); % transform headshape and eeg fiducials %---------------------------------------------------------------------- diff --git a/spm_eeg_inv_datareg_ui.m b/spm_eeg_inv_datareg_ui.m index e2ef91b6..23ed8553 100644 --- a/spm_eeg_inv_datareg_ui.m +++ b/spm_eeg_inv_datareg_ui.m @@ -1,7 +1,5 @@ function D = spm_eeg_inv_datareg_ui(varargin) -% Data registration user-interface routine -% commands the EEG/MEG data co-registration within original sMRI space -% +% User interface for EEG/MEG data coregistration within original sMRI space % FORMAT D = spm_eeg_inv_datareg_ui(D,[val], [meegfid, newmrifid, useheadshape]) % D - M/EEG dataset % @@ -11,12 +9,13 @@ % % D - same data struct including the new required files and variables %__________________________________________________________________________ -% Copyright (C) 2005-2014 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_eeg_inv_datareg_ui.m 6182 2014-09-18 12:03:18Z guillaume $ +% $Id: spm_eeg_inv_datareg_ui.m 7098 2017-06-07 15:00:03Z guillaume $ + -% initialise +%-Initialisation %-------------------------------------------------------------------------- [Finter, Fgraph] = spm('FnUIsetup','MEEG/MRI coregistration', 0); @@ -27,19 +26,21 @@ if nargin>=3 meegfid = varargin{3}; - interactive = 0; + interactive = false; else - interactive = 1; + interactive = true; meegfid = D.fiducials; meeglbl = meegfid.fid.label; if numel(meeglbl)> 3 - [selection,ok]= listdlg('ListString', meeglbl, 'SelectionMode', 'multiple',... + [selection,ok] = listdlg('ListString', meeglbl, ... + 'SelectionMode', 'multiple',... 'InitialValue', spm_match_str(upper(meeglbl), upper(mrilbl)), ... - 'Name', 'Select at least 3 fiducials', 'ListSize', [400 300]); + 'Name', 'Select at least 3 fiducials', ... + 'ListSize', [400 300]); if ~ok || length(selection) < 3 - error('At least 3 M/EEG fiducials are required for coregistration'); + error('At least 3 M/EEG fiducials are required for coregistration.'); end meegfid.fid.pnt = meegfid.fid.pnt(selection, :); @@ -49,12 +50,12 @@ meeglbl = meegfid.fid.label; -if numel(meeglbl)<3 - error('At least 3 M/EEG fiducials are required for coregistration'); +if numel(meeglbl) < 3 + error('At least 3 M/EEG fiducials are required for coregistration.'); end if all(ismember({'spmnas', 'spmlpa', 'spmrpa'}, meegfid.fid.label)) && isempty(D.sensors('MEG')) - S =[]; + S = []; S.sourcefid = meegfid; S.targetfid = mrifid; @@ -71,7 +72,7 @@ S.targetfid.fid.label = S.targetfid.fid.label(1:3, :); S.useheadshape = 1; end -elseif nargin>=4 +elseif nargin >= 4 M1 = []; S.sourcefid = meegfid; S.targetfid = varargin{4}; @@ -96,7 +97,7 @@ newmrifid.fid.pnt = [newmrifid.fid.pnt; mrifid.fid.pnt(selection, :)]; case 'type' - pnt = spm_input('Input MNI coordinates', '+1', 'r', '', 3); + pnt = spm_input('MRI coordinates {mm}', '+1', 'r', '', 3); newmrifid.fid.pnt = [newmrifid.fid.pnt; pnt(:)']; case 'click' while 1 @@ -128,7 +129,7 @@ % register %====================================================================== - S =[]; + S = []; S.sourcefid = meegfid; S.targetfid = newmrifid; end @@ -178,14 +179,14 @@ D.inv{val}.datareg(ind).modality = 'MEG'; end -% check and display registration +%-Check and display registration %-------------------------------------------------------------------------- -if interactive - if ~spm('CmdLine') +if ~spm('CmdLine') + if interactive spm_eeg_inv_checkdatareg(D); - end -else - for i = 1:numel(D.inv{val}.datareg) - spm_eeg_inv_checkdatareg(D, val, i); + else + for i = 1:numel(D.inv{val}.datareg) + spm_eeg_inv_checkdatareg(D, val, i); + end end end diff --git a/spm_eeg_inv_extract.m b/spm_eeg_inv_extract.m index 76b340b4..aebdb8c4 100644 --- a/spm_eeg_inv_extract.m +++ b/spm_eeg_inv_extract.m @@ -15,7 +15,7 @@ % Copyright (C) 2011 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak, Laurence Hunt, Karl Friston -% $Id: spm_eeg_inv_extract.m 6231 2014-10-07 13:42:16Z vladimir $ +% $Id: spm_eeg_inv_extract.m 7009 2017-02-07 18:14:16Z vladimir $ % SPM data structure %========================================================================== @@ -145,7 +145,7 @@ % unimodal data %------------------------------------------------------ - Y = D(Ic{1},It,c(j)); + Y = D(Ic{1},It,c(j))*TT; Y = U{1}*Y*scale; else @@ -153,7 +153,7 @@ % multimodal data %------------------------------------------------------ for k = 1:length(U) - Y = D(Ic{k},It,c(j)); + Y = D(Ic{k},It,c(j))*TT; UY{k,1} = U{k}*Y*scale(k); end Y = spm_cat(UY); diff --git a/spm_eeg_inv_forward.m b/spm_eeg_inv_forward.m index 6fe2d2fd..0f83b131 100644 --- a/spm_eeg_inv_forward.m +++ b/spm_eeg_inv_forward.m @@ -9,24 +9,30 @@ % Output: % D - EEG/MEG struct with filenames of Gain matrices) %__________________________________________________________________________ -% Copyright (C) 2008-2014 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2008-2017 Wellcome Trust Centre for Neuroimaging % Jeremie Mattout & Christophe Phillips -% $Id: spm_eeg_inv_forward.m 6819 2016-06-22 15:07:42Z vladimir $ +% $Id: spm_eeg_inv_forward.m 7116 2017-06-20 09:21:27Z guillaume $ +SVNrev = '$Rev'; + +%-Startup +%-------------------------------------------------------------------------- +spm('FnBanner', mfilename, SVNrev); + %-Initialisation %-------------------------------------------------------------------------- [D, val] = spm_eeg_inv_check(varargin{:}); if numel(D.inv{val}.datareg) ~= numel(D.inv{val}.forward) - error('Separate coregistration is required for every modality'); + error('Separate coregistration is required for every modality.'); end Fgraph = spm_figure('FindWin','Graphics'); spm_figure('Clear',Fgraph); spm('Pointer', 'Watch'); -if isempty(Fgraph) || spm('CmdLine'), graph = 'no'; else graph = 'yes'; end +if isempty(Fgraph) || spm('CmdLine'), graph = 'no'; else, graph = 'yes'; end for i = 1:numel(D.inv{val}.forward) M = D.inv{val}.datareg(i).fromMNI*D.inv{val}.mesh.Affine; @@ -73,12 +79,12 @@ vol = ft_prepare_headmodel(cfg, headshape); cfg = []; - cfg.vol = vol; - cfg.grid.pos = mesh.tess_ctx.vert; - cfg.spherify = 'yes'; - gridsphere = ft_prepare_sourcemodel(cfg); + cfg.headmodel = vol; + cfg.grid.pos = mesh.tess_ctx.vert; + cfg.spherify = 'yes'; + gridsphere = ft_prepare_sourcemodel(cfg); - mesh_correction = rmfield(cfg, {'vol', 'grid'}); + mesh_correction = rmfield(cfg, {'headmodel', 'grid'}); mesh.tess_ctx.vert = gridsphere.pos; modality = 'EEG'; @@ -113,9 +119,9 @@ cfg.siunits = 'yes'; vol = ft_prepare_headmodel(cfg, vol); - spm_progress_bar('Set', 1); drawnow; + spm_progress_bar('Set', 1); - save(volfile, 'vol'); + save(volfile, 'vol', spm_get_defaults('mat.format')); spm_progress_bar('Clear'); spm('Pointer', 'Arrow'); @@ -200,7 +206,7 @@ modality = 'MEG'; otherwise - error('Unsupported volume model type'); + error('Unsupported volume model type.'); end D.inv{val}.forward(i).vol = vol; @@ -220,4 +226,5 @@ % This is to force recomputing the lead fields try, D.inv{val} = rmfield(D.inv{val}, 'gainmat'); end +fprintf('%-40s: %30s\n','Completed',spm('time')); %-# spm('Pointer', 'Arrow'); diff --git a/spm_eeg_inv_prep_modes_xval.m b/spm_eeg_inv_prep_modes_xval.m index 8a8a153a..388d7dbe 100644 --- a/spm_eeg_inv_prep_modes_xval.m +++ b/spm_eeg_inv_prep_modes_xval.m @@ -1,127 +1,127 @@ -function [spatialmodename,Nmodes,newpctest,testchans]=spm_eeg_inv_prep_modes_xval(filenames, Nmodes, spatialmodename,Nblocks,pctest); -%function [spatialmodename,Nmodes,newpctest,testchans]=spm_eeg_inv_prep_modes_xval(filenames, Nmodes, spatialmodename,Nblocks,pctest); - - -%% prepare a spatial mode file for inversion -%% this file ensures the same spatial modes are used across different files (which would contain the same data but different head-models for example) -%% it also makes sure that the same channels groups are preserved to allow comparable cross validation and free energy metrics -%% input a list of the M/EEG dataset names: filenames -% Nmodes - number of required spatial modes (if empty uses all available -% channels) -% channels) -% spatialmodename- name of output file -% Nblocks- number of cross validation runs (optional and -% default 1) -% pctest- percentatge of channels to be used for testdata (optional and -% default 0) -%% if pctest*Nblocks=100 then will use independent MEG channels and may adjust pctest (in output) to -%% accomodate this. ( k-fold cross val) -%% if pctest*Nblocks~=100 then uses random selection of pctest channels for each block (Monte-Carlo cross val) - -%% in output file -%% megind- good meg channel indices -%% testchans - indices to megind of channels to be turned off during training phase (and tested later) -%% U{} - a different spatial modes matrix for each set of training channels or megind without indexed testchans or megind(setdiff(1:length(megind),testchans(b,:))) - -% Copyright (C) 2010 Wellcome Trust Centre for Neuroimaging -% -% Gareth Barnes -% $Id: spm_eeg_inv_prep_modes_xval.m 1 2016-09-12 15:02:25Z gareth $ - - - -if nargin<4, - Nblocks=[]; -end; -if nargin<5, - pctest=[]; -end; - -if isempty(Nblocks), - Nblocks=1; -end; -if isempty(pctest), - pctest=0; -end; - -Nfiles=size(filenames,1); -%% get lead fields for all files /headmodels and get unbiased mixture - -D=spm_eeg_load(deblank(filenames(1,:))); -val=D.val; -megind=D.indchantype(D.inv{val}.forward.modality); -origbadchans=D.badchannels; - -megind=setdiff(megind,origbadchans); -fprintf('Removed %d bad channels\n',length(origbadchans)); - -newpctest=pctest; -if round(Nblocks*pctest)==100, - newpctest=floor(length(megind)/Nblocks)/length(megind)*100; - fprintf('\nAdjusting pc test from %3.2f to %3.2f percent to make use of most MEG channels',pctest,newpctest); - -else - fprintf('\nTaking random selections of %3.2f percent of channels',newpctest); -end; - - -Ntest=round(newpctest*length(megind)/100); %% number of test channels per block - -testchans=zeros(Nblocks,Ntest); -Ntrain=length(megind)-Ntest; - -if isempty(Nmodes), - Nmodes=length(megind)-Ntest; - fprintf('\nUsing maximum of %d spatial modes\n',Nmodes); -else - fprintf('\nUsing %d spatial modes\n',Nmodes); -end; -allL=spm_eeg_lgainmat(D); - -if size(allL,1)~=length(megind), - error('Mismatch in channel numbers (internal error)'); -end; - - -U={}; -useind=zeros(Nblocks,Ntrain); -testchans=zeros(Nblocks,Ntest); - -alldum=randperm(length(megind)); - -for b=1:Nblocks, - if round(Nblocks*pctest)==100, - dum=alldum((b-1)*Ntest+1:b*Ntest); - else - dum=randperm(length(megind)); - end; - - testchans(b,:)=dum(1:Ntest); %% channels which will be used for testing (Set to bad during training) - useind(b,:)=setdiff(1:length(megind),testchans(b,:)); %% training channels used here to get the spatial modes -end; - -for f=2:Nfiles, - D=spm_eeg_load(deblank(filenames(f,:))); - val=D.val; - if D.indchantype(D.inv{val}.forward.modality)~=megind, - error('different active channels in these files'); - end; - L=spm_eeg_lgainmat(D); - allL=[allL L]; %% make composite lead field matrix -end; % for f - - -U={}; - -for b=1:Nblocks, - fprintf('\nPreparing modes file %d block %d of %d for %d training and %d test chans\n',f, b,Nblocks,Ntrain,Ntest); - if Nmodes 0 + writerObj = VideoWriter(filename,'Uncompressed AVI'); + writerObj.FrameRate = 24; + open(writerObj); + writeVideo(writerObj,M); + close(writerObj); + else + movie2avi(M,filename,'compression','Indeo3','FPS',24); %#ok + end end @@ -636,13 +644,21 @@ function movie_sens_Callback(hObject, eventdata, handles) % record movie if requested %---------------------------------------------------------------------- - if MOVIE, M(t) = getframe(handles.sensors_axes); end; + if MOVIE, M(t) = getframe(handles.sensors_axes); end end UpDate_Display_SRCS(hObject,handles); try filename = fullfile(handles.D.path,'SensorMovie'); - movie2avi(M,filename,'compression','Indeo3','FPS',24) + if spm_check_version('matlab','7.10') > 0 + writerObj = VideoWriter(filename,'Uncompressed AVI'); + writerObj.FrameRate = 24; + open(writerObj); + writeVideo(writerObj,M); + close(writerObj); + else + movie2avi(M,filename,'compression','Indeo3','FPS',24); %#ok + end end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/spm_eeg_invert.m b/spm_eeg_invert.m index e9c83a44..4df5462b 100644 --- a/spm_eeg_invert.m +++ b/spm_eeg_invert.m @@ -1,6 +1,6 @@ function [D] = spm_eeg_invert(D, val) % ReML inversion of multiple forward models for EEG-MEG -% FORMAT [D] = spm_eeg_invert(D) +% FORMAT [D] = spm_eeg_invert(D, val) % ReML estimation of regularisation hyperparameters using the % spatiotemporal hierarchy implicit in EEG/MEG data % @@ -111,7 +111,7 @@ % See: A Parametric Empirical Bayesian framework for fMRI-constrained % MEG/EEG source reconstruction. % Henson R, Flandin G, Friston K & Mattout J. -% Human Brain Mapping (in press). +% Human Brain Mapping. 2010. 1(10):1512-31. %__________________________________________________________________________ % % The routine essentially consists of two steps: @@ -119,11 +119,18 @@ % 1. Optimisation of spatial source priors over subjects % 2. Re-inversion of each subject, fusing across all modalities %__________________________________________________________________________ -% Copyright (C) 2006-2014 Wellcome Trust Centre for Neuroimaging - +% Copyright (C) 2006-2017 Wellcome Trust Centre for Neuroimaging + % Karl Friston -% $Id: spm_eeg_invert.m 6636 2015-12-05 23:28:50Z vladimir $ - +% $Id: spm_eeg_invert.m 7118 2017-06-20 10:33:27Z guillaume $ + + +SVNid = '$Rev: 7118 $'; + +%-Say hello +%-------------------------------------------------------------------------- +spm('FnBanner',mfilename,SVNid); + % check whether this is a group inversion for (Nl) number of subjects %-------------------------------------------------------------------------- if ~iscell(D), D = {D}; end @@ -162,7 +169,8 @@ try, woi = inverse.woi; catch, woi = []; end try, pQ = inverse.pQ; catch, pQ = []; end try, dp = inverse.dplot; catch, dp = 0; end - + + % get specified modalities to invert (default to all) %-------------------------------------------------------------------------- try @@ -195,12 +203,12 @@ Nc(i,m) = length(Ic{i,m}); if isempty(Ic{i,m}) - errordlg(['Modality ' modalities{m} 'is missing from file ' D{i}.fname]); + errordlg(['Modality ' modalities{m} ' is missing from file ' D{i}.fname]); return end if any(diff(Nd)) - errordlg('Please ensure subjects have the same number of dipoles') + errordlg('Please ensure subjects have the same number of dipoles.') return end @@ -220,9 +228,9 @@ % Compute spatial coherence: Diffusion on a normalised graph Laplacian GL %========================================================================== -fprintf('Computing Green function from graph Laplacian:') -%-------------------------------------------------------------------------- -Nd = Nd(1); % number of dipoles +fprintf('%-40s: %30s','Green function from graph Laplacian','...computing'); %-# + +Nd = Nd(1); % number of dipoles vert = D{1}.inv{D{1}.val}.mesh.tess_mni.vert; face = D{1}.inv{D{1}.val}.mesh.tess_mni.face; A = spm_mesh_distmtx(struct('vertices',vert,'faces',face),0); @@ -237,10 +245,11 @@ QG = QG.*(QG > exp(-8)); QG = QG*QG; clear Qi A GL -fprintf(' - done\n') + +fprintf('%s%30s\n',repmat(sprintf('\b'),1,30),'...done') %-# -% check for (e.g., empty-room) sensor components (in Qe{1}) +% Check for (e.g., empty-room) sensor components (in Qe{1}) %========================================================================== QE = cell(Nl,Nmod); for i = 1:Nl @@ -257,7 +266,6 @@ % assume i.i.d. if not specified %------------------------------------------------------------------ catch - QE{i,m} = 1; end end @@ -436,6 +444,13 @@ T = T(:,j); dct{i} = dct{i}(j); + % notch filter nf (Hz) + %---------------------------------------------------------------------- + % nf = 10.2/1000; + try + T0 = [sin(2*pi*nf*pst{i}(:)) cos(2*pi*nf*pst{i}(:))]; + T = T - T0*pinv(T0)*T; + end % Hanning operator (if requested) %---------------------------------------------------------------------- @@ -499,7 +514,7 @@ VE(i) = 1; % variance explained else - [U E] = spm_svd(YTY,exp(-8)); % get temporal modes + [U,E] = spm_svd(YTY,exp(-8)); % get temporal modes E = diag(E)/trace(YTY); % normalise variance Nr(i) = min(length(E),Nmax); % number of temporal modes S{i} = T*U(:,1:Nr(i)); % temporal modes @@ -596,12 +611,13 @@ %========================================================================== switch(type) - case {'MSP','GS','ARD'} + case {'MSP','GS','ARD','BMR'} % create MSP spatial basis set in source space %------------------------------------------------------------------ Qp = {}; LQpL = {}; + LQL = {}; Ip = ceil([1:Np]*Ns/Np); for i = 1:Np @@ -625,7 +641,7 @@ q = QG(:,Ip(i)) + QG(:,j); Qp{end + 1}.q = q; LQpL{end + 1}.q = UL*q; - + end case {'LOR','COH'} @@ -653,18 +669,18 @@ % Source reconstruction accuracy of MEG and EEG Bayesian inversion approaches. % Belardinelli P, Ortiz E, Barnes G, Noppeney U, Preissl H. PLoS One. 2012;7(12):e51985. %------------------------------------------------------------------ - InvCov = spm_inv(YY); - allsource = zeros(Ns,1); + InvCov = spm_inv(YY); + allsource = zeros(Ns,1); Sourcepower = zeros(Ns,1); for bk = 1:Ns - normpower = 1/(UL(:,bk)'*UL(:,bk)); + normpower = 1/(UL(:,bk)'*UL(:,bk)); Sourcepower(bk) = 1/(UL(:,bk)'*InvCov*UL(:,bk)); - allsource(bk) = Sourcepower(bk)./normpower; + allsource(bk) = Sourcepower(bk)./normpower; end allsource = allsource/max(allsource); % Normalise - Qp{1} = diag(allsource); - LQpL{1} = UL*diag(allsource)*UL'; + Qp{1} = diag(allsource); + LQpL{1} = UL*diag(allsource)*UL'; end @@ -675,7 +691,7 @@ switch(type) - case {'MSP','GS','ARD'} + case {'MSP','GS','ARD','BMR'} %-------------------------------------------------------------- if isvector(pQ{i}) && length(pQ{i}) == Ns @@ -737,7 +753,6 @@ % Accumulate empirical priors %------------------------------------------------------------------ - Qcp = Q*MVB.cp; QP{end + 1} = sum(Qcp.*Q,2); LQP{end + 1} = (UL*Qcp)*Q'; @@ -745,7 +760,49 @@ end - +switch(type) + + case {'BMR'} + + % convert patterns into covariance components + %------------------------------------------------------------------ + Np = length(Qp); + for i = 1:Np + LQpL{i} = LQpL{i}.q*LQpL{i}.q'; + end + + % hyperparameter estimation + %------------------------------------------------------------------ + [C,h,Ph,F,Fa,Fc,Eh,Ch,hE,hC] = spm_reml_sc(AYYA,[],[Qe LQpL],sum(Nn),-16,32); + + + % Bayesian model reduction + %------------------------------------------------------------------ + DCM.M.pE = hE; + DCM.M.pC = hC; + DCM.Ep = Eh; + DCM.Cp = Ch; + h = spm_dcm_sparse(DCM); + + % Spatial priors (QP) + %------------------------------------------------------------------ + Ne = length(Qe); + Np = length(Qp); + hp = h((1:Np) + Ne); + qp = sparse(0); + for i = 1:Np + qp = qp + hp(i)*Qp{i}.q*Qp{i}.q'; + end + + % Accumulate empirical priors + %------------------------------------------------------------------ + QP{end + 1} = diag(qp); + LQP{end + 1} = UL*qp; + LQPL{end + 1} = LQP{end}*UL'; + +end + + switch(type) case {'MSP','ARD'} @@ -758,7 +815,7 @@ %------------------------------------------------------------------ Ne = length(Qe); Np = length(Qp); - hp = h([1:Np] + Ne); + hp = h((1:Np) + Ne); qp = sparse(0); for i = 1:Np if hp(i) > max(hp)/128; @@ -780,7 +837,7 @@ % or ReML - ARD %------------------------------------------------------------------ - Q0 = exp(-2)*trace(AYYA)/sum(Nn)*AQ{1}/trace(AQ{1}); + Q0 = exp(-2)*trace(AYYA)/sum(Nn)*AQ{1}/trace(AQ{1}); [C,h] = spm_reml_sc(AYYA,[],[Qe LQpL],sum(Nn),-4,16,Q0); % Spatial priors (QP) @@ -874,8 +931,8 @@ % sum of squares %------------------------------------------------------------------ - SSR = SSR + sum(var((UY{i,j} - UL*J{j}),0,2)); - SST = SST + sum(var( UY{i,j},0,2)); + SSR = SSR + sum(var(full(UY{i,j} - UL*J{j}),0,2)); + SST = SST + sum(var(full(UY{i,j}),0,2)); end @@ -931,3 +988,5 @@ end if length(D) == 1, D = D{1}; end + +fprintf('%-40s: %30s\n','Completed',spm('time')) %-# diff --git a/spm_eeg_invert_prepro.m b/spm_eeg_invert_prepro.m index 447e23d2..ab5b28a0 100644 --- a/spm_eeg_invert_prepro.m +++ b/spm_eeg_invert_prepro.m @@ -21,12 +21,11 @@ % 'MSP' GS and ARD multiple sparse priors % 'LOR' LORETA-like model % 'IID' minimum norm -% 'EBB' for empirical bayes beamformer +% 'EBB' for empirical bayes beamformer % inverse.priors{} - a cell array of anatomical and functional priors to be % considered -%% - +% % inverse.woi - time window of interest ([start stop] in ms) % inverse.lpf - band-pass filter - low frequency cut-off (Hz) % inverse.hpf - band-pass filter - high frequency cut-off (Hz) @@ -85,7 +84,7 @@ % Copyright (C) 2015 Wellcome Trust Centre for Neuroimaging % Jose David Lopez, Gareth Barnes, Vladimir Litvak -% $Id: spm_eeg_invert_prepro.m 6618 2015-12-01 16:25:38Z spm $ +% $Id: spm_eeg_invert_prepro.m 7017 2017-02-15 12:50:58Z karl $ Nl = length(D); @@ -119,47 +118,36 @@ try, type = inverse.type; catch, type = 'GS'; end try, s = inverse.smooth; catch, s = 0.6; end try, Np = inverse.Np; catch, Np = 256; end -try, Nr = inverse.Nr; catch, Nr = 16; end %% requested number of temporal modes, could be changed depending on svd +try, Nr = inverse.Nr; catch, Nr = 16; end % requested number of temporal modes, could be changed depending on svd try, xyz = inverse.xyz; catch, xyz = [0 0 0]; end try, rad = inverse.rad; catch, rad = 128; end -try, hpf = inverse.hpf; catch, hpf = 48; end %% need to one day put these the correct way round +try, hpf = inverse.hpf; catch, hpf = 48; end % need to one day put these the correct way round try, lpf = inverse.lpf; catch, lpf = 0; end try, sdv = inverse.sdv; catch, sdv = 4; end try, Han = inverse.Han; catch, Han = 1; end try, woi = inverse.woi; catch, woi = []; end try, Nm = inverse.Nm; catch, Nm = []; end -try, Nt = inverse.Nt; catch, Nt = []; end %% fixed number of temporal modes +try, Nt = inverse.Nt; catch, Nt = []; end % fixed number of temporal modes try, Ip = inverse.Ip; catch, Ip = []; end -try, QE = inverse.QE; catch, QE=1; end % empty room noise measurement -try, Qe0 = inverse.Qe0; catch, Qe0 = exp(-5); end %% set noise floor at 1/100th signal power i.e. assume amplitude SNR of 10 -try, inverse.A; catch, inverse.A = []; end %% orthogonal channel modes - - - -% defaults -%-------------------------------------------------------------------------- -%type = inverse.type; % Type of inversion scheme +try, QE = inverse.QE; catch, QE = 1; end % empty room noise measurement +try, Qe0 = inverse.Qe0; catch, Qe0 = exp(-5); end % set noise floor at 1/100th signal power i.e. assume amplitude SNR of 10 +try, inverse.A; catch, inverse.A = [];end % orthogonal channel modes % get specified modalities to invert (default to all) - %-------------------------------------------------------------------------- -modalities = D.inv{val}.forward.modality; % MEG in this case - -Nmax = 16; % max number of temporal modes +modalities = D.inv{val}.forward.modality; % MEG in this case +Nmax = 16; % max number of temporal modes % check lead fields and get number of dipoles (Nd) and channels (Nc) %========================================================================== - fprintf('Checking leadfields') -[L,D] = spm_eeg_lgainmat(D); % Generate/load lead field -Nd=size(L,2); - +[L,D] = spm_eeg_lgainmat(D); % Generate/load lead field +Nd = size(L,2); % Check gain or lead-field matrices %------------------------------------------------------------------ - if size(modalities,1)>1, error('not defined for multiple modalities'); end; @@ -168,8 +156,6 @@ Nd = size(L,2); % Number of dipoles - - %========================================================================== % Spatial projectors (adjusting for different Lead-fields) %========================================================================== @@ -182,10 +168,10 @@ %inverse.A=eye(length(Ic)); Nm=size(inverse.A,1); if isempty(inverse.A), % no spatial modes prespecified - if isempty(Nm), %% number of modes not specifiedd - [U,ss,vv] = spm_svd((L*L'),exp(-16)); - A = U'; % spatial projector A - UL = A*L; + if isempty(Nm), % number of modes not specifiedd + [U,ss,vv] = spm_svd((L*L'),exp(-16)); + A = U'; % spatial projector A + UL = A*L; else % number of modes pre-specified [U,ss,vv] = spm_svd((L*L'),0); @@ -193,10 +179,8 @@ disp('number available'); length(ss) error('Not this many spatial modes in lead fields'); - - end; - - ss=ss(1:Nm); + end + ss = ss(1:Nm); disp('using preselected number spatial modes !'); A = U(:,1:Nm)'; % spatial projector A UL = A*L; @@ -205,13 +189,12 @@ disp('Using pre-specified spatial modes'); if isempty(Nm), error('Need to specify number of spatial modes if U is prespecified'); - end; - % - A=inverse.A; - UL=A*L; + end + A = inverse.A; + UL = A*L; end; -Nm = size(UL,1); % Number of spatial projectors +Nm = size(UL,1); % Number of spatial projectors clear ss vv @@ -231,9 +214,9 @@ %---------------------------------------------------------------------- if isempty(woi) - w = 1000*[min(D.time) max(D.time)]; + w = 1000*[min(D.time) max(D.time)]; else - w=woi; %% in milliseconds + w = woi; %% in milliseconds end; It = (w/1000 - D.timeonset)*D.fsample + 1; @@ -241,8 +224,6 @@ It = fix(It); disp(sprintf('Number of samples %d',length(It))); - - % Peristimulus time %---------------------------------------------------------------------- pst = 1000*D.time; % peristimulus time (ms) @@ -259,21 +240,18 @@ % Confounds and temporal subspace %---------------------------------------------------------------------- - -T = spm_dctmtx(Nb,Nb); % use plot(T) here! - +T = spm_dctmtx(Nb,Nb); % use plot(T) here j = find( (dct >= lpf) & (dct <= hpf) ); %% THis is the wrong way round but leave for nowfor compatibility with spm_eeg_invert T = T(:,j); % Apply the filter to discrete cosines dct = dct(j); % Frequencies accepted -%% Hanning window +% Hanning window %---------------------------------------------------------------------- - if Han W = sparse(1:Nb,1:Nb,spm_hanning(Nb)); %% use hanning unless specified else - W=1; -end; + W = 1; +end @@ -284,37 +262,33 @@ catch trial = D.condlist; end -Ntrialtypes=length(trial); +Ntrialtypes = length(trial); + % get temporal covariance (Y'*Y) to find temporal modes %====================================================================== - YY = 0; - -N=0; +N = 0; badtrialind=D.badtrials; -for j = 1:Ntrialtypes, % pool over conditions - c = D.indtrial(trial{j}); % and trials - - c=setxor(c,badtrialind); %% ignore bad trials +for j = 1:Ntrialtypes, % pool over conditions + c = D.indtrial(trial{j}); % and trials + c = setxor(c,badtrialind); % ignore bad trials Nk = length(c); for k = 1:Nk - Y = A*D(Ic{1},It,c(k)); + Y = A*D(Ic{1},It,c(k)); - YY = YY + Y'*Y; - N = N + 1; + YY = YY + Y'*Y; + N = N + 1; end end -YY=YY./N; +YY = YY./N; % Apply any Hanning and filtering %------------------------------------------------------------------ -YY = W'*YY*W; % Hanning -YTY = T'*YY*T; % Filter - +YY = W'*YY*W; % Hanning +YTY = T'*YY*T; % Filter %====================================================================== - if isempty(Nt), %% automatically assign appropriate number of temporal modes [U E] = spm_svd(YTY,exp(-8)); % get temporal modes if isempty(U), %% fallback @@ -349,79 +323,67 @@ %====================================================================== % loop over Ntrialtypes trial types %---------------------------------------------------------------------- -UYYU = 0; -AYYA=0; -Nn =0; % number of samples -AY={}; -Ntrials=0; +UYYU = 0; +AYYA = 0; +Nn = 0; % number of samples +AY = {}; +Ntrials = 0; for j = 1:Ntrialtypes, - UY{j} = sparse(0); - c = D.indtrial(trial{j}); - c=setxor(c,badtrialind); %% ignore bad trials + c = D.indtrial(trial{j}); + c = setxor(c,badtrialind); %% ignore bad trials Nk = length(c); % loop over epochs %------------------------------------------------------------------ - for k = 1:Nk % stack (scaled aligned data) over modalities %-------------------------------------------------------------- - - Y = D(Ic{1},It,c(k))*S; %% in temporal subspace - Y=A*Y; %% in spatial subspace + Y = D(Ic{1},It,c(k))*S; %% in temporal subspace + Y = A*Y; %% in spatial subspace % accumulate first & second-order responses %-------------------------------------------------------------- - Nn = Nn + Nr; % number of samples + Nn = Nn + Nr; % number of samples - YY = Y*Y'; % and covariance - Ntrials=Ntrials+1; + YY = Y*Y'; % and covariance + Ntrials = Ntrials+1; % accumulate statistics (subject-specific) %-------------------------------------------------------------- - UY{j} = UY{j} + Y; % condition-specific ERP - UYYU = UYYU + YY; % subject-specific covariance + UY{j} = UY{j} + Y; % condition-specific ERP + UYYU = UYYU + YY; % subject-specific covariance % and pool for optimisation of spatial priors over subjects %-------------------------------------------------------------- - AY{end + 1} = Y; % pooled response for MVB - AYYA = AYYA + YY; % pooled response for ReML + AY{end + 1} = Y; % pooled response for MVB + AYYA = AYYA + YY; % pooled response for ReML end end - -AY=spm_cat(AY); %% goes to MVB/GS algorithm - -ID = spm_data_id(AY); %% get a unique ID for these filtered data - - - +AY = spm_cat(AY); %% goes to MVB/GS algorithm +ID = spm_data_id(AY); %% get a unique ID for these filtered data %====================================================================== inverse.AY=AY; %% concatenated data in reduced spatial modes inverse.AYYA=AYYA;%% sensor level covariance of all trials, conditions and samples (containing Nn temporal modes in total) -%inverse.type = type; % inverse model -%inverse.Y = Y; % ERP data (reduced) -inverse.UY = UY; % ERP data (reduced) -inverse.L = UL; % Lead-field (reduced) -inverse.Nn=Nn; %% number of independent samples (temporal modes* trials* conditions) +inverse.UY = UY; % ERP data (reduced) +inverse.L = UL; % Lead-field (reduced) +inverse.Nn = Nn; %% number of independent samples (temporal modes* trials* conditions) inverse.qV = Vq; % temporal correlations inverse.T = S; % temporal projector inverse.U = {A}; % spatial projector -%inverse.Is = Is; % Indices of active dipoles -inverse.Ic=Ic; %% good channels -inverse.It=It; %% time indices +inverse.Ic = Ic; %% good channels +inverse.It = It; %% time indices inverse.Nd = Nd; % number of dipoles inverse.pst = pst; % peristimulus time inverse.dct = dct; % frequency range - inverse.ID = ID; % data ID inverse.woi = w; % time-window inverted @@ -435,8 +397,4 @@ disp('Done invert prepro'); - - - - return diff --git a/spm_eeg_invert_setuppatches.m b/spm_eeg_invert_setuppatches.m index 273aea96..54981200 100644 --- a/spm_eeg_invert_setuppatches.m +++ b/spm_eeg_invert_setuppatches.m @@ -18,7 +18,7 @@ % Copyright (C) 2010 Wellcome Trust Centre for Neuroimaging % Gareth Barnes -% $Id: spm_eeg_invert_setuppatches.m 6498 2015-07-15 19:13:31Z gareth $ +% $Id: spm_eeg_invert_setuppatches.m 7118 2017-06-20 10:33:27Z guillaume $ Npatchiter=size(allIp,1); @@ -97,7 +97,7 @@ fprintf('Saving %s\n',priorfname); F=[]; % no associated free energy value allpriornames=strvcat(allpriornames,priorfname); - save(priorfname,'Qp','Qe','UL','F'); + save(priorfname,'Qp','Qe','UL','F', spm_get_defaults('mat.format')); end; % for k diff --git a/spm_eeg_invert_ui.m b/spm_eeg_invert_ui.m index 4e4056ef..4ae5db1d 100644 --- a/spm_eeg_invert_ui.m +++ b/spm_eeg_invert_ui.m @@ -16,7 +16,7 @@ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_eeg_invert_ui.m 6849 2016-07-31 12:34:33Z karl $ +% $Id: spm_eeg_invert_ui.m 6933 2016-11-16 14:02:04Z vladimir $ % initialise %-------------------------------------------------------------------------- @@ -85,6 +85,7 @@ % Modality %------------------------------------------------------------------ [mod, list] = modality(D, 1, 1); + list = setdiff(list, 'MEGCOMB'); if strcmp(mod, 'Multimodal') [selection, ok]= listdlg('ListString', list, 'SelectionMode', 'multiple' ,... 'Name', 'Select modalities' , 'InitialValue', 1:numel(list), 'ListSize', [400 300]); diff --git a/spm_eeg_lgainmat.m b/spm_eeg_lgainmat.m index 1918b2ba..4d212f6e 100644 --- a/spm_eeg_lgainmat.m +++ b/spm_eeg_lgainmat.m @@ -1,18 +1,19 @@ function [L,D] = spm_eeg_lgainmat(D,Is,channels) -% loads or computes if necessary a gain matrix -% FORMAT [L,D] = spm_eeg_lgainmat(D,Is) +% Load or compute if necessary a gain matrix +% FORMAT [L,D] = spm_eeg_lgainmat(D,Is,channels) % D - Data structure % Is - indices of vertices % % L - Lead-field or gain matrix L(:,Is) %__________________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2008-2017 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_eeg_lgainmat.m 6849 2016-07-31 12:34:33Z karl $ +% $Id: spm_eeg_lgainmat.m 7118 2017-06-20 10:33:27Z guillaume $ +SVNrev = '$Rev: 7118 $'; -% get gain or lead-field matrix +%-Get gain or lead-field matrix %-------------------------------------------------------------------------- val = D.val; @@ -21,7 +22,7 @@ for ind = 1:numel(forward) modality = forward(ind).modality; - % channels + %-Channels %---------------------------------------------------------------------- if isequal(modality, 'MEG') chanind = D.indchantype({'MEG', 'MEGPLANAR'}, 'GOOD'); @@ -47,21 +48,25 @@ label = G.label; G = G.G; if numel(label) ~= size(G, 1) || ~all(ismember(channels, label)) - error('Gain matrix has an incorrect number of channels'); + error('Gain matrix has an incorrect number of channels.'); end catch + spm('sFnBanner', mfilename, SVNrev); + spm('Pointer', 'Watch'); + G = {}; label = {}; + for ind = 1:numel(forward) - % create a new lead-field matrix - %------------------------------------------------------------------ + %-Create a new lead-field matrix + %================================================================== - % Head Geometry (create tesselation file) + %-Head Geometry (create tesselation file) %------------------------------------------------------------------ vert = forward(ind).mesh.vert; - face = forward(ind).mesh.face; + face = forward(ind).mesh.face; - % normals + %-Normals %------------------------------------------------------------------ norm = spm_mesh_normals(struct('faces',face,'vertices',vert),true); @@ -70,25 +75,24 @@ if ischar(vol) vol = ft_read_vol(vol); end - + modality = forward(ind).modality; if isfield(forward, 'siunits') && forward(ind).siunits units = D.units(D.indchannel(forward(ind).channels)); sens = forward(ind).sensors; - siunits = isempty(strmatch('unknown', units)); + siunits = isempty(strmatch('unknown', units)); else siunits = false; sens = D.inv{val}.datareg(ind).sensors; - end + end - % Forward computation + %-Forward computation %------------------------------------------------------------------ [vol, sens] = ft_prepare_vol_sens(vol, sens, 'channel', forward(ind).channels); nvert = size(vert, 1); - spm('Pointer', 'Watch');drawnow; - spm_progress_bar('Init', nvert, ['Computing ' modality ' leadfields']); drawnow; + spm_progress_bar('Init', nvert, ['Computing ' modality ' leadfields']); if nvert > 100, Ibar = floor(linspace(1, nvert,100)); else Ibar = [1:nvert]; end @@ -102,8 +106,8 @@ Gxyz(:, (3*i - 2):(3*i)) = ft_compute_leadfield(vert(i, :), sens, vol); end - if ismember(i, Ibar) - spm_progress_bar('Set', i); drawnow; + if any(Ibar == i) + spm_progress_bar('Set', i); end end else @@ -115,21 +119,24 @@ end spm_progress_bar('Clear'); - spm_progress_bar('Init', nvert, ['Orienting ' modality ' leadfields']); drawnow; + + spm_progress_bar('Init', nvert, ['Orienting ' modality ' leadfields']); G{ind} = zeros(size(Gxyz, 1), size(Gxyz, 2)/3); for i = 1:nvert G{ind}(:, i) = Gxyz(:, (3*i- 2):(3*i))*norm(i, :)'; if ismember(i,Ibar) - spm_progress_bar('Set', i); drawnow; + spm_progress_bar('Set', i); end end - % condition the scaling of the lead-field - %-------------------------------------------------------------------------- + spm_progress_bar('Clear'); + + %-Condition the scaling of the lead-field + %------------------------------------------------------------------ [Gs, scale] = spm_cond_units(G{ind}); - + if siunits && abs(log10(scale))>2 warning(['Scaling expected to be 1 for SI units, actual scaling ' num2str(scale)]); G{ind} = Gs; @@ -137,10 +144,6 @@ scale = 1; end - spm_progress_bar('Clear'); - - spm('Pointer', 'Arrow');drawnow; - label = [label; forward(ind).channels(:)]; forward(ind).scale = scale; @@ -152,22 +155,24 @@ G = G{1}; end - % Save + %-Save %---------------------------------------------------------------------- D.inv{val}.gainmat = ['SPMgainmatrix_' spm_file(D.fname, 'basename') '_' num2str(val) '.mat']; - save(fullfile(D.path, D.inv{val}.gainmat), 'G', 'label'); + save(fullfile(D.path, D.inv{val}.gainmat), 'G', 'label', spm_get_defaults('mat.format')); save(D); + + spm('Pointer', 'Arrow'); end [sel1, sel2] = spm_match_str(channels, label); if length(sel2) ~= numel(channels) - error('Did not find a match for all the requested channels'); + error('Did not find a match for all the requested channels.'); end -L = sparse(G(sel2, :)); +L = sparse(G(sel2, :)); -% retain selected sources if necessary +%-Retain selected sources if necessary %-------------------------------------------------------------------------- if nargin > 1 && ~isempty(Is) L = L(:,Is); diff --git a/spm_eeg_merge.m b/spm_eeg_merge.m index 9193d17c..bb2b8370 100644 --- a/spm_eeg_merge.m +++ b/spm_eeg_merge.m @@ -1,6 +1,6 @@ function Dout = spm_eeg_merge(S) -% Concatenate epoched single trial files. -% FORMAT D = spm_eeg_merge(S) +% Concatenate epoched single trial files +% FORMAT Dout = spm_eeg_merge(S) % % S - input structure (optional) % fields of S: @@ -43,7 +43,7 @@ % S.recode(1).labelorg = '.*'; % S.recode(1).labelnew = '#labelorg# #file#'; % has the same effect as the 'addfilename' option. -% S.prefix - prefix for the output file (default - 'c') +% S.prefix - prefix for the output file (default - 'c') % % % Dout - MEEG object (also written to disk) @@ -55,20 +55,20 @@ % data (SPM displays data from only one file at a time), or merging % information that has been measured in multiple sessions. %__________________________________________________________________________ -% Copyright (C) 2008-2012 Wellcome Trust Centre for Neuroimaging -% +% Copyright (C) 2008-2017 Wellcome Trust Centre for Neuroimaging + % Stefan Kiebel, Vladimir Litvak, Doris Eckstein, Rik Henson -% $Id: spm_eeg_merge.m 6622 2015-12-03 11:54:13Z vladimir $ +% $Id: spm_eeg_merge.m 7125 2017-06-23 09:49:29Z guillaume $ -SVNrev = '$Rev: 6622 $'; +SVNrev = '$Rev: 7125 $'; %-Startup %-------------------------------------------------------------------------- spm('FnBanner', mfilename, SVNrev); spm('FigName','M/EEG Merge'); spm('Pointer','Watch'); -if ~isfield(S, 'prefix'), S.prefix = 'c'; end -if ~isfield(S, 'recode'), S.recode = 'same'; end +if ~isfield(S,'prefix'), S.prefix = 'c'; end +if ~isfield(S,'recode'), S.recode = 'same'; end %-Load MEEG data %-------------------------------------------------------------------------- @@ -82,14 +82,14 @@ end D = F; catch - error('Trouble reading files'); + error('Trouble reading files.'); end end Nfiles = length(D); if Nfiles < 2 - error('Need at least two files for merging'); + %error('Need at least two files for merging.'); end %-Check input and determine number of new number of trial types @@ -156,7 +156,7 @@ clb = [clb D{i}.conditions]; Find = [Find i*ones(1, D{i}.ntrials)]; end -uclb = unique(clb); +uclb = unique(clb); %-Specify condition labels recoding @@ -225,15 +225,15 @@ end end -%-Generate new meeg object with new filenames +%-Generate new meeg object with new filename %-------------------------------------------------------------------------- Dout = D{1}; -[p, f, x] = fileparts(fnamedat(Dout)); +newfilename = spm_file(fnamedat(Dout), 'path',pwd, 'prefix',S.prefix); if ~isTF - Dout = clone(Dout, fullfile(pwd, [S.prefix f x]), [Dout.nchannels Dout.nsamples sum(Ntrials)]); + Dout = clone(Dout, newfilename, [Dout.nchannels Dout.nsamples sum(Ntrials)]); else - Dout = clone(Dout, fullfile(pwd, [S.prefix f x]), [Dout.nchannels Dout.nfrequencies Dout.nsamples sum(Ntrials)]); + Dout = clone(Dout, newfilename, [Dout.nchannels Dout.nfrequencies Dout.nsamples sum(Ntrials)]); end @@ -293,36 +293,34 @@ %-Average sensor locations %-------------------------------------------------------------------------- +CmdLine = spm('CmdLine'); +if CmdLine, h = []; end if ~isempty(megsens) - spm_figure('GetWin','Graphics');clf; + if ~CmdLine, spm_figure('GetWin','Graphics');clf; end if ~isempty(eegsens) - h = subplot(2, 1, 1); + if ~CmdLine, h = subplot(2, 1, 1); end aeegsens = ft_average_sens(eegsens, 'weights', Ntrials, 'feedback', h); Dout = sensors(Dout, 'EEG', aeegsens); - h = subplot(2, 1, 2); + if ~CmdLine, h = subplot(2, 1, 2); end else - h = axes; + if ~CmdLine, h = axes; end end [amegsens,afid] = ft_average_sens(megsens, 'fiducials', fid, 'weights', Ntrials, 'feedback', h); Dout = sensors(Dout, 'MEG', amegsens); Dout = fiducials(Dout, afid); elseif ~isempty(eegsens) - spm_figure('GetWin','Graphics');clf; - h = axes; + if ~CmdLine, spm_figure('GetWin','Graphics');clf; end + if ~CmdLine, h = axes; end [aeegsens,afid] = ft_average_sens(eegsens, 'fiducials', fid, 'weights', Ntrials, 'feedback', h); Dout = sensors(Dout, 'EEG', aeegsens); Dout = fiducials(Dout, afid); end - - %-Write files %-------------------------------------------------------------------------- spm_progress_bar('Init', Nfiles, 'Files merged'); -if Nfiles > 100, Ibar = floor(linspace(1, Nfiles,100)); -else Ibar = [1:Nfiles]; end k = 0; @@ -351,7 +349,7 @@ Dout = trialtag(Dout, find(Find == i), D{i}.trialtag); Dout = events(Dout, find(Find == i), D{i}.events); - if ismember(i, Ibar), spm_progress_bar('Set', i); end + spm_progress_bar('Set', i); end @@ -363,4 +361,5 @@ %-Cleanup %-------------------------------------------------------------------------- spm_progress_bar('Clear'); +fprintf('%-40s: %30s\n','Completed',spm('time')); %-# spm('FigName','M/EEG merge: done'); spm('Pointer','Arrow'); diff --git a/spm_eeg_montage.m b/spm_eeg_montage.m index fbe5b5e8..14849a34 100644 --- a/spm_eeg_montage.m +++ b/spm_eeg_montage.m @@ -49,12 +49,12 @@ % correctly when no sensors are specified or when data and sensors are % consistent (which is ensured by spm_eeg_prep_ui). %__________________________________________________________________________ -% Copyright (C) 2008-2012 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2008-2017 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak, Robert Oostenveld, Stefan Kiebel, Christophe Phillips -% $Id: spm_eeg_montage.m 6835 2016-07-14 16:08:56Z vladimir $ +% $Id: spm_eeg_montage.m 7169 2017-09-19 10:42:27Z vladimir $ -SVNrev = '$Rev: 6835 $'; +SVNrev = '$Rev: 7169 $'; %-Startup %-------------------------------------------------------------------------- @@ -67,11 +67,11 @@ elseif ~isfield(S, 'mode') S.mode = 'write'; end -if ~isfield(S, 'blocksize'), S.blocksize = 655360; end %20 Mb -if ~isfield(S, 'keepothers'), S.keepothers = 1; end -if ~isfield(S, 'keepsensors'), S.keepsensors = 1; end -if ~isfield(S, 'updatehistory'), S.updatehistory = 1; end -if ~isfield(S, 'prefix'), S.prefix = 'M'; end +if ~isfield(S, 'blocksize'), S.blocksize = 655360; end %20 Mb +if ~isfield(S, 'keepothers'), S.keepothers = 1; end +if ~isfield(S, 'keepsensors'), S.keepsensors = 1; end +if ~isfield(S, 'updatehistory'), S.updatehistory = 1; end +if ~isfield(S, 'prefix'), S.prefix = 'M'; end %-Get MEEG object %-------------------------------------------------------------------------- @@ -114,6 +114,9 @@ error('Insufficient or illegal montage specification.'); end + % There is inconsistent naming in FT functions. + % montage.labelold = montage.labelorg; + % select and discard the columns that are empty if the corresponding % channels are not present in the data selempty = find(all(montage.tra == 0, 1)); @@ -124,18 +127,18 @@ montage.tra(:, selempty) = []; montage.labelorg(selempty) = []; - if isfield(montage, 'chantypeorg') - montage.chantypeorg(selempty) = []; + if isfield(montage, 'chantypeold') + montage.chantypeold(selempty) = []; end - if isfield(montage, 'chanunitorg') - montage.chanunitorg(selempty) = []; + if isfield(montage, 'chanunitold') + montage.chanunitold(selempty) = []; end % add columns for the channels that are not involved in the montage - [add, ind] = setdiff(D.chanlabels, montage.labelorg); - chlab = D.chanlabels; - ind = sort(ind); - add = chlab(ind); + [add, ind] = setdiff(D.chanlabels, montage.labelorg); + chlab = D.chanlabels; + ind = sort(ind); + add = chlab(ind); m = size(montage.tra, 1); n = size(montage.tra, 2); @@ -155,11 +158,11 @@ end montage.labelorg = cat(1, montage.labelorg(:), add(:)); - if isfield(montage, 'chantypeorg') - montage.chantypeorg = lower(cat(1, montage.chantypeorg(:), D.chantype(ind)')); + if isfield(montage, 'chantypeold') + montage.chantypeold = lower(cat(1, montage.chantypeold(:), D.chantype(ind)')); end - if isfield(montage, 'chanunitorg') - montage.chanunitorg = cat(1, montage.chanunitorg(:), D.units(ind)'); + if isfield(montage, 'chanunitold') + montage.chanunitold = cat(1, montage.chanunitold(:), D.units(ind)'); end % determine whether all channels are unique @@ -181,25 +184,25 @@ [selchan, selmont] = spm_match_str(D.chanlabels, montage.labelorg); montage.tra = montage.tra(:,selmont); montage.labelorg = montage.labelorg(selmont); - if isfield(montage, 'chantypeorg') - montage.chantypeorg = montage.chantypeorg(selmont); + if isfield(montage, 'chantypeold') + montage.chantypeold = montage.chantypeold(selmont); end - if isfield(montage, 'chanunitorg') - montage.chanunitorg = montage.chanunitorg(selmont); + if isfield(montage, 'chanunitold') + montage.chanunitold = montage.chanunitold(selmont); end end isTF = strncmp(D.transformtype, 'TF', 2); if isTF && ~isequal(S.mode, 'write') - error('Online montages are not supported for TF data'); + error('Online montages are not supported for TF data.'); end switch S.mode case 'write' - %% + %-Generate new MEEG object with new filenames - %---------------------------------------------------------------------- + %------------------------------------------------------------------ if ~isTF Dnew = clone(D, [S.prefix fname(D)], [m D.nsamples D.ntrials], 1); nblocksamples = floor(S.blocksize/max(D.nchannels, m)); @@ -305,11 +308,8 @@ Dnew = chantype(Dnew, ':', ctype); end - - - %-Apply montage to sensors - %---------------------------------------------------------------------- + %------------------------------------------------------------------ sensortypes = {'MEG', 'EEG'}; for i = 1:length(sensortypes) if S.keepsensors @@ -323,19 +323,19 @@ sensmontage.tra(selempty, :) = []; sensmontage.labelnew(selempty) = []; - if isfield(sensmontage, 'chantypeorg') - sensmontage.chantypeorg = sensmontage.chantypeorg(sel2); + if isfield(sensmontage, 'chantypeold') + sensmontage.chantypeold = sensmontage.chantypeold(sel2); end - if isfield(sensmontage, 'chanunitorg') - sensmontage.chanunitorg = sensmontage.chanunitorg(sel2); + if isfield(sensmontage, 'chanunitold') + sensmontage.chanunitold = sensmontage.chanunitold(sel2); - for c = 1:length(sensmontage.chanunitorg) + for c = 1:length(sensmontage.chanunitold) if isequal(sensortypes{i}, 'MEG') - sensmontage.chanunitorg{c} = strrep(sensmontage.chanunitorg{c}, 'fT', 'T'); + sensmontage.chanunitold{c} = strrep(sensmontage.chanunitold{c}, 'fT', 'T'); else - sensmontage.chanunitorg{c} = strrep(sensmontage.chanunitorg{c}, 'uV', 'V'); + sensmontage.chanunitold{c} = strrep(sensmontage.chanunitold{c}, 'uV', 'V'); end - sensmontage.chanunitorg{c} = strrep(sensmontage.chanunitorg{c}, 'mm', 'm'); + sensmontage.chanunitold{c} = strrep(sensmontage.chanunitold{c}, 'mm', 'm'); end end @@ -372,7 +372,7 @@ chanunitorig = sens.chanunit; labelorg = sens.label; - sens = ft_apply_montage(sens, sensmontage, 'keepunused', keepunused); + sens = ft_apply_montage(sens, sensmontage, 'keepunused', keepunused, 'warning', false); if isequal(sensortypes{i}, 'MEG') if isfield(sens, 'balance') && ~isequal(sens.balance.current, 'none') @@ -386,7 +386,6 @@ end - if isfield(sens, 'chanunit') chanunit = sens.chanunit; else @@ -432,7 +431,7 @@ %-Assign default EEG sensor positions if no positions are present or if % default locations had been assigned before but no longer cover all the % EEG channels. - %---------------------------------------------------------------------- + %------------------------------------------------------------------ if ~isempty(Dnew.indchantype('EEG')) && (isempty(Dnew.sensors('EEG')) ||... (all(ismember({'spmnas', 'spmlpa', 'spmrpa'}, Dnew.fiducials.fid.label)) && ... ~isempty(setdiff(Dnew.chanlabels(Dnew.indchantype('EEG')), getfield(Dnew.sensors('EEG'), 'label'))))) @@ -445,7 +444,7 @@ end %-Create 2D positions for EEG by projecting the 3D positions to 2D - %---------------------------------------------------------------------- + %------------------------------------------------------------------ if ~isempty(Dnew.indchantype('EEG')) && ~isempty(Dnew.sensors('EEG')) S1 = []; S1.task = 'project3D'; @@ -457,7 +456,7 @@ end %-Create 2D positions for MEG by projecting the 3D positions to 2D - %---------------------------------------------------------------------- + %------------------------------------------------------------------ if ~isempty(Dnew.indchantype('MEG')) && ~isempty(Dnew.sensors('MEG')) S1 = []; S1.task = 'project3D'; @@ -469,7 +468,7 @@ end %-Transfer the properties of channels not involved in the montage - %---------------------------------------------------------------------- + %------------------------------------------------------------------ if ~isempty(add) && S.keepothers old_add_ind = D.indchannel(add); new_add_ind = Dnew.indchannel(add); @@ -502,13 +501,14 @@ %-Cleanup %-------------------------------------------------------------------------- spm_progress_bar('Clear'); +fprintf('%-40s: %30s\n','Completed',spm('time')); %-# spm('FigName','M/EEG montage: done'); spm('Pointer','Arrow'); -%% PROGRAMMER'S NOTES by CP +% PROGRAMMER'S NOTES by CP % Observed a weird behaviour of the montage method for the @meeg object % under WinXP, matlab R2007b. % 'montage' is initialized as a variable at "compilation" and then all % calls like Nmont = montage(D,'getnumber'); are crashing. % I therefore used the not so good looking Nmont = D.montage('getnumber'); % call. Same goes for the other calls to 'montage', even wih an extra -% argument. \ No newline at end of file +% argument. diff --git a/spm_eeg_montage_ui.m b/spm_eeg_montage_ui.m index 0fb5a713..30484cff 100644 --- a/spm_eeg_montage_ui.m +++ b/spm_eeg_montage_ui.m @@ -9,10 +9,10 @@ % % Output is empty if the GUI is closed. %__________________________________________________________________________ -% Copyright (C) 2008-2011 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2008-2017 Wellcome Trust Centre for Neuroimaging % Jean Daunizeau -% $Id: spm_eeg_montage_ui.m 6072 2014-06-27 16:35:30Z guillaume $ +% $Id: spm_eeg_montage_ui.m 7119 2017-06-20 11:25:48Z guillaume $ % Create the figure @@ -81,8 +81,7 @@ function doAddRow(obj,evd,h) colnames = cat(2,'channel labels',ud.montage.labelorg(:)'); pause(1) % This is weird, but fixes java troubles. ht = my_uitable(table,colnames); -set(ht,'position',pos,... - 'units','normalized'); +set(ht,'position',pos, 'units','normalized'); ud.ht = ht; set(h,'userdata',ud); doCheck(obj,evd,h); @@ -130,7 +129,11 @@ function doSave(obj,evd,h) montage.tra = M; montage.labelorg = ud.montage.labelorg; montage.labelnew = newLabels; -uisave('montage','SPMeeg_montage.mat'); +[filename, pathname] = uiputfile({'*.mat','MAT-files (*.mat)'}, ... + 'Save montage', 'SPMeeg_montage.mat'); +if ~isequal(filename, 0) + save(fullfile(pathname, filename), 'montage', spm_get_defaults('mat.format')); +end %========================================================================== function doOK(obj,evd,h) @@ -220,12 +223,20 @@ function addButtons(h) set(hCheck,'units','normalized'); %========================================================================== -function h = my_uitable(varargin) +function [ht,hc] = my_uitable(varargin) %========================================================================== % conversion layer for various MATLAB versions -if spm_check_version('matlab','8.4') >= 0 - warning('Consider migrating to the new uitable component.'); - h = uitable('v0',varargin{:}); -else - h = spm_uitable(varargin{:}); +persistent runOnce +try + if spm_check_version('matlab','8.4') >= 0 + if isempty(runOnce) + warning('Consider migrating to the new uitable component.'); + runOnce = true; + end + [ht,hc] = uitable('v0',varargin{:}); + else + [ht,hc] = spm_uitable(varargin{:}); + end +catch + [ht,hc] = deal([]); end diff --git a/spm_eeg_morlet.m b/spm_eeg_morlet.m index 5c5c3f72..2b451576 100644 --- a/spm_eeg_morlet.m +++ b/spm_eeg_morlet.m @@ -20,32 +20,36 @@ % from the wavelet coefficients. % % [1] C. Tallon-Baudry, O. Bertrand, F. Peronnet and J. Pernier, 1998. -% Induced \gamma-Band Activity during the Delay of a Visual Short-term +% Induced gamma-Band Activity during the Delay of a Visual Short-term % memory Task in Humans. The Journal of Neuroscience (18): 4244-4254. %__________________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging % Stefan Kiebel -% $Id: spm_eeg_morlet.m 5900 2014-02-27 21:54:51Z karl $ +% $Id: spm_eeg_morlet.m 7122 2017-06-22 14:54:01Z guillaume $ -M = {}; -for f0 = f +if nargin < 4 + ff = f; +else + ff = repmat(ff,1,numel(f)); +end + +M = cell(1,numel(f)); + +for i = 1:numel(f) % fixed or scale-dependent window %---------------------------------------------------------------------- - if nargin < 4 - sigma_t = Rtf/(2*pi*f0); - else - sigma_t = Rtf/(2*pi*ff); - end + sigma_t = Rtf/(2*pi*ff(i)); - % this scaling factor is proportional to (Tallon-Baudry 98): + % this scaling factor is proportional to (Tallon-Baudry, 1998): % (sigma_t*sqrt(pi))^(-1/2); %---------------------------------------------------------------------- t = 0:ST*0.001:5*sigma_t; t = [-t(end:-1:2) t]; - M{end+1} = exp(-t.^2/(2*sigma_t^2)) .* exp(2 * 1i * pi * f0 *t); - M{end} = M{end}./(sqrt(0.5*sum(real(M{end}).^2 + imag(M{end}).^2))); - M{end} = M{end} - mean(M{end}); + M{i} = exp(-t.^2/(2*sigma_t^2)) .* exp(2 * 1i * pi * f(i) *t); + M{i} = M{i} ./ (sqrt(0.5*sum(real(M{i}).^2 + imag(M{i}).^2))); + M{i} = M{i} - mean(M{i}); + end diff --git a/spm_eeg_planarchannelset.m b/spm_eeg_planarchannelset.m index 3de25caf..5c83b66a 100644 --- a/spm_eeg_planarchannelset.m +++ b/spm_eeg_planarchannelset.m @@ -8,7 +8,7 @@ % Copyright (C) 2013-2015 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_eeg_planarchannelset.m 6781 2016-04-27 10:01:38Z vladimir $ +% $Id: spm_eeg_planarchannelset.m 7169 2017-09-19 10:42:27Z vladimir $ if isa(data, 'cell') && ~isempty(data) && isa(data{1}, 'char') @@ -17,4 +17,8 @@ input = data; end -planar = ft_senslabel(lower(ft_senstype(input)), 'output', 'planarcombined'); +try + planar = ft_senslabel(lower(ft_senstype(input)), 'output', 'planarcombined'); +catch + planar = ft_senslabel([lower(ft_senstype(input)) '_planar'], 'output', 'planarcombined'); +end \ No newline at end of file diff --git a/spm_eeg_prep.m b/spm_eeg_prep.m index 02c58194..9e3126e8 100644 --- a/spm_eeg_prep.m +++ b/spm_eeg_prep.m @@ -17,7 +17,7 @@ % Copyright (C) 2008-2012 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_eeg_prep.m 6817 2016-06-20 17:10:50Z vladimir $ +% $Id: spm_eeg_prep.m 7175 2017-09-26 14:50:54Z vladimir $ D = spm_eeg_load(S.D); @@ -78,6 +78,48 @@ D = chantype(D, ind, spmtype); %---------------------------------------------------------------------- + + case 'bidschantype' + + dictionary = { % Should be updates with updates to BIDS specification + 'MEGMAG' 'MEGMAG' + 'MEGGRAD' 'MEGPLANAR' + 'MEG' 'MEG' + 'MEGREF' 'REF' + 'EEG' 'EEG' + 'EOG' 'EOG' + 'ECG' 'ECG' + 'EMG' 'EMG' + 'TRIG' 'Other' + 'AUDIO' 'Other' + 'PD' 'Other' + 'ET' 'Other' + 'MISC' 'Other' + }; + + bids_chan = spm_load(S.filename); + + [sel1, sel2] = spm_match_str(D.chanlabels, bids_chan.name); + + type = bids_chan.type(sel2); + + [sel3, sel4] = spm_match_str(type, dictionary(:, 1)); + + type(sel3) = dictionary(sel4, 2); + + D = chantype(D, sel1, type); + + case 'bidschanstatus' + bids_chan = spm_load(S.filename); + + [sel1, sel2] = spm_match_str(D.chanlabels, bids_chan.name); + + sel3 = strmatch('bad', bids_chan.status(sel2)); + + D = badchannels(D, sel1, 0); + + D = badchannels(D, sel1(sel3), 1); + case {'loadtemplate', 'setcoor2d', 'project3d'} %---------------------------------------------------------------------- chanind = 1:D.nchannels; @@ -108,6 +150,8 @@ chanind = D.indchantype('EEG'); case 'MEG' chanind = D.indchantype('MEGANY'); + case 'MEGCOMB' + chanind = D.indchantype('MEGCOMB'); end end @@ -203,6 +247,8 @@ hspind = strmatch('headshape', elec.label); elec.chanpos(hspind, :) = []; elec.elecpos(hspind, :) = []; + elec.chantype(hspind, :) = []; + elec.chanunit(hspind, :) = []; elec.label(hspind) = []; % This handles FIL Polhemus case and other possible cases @@ -484,6 +530,24 @@ D = condlist(D, cl); %---------------------------------------------------------------------- + case 'loadbidsevents' + if ~isequal(D.type, 'continuous') + error('This operation can only be applied to continuous datasets'); + end + + ev_bids = spm_load(S.filename); + + ev_spm = struct('type', repmat({'BIDS'}, length(ev_bids.onset), 1), 'value', ev_bids.stim_type,... + 'time', num2cell(ev_bids.onset), 'duration', num2cell(ev_bids.duration)); + + if S.replace + D = events(D, 1, ev_spm); + else + D = events(D, 1, spm_cat_struct(D.events(1), ev_spm)); + end + + D = D.check; + otherwise %---------------------------------------------------------------------- fprintf('Unknown task ''%s'' to perform: Nothing done.\n',S.task); diff --git a/spm_eeg_prep_ui.m b/spm_eeg_prep_ui.m index 5af1e409..ede5536a 100644 --- a/spm_eeg_prep_ui.m +++ b/spm_eeg_prep_ui.m @@ -6,7 +6,7 @@ function spm_eeg_prep_ui(callback) % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_eeg_prep_ui.m 6437 2015-05-14 12:27:21Z vladimir $ +% $Id: spm_eeg_prep_ui.m 7169 2017-09-19 10:42:27Z vladimir $ spm('Pointer','Watch'); @@ -23,7 +23,7 @@ function spm_eeg_prep_ui(callback) %========================================================================== function CreateMenu -SVNrev = '$Rev: 6437 $'; +SVNrev = '$Rev: 7169 $'; spm('FnBanner', 'spm_eeg_prep_ui', SVNrev); Finter = spm('FnUIsetup', 'M/EEG prepare', 0); @@ -93,6 +93,14 @@ function spm_eeg_prep_ui(callback) 'HandleVisibility','on',... 'Callback', 'spm_eeg_prep_ui(''TrialsCB'')'); +BInputsEventsBIDSMenu = uimenu(BatchInputsMenu, ... + 'Label','Load events from BIDS',... + 'Separator','off',... + 'Enable','off',... + 'Tag','EEGprepUI',... + 'HandleVisibility', 'on',... + 'Callback', 'spm_eeg_prep_ui(''EventsBIDSCB'')'); + BInputsEventsMenu = uimenu(BatchInputsMenu, 'Label', 'Event list',... 'Tag','EEGprepUI',... 'Enable', 'off', ... @@ -159,6 +167,12 @@ function spm_eeg_prep_ui(callback) 'Separator', 'on',... 'Callback', 'spm_eeg_prep_ui(''ChanTypeDefaultCB'')'); +CTypesBIDSMenu = uimenu(ChanTypeMenu, 'Label', 'From BIDS',... + 'Tag','EEGprepUI',... + 'Enable', 'on', ... + 'HandleVisibility','on',... + 'Callback', 'spm_eeg_prep_ui(''ChanTypeBIDSCB'')'); + CTypesReviewMenu = uimenu(ChanTypeMenu, 'Label', 'Review',... 'Tag','EEGprepUI',... 'Enable', 'on', ... @@ -443,7 +457,7 @@ function spm_eeg_prep_ui(callback) label = D.chanlabels(selection); -save(fullfile(chanpathname, chanfilename), 'label'); +save(fullfile(chanpathname, chanfilename), 'label', spm_get_defaults('mat.format')); end @@ -467,6 +481,30 @@ function spm_eeg_prep_ui(callback) end +%========================================================================== +% function EventsBIDSCB +%========================================================================== +function EventsBIDSCB + +D = getD; + +S = []; +S.task = 'loadbidsevents'; +S.D = D; +[S.filename, sts] = spm_select(1, '.*_events.tsv$', 'Select BIDS tsv file'); + +if sts + S.replace = spm_input('Replace existing','1','replace|add',[1 0], 1); +end + +D = spm_eeg_prep(S); + +setD(D); + +update_menu; + +end + %========================================================================== % function EventsCB %========================================================================== @@ -748,6 +786,26 @@ function spm_eeg_prep_ui(callback) update_menu; end + +%========================================================================== +% function ChanTypeBIDSCB +%========================================================================== +function ChanTypeBIDSCB + +S = []; +S.D = getD; +S.task = 'bidschantype'; +[S.filename, sts] = spm_select(1, '.*_channels.tsv$', 'Select BIDS tsv file'); + +if sts + D = spm_eeg_prep(S); + + setD(D); + update_menu; +end + +end + %========================================================================== % function LoadEEGSensTemplateCB %========================================================================== @@ -1206,6 +1264,7 @@ function spm_eeg_prep_ui(callback) end set(findobj(Finter,'Tag','EEGprepUI', 'Label', 'Save'), 'Enable', 'on'); +set(findobj(Finter,'Tag','EEGprepUI', 'Label', 'Load events from BIDS'), 'Enable', Dloaded); set(findobj(Finter,'Tag','EEGprepUI', 'Label', 'Batch inputs'), 'Enable', Dloaded); set(findobj(Finter,'Tag','EEGprepUI', 'Label', 'Trial definition'), 'Enable', IsEpochable); diff --git a/spm_eeg_review_callbacks.m b/spm_eeg_review_callbacks.m index a381db93..ffd1b6e5 100644 --- a/spm_eeg_review_callbacks.m +++ b/spm_eeg_review_callbacks.m @@ -4,7 +4,7 @@ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Jean Daunizeau -% $Id: spm_eeg_review_callbacks.m 6437 2015-05-14 12:27:21Z vladimir $ +% $Id: spm_eeg_review_callbacks.m 7217 2017-11-15 14:33:10Z vladimir $ spm('pointer','watch'); drawnow expose @@ -705,6 +705,7 @@ end xlim0 = get(handles.axes,'xlim'); if ~isequal(xlim0,[1 D.nsamples]) + length_window = round(xlim0(2)-xlim0(1)); if offset < round(0.5*length_window) offset = round(0.5*length_window); set(handles.BUTTONS.slider_step,'value',1); @@ -1600,62 +1601,28 @@ if length(cn) == 5 % channel info - if ~emptyTable + if ~emptyTable nc = D.nchannels; - for i=1:nc - if ~isempty(table(i,1)) - D = chanlabels(D,i,table(i,1)); - end - if ~isempty(table(i,2)) - switch lower(table(i,2)) - case 'eeg' - D = chantype(D,i,'EEG'); - case 'meg' - D = chantype(D,i,'MEG'); - case 'megplanar' - D = chantype(D,i,'MEGPLANAR'); - case 'megcomb' - D = chantype(D,i,'MEGCOMB'); - case 'megmag' - D = chantype(D,i,'MEGMAG'); - case 'meggrad' - D = chantype(D,i,'MEGGRAD'); - case 'refmag' - D = chantype(D,i,'REFMAG'); - case 'refgrad' - D = chantype(D,i,'REFGRAD'); - case 'lfp' - D = chantype(D,i,'LFP'); - case 'eog' - D = chantype(D,i,'EOG'); - case 'veog' - D = chantype(D,i,'VEOG'); - case 'heog' - D = chantype(D,i,'HEOG'); - case 'phys' - D = chantype(D,i,'PHYS'); - case 'ilam' - D = chantype(D,i,'ILAM'); - case 'src' - D = chantype(D,i,'SRC'); - case 'other' - D = chantype(D,i,'Other'); - otherwise - D = chantype(D,i,'Other'); - end - end - if ~isempty(table(i,3)) - switch lower(table(i,3)) - case 'yes' - D = badchannels(D,i,1); - otherwise - D = badchannels(D,i,0); - end - end - if ~isempty(table(i,5)) - D = units(D,i,table(i,5)); - end - end + + newlabels = cell(table(:, 1)); + valid = find(~cellfun(@isempty, newlabels)); + D = chanlabels(D, valid, newlabels(valid)); + + newtypes = cell(table(:, 2)); + valid = find(~cellfun(@isempty, newtypes)); + D = chantype(D, valid, newtypes(valid)); + + newbad = cell(table(:, 3)); + valid = find(~cellfun(@isempty, newbad)); + bad = strmatch('yes', newbad(valid)); + good = strmatch('no', newbad(valid)); + D = badchannels(D, valid(bad), 1); + D = badchannels(D, valid(good), 0); + + newunits = cell(table(:, 5)); + valid = find(~cellfun(@isempty, newunits)); + D = units(D, valid, newunits(valid)); + % Find indices of channel types (these might have been changed) D.PSD.EEG.I = indchantype(D,'EEG'); D.PSD.MEG.I = sort(indchantype(D,'MEG')); @@ -1736,10 +1703,21 @@ else if ~emptyTable nt = D.ntrials; - for i=1:nt - if ~isempty(table(i,1)) - D = conditions(D,i,table(i,1)); - end + newconditions = cell(table(:, 1)); + valid = find(~cellfun(@isempty, newconditions)); + D = conditions(D, valid, newconditions(valid)); + + newbad = cell(table(:, 6)); + valid = find(~cellfun(@isempty, newbad)); + bad = strmatch('yes', newbad(valid)); + good = strmatch('no', newbad(valid)); + D = badtrials(D, valid(bad), 1); + D = badtrials(D, valid(good), 0); + + + ind = []; + newevents = {}; + for i=1:nt Events = events(D,i); Events = [Events{:}]; ne = length(Events); @@ -1750,16 +1728,11 @@ if ~isempty(table(i,3)) Events.value = table(i,3);%str2double(table(i,3)); end - D = events(D,i,Events); - end - if ~isempty(table(i,6)) - switch lower(table(i,6)) - case 'yes' - D = badtrials(D,i,1); - otherwise - D = badtrials(D,i,0); - end - end + + ind = [ind i]; + newevents = [newevents {Events}]; + end + if badtrials(D,i) str = ' (bad)'; else @@ -1768,6 +1741,8 @@ D.PSD.trials.TrLabels{i} = ['Trial ',num2str(i),': ', ... char(conditions(D,i)),str]; end + + D = events(D,ind,newevents); else end end diff --git a/spm_eeg_review_switchDisplay.m b/spm_eeg_review_switchDisplay.m index 86fd132c..672568b9 100644 --- a/spm_eeg_review_switchDisplay.m +++ b/spm_eeg_review_switchDisplay.m @@ -4,7 +4,7 @@ % Copyright (C) 2008-2015 Wellcome Trust Centre for Neuroimaging % Jean Daunizeau -% $Id: spm_eeg_review_switchDisplay.m 6405 2015-04-14 15:13:02Z guillaume $ +% $Id: spm_eeg_review_switchDisplay.m 7169 2017-09-19 10:42:27Z vladimir $ try % only if already displayed stuffs handles = rmfield(D.PSD.handles,'PLOT'); @@ -542,7 +542,7 @@ table{i,6} = 'Undefined'; table{i,7} = num2str(trialonset(D,1)); end - colnames = {'label','type','value','duration','time','bad','onset'}; + colnames = {'label','type','value','duration','time','bad','offset'}; [ht,hc] = my_uitable(table,colnames); set(ht,'units','normalized'); set(hc,'position',[0.1 0.05 0.74 0.7],... diff --git a/spm_eeg_simulate.m b/spm_eeg_simulate.m index a52fb919..aa2d119e 100644 --- a/spm_eeg_simulate.m +++ b/spm_eeg_simulate.m @@ -19,7 +19,7 @@ %% Outputs %% Dnew- new dataset %% meshsourceind- vertex indices of sources on the mesh -% $Id: spm_eeg_simulate.m 6424 2015-04-24 14:33:33Z gareth $ +% $Id: spm_eeg_simulate.m 7118 2017-06-20 10:33:27Z guillaume $ %% LOAD IN ORGINAL DATA useind=1; % D to use @@ -363,7 +363,7 @@ F=[]; UL=L; -save(priorfname,'Qp','Qe','UL','F'); +save(priorfname,'Qp','Qe','UL','F', spm_get_defaults('mat.format')); figure; ploton=1; diff --git a/spm_eeg_spatial_confounds.m b/spm_eeg_spatial_confounds.m index 94068dcc..9f659020 100644 --- a/spm_eeg_spatial_confounds.m +++ b/spm_eeg_spatial_confounds.m @@ -13,10 +13,10 @@ % Copyright (C) 2008-2014 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_eeg_spatial_confounds.m 6625 2015-12-03 21:49:24Z vladimir $ +% $Id: spm_eeg_spatial_confounds.m 7128 2017-07-03 11:58:47Z vladimir $ -SVNrev = '$Rev: 6625 $'; +SVNrev = '$Rev: 7128 $'; %-Startup %-------------------------------------------------------------------------- @@ -24,7 +24,7 @@ spm('FigName','Define spatial confounds'); if ~isfield(S, 'mode') && isfield(S, 'method'), S.mode = S.method; end -if ~isfield(S, 'threshold') && isfield(S, 'svdthresh'), S.threshold = S.svdthreshd; end +if ~isfield(S, 'threshold') && isfield(S, 'svdthresh'), S.threshold = S.svdthresh; end D = spm_eeg_load(S.D); @@ -111,7 +111,7 @@ case 'BESA' sconf = spm_eeg_read_bsa(S.conffile ); case 'SVD' - cl = D.condlist; + cl = S.conditions; svdinput = []; for i = 1:numel(cl) tmp = D(D.indchantype('MEEG', 'GOOD'), D.indsample(1e-3*S.timewin(1)):D.indsample(1e-3*S.timewin(2)), D.indtrial(cl{i})); @@ -124,7 +124,7 @@ temp = zeros(size(svdinput)); for n = size(V, 2):-1:1 temp = temp+U(:, n)*L(n,n)*V(:,n)'; - if max(max(temp))>S.threshold; + if max(max(abs(temp)))>S.threshold; S.ncomp = min(n+1, size(V, 2)); break; else diff --git a/spm_eeg_specest_morlet.m b/spm_eeg_specest_morlet.m index 2cb7e636..4eb2682c 100644 --- a/spm_eeg_specest_morlet.m +++ b/spm_eeg_specest_morlet.m @@ -20,78 +20,69 @@ % res.fourier - the complex output of wavelet transform % res.time - time axis % res.freq - frequency axis -%______________________________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2010-2017 Wellcome Trust Centre for Neuroimaging -% Vladimir Litvak based on the code from Stefan Kiebel and Will Penny -% $Id: spm_eeg_specest_morlet.m 3749 2010-03-04 13:17:17Z vladimir $ +% Vladimir Litvak +% $Id: spm_eeg_specest_morlet.m 7129 2017-07-04 16:24:53Z guillaume $ %-This part if for creating a config branch that plugs into spm_cfg_eeg_tf % Any parameters can be specified and they are then passed to the plugin % when it's called. %-------------------------------------------------------------------------- -if nargin == 0 - subsample = cfg_entry; - subsample.tag = 'subsample'; - subsample.name = 'Subsample'; +if nargin == 0 + subsample = cfg_entry; + subsample.tag = 'subsample'; + subsample.name = 'Subsample'; subsample.strtype = 'n'; - subsample.num = [1 1]; - subsample.val = {1}; - subsample.help = {'Set to N to subsample the time axis to every Nth sample (to reduce the dataset size).'}; + subsample.num = [1 1]; + subsample.val = {1}; + subsample.help = {'Set to N to subsample the time axis to every Nth sample (to reduce the dataset size).'}; - ncycles = cfg_entry; - ncycles.tag = 'ncycles'; - ncycles.name = 'Number of wavelet cycles'; + ncycles = cfg_entry; + ncycles.tag = 'ncycles'; + ncycles.name = 'Number of wavelet cycles'; ncycles.strtype = 'n'; - ncycles.num = [1 1]; - ncycles.val = {7}; - ncycles.help = {'Number of wavelet cycles (a.k.a. Morlet wavelet factor)',... + ncycles.num = [1 1]; + ncycles.val = {7}; + ncycles.help = {'Number of wavelet cycles (a.k.a. Morlet wavelet factor).',... 'This parameter controls the time-frequency trade-off',... 'Increasing it increases the frequency resolution at the expense of time resolution.'}; - - timeres = cfg_entry; - timeres.tag = 'timeres'; - timeres.name = 'Fixed time window length'; + + timeres = cfg_entry; + timeres.tag = 'timeres'; + timeres.name = 'Fixed time window length'; timeres.strtype = 'r'; - timeres.num = [1 1]; - timeres.val = {0}; - timeres.help = {'Fixed time window for all frequencies.',... + timeres.num = [1 1]; + timeres.val = {0}; + timeres.help = {'Fixed time window for all frequencies.',... 'Specify time window length in ms.',... - 'Default valued of 0 specifies variable time window length'}; + 'Default valued of 0 specifies variable time window length.'}; - - morlet = cfg_branch; - morlet.tag = 'morlet'; + morlet = cfg_branch; + morlet.tag = 'morlet'; morlet.name = 'Morlet wavelet transform'; - morlet.val = {ncycles, timeres, subsample}; + morlet.val = {ncycles, timeres, subsample}; res = morlet; - return -elseif nargin < 3 - error('Three input arguments are required'); + return; end %-Defaults %-------------------------------------------------------------------------- -if ~isfield(S, 'subsample') - S.subsample = 1; -end - -if ~isfield(S, 'ncycles') - S.ncycles = 7; -end +try, S.subsample; catch, S.subsample = 1; end +try, S.ncycles; catch, S.ncycles = 7; end dt = time(end) - time(1); - if ~isfield(S, 'frequencies') || isempty(S.frequencies) S.frequencies = (1/dt):max(1/dt, floor(dt)/dt):48; end %-Generate wavelets %-------------------------------------------------------------------------- -if ~isfield(S, 'timeres') || (S.timeres == 0) +if ~isfield(S, 'timeres') || S.timeres == 0 M = spm_eeg_morlet(S.ncycles, 1000*diff(time(1:2)), S.frequencies); else M = spm_eeg_morlet(S.ncycles, 1000*diff(time(1:2)), S.frequencies, 1000./S.timeres); @@ -99,15 +90,14 @@ %-Data dimensions %-------------------------------------------------------------------------- -Nchannels = size(data, 1); -Nsamples = size(data, 2); +Nchannels = size(data, 1); +Nsamples = size(data, 2); Nfrequencies = numel(M); %-Initialize output struct %-------------------------------------------------------------------------- -res = []; -res.freq = S.frequencies; -res.time = time(1:S.subsample:end); +res.freq = S.frequencies; +res.time = time(1:S.subsample:end); res.fourier = zeros(Nchannels, Nfrequencies, length(res.time)); %-Compute wavelet transform @@ -124,3 +114,12 @@ res.fourier(j, i, :) = tmp; end end + +%% The following is often faster but requires more memory +%for i = 1:Nfrequencies +% H = spm_convmtx(M{i}',Nsamples); % faster than conv for large Nchannels +% tmp = data * H'; +% % subsample and time shift to remove delay +% tmp = tmp(:,(1:S.subsample:Nsamples) + (length(M{i})-1)/2); +% res.fourier(:,i,:) = tmp; +%end diff --git a/spm_eeg_tf.m b/spm_eeg_tf.m index 39d35da4..4dfd558e 100644 --- a/spm_eeg_tf.m +++ b/spm_eeg_tf.m @@ -37,16 +37,16 @@ % % hilbert (spm_eeg_specest_hilbert) - filtering + Hilbert transform % -% ft_mtmconvol (spm_eeg_specest_ft_mtmconvol) - Fieldtrip implementation +% ft_mtmconvol (spm_eeg_specest_mtmconvol) - Fieldtrip implementation % of multi-taper spectral % analysis %__________________________________________________________________________ % Copyright (C) 2010 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_eeg_tf.m 6146 2014-09-02 11:27:43Z vladimir $ +% $Id: spm_eeg_tf.m 7125 2017-06-23 09:49:29Z guillaume $ -SVNrev = '$Rev: 6146 $'; +SVNrev = '$Rev: 7125 $'; %-Startup %-------------------------------------------------------------------------- @@ -249,4 +249,5 @@ %-Cleanup %-------------------------------------------------------------------------- +fprintf('%-40s: %30s\n','Completed',spm('time')); %-# spm('FigName','M/EEG Time Frequency: done'); spm('Pointer','Arrow'); diff --git a/spm_est_V.m b/spm_est_V.m index 8a75b962..fea550eb 100644 --- a/spm_est_V.m +++ b/spm_est_V.m @@ -9,7 +9,7 @@ % Copyright (C) 2012 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_est_V.m 5219 2013-01-29 17:07:07Z spm $ +% $Id: spm_est_V.m 6958 2016-12-03 12:30:53Z karl $ % get data and model %========================================================================== @@ -86,7 +86,7 @@ % ReML and whitening matrix (W) %---------------------------------------------------------------------- - [V,h] = spm_reml(C,X,Q{q},1,1,1,0,4); + [V,h] = spm_reml(C,X,Q{q},1,1,0,4); W = spm_inv(spm_sqrtm(V)); % scales for plotting later and effective degrees of freedom diff --git a/spm_est_non_sphericity.m b/spm_est_non_sphericity.m index c877ad06..b33922b6 100644 --- a/spm_est_non_sphericity.m +++ b/spm_est_non_sphericity.m @@ -27,13 +27,13 @@ % array of non-sphericity components (xVi.Vi), providing a high precise % estimate of the non-sphericity matrix (xVi.V). %__________________________________________________________________________ -% Copyright (C) 1994-2012 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 1994-2016 Wellcome Trust Centre for Neuroimaging % Karl Friston & Guillaume Flandin -% $Id: spm_est_non_sphericity.m 6827 2016-07-04 15:19:35Z guillaume $ +% $Id: spm_est_non_sphericity.m 6913 2016-10-31 10:12:27Z guillaume $ -SVNid = '$Rev: 6827 $'; +SVNid = '$Rev: 6913 $'; %-Say hello %-------------------------------------------------------------------------- @@ -43,6 +43,7 @@ %-Get data, design, mask and variance components details %-------------------------------------------------------------------------- VY = SPM.xY.VY; +M = VY(1).mat; DIM = VY(1).dim; YNaNrep = spm_type(VY(1).dt(1),'nanrep'); @@ -102,7 +103,7 @@ %========================================================================== mask = true(DIM); for i = 1:numel(xM.VM) - if ~isfield(SPM.xVol,'G') + if ~(isfield(SPM,'xVol') && isfield(SPM.xVol,'G')) %-Assume it fits entirely in memory C = spm_bsplinc(xM.VM(i), [0 0 0 0 0 0]'); v = true(DIM); diff --git a/spm_existfile.mexmaci64 b/spm_existfile.mexmaci64 index 81e20528b091528de754ca7d3c1cc1dae5ce26fb..ea3c318cfb8f616f35577eb9900a682f361e6c54 100755 GIT binary patch literal 8816 zcmeHNU5Fc16uz@to82{R(z4KsTbN3>v~I~}p~zCLB-?CBG;V7XYenmIvOBv8^Zs%okTd7! zp8MT%&%J?}xpQat=RZA+DZ`Ah5n?~F`T%1aBtZ`m9~)wf^W?&%q~+?qpo5!)O_+>e z*j~}bxv5voPGB#dI&QbUFG67N>4d{rcblA-%yO#KcJ<=j6?jKP1Z<@pO>-4^o&12u z(|We38x+@z_nW|r3k=v)mJaphw^TBXOny~F^x{Q)cEhY_cWei+3!9vrm-AOL`DLET zuM{l1dp#-w@4Ntj-HYL1LvpUC`HG?CblcmT-)(^x6rEsWj|?L0lO{3ek#I8XigNbH z0EvA9Tqjq~^I2Z1=2C?$FPg?cJO>UN)}0sD(^*qw!Fg8uCp^CZ3L=;Ywi^%m;eX)} z<{2gCJRVzodLa^X{u8Q*5O_@3MKLkpxcA>9jICQ^QXKF{NFF5Vkg8Gu8Fi9#BmskV z|6#^PN$!xmLGnT3^TcjKEEr=BqB`{#Te>UcVX`oe=d&;VSbQ(oc;o)tk>lgFukk;! zrZzgp*w`3*)Uio|yu_Ff`eJN{LPk+D(=*vjDpv_CS4r9}{~}&@cj%9=5Rk%V$|VEn z;HBy5z^oVq@pHtTd_LLJ8=t6_Og$HvcjtAK`e2?rs=Y49h5a4bplM>X!^V6i$qL8{ z$O^~`$O^~`$O`=5D)3yic0c@l_+lb@?WY?wxoGY4Snb#AyGr?m=HLsIr_REb%`GD`^jhDzd#eQMzG;VTzZ#H}% z?I0*lK|hWY*t?`OpR&5tzHQEs607ZvUi%a&ycm8t%rD>CvIzNYd#)-&Y@2TTgPzN` zT2phBNo(qqb$!CRK51P;)^(n)jKwz(jgk^hw5EP1b1Mz!58qQ>=>yQdf_4(xU1;;r zZbQ2O?IyGpXdjSvF0ZSZe6eh*g?zTE8v0r}W9Z8P7PFkWa>-Ovx~i%66Jdb*S9?T_s)3s#n9k;;wBwBo=d!RcRgX>VJmgAi4;v4RwitnDOWErrQ%ooUeCxDO>mH3 zg!hRN@!Ypx$VnlO3K)w%D3~Ux?=_VZ+d>$wIq`^Xm#yvcIDN5E?i*bVU>2Irn+I{mCOMzZN=Q_OB}+pqN4 zc+cdH$F~M#w{u(Xv5^=Woo^{HucFb0&ZdoB9bnjC+(%H+1zm!w$P M?)B^2O_Vq2FTm=HZ2$lO literal 8856 zcmeHNU1(fI6h7N*o2Y5B71JNo_C}0G0-NMPN!7x}CS}*IZ8cH)piXzQH`&$wN$%dI zi6TbRh)Ws`Qm~3h3O-byMEt{62sPjzBECqW5A{XdP%TjqO2uBkGj}H0n>5nLKHLK{ zXTCFY&dh!@3v*}Y$IE|QsU-^35K$e{Mx>MLi6)_0wjs5yBNC#&_h7#?d9#oglER2d z2tylGwGg&BYA?548E>3BhE!ZdjDxByRglK3p%BHfT(XcAMZ1*jTs^*YgWLK}<-|Bp z6`)SVTOQv)(Y7-AA=PH(_>QW0=t_#l3KA&t2*!tjiL{v=HZ9bwjQ6FA_nPw3cqz!L z-&@Kb&g4@flOHTxCEkHX*HcdsV-J5zf!%@-W?BqdiJYmicYaT*cn6gqV_qX#ZX!CQ z%dB~wbb(+Ydb<0&t7`Q6SVQwV;kY`s5UH_jYT19Scsd-fH|@LZwOkS+k2T^hm0{aj zHNKDvq~kHJo=aXIdW~>YA+m}8i)W}n9cl=StK;$S<^P!$<}HdOL_D@{Z*NabPoSY% zsCcCCaTSc?RIle-fwv-EeBt$XE?(Yu`sbG$w(UK!<(@lWlVdU5e(RvQofg9&8U;8G z&2|pY`WN7O=(Ej4bI_P?I)KE&>xvWi&;M~A%UUuEf3?(QlMfA-PmbM%r2CYW$RgQ7 zB4t`)IAN#TvzcUWG>iq2N$UD*_A|YX*X)BQtHvEiV8>o_YG>tD=p%FX z)6uC1D$lTO`jbPB<3!6}$IA1SVOS>T?7KS8#mm1{o&ZA77}V8*QsZZnY51Pvy*V4q6Noiqb(B>bgg(6!}aQDQw zDQ&O;VjwXKT6llQDG+ikT;^|>dgNQ>K9Oj4BL(=I^(U%9mqa{jmcVn5QD8I_2-Vlt z&7kH%*toy5|6&M`Z@3Xlklh+WudEAl=#3kKbx_ka6YGP#9X}dGCM7f{oEPzJptLq? zeO_(e|5Un0eHS(`Wm~p&FXyD^7Wqf|HF6tthkZP+Fd+07n$&6CAGRbC>NXXlX*B0a(8`2rGO{y+7y% z-j2f&eILIcxDoAf9wX&R5BOSiI=aO^&1L( zZ+rvlZ$yGbIIUH0;6^!@7RgdRl{N7UfiG3bJH>eHpx-CBx9(yPbc<}E@N8+AaL86l m8t(grB6%jmyB=1p1Q@Qi24I%653T0iopJA=Sy?Z0&OZ diff --git a/spm_existfile.mexw32 b/spm_existfile.mexw32 index 116428a9364149b021d33bf5d766c7589f7cd5da..6fac360d79630686f65dabd2c26ba0a5ff70403d 100755 GIT binary patch delta 32 ncmZoLX)u}agQZXUS>(h&K1~0&ZT4b}5@P8E@;9##j$i`-?D-9j delta 32 lcmZoLX)u}agXPrUPoWe4_%KZ>-t5H~B?RVgULhR81^@=s4=Vrw diff --git a/spm_existfile.mexw64 b/spm_existfile.mexw64 index f6a0f27d80717d6bf1fff8c9772da00a6575ef59..cf7ff3ba6f7c90a207ec7700757c052312a96434 100755 GIT binary patch delta 32 lcmZp$X|S2_f<^t=)5wW$e3&-7Znk3lB?RVgwh%eN2>|gh4jcdg delta 32 lcmZp$X|S2_g5~$#n9zxDe3(4mY_?+jB?RVgwh%eN2>|;K4wL`@ diff --git a/spm_fMRI_design.m b/spm_fMRI_design.m index bfea0d02..774264dc 100644 --- a/spm_fMRI_design.m +++ b/spm_fMRI_design.m @@ -166,10 +166,10 @@ % Copyright (C) 1999-2012 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_fMRI_design.m 5183 2013-01-10 15:30:20Z ged $ +% $Id: spm_fMRI_design.m 7210 2017-11-10 16:33:17Z guillaume $ -SVNid = '$Rev: 5183 $'; +SVNid = '$Rev: 7210 $'; %-Say Hello %-------------------------------------------------------------------------- @@ -267,7 +267,7 @@ SPM.Sess(s).U = U; SPM.Sess(s).C.C = C; SPM.Sess(s).C.name = Cname; - SPM.Sess(s).row = size(Xx,1) + (1:k); + SPM.Sess(s).row = size(Xb,1) + (1:k); SPM.Sess(s).col = size(Xx,2) + (1:size(X,2)); SPM.Sess(s).Fc = Fc; diff --git a/spm_field.mexa64 b/spm_field.mexa64 index 7a15ff466129a4db3ff0a62d662cfd11a1e286f9..6ac6b7877c6e48a348c05926bbd6e912d62fa6e3 100755 GIT binary patch delta 9565 zcmaJ{4O~=Zx}S4~K_v9dAjrq6pd#|2gdeGBAcHe{h8@&06^snCb^Y~qZ3E>l=HMNt zJUgDE-ni>l?Bcyk>-DZzi%Y8|28e=gA6S_myOnLV9>ml@jntg|KkqpM=-STjch37h z-_QHJ&+~p9*jy!Ut`e(C!nc%|_-{+e3yv34Pl$iQT5gkt03%Pqb)Jwi9$Bh z@>-bdDaXH+J@nYm*r%4!^@Bst2;$tr`tCvFMDf`C`nYhHD4ue&ha++l;tNbBt?Wi1 z;PT&{q>Vtwt{n3AhHQwC)oj(xnj?xl-9H2Zo0>|~T>kY*VcJvzyKF8PwjAfJP) zAm@e=J*JOdW{}@A$W|ho`p8Q_mi@W0vSR6ZD5%q}BNKuAdmnOwj!XgaB#?G*z+4(B z`wQ5|L!wuF4q`9{R&6wg^cYw*rb9diRxMhGXq@3R&IZ6V600@~J$aV1oyTAl(SFlM z`yI<4`q-QouaUFW+rLAjh_ceAB?9A84)WQFBC4wH2DL!ZWHp+tNHodHAzArcTR75W zk~g-_2xGgQBiV2%*|X0D1Ha}9XK5a^a6d`*&(aQDrG8l~^`~=uSp@a{!M>Vp%7^Uz zfZb|EnC!0z({gkL<2kTV*AUNvOFA%w1M~WHjLYT@!~nr5`@uFKweBSEu3lxQr5M4+ zdZjGSQqIsC%)NFQ42*Ez>mg+_IoR+$=~~<_tNDT~?K&zSJu7D|jFmQhX~y8yYzui^ zLL&QtFxmG}f!Q1B?N+lH6m~^Jn^`A2rTLefzAK&+T`8p8QwZ(({`|K9ww?OUHxuu)(^S^B_`!G(KVwTXdpcH4}qWw?X~ALA7>!sHlSE43LeYxg&^+*Kt%cf#rsg zP#s4l(-XvXBR#tv(uDF%?#Gt~xMl`QJh~2C-BQtq=nvVZ_YYI)*DPlfBh$q1WmXiK zY(I(6c1wj{f^*zr&Sf3x(N?;vRhn?3A_v9DYq&gxpiqFRwe zsf1B{ynd-_;#kM9=r}X5sA0EqMq4}vnYyxfe+Y6?yPw?{Hd^=%ON@#h{ODK^P{$Q4 zCu)i3!W@$c#lH=W)AyD1T#^VX^uK$Vh9qr@GT=V~_BILfR#|aw-wz~ov}w-(>r&cK zD%)vwfLtpud&7vVW*0b64$6(5*Q8&!NG~?cXek>_x&As>Wc8hw;pML3dro7BBtg-f+>u|53k~h^0&s`6=6<;|Zl!iSP`FUj8T#dRqdlaH*Sc$@I}boXt%T_r6A&c^Ao-^b(PZ3;t4^>P(89OGXUCVQ_M zs>sQIR)sS|P!}=u>#{b&Kd2gdq9;6Ny9vIelB}*8?6nD3nbg z79%p2uX6aJcI$Yt6xynZ2W|*u(?|mGqwrbYxV^+zkf_snY<1*7S442E1aZrrLQ-^s zEBfa!b5pB`gJytOnwgT9Sm4$ zX}+59-S=;s`})_||BVbCv<8a7#@-$oH=zWw^2(F4Qd3Ah<)qyF1rAuM45;(@A+)@X zoOe$mn#MIRj*9lk{szi5w|^QiyPYR^p}CcvTW`{VJ?9oTT+LsJFtrd?UCm#k zyHn=fzl#OZuJ7PvI}ISc+HkAetu$m3M)z6v+vMiIL2J!jG#H$*h8gD3?U0q~6wceg zgQ+x_0Ck?Z1IHj~SG#Oh*RY&~L}4L&Fd=?XC1|G7m9m;gN3|9#!t&7zrHlF;#;LMe z53uNJJ}tgQ^U6cX4|eA2HM;#zWZ@LFcgW`IO7?C-yl24z%#m7ggY()0F(_v~q~HJs zV@{jMOSJ-{GL{W}lECd!THWb&5`IMylINhVq!wk;gql|K?At5p%h(II`#5yb{104&r+g!JmnDz9qatu!?o4N+#?)HL zvRl2|rw6~fioHK(gr||j-0BE^S8ypUZloIz7m7ha^7(jz=uvJb3w|FTf!W8?Kqqk1 zoO=Lr_f6b1VaBX%Cj#fLJ%_9^u$ymUrztZC+#F{gfTYO0Lj$q%uwgN+J`EAHH640e zr|&-2o$Wf@(4@DGd#H6_2iT2{hkEK}1H~75!qjXBra)=V_isAbLH9V}M2}=ONz0n@ z{VyHtz_GUnTuJdxY1vn+oKi|Bgo?DDxsrA24B)N+EWX&2Cs`v>q-8kf7q@rYrNZ~I z-yEUNdzkeSjG)KifrPbB0`ptQ(UNsS7_i@v9 zLAWUMh%}YLrH7q|3jwD5Z?Yn3rj|+1N+bo)|?#ciHPILTeRg^2Ny4Hmg&l+w8&W( z%Rc4`-XnPzux_OdOO7k+qVyksqK`d>$}-92%`r*7ESyj}RlH!KO4@V{mn**U?d6LR zs$1H1NEUF0)=x=TiOXrnfy*JsaneE+au47!b!2Zd+&CgDpOubUk0|kr;n3|oZXo+)Z@%LU*^Ph1GkA5mHZ3Eff0v9E6-6J8js-6hy!E_ zaQ7TuC1o707_5E#MS!k3n0ViIh~P*W))gbKJb;YR;pHN5x=(iRLBU+J8*GlOo$Y9( z=d&?Fr}~5-d-WKEIm~s$;N{~N489HHoXUB}EH3l(QGX4|+NE8eI)omFpO3QhGCr!h z{X8%@Sy5C9{KFl}ai{M?Siz;e>%oGR?MNi+CZ0$RrOB%a^*?bk@}t3KV6>HKv?Nn2Yp)c@>7r*VKi~^;L%IY`fTlN#JCn%m-i4pZ5l^}dtzlo zc~cU9_{4jLrli0oZj$MTNPztW@g`IfLqJI^*>;oCRR)0Xh7r0AkyD?Wc zkj#yl&6N0#|fxl|xEtqpi6aFPkqHEFR#Y%hp)J{V4iY*I{c|2-vu(uN|%{ zD(V3dkF7xlk>BU81R<9?k1pr6^nuI2l;6tx#7HL|Tf>Z-#0YYE)OmCf-^%6C#SOeq z4r8J5*c#}Q9XE$H!B$NW-Mveb;nqjsiEf<8<8TapESW`rMGSzqRj($wyZJSkF2>wh z8Z_NpORYGlEN!9<$L8aVQFQGjF+CKzI2VrM0yBdu3Q6q(7(YtJ?Yi-^=pV%MF5gU` zleqX5d0bZvH^nVcSb2xYQ0U>-4gYomJ%#TG|oRMO2lP$X9ZD^La*xDnndr=GxlhHjSI zNnD+S9mThqi&pCzCgbYX?*ZxxM7Mtugs1Dm7jcKI<-!$o8PcUP*|QVxokEvr(k1O0 z4qh~Lhdd38{!za3oQ2;VJKVw%5I=FLQBlm2F+TRN+kY3EjX&0?>yv^vz2WXujeR>| zSkC&S{&5Gd3q-{CJ=_!%u<>k#H!igRLs2XFPA)puu16vW?Wv(cG95ueRwIhiTq1KDhKX38B?vJ*{#NEE4>$X?03OIXd0 zW>zr&O-g{{mw zbz++SM~xaDbET%7``b5pS)WPI7SlKOjjiQ_`CoRFsSo8GOTzcX86P2~+|mSmSs2?b zOKEdZ^F@}oh&0k5VOk#z8I-N&JGpCH%~H0&e&1sFi3oq!GZN6de|*_)7XSY ztNVoca-I>}jYE4+vef+74-AlkCySzvTF$=B^ObWYggTi)H0&q7t6INTF{T8p|HDe~{~o z;fsy01cgdLDC4lrxrcaGbD+?y{;9-wu%kmO((D_5~|H|53@ zXwaJQhb01%4RuYFJNP4u!6OmRs|Jr4$zI4GKIN`I^Hto+V4V1B zBFiWkC9Y3o^9xeNdlK2d7o;voPNa1q7+?xQ6InqX6P}gREG)lDq+d6 zUzQdc3qRw{?73wz(bvR?LG-sg{3hUW;}PFrZ!OCZC;y3^MYDA;i@!fvjDMTu-Jc;o z{Wkl>{TZIq7*IJX*km7So%4)1B-H$g;2pFjRJA-8^1RtxV>OhL%7-z)l=lMxOZWi( zMFY6M8GMrqFMhqpBFVa7@On!2I zh}d4hy2~=cQ;OgNeknyPZSAzkTmuZYCNulR+Kli4|8%os?X>V-<9~5_i|fy>-5-)4 zRHCcW-)56!>eDiSU^ZDzL3IPrCbP+Ag1+vGWKrB)!s0h%h!+c4{)YJ?=JDkX$wEGB z-Y_pN7kdZ&c2Ml_OG7J~hM3N>(VmzwPsiz4rZ=V>gKCY}5#^C=nI}0vVvY_jH`r(* zNXa7xKFz>CXy9Km@YzT(`aN#okIrL9JQ?xVm+ENzKL!8&)*#OOI%_&1noyLAuIafSUz&@;;Yuij2h96HZw3FGkjWH~DW0?47glA($yk=DL j7%Xb^y9eb%gV|JA|Ki5a1o{`JUwAWw9rfG1KM(l_CZIi; delta 8902 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 diff --git a/spm_field.mexmaci64 b/spm_field.mexmaci64 index 2fe12672a384ee5c6036f7f5177f05ddd67d1a82..78acbafc2bc21782f2f61530c88f89289756e737 100755 GIT binary patch literal 34900 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 literal 34824 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 XTGm+HmPX6>ExRnwSo)4Wx=s22h_d9H diff --git a/spm_field.mexw64 b/spm_field.mexw64 index a633c4ad70ff3a6454a861d583abbb8b281ccb23..d954133955b5d122ecdf0d3f0e2ad5db9e0cd391 100755 GIT binary patch delta 8948 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 a_fH_`0C%FDumOW^)&D8J?X^|*1pObRz44m> delta 8402 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 NIq3~w*yG(n{|kl!L&X39 diff --git a/spm_fieldindices.m b/spm_fieldindices.m index 914a45e9..298174fd 100644 --- a/spm_fieldindices.m +++ b/spm_fieldindices.m @@ -15,7 +15,7 @@ % Copyright (C) 2010-2013 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_fieldindices.m 6809 2016-06-15 12:51:55Z peter $ +% $Id: spm_fieldindices.m 7031 2017-02-27 19:46:48Z karl $ % if varargin is a vector simply return fieldnames @@ -59,8 +59,8 @@ end end - % or return the name of the field - %---------------------------------------------------------------------- + % or return the name of the field + %---------------------------------------------------------------------- elseif isnumeric(varargin{i}) ind = varargin{i}; @@ -73,9 +73,15 @@ if any(spm_vec(x.(name{j}))) if iscell(x.(name{j})) for k = 1:numel(x.(name{j})) - if any(spm_vec(x.(name{j}){k})) - [p,q] = find(x.(name{j}){k}); - ix = sprintf('%s{%i}(%i,%i)',name{j},k,p,q); + xv = spm_vec(x.(name{j}){k}); + if any(xv) + if isstruct(x.(name{j}){k}) + s = spm_fieldindices(x.(name{j}){k},find(xv)); + ix = sprintf('%s{%i}.%s',name{j},k,s); + else + [p,q] = find(x.(name{j}){k}); + ix = sprintf('%s{%i}(%i,%i)',name{j},k,p,q); + end return end end @@ -83,17 +89,17 @@ s = size(x.(name{j})); if numel(s) < 3 if min(s) == 1 - p = find(x.(name{j})); - ix = sprintf('%s(%i)',name{j},p); + p = find(x.(name{j})); + ix = sprintf('%s(%i)',name{j},p); return else [p,q] = find(x.(name{j})); - ix = sprintf('%s(%i,%i)',name{j},p,q); + ix = sprintf('%s(%i,%i)',name{j},p,q); return end else [p,q,r] = ind2sub(s,find(x.(name{j}))); - ix = sprintf('%s(%i,%i,%i)',name{j},p,q,r); + ix = sprintf('%s(%i,%i,%i)',name{j},p,q,r); return end end diff --git a/spm_figure.m b/spm_figure.m index 1f60dadc..9adaccf6 100644 --- a/spm_figure.m +++ b/spm_figure.m @@ -57,7 +57,7 @@ % Copyright (C) 1994-2015 Wellcome Trust Centre for Neuroimaging % Andrew Holmes -% $Id: spm_figure.m 6862 2016-08-25 14:42:19Z guillaume $ +% $Id: spm_figure.m 7112 2017-06-16 11:30:37Z guillaume $ %========================================================================== @@ -1072,8 +1072,7 @@ function spm_about(obj,evt) 'Tag','AboutSPM',... 'WindowStyle','Modal',... 'Color',[1 1 1],... - 'Visible','off',... - 'DoubleBuffer','on'); + 'Visible','off'); pos = get(h,'Position'); pos([3 4]) = [300 400]; set(h,'Position',pos); diff --git a/spm_file.m b/spm_file.m index eaf00540..def32b62 100644 --- a/spm_file.m +++ b/spm_file.m @@ -10,7 +10,7 @@ % str - character array, or cell array of strings % opt_key - string of targeted item - one among: % {'path', 'basename', 'ext', 'filename', 'number', 'prefix', -% 'suffix','link'} +% 'suffix','link','local'} % opt_val - string of new value for feature %__________________________________________________________________________ % @@ -51,10 +51,10 @@ % % See also: spm_fileparts, spm_select, spm_file_ext, spm_existfile %__________________________________________________________________________ -% Copyright (C) 2011-2014 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2011-2017 Wellcome Trust Centre for Neuroimaging % Guillaume Flandin -% $Id: spm_file.m 6346 2015-02-24 11:01:50Z volkmar $ +% $Id: spm_file.m 7110 2017-06-15 11:45:05Z guillaume $ needchar = ischar(str); @@ -164,10 +164,32 @@ m = repmat(str(n),1,p); str{n} = sprintf(cmd,m{:}); end + case 'local' + protocol = str{n}(1:find(str{n}==':',1)-1); + if ismember(protocol,{'file','http','https','ftp'}) + switch lower(options{2}) + case 'temp' + [str{n}, sts] = urlwrite(str{n},tempname); + case 'content' + [str{n}, sts] = urlread(str{n}); + otherwise + if exist(options{2},'dir') == 7 + options{2} = fullfile(options{2},[nam ext]); + end + [str{n}, sts] = urlwrite(str{n},options{2}); + end + if ~sts + error('An error occured while accessing %s.',str{n}); + end + else + if strcmpi(options{2},'content') + str{n} = fileread(str{n}); + end + end otherwise warning('Unknown item ''%s'': ignored.',lower(options{1})); end - if ~strcmpi(options{1},'link') + if ~any(strcmpi(options{1},{'link','local'})) str{n} = fullfile(pth,[nam ext num]); end end diff --git a/spm_find_pC.m b/spm_find_pC.m index 16cc5f7f..3f43b098 100644 --- a/spm_find_pC.m +++ b/spm_find_pC.m @@ -20,7 +20,7 @@ % Copyright (C) 2015 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_find_pC.m 6793 2016-05-04 12:18:44Z adeel $ +% $Id: spm_find_pC.m 7075 2017-05-10 15:08:31Z peter $ %-parse input arguments %-------------------------------------------------------------------------- @@ -66,7 +66,10 @@ if ischar(fields), fields = {fields}; end if isstruct(pE) j = spm_fieldindices(pE,fields{:}); - if ~isempty(j) + if isempty(j) && ~(~isempty(fields) && strcmp(fields{1},'none')) + warning('%s not found. Returning all fields',... + strjoin(cellstr(fields),',')); + else i = j(ismember(j,i)); end end diff --git a/spm_fmri_concatenate.m b/spm_fmri_concatenate.m index 7aaa77bc..7adcc9a5 100644 --- a/spm_fmri_concatenate.m +++ b/spm_fmri_concatenate.m @@ -19,10 +19,10 @@ function spm_fmri_concatenate(P, scans) % this, acquire additional volumes at the end of each session and / or % add regressors to model the trials at the session borders. %__________________________________________________________________________ -% Copyright (C) 2015 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2015-2017 Wellcome Trust Centre for Neuroimaging % Guillaume Flandin & Peter Zeidman -% $Id: spm_fmri_concatenate.m 6533 2015-08-24 10:57:35Z peter $ +% $Id: spm_fmri_concatenate.m 7018 2017-02-15 13:36:48Z guillaume $ %-Input parameters @@ -104,8 +104,10 @@ function spm_fmri_concatenate(P, scans) %-------------------------------------------------------------------------- switch lower(SPM.xVi.form) case {'ar(1)','ar(0.2)'} - SPM.xVi.Vi = spm_Ce(SPM.nscan,0.2); + SPM.xVi.Vi = spm_Ce('ar',SPM.nscan,0.2); SPM.xVi.form = 'AR(0.2)'; + case 'fast' + SPM.xVi.Vi = spm_Ce('fast',SPM.nscan,SPM.xY.RT); case {'i.i.d', 'none'} otherwise warning('Unhandled temporal non-sphericity.'); diff --git a/spm_fmri_spm_ui.m b/spm_fmri_spm_ui.m index 8ba04ad4..a862297e 100644 --- a/spm_fmri_spm_ui.m +++ b/spm_fmri_spm_ui.m @@ -169,13 +169,13 @@ % Map. 5:243-248 % %__________________________________________________________________________ -% Copyright (C) 1994-2013 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 1994-2017 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_fmri_spm_ui.m 6088 2014-07-03 17:57:09Z guillaume $ +% $Id: spm_fmri_spm_ui.m 7018 2017-02-15 13:36:48Z guillaume $ -SVNid = '$Rev: 6088 $'; +SVNid = '$Rev: 7018 $'; %========================================================================== % - D E S I G N M A T R I X @@ -243,30 +243,12 @@ case 'fast' %-------------------------------------------------------------- - dt = SPM.xY.RT; - Q = {}; - l = sum(nscan); - k = 0; - for m=1:length(nscan) - T = (0:(nscan(m) - 1))*dt; - d = 2.^(floor(log2(dt/4)):log2(64)); - for i = 1:length(d) - for j = 0:2 - QQ = toeplitz((T.^j).*exp(-T/d(i))); - [x,y,q] = find(QQ); - x = x + k; - y = y + k; - Q{end + 1} = sparse(x,y,q,l,l); - end - end - k = k + nscan(m); - end - SPM.xVi.Vi = Q; + SPM.xVi.Vi = spm_Ce('fast',nscan,SPM.xY.RT); cVi = upper(cVi); otherwise % otherwise assume AR(0.2) in xVi.Vi %-------------------------------------------------------------- - SPM.xVi.Vi = spm_Ce(nscan,0.2); + SPM.xVi.Vi = spm_Ce('ar',nscan,0.2); cVi = 'AR(0.2)'; end end diff --git a/spm_gamrnd.mexmaci64 b/spm_gamrnd.mexmaci64 index eeb92c293cf911c7f4243b532645ae7acbe093da..10c956fa950f8fb210c5e16dd8759ffcf576ff2d 100755 GIT binary patch literal 9048 zcmeHNZ%kX)6~8udp$X>M5!u+k#>tiplFR|ENi(&mIN;>bLPQg2%nCdV*uj!9U_U32 zv?_=(<;{x3mwi|@snJ$d6Wi3RnzS@h8xz`KB6TI1)>Y~>@nOqe)?{O_rD>YP`ly>vSegceBJ$#SSI0IzO#aF zLNE|sk#B~XTZ+;hQ=_5CG2zeUtCWn6{i5H*06U}HHn2*lt8Z%jQaZmh9ft=l;AV>gD{=BwS>;yX>6FH)OngcS);`H;s=%7Ihf8H z@tU<%lt@^K4fl2Rhm`>}x+b4VLwwnB(fJTZ6Bfl2_Wvh7hajrqqY+*XAH}y`^pR4O z9>40(ICArC5`1N12;uDbGBXWJQMzK8PsQr`^$I?-J~S(PU$Z|W)JOXuqbW*5{h_D5 zb@k?faKT9;_?U|$<`cnDp4nVm85^mjAugkyMbKtW+zmVd;~expXo`vY%eOGL5qbgy zDd-JoO=u*v1~nS{uxL>KR%Fa4o?Q779JJ0SdzU_(oP2Ei=&v3W?UpxWEhT^a7uj+}*5>3X{YiQ1ZlP?sB!@2j0q&_}sd-nbByN>f3p)!qr( zpyadna$P|kt+PR?d@3kyN-j!1Xt(VYI%98;H3}t&Fg3Jy|E~@+Irwzlsdfg zi_$YGsoc8&=afA5wyS+QJDw(~Jhdn}HhqIH<-U4+&!XgPOzOApr_*{f=j!k#^*U}j zHa)~y9gT>>={=87?EgT|M>fC~4)61UU;wG@4hOAM2m!cbjz)bTZ5}c5#|k2UZe`^^ zf_aqxX|C7GADtq9Seg9sCBpNE)6739fgDcC)cXMy0>!+F=xuxX3P({~cS;)TO{dem z9<8&+XlLU*jB8Rw%Yy#lJ&L!y1)EWR1z!7BzCtT(pZ%{`l{iiu);IG2oZdN6bek39 zXrHMfm(gidoHnKn0XZ8}`b~VngT)Kj>P?b`MciQc?)x|z6f|nfds@Bo*u$pw=?OYd zo}->;JuRN*Bl6hIGFfX(X}_u0J|0V3pD&irRKJ9^^l?y+eQJ4;9Iuc=X^p4+B)duZ_IS+SutI|QYd7j5U zwVtO@>JxIpn|dno{2hmW4_KTp8?Q>+l|@+Us3 zuPxN4XBxkCKR(%@=?#e&=Hx_ss$P3XPCTyv1k>p7!FQ@ie@UR!1$^9C)og?Iw+8LH zJ_t~+70TL-PWK?PHr+UWTP+U;Gx1VY=k(jyR4OfPM1eduT~wd`b^MPF+MiM7vgbT) zo_0@%M`^#Y9V`ftZdl`gy&#!K*L z2JuF2(BZ66`i5$w0lykJghw6GP`4)<^$#nLeY2AK%Xt5RXdpny#nHil+7u;NZo(to z{;;3BD!HrC9}f3-(~x}|!5pm%&p=e%{ok}RNSv?O=`P)z@6 zunP^(hL?pN$&iRgF_y9%z3(Mz#z#2z^pC*2eR-U!BPd0k^nT9q_vtfvH3?NSMs!xrPC;JyI CNuxdh literal 9112 zcmeHNU2qfE6}~bORsebBw1H&Wh6RR+A*sP(2+kBH79hM%ENZ}RJ(>(P_XXfm==iGC?z4z?V?&{vXG;?FNm@(TD#+VcA0>8eLu|7zm2f)c9##FW5 z>#ygg{DV7RWkLrgbAU+_sj41K>So*2^YJExV>JbVNVl6!^Jr&1xvHvaU6JNkSk?4I zbH&2(mC-~%n@zz;w~00hr@+HhIjL$(EUMie;Qaae1zw%-C!KP(7y(byCuSch_*iRCTwf-jmZ~ z)!QPH%7}1986m#4E8KcJela`?j_NmeT(=|5ma0Zkb7tvv>hT5Ra|<8~kM!JYN%cm* zGmBI;9Jm{vEP$#+0O`4SG~ZFn=+=BTg1zv7# zn<>80RAIl9~5XZA+%ZqDoX;HQEirg@s&)mG&ZFD!v zk2}z%>A^_(&b&Y?K?Ql&40sOIra!l8I-B(z$gY?0i;z~c?D`Tk1~@7Gt`HPuXw$?$ zADh{==3Il4`m2%}RsQvNI%cMyP;750nVDi`!+9li{--#ZV!NVj$S7(17}x^Wuc1eBSu6IkdUKPKdU*Kbg69OrFi z=*Wx9n(fmb7v7meiEFC6zih zp?~a_^vv+cfRcWx#XQF{7~eagq)+TH^&;q#v1~TmCavC0*P#bvWjx)z*JWw-aZ;Ia zcs84zlKjI{Qj_B%Zhlizsdw6Fn6tWl(^FF875Qc?sEJp?q>oeMj-G0|!a2p2n zWsL@V8CDt=B&LqWTZC}a*!LgGT^R!0-0T=f6uL?AJHBZ`WR5<==ewWxxn0M(EcIGZ zO}?85aeUh}`_71SxV<-x)n*9U{BUoi9Ql3I7?*EUdTEy!_cb~_VfZF+5gIci#<`EP zS>qj^l7rrHz)y?mk|(`qwzkE1GQIrqUi7xgpD<1|0c@Z-n)ILnXxg{u4d9`-Bn-@tQp^NG2p z*%)r%^ao*ITNQb8_UyA$r`|BTCxm@sSA8rdM*`61aTNQl1 zLzV!yz(AHhvV4&&WXK`d*=NBdWiXKp#z^Lf-Y1AZ68|}=paTCH56)^cH_@ zY1;a41Rd|&!)o>gyrT-qZ8?XN;(y?CLLL^fQOIf`w+gvV$Wlu_WP(jnc0l6qp{W#( zg$xujP{=?b1BDC}GEm4sAp?aB6f#iAKp_K#3=}f(f5|}U8krVz*vcx}Cp9;jo3Ss9 zP3C<^+ym^0ys}CSCOffdcBBl=aIBr0oA0esBf+FM9`|YO_1M^lt+EuhZetq2hp&I_5w?w({~6& z9eN3tzpVY(!$R+HqXD8_FzW9V zIxTOOUpr(3l$P26uszOih$; q+4ksGmRD%}H^8euzwQ^Wc=YgEhcv6)Y>4`XA}Tw7GW_EXB<8<=4+ACu diff --git a/spm_gamrnd.mexw32 b/spm_gamrnd.mexw32 index c76ebf9ee2a8bbd60a642933ff8ab7660d8ca921..5a55b2ca165993191120b637e7e1254d1c88da49 100755 GIT binary patch delta 32 lcmZp0XmFVDgJq)hv&e~me3&M*ZT4c65(o1)XGqLo2LR%r4A}qx delta 32 lcmZp0XmFVDgXQ$!PoWe4_%O*iZ}wu85(o1)XGqLo2LSuZ4r~Ab diff --git a/spm_gamrnd.mexw64 b/spm_gamrnd.mexw64 index fd535626d14ca2cc844b577efa36e906dae9042c..bae6b3f0fe2c1c645b9a57814f0b6b7839713f0e 100755 GIT binary patch delta 32 lcmZqhY4Dlwfkorl)5wWme3%mZH#;!~$$ 2 j = fix(linspace(1,t,M.ns)); diff --git a/spm_getSPM.m b/spm_getSPM.m index 2864faad..e01ca698 100644 --- a/spm_getSPM.m +++ b/spm_getSPM.m @@ -179,10 +179,10 @@ % see spm_results_ui.m for further details of the SPM results section. % see also spm_contrasts.m %__________________________________________________________________________ -% Copyright (C) 1999-2016 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 1999-2017 Wellcome Trust Centre for Neuroimaging % Andrew Holmes, Karl Friston & Jean-Baptiste Poline -% $Id: spm_getSPM.m 6827 2016-07-04 15:19:35Z guillaume $ +% $Id: spm_getSPM.m 7092 2017-06-05 15:08:49Z guillaume $ %-GUI setup @@ -518,9 +518,9 @@ % For VB - set default effect size %-------------------------------------------------------------- - try + if exist('xSPM','var') && isfield(xSPM,'gamma') && ~isempty(xSPM.gamma) xCon(Ic).eidf = xSPM.gamma; - catch + else Gamma = 0.1; xCon(Ic).eidf = spm_input(str,'+1','e',sprintf('%0.2f',Gamma)); end @@ -537,10 +537,14 @@ end % If Bayesian then get effect size threshold (Gamma) stored in xCon(Ic).eidf % The default is one conditional s.d. of the contrast - %---------------------------------------------------------- + %-------------------------------------------------------------- if strcmp(xCon(Ic).STAT,'P') - Gamma = full(sqrt(xCon(Ic).c'*SPM.PPM.Cb*xCon(Ic).c)); - xCon(Ic).eidf = spm_input(str,'+1','e',sprintf('%0.2f',Gamma)); + if exist('xSPM','var') && isfield(xSPM,'gamma') && ~isempty(xSPM.gamma) + xCon(Ic).eidf = xSPM.gamma; + else + Gamma = full(sqrt(xCon(Ic).c'*SPM.PPM.Cb*xCon(Ic).c)); + xCon(Ic).eidf = spm_input(str,'+1','e',sprintf('%0.2f',Gamma)); + end end end else diff --git a/spm_get_dataset.m b/spm_get_dataset.m new file mode 100644 index 00000000..c3f94444 --- /dev/null +++ b/spm_get_dataset.m @@ -0,0 +1,143 @@ +function spm_get_dataset(repo, name, rev, outdir) +% Download a dataset from an online repository +% FORMAT spm_get_dataset(repo, name, outdir) +% repo - name of repository, one of ['spm', 'openfmri'] +% name - name of dataset, e.g. 'auditory' or 'ds000117' +% rev - revision of dataset [default: ''] +% outdir - output directory [default: pwd] +%__________________________________________________________________________ +% Copyright (C) 2017 Wellcome Trust Centre for Neuroimaging + +% Guillaume Flandin +% $Id: spm_get_dataset.m 7171 2017-09-21 11:11:00Z guillaume $ + + +SVNrev = '$Rev: 7171 $'; + +spm('FnBanner', mfilename, SVNrev); + +if nargin < 1, error('A repository name is mandatory.'); end +if nargin < 2, error('A dataset name is mandatory.'); end +if nargin < 3, rev = ''; end +if nargin < 4, outdir = pwd; end + +%-Options +%-------------------------------------------------------------------------- +timeout = []; +delraw = true; + +%-Get download URL from data repository +%-------------------------------------------------------------------------- +switch lower(repo) + case 'spm' + base = 'http://www.fil.ion.ucl.ac.uk/spm/download/data/'; + switch lower(name) + case 'auditory' + url = fullfile(base,'MoAEpilot','MoAEpilot.zip'); + case 'attention' + url = fullfile(base,'attention','attention.zip'); + case 'face_rep' + url = fullfile(base,'face_rep','face_rep.zip'); + case 'face_rfx' + url = fullfile(base,'face_rfx','face_rfx.zip'); + case 'eeg_mmn' + url{1} = fullfile(base,'eeg_mmn','subject1.bdf'); + url{2} = fullfile(base,'eeg_mmn','sensors.pol'); + otherwise + error('Unknown dataset "%s" in datastore "%s".',name,repo); + end + url = strrep(url,'\','/'); + + case 'openfmri' + % see https://www.mathworks.com/matlabcentral/answers/92506 + url = 'https://openfmri.org/dataset/api/?format=json'; + [js, sts] = urlread(url,'Timeout',timeout); + if ~sts, error('Connection to openfMRI failed.'); end + of = spm_jsonread(js); + idx = find(ismember({of.accession_number},name)); + if isempty(idx) + error('Unknown dataset "%s" in repository "%s".',name,repo); + end + revs = {of(idx).revision_set.revision_number}; + if isempty(rev) + rev = revs{end}; % use last revision, sort(revs)? + else + if ~ismember(rev,revs) + warning('Files with revision "%s" not found.',rev); + end + end + lnk = of(idx).link_set; + url = {}; + for i=1:numel(lnk) + if strcmp(lnk(i).revision,rev) + url{end+1} = lnk(i).url; + end + end + + case 'neurovault' + % http://neurovault.org/api/?format=api + error('Work in progress.'); + + otherwise + error('Unknown repository "%s".',repo); +end + +%-Download +%-------------------------------------------------------------------------- +url = cellstr(url); +F = cell(numel(url),1); +for i=1:numel(url) + s = get_file_size(url{i}); + f = spm_file(url{i},'filename'); + if ~isnan(s) + f = [f, sprintf(' [%dM]',round(s/1024/1024))]; + end + if exist(fullfile(outdir,spm_file(url{i},'filename')),'file') == 7 + F{i} = fullfile(outdir,spm_file(url{i},'filename')); + sts = true; + fprintf('%-40s: %30s', f,'...cached'); %-# + else + fprintf('%-40s: %30s', f,'...downloading'); %-# + [F{i}, sts] = urlwrite(url{i}, ... + fullfile(outdir,spm_file(url{i},'filename')), 'Timeout',timeout); + end + if sts, msg = '...done'; else, msg = '...failed';end + fprintf('%s%30s\n',repmat(sprintf('\b'),1,30),msg); %-# + if ~sts, error('Download failed.'); end +end + +%-Uncompress (and delete archive) +%-------------------------------------------------------------------------- +filenames = {}; +for i=1:numel(F) + switch lower(spm_file(F{i},'ext')) + case 'zip' + f = unzip(F{i},spm_file(F{i},'path')); + if delraw, spm_unlink(F{i}); end + filenames = [filenames; f(:)]; + case {'tar','gz','tgz'} + f = untar(F{i},spm_file(F{i},'path')); + if delraw, spm_unlink(F{i}); end + filenames = [filenames; f(:)]; + otherwise + filenames = F; + end +end + +fprintf('%-40s: %30s\n','Completed',spm('time')); %-# + + +%========================================================================== +% function s = get_file_size(url) +%========================================================================== +function s = get_file_size(url) +try + uri = matlab.net.URI(url); + method = matlab.net.http.RequestMethod.HEAD; + req = matlab.net.http.RequestMessage(method); + resp = req.send(uri); + s = convert(getFields(resp,'Content-Length')); + if isempty(s), s = NaN; end +catch + s = NaN; +end diff --git a/spm_get_lm.mexmaci64 b/spm_get_lm.mexmaci64 index 56527d3c82fd79b0dc3cf07fdce1321001236694..6c201023dae7d61c46edf6729d9a73d1d293aa0e 100755 GIT binary patch literal 13828 zcmeHOe{dAnecuz3kumlj7#!h1SrZ7qgx~}P4(y-VQEYIGUGVxO-ANiwcVh1r z4vzs@(k0$rE>RmMR>eohh_28D*xxfdI)r3JUHdZsQnQr_3oLu__Ff0qgqt zzTG`Zhs2~a{iA=}8}0jkzwdp&-}imr_kG`8z1_Qb>$k&`1;H^%5QI`(PF(2{K}Y~n znT0D}BnYay-MeEuZyH-kV@biHp;LewfglxCjRoQ{6F2Fx`Z}hXeSa;Qkm%wOb|P9v zld2kx={3<@Q@(wbv&}Be;vm|QyrarYH5NZyPOuoLqvGiTA_=$#FM#^3G z)keb6kqPJPYnfw;ZnZQJJ!ZZmnmMMbwb7W?7_PV4^Y!&w`u@tAq)ppu#@LERRn^1$ z8pCyJV>lS$^w{-io@+|lOHOpY4qG=tRSh(#LCxP3FkAEO>#_8$u!M-Fn473j+^xl2 zRJGc(-7|_yvTzDiDiW{Fzy(V2MtW`Csu~Wd(fv&|k&xOP(??yjmDf!m5ItHS&G!+jj{y0N;Zjva z-tu*CwQMh-?Ra~l7F}#@0MY|@=gK@mXyGiVXfCCIYjeGVPzCxm2=utjc8ZNMTve5V z@F-yWDkwnz1HiZ9qC$4lMZA<7M*9Kem~v&MAS@o!ViI2lpmBP4CmsvG>ALfex9@Y+ zhyS&1KH8kba{m-Tm@-9JV$;-yLg@u2bJ@{xT%|SpV-3qgjWtd2in{%P#Ql5m2Sy9r ztv?Pe4q>?-)kr&CwM&;)xU4~lpZrO4G3_~l?LU@(+x}=Q&{VN;v|V2XKc6T3Opts; z&3#&1Bhk6!GXgn^V;fWo7Ybnx(2IXLogpbKCi3NuTFA&o?~J zdbV#Pv877#5!ro7Tf!1=$I6vt7#jaYTjEQki3&P>?z7P)u5=&66A^&N1nW$&(gfuu zSODNlHD`TBzfU~+5lomxCY(`HFJ~3wHgj~vmwVbizfWwviKnbV(OG;MBk!HZQnQ^b z@ymm=&@}aOP^{?L`w)iuIhX)00*V$VQb^MJkXVieueBCo|yMJ&bucI2kc#>7#Z$N$H2q_UnLt-JD~jIC^`TB%z1pVT8PQ1W(UO57*lLZ^6~XfW_;9l z4bNqmp9AKC_NIM_tk}K*&$K@GEh`{p_YG~ny#y1j)i56HNMs9ZJJ2h{o>JB~^=h8n zYUIQ!Mwa+1SmJJoVd!J7Un2I!cA2bke;VBk_w+pu0xHGUV`OjA+etI7lig>vdVA$2 zd3$N;a@x0yXx{|wjnJOY$~`N7=R-`9GrQ6hZx~Pf);h5Fokxe_4)jEy=oe{1t9{s% zE}#2Tt=wFGZx72KHZN`m@%&F)c^`Rh9URgr#8xWn1D)DP$n{JdazD1j*OK^38oq*t zUz{7>aS!3WB+QrK5MP3?nZvK)!!NO&k*apwW0O?obgbt({*Y`~K{hPS*>GGa>Hx#MXZR zVq0#`-3)Z`JBQJeTXON636NNJ4dY=!Dc&(0kL;v=Ol+V1MK(*rwmu95a}wL90Aa8b za}!&?xC6q_k1^xCInA!zLYv!hPHre>3@}pp&9@5+_{w&ZGUEf%t~7gJOJbbD)hU2aynL%aO&?d7!(=zExxFv!*&hdVd$IMUHZlqcFRC zd+sfrg0y7@g}X;Q-0dmt)?<8jYsi*LvSlG|TIZ04tav9=a2Gu29Nd_@)fBtZ{Tn?u zyRl?k*hQw4lWR!0AHs|IX31q4XD$vpVT7=+gqBVCW6w^{F3*b|bywHe`*GW~wLas5 zV(3Sz4exuh@g6hYmyH|DIFLR?$6+Vw=ppkbxX;SQX`k_s3$giYvHkC8`P#aioy3FG ze9V=_xHFG|8*mOm`6P{x(&BYxgTV^>c>w*J1_s3)XT(K4gW}G22boxYT5$~!>_xik zV&bM=Vj7x&smEf1v~$vUJc?LOd9zCqH(`%m65IP=g`D&X%-t)teh30j9%B3Zyj3q{ z?h9h;c@Xfu*nWZ#x7R7Q{+Jkz1HE!8p2eN@GnR_E2pM3GpR??Rcvvxfoh*4Etr)+n zPWs-mRfaAkf5!^c9&vY%zT$__h5x%!F@zAN-?3C zO>i~f9D;J{DTiznf6lVq{fmgTe;z3$j952XtOQ5=D`&g0GG#vZ9Wl`{oXr|TtnKXD zQ2`L-CAS`9oI=8jN?1-6zDOAS+XQ>KUqs_-OIYYN5CX_6WK#kS?Y-? z7(dgE8@Z<~Tl@;O%%GOzyk)qEx6G!NAEJdN*JljC_H=AM;k!Amml3|t#HSMeyp5-x zxD7{T>OofW1KcVnnV2VUxH0BPHaV+&$xz% z-H);Nu6{lBc%8XDc5|67mh>Us5Ls=wM=8dejN9t%blqge8L#W6D=W^eLhKBW9xM-vJ4^n8!&lM>?UD$`4|!Xl`3~s_>@tw>kuo-LeSWt|VEQav)jpCu=>x?H6 zK^Qo-*{Htm?5_%T(6D$6t||E#vnG4{IW+A(1svIHTJd#pk+*}e>g%OY>1{D_r`&da z5=AJcBfBqZt%!WYGq+1|4EGlYJ6vze*>iYw6kDfr|G}rm8J6U3;{BJf9hm!~*!oY1 z?!LqDq?|ldnptH|U?C@FazcNU6Ou_h$O(GS(w^2SUcP{_84)x^1#L zbP#Q=d*)3v%f@-uc6*X|_%tK{&UjwC=#@S}TakD;-TsdLh_^kfPpg(PT>mA~f0WcE z6BIiv886L5xSq3=#=qfd`OKkjl~X(CQ`UY^gDFaC*#{8w8J~^h%koL$bBKl|6cMKf zk=)vb95Dp!Cz)rUj3n1Wk~Y1Zy{KPAT<$gF@_qOQcWB&NJBswJE;uqlF-c>;B)6R{ zWvNY0_EUrs%D@K27^L_d^oY*t`AELgss;!zo=@lyGfE-iWNqm({KKdJTmP3fr;2Zo zBumYxV#Z~~xSF}ZH_CAu#B*vo`phjf>A?L;l5dCpJxcO8`9e+}bY@-!J7P}c#8xtv zW=2ahi(D5&3-9s(q22H_O&8gH2#MxVOXI!=I;(`@;%f1SL)r{T-i9kO>mbm7pJ@V1 z>Bp3m?+8MOHZ?Q;T`~T{YYb(s4^eLG_8P;dz%IBhDaOsr-_nGVDaw1yz&{?{8M=)j z(<#XVM`EjJcl3ihC@y;NI-p{FeqB5`4ch^?uAM&%imzM>iVwp}r%U0fQaO7;zYO1G zo`n*{$Yy+8eMuRnN6B=(w^yIeUOh`WcT|SXw1Dog3gzeS$uB#Kgl^=)6_a;$Wfxq* zB(n?tlh?oI^;KSHc>Nn*U*q-fcs;;tdi2jO_>|W-c|FAITfDx*>tSBgZ7REI={_JLC-J#cDEBqjyI z5xu@aY795)G0Csh>rH`hELtIKk3^&H7VwA4rJx=PN&ax1R2R`}LV*h5E}6<@QbdzhE~{&VDbdDA*dNMqg&L!=|F!C| zLM!88X%PmfjE5IX)FnlN(%wis5Rz&m5v{HGwSFWz0H9`~!cy-L71V}}~ zh1^2LLGQiS0-NVA`eV^tn4NF zzIjHKN}s^{Yj>-)4ZGEP-LKUNPw#PdRNu^Hueo9#I^~Y3 z_;D2Pq;so3K(GD#jR!6I3eK^pl;NWOX6qnoK4^MP-eP^Uj?c$AEm`MA3TSla#(pu6 z-jhe~H)-qmOc1_h(okWRKh2~6K98o?tYFUZ_vF#NdGrT)G`)iuEkD&Ha{6ZG(ev`? z<$3h_JerP@%|8r;@^l`(E01n4>74)Y-c-OB@%%e{S`u2Hhj7u)Z0PWO8ZLTO!gB!N zOkA`yU&2Lehga#j-|^6I3s9=?B0%`R)GG;UeISNkqSPUR)yAmWLLVV&*k__mG~EJvWlZ2pd0vp@*j~z`K){+2|8YxW$I!rznfb>dYl4 pvl(g0M684aVk8xD!b(CMr}SeYR^H)+m2iODndYuc&X-dV{s+plJ&ynY literal 13832 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 diff --git a/spm_global.mexmaci64 b/spm_global.mexmaci64 index 001c9c4bd0efc2084865a928004bde3120071ee2..c38f00450ab08878353a2661d1b2e2a0dcaf17ba 100755 GIT binary patch literal 182012 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 z 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ÁrJ(N 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 zř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¨V>Wh@Go%XnuJd>H53s|J_n^{*sJm1s^R@tE2U6e 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 IuWl&+2VW34_W%F@ diff --git a/spm_global.mexw32 b/spm_global.mexw32 index 621465867b0d664b648ff8973d42c0729d97b5de..ac88a4c901383435db448184f12c53c85e5bdec3 100755 GIT binary patch delta 12569 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 TQANlRPToXz@kldzFZh1|;yLdb delta 12196 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 f numel(SPM.xCon) + xG.spec.Ic = spm_input('Contrast weights','!+1','x','',Inf,SPM.xX.X); + end + + % select contrast if + %------------------------------------------------------------------ + case {'Fitted responses'} + % determine which contrast + %-------------------------------------------------------------- + xG.spec.Ic = spm_input('Which contrast?','!+1','m',{SPM.xCon.name}); + % select session and trial if %------------------------------------------------------------------ case {'Event-related responses','Parametric responses','Volterra Kernels'} @@ -304,7 +316,12 @@ 'LineWidth',6,'Color',Col(3,:),'Parent',ax) end - TTLstr = {xG.def SPM.xCon(xG.spec.Ic).name}; + TTLstr = {xG.def}; + if numel(xG.spec.Ic) == 1 + TTLstr = [TTLstr {SPM.xCon(xG.spec.Ic).name}]; + else + TTLstr = [TTLstr {'user-defined contrast'}]; + end if isfield(SPM,'VCbeta') TTLstr = [TTLstr {'(conditional estimates)'}]; end diff --git a/spm_hist.mexmaci64 b/spm_hist.mexmaci64 index 3728f9c2e4f6c5ffec0ba2f5bb08782661d486df..73de247a8e787a5c801692177d079313f4c23622 100755 GIT binary patch literal 8928 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 F>>tvqH?RNz diff --git a/spm_hist.mexw32 b/spm_hist.mexw32 index 10e9c84d2f7fdcc26997cfe2105c20e097cf2811..7f8689e2e0c7728a58108e0851bf1e31694de274 100755 GIT binary patch delta 33 mcmZoLX)u}af@P}ov&e~We3*AKGj6tKtP}zZY~CU4!3F^1Y7CYD delta 33 mcmZoLX)u}ag5}KLPoWdv_%J&jVAyQUSSbV+*t|p7gAD);Ee{+3 diff --git a/spm_hist.mexw64 b/spm_hist.mexw64 index 769f86a806ca70d7cf070b543cd18cf5400a0343..65e98d821386df6a3fa4232f576340a281011b5f 100755 GIT binary patch delta 32 lcmZp$X|S2_fJO7!)5wWWe3)9dZZ=|c5(e`(SBP|Q0s!l24U+%> delta 32 kcmZp$X|S2_faUMrn9zw&e3+zTHXAWI34{5YD?~at0p(c@3;+NC diff --git a/spm_hist2.mexmaci64 b/spm_hist2.mexmaci64 index ad296a8b8f09295050738aa03b409fc8005b5bf9..865330f806df17921e29015d663417d5a32055af 100755 GIT binary patch literal 13572 zcmeHOdvH|M8NW+5ut4zcDrf*9i-a~nT!K=Fh1{Ekti5X!z>+lCm~h!_Hp!M`6ZQei zOCurR8q=m08HSlw`cgz&v06)K6cPxK0AhHwgNTYRSWK%x6eC5pzwg|;Np>lYGyc_? zJ;OQY`+cu-&Ue3aLe9N;^Xk8^58*gX0>^PWR6S~IBF8nNr!pEfFo@%1Ip0#0&sfoo zF&c6zhEEP|IO?g$vdp@ zss>?ApElO2`WvkB6n}D+v%1dd0Wa3y8r9!3sy<s9%YPL`cja)rlU<5W1Y^XpRmWvB*(Dd%ohDDN^68(GdV=bHy;8C9ARm5PzI zO5%c~d?UXR-?Hqkmc1)$%4)0SI-lpJ{vz(kU&Iz}ILZ&62(`#^Wo`dcy>WheqoPQA zi3;IZe+DK|8deNv9g2F`#%-E@Udxsi+-0=^ynk$aWrHyrdrR4O!Y zs-#Q94vYg}RFPmmA&R4bvFK==mogvP{BZXVfBtgg<0-o&S9U6RdQurWjN^t4n~dA^*L)ya|h1rd(fwKZbzJ{pRD3tz*MH95}z=wH(ufqh({nE zfp`Ss5r{`19)WlS;t_~PARdAL*9a6y!H>;_=AWAL7fB8OGWPI>f|F?S&Y-cJvIal5 z2Cs*HjZ37S96r6b$IMST*u(4dPWA959i#_BpEwJ@BZARJHeFy?&V+tOCVcuSzOc22 zpR$i^;8L*xp-)U0U~`0QPKIVGHm!;c?DTn<3v69OSEAN|Eg9iHRlc{Dk({7p0ANK#~=gE zzj$40&KVL0nxlodM5~dSM`nN;ITC`w8VI!7$O5o5TN{Od)>w*_+fMZGMFgB!f$b#C z8&ZV9*2bq@;tM-riE2B{r*%UU0n@L=;%#pN9D=H?Q&}oPYCFIe9w%$KwEaVIYdcAd z(_p;Y7ZTfk$Pi8&Y>M`h55%dcO=@U2K4dO2FE-1i`zk6bOnl0EmXdwXw?KKqf!tu; z&fMTWDVVoS3Kl#j1^xBb;5Dhqtd|;F14DWweoAZi?NYE!I(9*7IIEF{b}$}BX_cBR zdU_a=4y~a%5Dtei1NPh-*8uRQ#B^M4@EgkUyEl}#NlgoNQt+uN$Rf52wPgF0k8I&8 z@jtjJu}r@r1-qnUAt`uFYIq-Gw$YdfT@k9Gxtx3>n&2HGyaYJ6`R*<<<X~ssM--XSe91@NcHT7N5jfyCY{wmnGFi+uZ%bsN8RW{p2?K-%#FLmc zT~cFbU{p^oKjr=INf>>ATncv3I@CpwMvsLr`Up+QIkI&gvGAs|Wo3Gz@nVgIwbRDzPO7wjT(y^KYraP+{uupHZ|g+ zI@JiW8#W=uMYif{~(F%2RdJm87OY_Y9G_sS?P;q?emo1-(wGX&y^o17G+y zWyz^-BcD=F8z3r?BU0qm+q~&Czu{rrxFHW#;P#APw+sM|bhHnKMO3>-e}jj&_ziQI zhr}N+57U^3gm3TQ6u;p=Y?ALuP5#Fac0V0GSBAEI1jO!Bi13z9?}gltUjPxk%oQhIyq!3LCDbi(3CCYD-_BHZh<$ z*Y|BowzDtu>FgxN5rng*1gB{l#-hz$+}d_lH@7({Q*t2k1v@dO_RwYCpgm-MG<+TF zd1Nv>uZr8uI9xSI*QPwCgbXog+oJXh<=d4U-gJ)NcOOt|!&B2q_;1#JUu@<=~H6bS~U6@(w z*A2az6^RYuL2K|+A!{%mVd%HWQ>kfos2TnGR$nsF8x=ZsBh>^ z@R6sFNm8gvMpGZO?2?*R>q0XD;C2iH(-bg*0lfmqyp_z8$&5_8DW@Wy=}t5BHOn%H zc7w16_d`t|Is;nutPgc6fIRC%uPT5%Zy|HCVuD5@8hW*Up20OLWJ_32n)EKk+;C0H zH*TRMZCafi@`Ht8?qi@#0qG1ZV8EZkz!U&$u$|GVMDs7U_bp-$`KEUfOl$ygnb)Hh zBfXI8j7z%$+-zNh-ND!&sce0OeWZKTLCX=`t&7qwY8e%@wC|zI_ubS?KOTAPJG7FK2f@~bYCucDeby!+R8M4cUb_@bO3e+P&kbIef~S#zyYhk|Yp^Y} zqnCb|B~HXDD3@kix)8vI_Ot?MxxFTMfchljuVwjR0mP?Qt!fUqR8aJD?~LBwS%awL~SGLPeg4dY7bFQ5OtiW zbwqtg6#bu|>Pw>BMDch67wE@#)i|PxK|vN(=%Gc*S#er&n)qaDxtQ?jS3=VGhsDjQ zdjyA0C!XJNpHTS-CtjL-O4x0fEN<|ni<@rqi;aOCVb=Z+v+U36#d%``;xE_jowMq| zV)4QBGjmRdwc=;za|GwCS>nv1df}jf0I?i1g*>xl4|b$=7?&_5}>vv{$%wZteM{$jcClw*~6_REQ4 zuym==yVN8u@lFxf_Y4)@owsXFkFY^l`t+w+FJEcSdfHYjzO+44Slp@2`qc-sMU!o) zcyv*-u<@DK1b)JzIhx-)#O9Yv#U1JEgms+;vGn$dLRMO`c(L(0;hn8%;`lpC#oY@G z;!$q3SpU}t#I5E#g}LSe@wF8>!n2zuiks(66@T%pMSOI{Ucr6G2f`l~eJT9&g|T98 z<_ux(9_{Ru+y}(>S0{+C6cr0w-Z_!gbLRx%=pVa;jr+TVypx4lhsG=u=RG-Ec>YMc zV4U}~aQCKk;qQ+-MXTFU>+v`pKBM1juXLKYLQk!`(&(-A_>8p`#&WyQZcLj#Il_1Q zYs#D+CUMnx2TGzX?zyQ&za(N&W5>(cfQidvy|Kpc^%={Y#uO@tEXzUNX!%D#WBBHoKXEmH=34X;u(HtvE)EI_q z$t^dM8Whc{pKzLhUZYPMqHBTVW_(5a#`Xzy?9FPwP3?E6{VQs}TkSj4{7m+4!w@lk9!``BJC!}sF&IKDoFTQOEN zE!?tXL$+KKnCEfYea@U(e_6FtxdV}B-J8KdZe;QwIej^}h9O2;AH!ASbbDR+Og^HU z5fSB)VrB%*CzRcX*!9hVikutFrHINx4_Pc^(CVF6TT@r<3=peGWhoOS&JvX~-(TbO zxE#c)QdtEqw=a_zb+=-P&Va?^$@5m`*tF7vxQ&T@O5Yq`@yQQ@X1aP{}%x~GM{6W%%LY{JE% zE%ezmD_7r5B03!vH>rJv-2nm7RT33;SwsXe#zPwUI}7@zn{bPIF+@3V3p{13_b_9C z=`ysQJ}5`|J}P0odVez)7_e{b{1{vrgWWNBxq>6}|CI(MZaNqjzbpSUUHHmCdZ$YJ)(zn8aF=+Ac>p;DjB_j6=oj%k>31B|G#&;qJ(`8qJM`opzdu(M|L#>%6`7# IIODkg0-$}j%>V!Z literal 13552 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 diff --git a/spm_hist2.mexw64 b/spm_hist2.mexw64 index ac752e26ad07d48f1fc533ff2227adef6bda0e2d..8ef81ca2c755205856f449a545ed5ffe35ab4419 100755 GIT binary patch delta 33 mcmZn&Xb70_fkpe-)5wWme3-k-88$mJ8p?tNHdn}XZ~_4M-3`0| delta 33 mcmZn&Xb70_f#v_+n9zw|e3%vF7&kjJ8p?tNHdn}XZ~_4GCJi+J diff --git a/spm_imcalc.m b/spm_imcalc.m index 65c2d5e3..929167bb 100644 --- a/spm_imcalc.m +++ b/spm_imcalc.m @@ -9,17 +9,19 @@ % ( and can be omitted from Vo on input. See spm_vol ) % or output image filename % f - MATLAB expression to be evaluated -% flags - cell array of flags: {dmtx,mask,interp,dtype} +% flags - cell array of flags: {dmtx,mask,interp,dtype,descrip} % or structure with these fieldnames -% dmtx - Read images into data matrix? +% dmtx - read images into data matrix? % [defaults (missing or empty) to 0 - no] % mask - implicit zero mask? -% [defaults (missing or empty) to 0] +% [defaults (missing or empty) to 0 - no] % ( negative value implies NaNs should be zeroed ) % interp - interpolation hold (see spm_slice_vol) % [defaults (missing or empty) to 0 - nearest neighbour] % dtype - data type for output image (see spm_type) % [defaults (missing or empty) to 4 - 16 bit signed shorts] +% descrip - content of the 'descrip' field of the NIfTI header +% [defaults (missing or empty) to 'spm - algebra'] % extra_vars... - additional variables which can be used in expression % % Vo (output) - spm_vol structure of output image volume after @@ -77,13 +79,13 @@ % Here we've pre-specified the expression and passed the vector c as an % additional variable (you'll be prompted to select the n images). %__________________________________________________________________________ -% Copyright (C) 1998-2011 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 1998-2016 Wellcome Trust Centre for Neuroimaging % John Ashburner & Andrew Holmes -% $Id: spm_imcalc.m 6124 2014-07-29 11:51:11Z guillaume $ +% $Id: spm_imcalc.m 6961 2016-12-05 17:36:44Z guillaume $ -SVNid = '$Rev: 6124 $'; +SVNid = '$Rev: 6961 $'; %-Parameters & arguments %========================================================================== @@ -118,21 +120,24 @@ %-------------------------------------------------------------------------- if nargin < 4, flags = {}; end if iscell(flags) - if length(flags) < 4, dtype = []; else dtype = flags{4}; end - if length(flags) < 3, interp = []; else interp = flags{3}; end - if length(flags) < 2, mask = []; else mask = flags{2}; end - if length(flags) < 1, dmtx = []; else dmtx = flags{1}; end + if numel(flags) < 5, descrip = []; else descrip = flags{5}; end + if numel(flags) < 4, dtype = []; else dtype = flags{4}; end + if numel(flags) < 3, interp = []; else interp = flags{3}; end + if numel(flags) < 2, mask = []; else mask = flags{2}; end + if numel(flags) < 1, dmtx = []; else dmtx = flags{1}; end else - if isfield(flags,'dmtx'), dmtx = flags.dmtx; else dmtx = []; end - if isfield(flags,'mask'), mask = flags.mask; else mask = []; end - if isfield(flags,'interp'), interp = flags.interp; else interp = []; end - if isfield(flags,'dtype'), dtype = flags.dtype; else dtype = []; end + if isfield(flags,'dmtx'), dmtx = flags.dmtx; else dmtx = []; end + if isfield(flags,'mask'), mask = flags.mask; else mask = []; end + if isfield(flags,'interp'), interp = flags.interp; else interp = []; end + if isfield(flags,'dtype'), dtype = flags.dtype; else dtype = []; end + if isfield(flags,'descrip'), descrip = flags.descrip; else descrip = ''; end end -if ischar(dtype), dtype = spm_type(dtype); end -if isempty(interp), interp = 0; end -if isempty(mask), mask = 0; end -if isempty(dmtx), dmtx = 0; end -if isempty(dtype), dtype = spm_type('int16'); end +if ischar(dtype), dtype = spm_type(dtype); end +if isempty(interp), interp = 0; end +if isempty(mask), mask = 0; end +if isempty(dmtx), dmtx = 0; end +if isempty(dtype), dtype = spm_type('int16'); end +if isempty(descrip), descrip = 'spm - algebra'; end %-Output image %-------------------------------------------------------------------------- @@ -141,10 +146,10 @@ Vo = struct('fname', fullfile(p, [n, e]),... 'dim', Vi(1).dim(1:3),... 'dt', [dtype spm_platform('bigend')],... - 'pinfo', [Inf Inf Inf]',... + 'pinfo', [Inf Inf 0]',... 'mat', Vi(1).mat,... 'n', 1,... - 'descrip', 'spm - algebra'); + 'descrip', descrip); end %-Process any additional variables diff --git a/spm_int_L.m b/spm_int_L.m index 23da54f2..4729991b 100644 --- a/spm_int_L.m +++ b/spm_int_L.m @@ -1,10 +1,12 @@ -function [y] = spm_int_L(P,M,U) +function [y] = spm_int_L(P,M,U,N) % Integrate a MIMO nonlinear system using a fixed Jacobian: J(x(0)) -% FORMAT [y] = spm_int_L(P,M,U) +% FORMAT [y] = spm_int_L(P,M,U,[N]) % P - model parameters % M - model structure % U - input structure or matrix % +% N - number of local linear iterations per time step [default: 1] +% % y - (v x l) response y = g(x,u,P) %__________________________________________________________________________ % Integrates the MIMO system described by @@ -58,13 +60,14 @@ % Copyright (C) 2008-2016 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_int_L.m 6855 2016-08-06 10:06:35Z karl $ +% $Id: spm_int_L.m 7143 2017-07-29 18:50:38Z karl $ % convert U to U.u if necessary %-------------------------------------------------------------------------- if ~isstruct(U), u.u = U; U = u; end try, dt = U.dt; catch, dt = 1; end +if nargin < 4; N = 1; end % Initial states and inputs %-------------------------------------------------------------------------- @@ -104,10 +107,10 @@ end M.g = g; -% dx(t)/dt and Jacobian df/dx and check for delay operator +% dx(t)/dt and Jacobian df/dx (and check for delay operator) %-------------------------------------------------------------------------- -D = 1; -n = spm_length(x); +D = 1; +n = spm_length(x); if nargout(f) >= 3 [fx,dfdx,D] = f(x,u,P,M); @@ -115,14 +118,13 @@ [fx,dfdx] = f(x,u,P,M); else - dfdx = spm_cat(spm_diff(f,x,u,P,M,1)); -end -OPT.tol = 1e-6*norm((dfdx),'inf'); -while true - try, p = abs(eigs(dfdx,1,'SR',OPT)); break; end + dfdx = spm_cat(spm_diff(f,x,u,P,M,1)); end -N = ceil(max(1,dt*p*2)); -Q = (spm_expm(dt*D*dfdx/N) - speye(n,n))*spm_inv(dfdx); + +% local linear update operator Q = (expm(dt*J) - I)*inv(J) +%-------------------------------------------------------------------------- +dfdx = dfdx - speye(n,n)*exp(-16); +Q = (spm_expm(dt*D*dfdx/N) - speye(n,n))/dfdx; % integrate %========================================================================== diff --git a/spm_inv.m b/spm_inv.m index f5024a9c..3670c380 100644 --- a/spm_inv.m +++ b/spm_inv.m @@ -12,7 +12,7 @@ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_inv.m 4360 2011-06-14 16:46:37Z ged $ +% $Id: spm_inv.m 7143 2017-07-29 18:50:38Z karl $ % check A %-------------------------------------------------------------------------- @@ -22,7 +22,7 @@ % tolerance %-------------------------------------------------------------------------- if nargin == 1 - TOL = max(eps(norm(A,'inf'))*max(m,n),exp(-32)); + TOL = max(eps(norm(A,'inf'))*max(m,n),exp(-32)); end % inverse diff --git a/spm_jobman.m b/spm_jobman.m index ee957556..0ab62a85 100644 --- a/spm_jobman.m +++ b/spm_jobman.m @@ -53,10 +53,10 @@ % jobs - char or cell array of filenames, or % 'jobs'/'matlabbbatch' variable %__________________________________________________________________________ -% Copyright (C) 2005-2015 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2005-2016 Wellcome Trust Centre for Neuroimaging % Volkmar Glauche -% $Id: spm_jobman.m 6656 2015-12-24 16:49:52Z guillaume $ +% $Id: spm_jobman.m 6968 2016-12-09 15:58:00Z guillaume $ %__________________________________________________________________________ @@ -323,13 +323,24 @@ end case 'm' try - fid = fopen(filenames{i},'rt'); - str = fread(fid,'*char'); - fclose(fid); + str = fileread(filenames{i}); eval(str); catch warning('spm:spm_jobman:loadFailed','Load failed: ''%s''',filenames{i}); end + case 'json' + try + S = spm_jsonread(filenames{i}); + if isstruct(S) + for j=1:numel(S) + matlabbatch{j} = S(j); + end + else + matlabbatch = S; + end + catch + warning('spm:spm_jobman:loadFailed','Load failed: ''%s''',filenames{i}); + end otherwise warning('spm:spm_jobman:unknownExt','Unknown extension: ''%s''',filenames{i}); end diff --git a/spm_jsonread.m b/spm_jsonread.m index 462f068a..77f09b29 100644 --- a/spm_jsonread.m +++ b/spm_jsonread.m @@ -1,18 +1,22 @@ -function json = spm_jsonread(filename) +function json = spm_jsonread(filename, opts) % JSON (JavaScript Object Notation) parser - a compiled routine -% FORMAT json = spm_jsonread(filename) +% FORMAT json = spm_jsonread(filename, opts) % filename - name of a JSON file or JSON string % json - JSON structure +% opts - structure of optional parameters: +% replacementStyle: string to control how non-alphanumeric +% characters are replaced {'underscore','hex','delete','nop'} +% [Default: 'underscore'] % % References: % JSON Standard: http://www.json.org/ % JSMN C parser: http://zserge.com/jsmn.html % jsondecode: http://www.mathworks.com/help/matlab/ref/jsondecode.html %__________________________________________________________________________ -% Copyright (C) 2015-2016 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2015-2017 Wellcome Trust Centre for Neuroimaging % Guillaume Flandin -% $Id: spm_jsonread.m 6863 2016-08-30 14:56:27Z guillaume $ +% $Id: spm_jsonread.m 7045 2017-03-17 10:41:12Z guillaume $ %-This is merely the help file for the compiled routine diff --git a/spm_jsonread.mexa64 b/spm_jsonread.mexa64 index 0691604a47988458d39af1172a6a51476e6b3f0a..c9303a7976fb128df74f40c342791911724db54b 100755 GIT binary patch literal 22943 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 YEyvoK6(DBW^9Y5VmnEjf)KL&k=l}18W~e+ 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 Ua@=&@JX<5#Bm5$7^U44J0*~!YfB*mh diff --git a/spm_jsonread.mexmaci64 b/spm_jsonread.mexmaci64 index a4bec1ea2b4bf8e8f79d11d84d83d093f8451e3c..423167e70e68e3c9c49fc7a5b984465bd8a2df05 100755 GIT binary patch literal 19748 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 Q-p~+EJDEZ6I&9(iPrP#T_5c6? literal 14996 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 Kz~et8YySuPUZt=!~_P!)+Wc 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 delta 6197 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 1 - filename = varargin{1}; - json = varargin{2}; - root = inputname(2); + if ischar(varargin{1}) + filename = varargin{1}; + json = varargin{2}; + else + filename = ''; + json = varargin{1}; + opt = varargin{2}; + end + if nargin > 2 + opt = varargin{3}; + end else filename = ''; json = varargin{1}; - root = inputname(1); end +fn = fieldnames(opt); +for i=1:numel(fn) + if ~isfield(opts,lower(fn{i})), warning('Unknown option "%s".',fn{i}); end + opts.(lower(fn{i})) = opt.(fn{i}); +end +optregistry(opts); %-JSON serialization %-------------------------------------------------------------------------- -if ~isstruct(json) && ~iscell(json) - if ~isempty(root) - json = struct(root,json); - else - error('Invalid JSON structure.'); - end -end -S = jsonwrite_var(json,NaN); % 0 or NaN +fmt('init',sprintf(opts.indent)); +S = jsonwrite_var(json,~isempty(opts.indent)); %-Output %-------------------------------------------------------------------------- @@ -54,76 +74,177 @@ end -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%========================================================================== function S = jsonwrite_var(json,tab) -if nargin < 2, tab = 0; end -if isstruct(json) +if nargin < 2, tab = ''; end +if isstruct(json) || isa(json,'containers.Map') S = jsonwrite_struct(json,tab); elseif iscell(json) S = jsonwrite_cell(json,tab); elseif ischar(json) - S = jsonwrite_char(json); + if size(json,1) <= 1 + S = jsonwrite_char(json); + else + S = jsonwrite_cell(cellstr(json),tab); + end elseif isnumeric(json) || islogical(json) S = jsonwrite_numeric(json); +elseif isa(json,'string') + if numel(json) == 1 + if ismissing(json) + S = 'null'; + else + S = jsonwrite_char(char(json)); + end + else + json = arrayfun(@(x)x,json,'UniformOutput',false); + json(cellfun(@(x) ismissing(x),json)) = {'null'}; + idx = find(size(json)~=1); + if numel(idx) == 1 % vector + S = jsonwrite_cell(json,tab); + else % array + S = jsonwrite_cell(num2cell(json,setdiff(1:ndims(json),idx(1))),tab); + end + end +elseif isa(json,'datetime') || isa(json,'categorical') + S = jsonwrite_var(string(json)); +elseif isa(json,'table') + S = struct; + s = size(json); + vn = json.Properties.VariableNames; + for i=1:s(1) + for j=1:s(2) + if iscell(json{i,j}) + S(i).(vn{j}) = json{i,j}{1}; + else + S(i).(vn{j}) = json{i,j}; + end + end + end + S = jsonwrite_struct(S,tab); else - error('Class "%s" is not supported.',class(json)); + if numel(json) ~= 1 + json = arrayfun(@(x)x,json,'UniformOutput',false); + S = jsonwrite_cell(json,tab); + else + p = properties(json); + if isempty(p), p = fieldnames(json); end % for pre-classdef + s = struct; + for i=1:numel(p) + s.(p{i}) = json.(p{i}); + end + S = jsonwrite_struct(s,tab); + %error('Class "%s" is not supported.',class(json)); + end end -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%========================================================================== function S = jsonwrite_struct(json,tab) if numel(json) == 1 - fn = fieldnames(json); + if isstruct(json), fn = fieldnames(json); else fn = keys(json); end S = ['{' fmt('\n',tab)]; for i=1:numel(fn) - S = [S fmt((tab+1)*2) jsonwrite_char(fn{i}) ':' fmt(~isnan(tab)) ... - jsonwrite_var(json.(fn{i}),tab+1)]; + key = fn{i}; + if strcmp(optregistry('replacementStyle'),'hex') + key = regexprep(key,... + '^x0x([0-9a-fA-F]{2})', '${native2unicode(hex2dec($1))}'); + key = regexprep(key,... + '0x([0-9a-fA-F]{2})', '${native2unicode(hex2dec($1))}'); + end + if isstruct(json), val = json.(fn{i}); else val = json(fn{i}); end + S = [S fmt(tab) jsonwrite_char(key) ':' fmt(' ',tab) ... + jsonwrite_var(val,tab+1)]; if i ~= numel(fn), S = [S ',']; end S = [S fmt('\n',tab)]; end - S = [S fmt(2*tab) '}']; + S = [S fmt(tab-1) '}']; else S = jsonwrite_cell(arrayfun(@(x) {x},json),tab); end -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%========================================================================== function S = jsonwrite_cell(json,tab) +if numel(json) == 0 ... + || (numel(json) == 1 && iscellstr(json)) ... + || all(all(cellfun(@isnumeric,json))) ... + || all(all(cellfun(@islogical,json))) + tab = ''; +end S = ['[' fmt('\n',tab)]; for i=1:numel(json) - S = [S fmt((tab+1)*2) jsonwrite_var(json{i},tab+1)]; + S = [S fmt(tab) jsonwrite_var(json{i},tab+1)]; if i ~= numel(json), S = [S ',']; end S = [S fmt('\n',tab)]; end -S = [S fmt(2*tab) ']']; +S = [S fmt(tab-1) ']']; -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%========================================================================== function S = jsonwrite_char(json) % any-Unicode-character-except-"-or-\-or-control-character % \" \\ \/ \b \f \n \r \t \u four-hex-digits -json = regexprep(json,'[^\\]"','\\"'); +json = strrep(json,'\','\\'); +json = strrep(json,'"','\"'); +%json = strrep(json,'/','\/'); +json = strrep(json,sprintf('\b'),'\b'); +json = strrep(json,sprintf('\f'),'\f'); +json = strrep(json,sprintf('\n'),'\n'); +json = strrep(json,sprintf('\r'),'\r'); +json = strrep(json,sprintf('\t'),'\t'); S = ['"' json '"']; -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%========================================================================== function S = jsonwrite_numeric(json) -if numel(json) > 1 +if any(imag(json(:))) + error('Complex numbers not supported.'); +end +if numel(json) == 0 + S = jsonwrite_cell({}); + return; +elseif numel(json) > 1 idx = find(size(json)~=1); if numel(idx) == 1 % vector - S = jsonwrite_cell(num2cell(json),NaN); + S = jsonwrite_cell(num2cell(json),''); else % array - S = jsonwrite_cell(num2cell(json,setdiff(1:ndims(json),idx(1))),NaN); + S = jsonwrite_cell(num2cell(json,setdiff(1:ndims(json),idx(1))),''); end return; end if islogical(json) if json, S = 'true'; else S = 'false'; end +elseif ~isfinite(json) + if optregistry('convertinfandnan') + S = 'null'; + else + if isnan(json) + S = 'NaN'; + elseif json > 0 + S = 'Infinity'; + else + S = '-Infinity'; + end + end else - S = num2str(json); + S = num2str(json,16); end -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%========================================================================== function b = fmt(varargin) +persistent tab; +if nargin == 2 && isequal(varargin{1},'init') + tab = varargin{2}; +end b = ''; if nargin == 1 - if ~isnan(varargin{1}), b = blanks(varargin{1}); end + if varargin{1} > 0, b = repmat(tab,1,varargin{1}); end elseif nargin == 2 - if ~isnan(varargin{2}), b = sprintf(varargin{1}); end + if ~isempty(tab) && ~isempty(varargin{2}), b = sprintf(varargin{1}); end +end + +%========================================================================== +function val = optregistry(opts) +persistent options +if isstruct(opts) + options = opts; +else + val = options.(lower(opts)); end diff --git a/spm_kernels.m b/spm_kernels.m index 355b2bb9..25c54f39 100644 --- a/spm_kernels.m +++ b/spm_kernels.m @@ -34,7 +34,7 @@ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_kernels.m 6755 2016-03-25 09:48:34Z karl $ +% $Id: spm_kernels.m 6937 2016-11-20 12:30:40Z karl $ % assign inputs @@ -114,32 +114,6 @@ end end - -% check for convergence -%-------------------------------------------------------------------------- -q = 0; -for p = 1:m - q = q | norm(M{N,p},'inf') > norm(M{1,p},'inf'); - q = q | norm(M{N,p},'inf') > exp(16); - q = q | isnan(norm(M{N,p})); -end - -% if necessary, remove unstable modes and repeat with a pseudoinverse -%-------------------------------------------------------------------------- -if q - M0 = spm_bilinear_condition(M0); - e1 = expm(dt*M0); - ei = 1; - for i = 1:N - ei = e1*ei; - ie = spm_pinv(ei); - for p = 1:m - M{i,p} = ei*M1{p}*ie; - end - end -end - - % 0th order kernel %-------------------------------------------------------------------------- X0 = sparse(1,1,1,n,1); @@ -148,7 +122,6 @@ K0 = L1*H0; end - % 1st order kernel %-------------------------------------------------------------------------- if nargout > 1 @@ -160,7 +133,6 @@ end end - % 2nd order kernels %-------------------------------------------------------------------------- if nargout > 2 diff --git a/spm_krutil.mexmaci64 b/spm_krutil.mexmaci64 index 4261520369a469ca10677fc78663cbc58939d5ca..188344875ffa438563814ade4069aee379b8c013 100755 GIT binary patch literal 17636 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 delta 32 lcmZq3X~>!Ig2hB`S=hukK1|Q^Hd`^C(gE`~bLjnG2LR$i4B-F( diff --git a/spm_krutil.mexw64 b/spm_krutil.mexw64 index 2d7daf1e2b68caf38f91e9b3c6a474856f2ceb1c..e9c3a85485799ed195d0a6f9046548dbf86aac8d 100755 GIT binary patch delta 35 ocmZo@VQgq&obZ7~>)F%DiC=t}4VE!%c4ibb2McVDuvozf00k2c3;+NC delta 35 ocmZo@VQgq&obZ8#OL|$@#4kR~1)PkVof!qq!2+8jELLy=0NA7pRsaA1 diff --git a/spm_list.m b/spm_list.m index 70009caa..74c2fc54 100644 --- a/spm_list.m +++ b/spm_list.m @@ -114,7 +114,7 @@ % Copyright (C) 1999-2015 Wellcome Trust Centre for Neuroimaging % Karl Friston, Andrew Holmes, Guillaume Flandin -% $Id: spm_list.m 6903 2016-10-12 11:36:41Z guillaume $ +% $Id: spm_list.m 6950 2016-11-25 12:05:08Z guillaume $ %========================================================================== @@ -923,12 +923,15 @@ if nargin == 3, ofile = varargin{3}; else ofile = [tempname '.csv']; end - fid = fopen(ofile,'wt'); - fprintf(fid,[repmat('%s,',1,11) '%d,,\n'],TabDat.hdr{1,:}); - fprintf(fid,[repmat('%s,',1,12) '\n'],TabDat.hdr{2,:}); - fmt = TabDat.fmt; + fid = fopen(ofile,'wt'); + ncol = size(TabDat.hdr,2); + fmt = repmat('%s,',1,ncol); + c = repmat(',',1,nnz([TabDat.hdr{2,:}]==',')); + fprintf(fid,[fmt(1:end-1) c '\n'],TabDat.hdr{1,:}); + fprintf(fid,[fmt(1:end-1) '\n'],TabDat.hdr{2,:}); + fmt = strtrim(TabDat.fmt); [fmt{2,:}] = deal(','); fmt = [fmt{:}]; - fmt(end:end+1) = '\n'; fmt = strrep(fmt,' ',','); + fmt = [fmt(1:end-1) '\n']; fmt = strrep(fmt,' ',','); for i=1:size(TabDat.dat,1) fprintf(fid,fmt,TabDat.dat{i,:}); end diff --git a/spm_load.m b/spm_load.m index 57963d3b..89602f3d 100644 --- a/spm_load.m +++ b/spm_load.m @@ -1,16 +1,16 @@ function x = spm_load(f,v) % Load text and numeric data from file % FORMAT x = spm_load(f,v) -% f - filename {txt,mat,csv,tsv,json} +% f - filename (can be gzipped) {txt,mat,csv,tsv,json} % v - name of field to return if data stored in a structure [default: ''] % or index of column if data stored as an array % % x - corresponding data array or structure %__________________________________________________________________________ -% Copyright (C) 1995-2015 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 1995-2017 Wellcome Trust Centre for Neuroimaging % Guillaume Flandin -% $Id: spm_load.m 6894 2016-09-30 16:48:46Z spm $ +% $Id: spm_load.m 7097 2017-06-07 13:53:55Z guillaume $ %-Get a filename if none was passed @@ -39,17 +39,11 @@ case 'mat' x = load(f,'-mat'); case 'csv' - try - x = csvread(f); - catch - x = dsvread(f,','); - end + % x = csvread(f); % numeric data only + x = dsvread(f,','); case 'tsv' - try - x = dlmread(f,'\t'); - catch - x = dsvread(f,'\t'); - end + % x = dlmread(f,'\t'); % numeric data only + x = dsvread(f,'\t'); case 'json' x = spm_jsonread(f); case 'gz' @@ -142,7 +136,7 @@ try var = genvarname(var); catch - var = matlab.lang.makeValidName(var); + var = matlab.lang.makeValidName(var,'ReplacementStyle','hex'); var = matlab.lang.makeUniqueStrings(var); end S = S(h+1:end); @@ -156,6 +150,10 @@ %-Parse file %-------------------------------------------------------------------------- +if strcmpi(spm_check_version,'octave') % bug #51093 + S = strrep(S,delim,'#'); + delim = '#'; +end d = textscan(S,'%s','Delimiter',delim); if rem(numel(d{1}),N), error('Varying number of delimiters per line.'); end d = reshape(d{1},N,[])'; diff --git a/spm_maff8.m b/spm_maff8.m index a41194ad..39322fc8 100644 --- a/spm_maff8.m +++ b/spm_maff8.m @@ -20,7 +20,7 @@ % Copyright (C) 2008-2014 Wellcome Trust Centre for Neuroimaging % John Ashburner -% $Id: spm_maff8.m 6421 2015-04-23 16:54:25Z john $ +% $Id: spm_maff8.m 7202 2017-11-08 12:30:01Z john $ [buf,MG,x,ff] = loadbuf(varargin{1:3}); [M,ll,h] = affreg(buf, MG, x, ff, varargin{4:end}); @@ -189,7 +189,7 @@ h0(:,k) = h0(:,k) + accumarray(gm,q(:,k)./sq,[256 1]); end end - h1 = conv2((h0+eps)/sum(h0(:)),krn,'same'); + h1 = conv2((h0+eps)/sum(h0(:)+eps),krn,'same'); h1 = h1./(sum(h1,2)*sum(h1,1)); if ~rem(subit,4), if (ll1-ll0)/sum(h0(:)) < 1e-5, break; end diff --git a/spm_mesh_contour.m b/spm_mesh_contour.m new file mode 100644 index 00000000..33c89236 --- /dev/null +++ b/spm_mesh_contour.m @@ -0,0 +1,319 @@ +function S = spm_mesh_contour(M,z) +% Compute contour lines of a triangular mesh +% FORMAT S = spm_mesh_contour(M,z) +% M - a GIfTI object or patch structure +% z - height of z-plane +% +% S - structure of contour levels +%__________________________________________________________________________ +% +% figure +% hold on +% M = gifti(fullfile(spm('Dir'),'canonical','cortex_20484.surf.gii')); +% S = spm_mesh_contour(M,linspace(min(M.vertices(:,3)),max(M.vertices(:,3)),20)); +% for i=1:numel(S) +% plot3(S(i).xdata,S(i).ydata,repmat(S(i).level,1,numel(S(i).xdata))); +% end +%__________________________________________________________________________ +% Copyright (C) 2017 Wellcome Trust Centre for Neuroimaging + +% Guillaume Flandin +% $Id: spm_mesh_contour.m 7183 2017-10-09 15:26:47Z guillaume $ + + +if numel(z) == 1, z = [z z]; end +[C,H] = tricontour(M.faces, ... + M.vertices(:,1), M.vertices(:,2), M.vertices(:,3), z); +if ~isempty(C) + S = contourdata(C); +else + S = struct('xdata',{},'ydata',{},'level',{},'numel',{},'isopen',{}); +end + + +%========================================================================== +% Copyright (c) 2006, Duane Hanselman +% All rights reserved. +% +% Redistribution and use in source and binary forms, with or without +% modification, are permitted provided that the following conditions are +% met: +% +% * Redistributions of source code must retain the above copyright +% notice, this list of conditions and the following disclaimer. +% * Redistributions in binary form must reproduce the above copyright +% notice, this list of conditions and the following disclaimer in +% the documentation and/or other materials provided with the distribution +% +% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +% POSSIBILITY OF SUCH DAMAGE. +%========================================================================== + +function [c,h]=tricontour(tri,x,y,z,nv) +%TRICONTOUR Triangular Contour Plot. +% TRICONTOUR(TRI,X,Y,Z,N) draws scalar N contour lines treating the values +% in Z as heights above a plane. TRI,X,Y,and Z define a triangulation where +% the triangles are defined by the M-by-3 face matrix TRI, such as that +% returned by DELAUNAY. Each row of TRI contains indices into the X,Y, and +% Z vertex vectors to define a single triangular face. Contours are +% computed directly from the triangulation rather than interpolating back +% to a cartesian grid using GRIDDATA. +% TRICONTOUR(TRI,X,Y,Z,V) draws length(V) contour lines at the values +% specified in vector V. +% TRICONTOUR(TRI,X,Y,Z,[v v]) draws a single contour line at the level v. +% +% [C,H] = TRICONTOUR(...) returns contour matrix C as described in CONTOURC +% and a vector of handles H to the created patch objects. +% H can be used to set patch properties. +% CLABEL(C) or CLABEL(C,H) labels the contour levels. +% +% Example: +% x=linspace(-3,3,39); +% y=linspace(-2.5,2.5,49); +% [xx,yy]=meshgrid(x,y); +% zz=peaks(xx,yy); +% v=-3:1:5; % contour levels +% subplot(1,2,1) +% [C,h]=contour(xx,yy,zz,v); % standard contour for comparison +% clabel(C) +% title Contour +% +% idx=randperm(numel(zz)); % grab some scattered indices +% n=idx(1:ceil(numel(zz)/2))'; % one half of them +% x=xx(n); % get scattered data +% y=yy(n); +% z=zz(n); +% tri=delaunay(x,y); % triangulate scattered data +% subplot(1,2,2) +% [C,h]=tricontour(tri,x,y,z,v); +% clabel(C,h) +% title TriContour +% +% view(3) displays the contour in 3-D. +% +% See also DELAUNAY, CONTOUR, TRIMESH, TRISURF, TRIPLOT, PATCH. + +% D.C. Hanselman, University of Maine, Orono, ME 04469 +% MasteringMatlab@yahoo.com +% Mastering MATLAB 7 +% 2006-05-07, 2006-05-16, 2006-07-25 + +% https://www.mathworks.com/matlabcentral/fileexchange/38858 + +if nargin<5 + error('Not Enough Input Arguments.') +end +x=x(:); % convert input data into column vectors +y=y(:); +z=z(:); +xlen=length(x); +if ~isequal(xlen,length(y),length(z)) + error('X, Y, and Z Must Have the Same Number of Elements.') +end +if size(tri,2)~=3 || any(tri(:)<0) || any(tri(:)>xlen) + error('TRI Must Be a Valid Triangulation of the Data in X, Y, Z.') +end + +zs=z(tri); +zmax=max(max(zs)); % find max and min in z data that is in tri +zmin=min(min(zs)); + +if length(nv)==1 % nv is number of contours + zlev=linspace(zmax,zmin,nv+2); +elseif length(nv)==2 && nv(1)==nv(2) % nv is one contour level + zlev=nv(1); +else % nv is vector of contour levels + zlev=sort(nv,'descend'); +end +zlev(zlev>=zmax | zlev<=zmin)=[]; % eliminate contours outside data limits +nlev=length(zlev); + +if nlev==0 + %warning('No Contours to Plot. Chosen Contours Outside Limits of Data.'); + c = []; h = []; return; +end + +% precondition the input data +[zs,zidx]=sort(zs,2); % sort vertices by z value ascending +%for k=1:size(zs,1) % shuffle triangles to match +% tri(k,:)=tri(k,zidx(k,:)); +%end +tri2 = tri'; tri = tri2(zidx+repmat(3*(0:size(zidx,1)-1)',1,3)); clear tri2; + +if nargout<2 % Added by Torben to suppress graphics + hax=newplot; % create new axis if needed +end +h=[]; % patch handle storage + +C=zeros(2,0); % Clabel data storage +cs=[2 1]; % column swap vector cs(1)=2, cs(2)=1; + +% Main Loop --------------------------------------------------------------- +for v=1:nlev % one contour level at a time + zc=zlev(v); % chosen level + above=zs>=zc; % true for vertices above given contour + numabove=sum(above,2); % number of triangle vertices above contour + tri1=tri(numabove==1,:); % triangles with one vertex above contour + tri2=tri(numabove==2,:); % triangles with two vertices above contour + n1=size(tri1,1); % number with one vertex above + n2=size(tri2,1); % number with two vertices above + + edge=[tri1(:,[1 3]) % first column is indices below contour level + tri1(:,[2 3]) % second column is indices above contour level + tri2(:,[1 2]) + tri2(:,[1 3])]; + if n1==0 % assign edges to triangle number + n=[1:n2 1:n2]'; + elseif n2==0 + n=[1:n1 1:n1]'; + else + n=[1:n1 1:n1 n1+(1:n2) n1+(1:n2)]'; + end + + [edge,idx]=sortrows(edge); % put shared edges next to each other + n=n(idx); % shuffle triangle numbers to match + + idx=all(diff(edge)==0,2); % find shared edges + idx=[idx;false]|[false;idx]; % True for all shared edges + + % eliminate redundant edges, two triangles per interior edge + edgeh=edge(~idx,:); % hull edges + nh=n(~idx); % hull triangle numbers + if ~isempty(nh) + nh(end,2)=0; % zero second column for hull edges + end + edges=edge(idx,:); % shared edges + edges=edges(1:2:end-1,:); % take only unique edges + ns=n(idx); % interior triangle numbers + ns=[ns(1:2:end) ns(2:2:end)]; % second column is second triangle + edge=[edgeh;edges]; % unique edges + nn=[nh;ns]; % two columns of triangle numbers + ne=size(edge,1); % number of edges + + flag=true(ne,2); % true for each unused edge per triangle + tmp=zeros(ne+1,1); % contour data temporary storage + + xe=x(edge); % x values at vertices of edges + ye=y(edge); % y values at vertices of edges + ze=z(edge); % z data at vertices of edges + + alpha=(zc-ze(:,1))./(ze(:,2)-ze(:,1)); % interpolate all edges + xc=alpha.*(xe(:,2)-xe(:,1)) + xe(:,1); % x values on this contour + yc=alpha.*(ye(:,2)-ye(:,1)) + ye(:,1); % y values on this contour + + while any(flag) % while there are still unused edges ----------------- + + xtmp=tmp; + ytmp=tmp; + [ir,ic]=find(flag,1); % find next unused edge + flag(ir,ic)=false; % mark this edge used + + k=1; % first data point in subcontour + xtmp(k)=xc(ir); % store data from this edge + ytmp(k)=yc(ir); + + while true % complete this subcontour --------------------------- + + [ir,ic]=find(flag&nn(ir,ic)==nn,1);% find other edge of triangle + flag(ir,ic)=false; % mark this edge used + k=k+1; + xtmp(k)=xc(ir); % store data from this edge + ytmp(k)=yc(ir); + + ic=cs(ic); % other triangle that shares edge + + if nn(ir,ic)==0 % reached hull, subcontour complete + k=k+1; + xtmp(k)=nan; % don't let subcontour close + ytmp(k)=nan; + break + elseif ~flag(ir,ic) % complete closed subcontour + break + else % more points remain on subcontour + flag(ir,ic)=false; % mark this edge used + end + end % while true ---------------------------------------------------- + xtmp(k+1:end)=[]; % throw away unused storage + ytmp(k+1:end)=[]; % xtmp,ytmp contain subcontour + + if nargout<2 % plot the subcontour + patch('XData',xtmp,'YData',ytmp,'CData',repmat(zc,k,1),... + 'Parent',hax,'FaceColor','none','EdgeColor','flat',... + 'UserData',zc) + C=horzcat(C,[zc xtmp';k ytmp']); % contour label data + else %MODIFIED by TEL to suppress plot % plot subcontour and create output + % h=[h;patch('XData',xtmp,'YData',ytmp,'CData',repmat(zc,k,1),... + % 'Parent',hax,'FaceColor','none','EdgeColor','flat',... + % 'UserData',zc)]; %#ok + C=horzcat(C,[zc xtmp';k ytmp']); % contour label data + end + end % while any(flag) -------------------------------------------------- +end % for v=1:nlev +if nargout + c=C; +end + +function s = contourdata(c) +%CONTOURDATA Extract Contour Data from Contour Matrix C. +% CONTOUR, CONTOURF, CONTOUR3, and CONTOURC all produce a contour matrix +% C that is traditionally used by CLABEL for creating contour labels. +% +% S = CONTOURDATA(C) extracts the (x,y) data pairs describing each contour +% line and other data from the contour matrix C. The vector array structure +% S returned has the following fields: +% +% S(k).level contains the contour level height of the k-th line. +% S(k).numel contains the number of points describing the k-th line. +% S(k).isopen is True if the k-th contour is open and False if it is closed. +% S(k).xdata contains the x-axis data for the k-th line as a column vector. +% S(k).ydata contains the y-axis data for the k-th line as a column vector. +% +% For example: PLOT(S(k).xdata,S(k).ydata)) plots just the k-th contour. +% +% See also CONTOUR, CONTOURF, CONTOUR3, CONTOURC. + +% From the help text of CONTOURC: +% The contour matrix C is a two row matrix of contour lines. Each +% contiguous drawing segment contains the value of the contour, +% the number of (x,y) drawing pairs, and the pairs themselves. +% The segments are appended end-to-end as +% +% C = [level1 x1 x2 x3 ... level2 x2 x2 x3 ...; +% pairs1 y1 y2 y3 ... pairs2 y2 y2 y3 ...] + +% D.C. Hanselman, University of Maine, Orono, ME 04469 +% MasteringMatlab@yahoo.com +% Mastering MATLAB 7 +% 2007-05-22 + +% https://www.mathworks.com/matlabcentral/fileexchange/38863 + +if nargin<1 || ~isfloat(c) || size(c,1)~=2 || size(c,2)<4 + error('CONTOURDATA:rhs',... + 'Input Must be the 2-by-N Contour Matrix C.') +end + +tol=1e-12; +k=1; % contour line number +col=1; % index of column containing contour level and number of points + +while coltol || ... + abs(diff(c(2,idx([1 end]))))>tol; %#ok + k=k+1; + col=col+c(2,col)+1; +end diff --git a/spm_mesh_join.m b/spm_mesh_join.m new file mode 100644 index 00000000..c18fc4f2 --- /dev/null +++ b/spm_mesh_join.m @@ -0,0 +1,35 @@ +function M = spm_mesh_join(Ms) +% Join a list of surface meshes into a single one +% FORMAT M = spm_mesh_join(Ms) +% Ms - a patch structure array +% +% M - a patch structure +% +% See also spm_mesh_split +%__________________________________________________________________________ +% Copyright (C) 2016 Wellcome Trust Centre for Neuroimaging + +% Guillaume Flandin +% $Id: spm_mesh_join.m 6912 2016-10-26 14:50:53Z guillaume $ + + +fn = fieldnames(Ms(1)); +M = cell2struct(cell(numel(fn),1),fn); + +for i=1:numel(Ms) + if i==1 + M.faces = Ms(i).faces; + else + M.faces = [M.faces; Ms(i).faces+size(M.vertices,1)]; + end + M.vertices = [M.vertices; Ms(i).vertices]; + try, M.cdata = [M.cdata; Ms(i).cdata]; end + try + if i==1, M.mat = Ms(i).mat; end + end + if isfield(M,'mat') + if sum(sum(M.mat - Ms(i).mat)) > 10*eps + error('Meshes have different orientation.'); + end + end +end diff --git a/spm_mesh_normals.m b/spm_mesh_normals.m index 46023332..4b439447 100644 --- a/spm_mesh_normals.m +++ b/spm_mesh_normals.m @@ -1,34 +1,80 @@ -function N = spm_mesh_normals(M, unit) +function [Nv, Nf] = spm_mesh_normals(M, unit) % Compute (unit) normals of a surface mesh -% FORMAT N = spm_mesh_normals(M) -% M - a patch structure or a handle to a patch -% unit - boolean to indicate unit normals or not [default: false] +% FORMAT [Nv, Nf] = spm_mesh_normals(M, unit) +% M - a patch structure or a handle to a patch +% unit - boolean to indicate unit normals or not [default: false] % -% N - a [Nx3] array of (unit) normals on vertices +% Nv - a [nx3] array of (unit) normals on vertices +% Nf - a [mx3] array of (unit) normals on faces %__________________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2008-2017 Wellcome Trust Centre for Neuroimaging % Guillaume Flandin -% $Id: spm_mesh_normals.m 5903 2014-03-03 14:56:10Z guillaume $ +% $Id: spm_mesh_normals.m 7186 2017-10-16 10:12:30Z guillaume $ + if nargin < 2, unit = false; end -if ~ishandle(M) - f = figure('visible','off'); - M = patch(M, 'parent',axes('parent',f), 'visible', 'off'); +if ishandle(M) + Nv = double(get(M,'VertexNormals')); + if nargout > 1 + Nf = double(get(M,'FaceNormals')); + end + if isempty(Nv) + M = struct('faces',get(M,'Faces'), 'vertices',get(M,'Vertices')); + if nargout > 1 + [Nv, Nf] = spm_mesh_normals(M, unit); + else + Nv = spm_mesh_normals(M, unit); + end + end +else + try + t = triangulation(double(M.faces),double(M.vertices)); + Nv = -double(t.vertexNormal); % unit norm + if nargout > 1 + Nf = -double(t.faceNormal); % unit norm + end + catch + [Nv,Nf] = mesh_normal(M); + % f = figure('visible','off'); + % M = patch(M, 'parent',axes('parent',f), 'visible', 'off'); + % [Nv, Nf] = spm_mesh_normals(M, unit); + % close(f); + end +end + +if unit + Nv = normit(Nv); + if nargout > 1 + Nf = normit(Nf); + end end -N = double(get(M,'VertexNormals')); -if isempty(N) - t = triangulation(double(get(M,'Faces')),double(get(M,'Vertices'))); - N = -double(t.vertexNormal); +function [Nv,Nf] = mesh_normal(M) +Nf = cross(... + M.vertices(M.faces(:,2),:)-M.vertices(M.faces(:,1),:), ... + M.vertices(M.faces(:,3),:)-M.vertices(M.faces(:,1),:)); +Nf = normit(Nf); % it seems the way triangulation.vertexNormal works + % i.e. Nv is not a weighted sum by faces' area. + +Nv = zeros(size(M.vertices)); +for i=1:size(M.faces,1) + f = M.faces(i,:); + for j=1:3 + Nv(f(j),:) = Nv(f(j),:) + Nf(i,:); + end +end + +C = bsxfun(@minus,M.vertices,mean(M.vertices,1)); +if nnz(sign(sum(C.*Nv,2))) > size(C,1)/2 + Nv = -Nv; + Nf = -Nf; end -try, close(f); end -if unit - normN = sqrt(sum(N.^2,2)); - normN(normN < eps) = 1; - N = N ./ repmat(normN,1,3); -end \ No newline at end of file +function N = normit(N) +normN = sqrt(sum(N.^2,2)); +normN(normN < eps) = 1; +N = bsxfun(@rdivide,N,normN); diff --git a/spm_mesh_project.m b/spm_mesh_project.m index 9ef77ef3..a6614998 100644 --- a/spm_mesh_project.m +++ b/spm_mesh_project.m @@ -15,7 +15,7 @@ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Guillaume Flandin -% $Id: spm_mesh_project.m 4018 2010-07-27 18:22:42Z guillaume $ +% $Id: spm_mesh_project.m 6987 2017-01-13 16:07:00Z volkmar $ if ishandle(M) V = get(M,'Vertices'); @@ -44,7 +44,8 @@ if isfield(dat,'Z') %-xSPM structure dat = struct('dim',dat.DIM,'XYZ',dat.XYZ,'t',dat.Z,'mat',dat.M); end - Y = zeros(dat(i).dim(1:3)'); + dim = dat(i).dim(1:3); + Y = zeros(dim(:)'); OFF = dat(i).XYZ(1,:) + ... dat(i).dim(1)*(dat(i).XYZ(2,:)-1 + ... dat(i).dim(2)*(dat(i).XYZ(3,:)-1)); diff --git a/spm_mesh_render.m b/spm_mesh_render.m index 2acff90d..57a8b23b 100644 --- a/spm_mesh_render.m +++ b/spm_mesh_render.m @@ -27,15 +27,19 @@ % FORMAT MAP = spm_mesh_render('ColourMap',AX) % Retrieves the current colourmap. % +% FORMAT H = spm_mesh_render('View',AX, V) +% AX - axis handle or structure returned by spm_mesh_render('Disp',...) +% V - viewpoint specification (see view()) +% % FORMAT spm_mesh_render('Register',AX,hReg) % AX - axis handle or structure returned by spm_mesh_render('Disp',...) % hReg - Handle of HandleGraphics object to build registry in. % See spm_XYZreg for more information. %__________________________________________________________________________ -% Copyright (C) 2010-2011 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2010-2017 Wellcome Trust Centre for Neuroimaging % Guillaume Flandin -% $Id: spm_mesh_render.m 6867 2016-09-12 15:04:44Z guillaume $ +% $Id: spm_mesh_render.m 7177 2017-09-28 09:52:56Z guillaume $ %-Input parameters @@ -57,12 +61,13 @@ %====================================================================== case 'disp' if isempty(varargin) - [M, sts] = spm_select(1,'mesh','Select surface mesh file'); + [M, sts] = spm_select([1,Inf],'mesh','Select surface mesh file'); if ~sts, return; end else M = varargin{1}; end - if ischar(M) || isstruct(M), M = gifti(M); end + M = gifti(M); + if numel(M) > 1, M = gifti(spm_mesh_join(M)); end if ~isfield(M,'vertices') try MM = M; @@ -128,9 +133,11 @@ %-Set viewpoint, light and manipulation options %------------------------------------------------------------------ + if isfield(O,'azimuth'), az = O.azimuth; else az = -90; end + if isfield(O,'elevation'), el = O.elevation; else el = 0; end axis(H.axis,'image'); axis(H.axis,'off'); - view(H.axis,[-90 0]); + view(H.axis,[az el]); material(H.figure,'dull'); H.light = camlight; set(H.light,'Parent',H.axis); @@ -146,6 +153,7 @@ %------------------------------------------------------------------ setappdata(H.axis,'handles',H); set(H.patch,'Visible','on'); + camlight(H.light); %-Add context menu %------------------------------------------------------------------ @@ -220,14 +228,16 @@ uimenu(cmenu, 'Label','Save As...', 'Separator', 'on', ... 'Callback', {@mySave, H}); - set(H.rotate3d,'enable','off'); - try, set(H.rotate3d,'uicontextmenu',cmenu); end - try, set(H.patch, 'uicontextmenu',cmenu); end - set(H.rotate3d,'enable','on'); + set(H.rotate3d,'Enable','off'); + try, set(H.rotate3d,'UIContextMenu',cmenu); end + try, set(H.patch, 'UIContextMenu',cmenu); end + set(H.rotate3d,'Enable','on'); - dcm_obj = datacursormode(H.figure); - set(dcm_obj, 'Enable','off', 'SnapToDataVertex','on', ... - 'DisplayStyle','Window', 'Updatefcn',{@myDataCursorUpdate, H}); + try + dcm_obj = datacursormode(H.figure); + set(dcm_obj, 'Enable','off', 'SnapToDataVertex','on', ... + 'DisplayStyle','Window', 'Updatefcn',{@myDataCursorUpdate, H}); + end %-Overlay %====================================================================== @@ -318,6 +328,32 @@ updateTexture(H,d); end + %-View + %====================================================================== + case 'view' + if isempty(varargin), varargin{1} = gca; end + H = getHandles(varargin{1}); + if numel(varargin) < 2, v = 'left'; else v = varargin{2}; end + if ischar(v) + switch lower(v) + case 'right' + v = [90 0]; + case 'left' + v = [-90 0]; + case 'top' + v = [0 90]; + case 'bottom' + v = [-180 -90]; + case 'front' + v = [-180 0]; + case 'back' + v = [0 0]; + otherwise + error('Unknown view position.'); + end + end + myView([],[],H,v); + %-Register %====================================================================== case 'register' @@ -509,11 +545,11 @@ function myTransparency(obj,evt,H) %========================================================================== function mySwitchRotate(obj,evt,H) -if strcmpi(get(H.rotate3d,'enable'),'on') - set(H.rotate3d,'enable','off'); +if strcmpi(get(H.rotate3d,'Enable'),'on') + set(H.rotate3d,'Enable','off'); set(obj,'Checked','off'); else - set(H.rotate3d,'enable','on'); + set(H.rotate3d,'Enable','on'); set(obj,'Checked','on'); end @@ -591,7 +627,8 @@ function mySave(obj,evt,H) '*.png' 'PNG files (*.png)';... '*.dae' 'Collada files (*.dae)';... '*.idtf' 'IDTF files (*.idtf)';... - '*.vtk' 'VTK files (*.vtk)'}, 'Save as'); + '*.vtk' 'VTK files (*.vtk)';... + '*.obj' 'OBJ files (*.obj)'}, 'Save as'); if ~isequal(filename,0) && ~isequal(pathname,0) [pth,nam,ext] = fileparts(filename); switch ext @@ -605,6 +642,8 @@ function mySave(obj,evt,H) filterindex = 4; case {'.vtk','.vtp'} filterindex = 5; + case '.obj' + filterindex = 6; otherwise switch filterindex case 1 @@ -617,6 +656,8 @@ function mySave(obj,evt,H) filename = [filename '.idtf']; case 5 filename = [filename '.vtk']; + case 6 + filename = [filename '.obj']; end end switch filterindex @@ -656,11 +697,7 @@ function mySave(obj,evt,H) set(get(h,'children'),'visible','off'); %a = get(h,'children'); %set(a,'Position',get(a,'Position').*[0 0 1 1]+[10 10 0 0]); - if isdeployed - deployprint(h, '-dpng', '-opengl', fullfile(pathname, filename)); - else - print(h, '-dpng', '-opengl', fullfile(pathname, filename)); - end + print(h, '-dpng', '-opengl', fullfile(pathname, filename)); close(h); set(getappdata(obj,'fig'),'renderer',r); case 3 @@ -669,6 +706,8 @@ function mySave(obj,evt,H) saveas(gifti(H.patch),fullfile(pathname, filename),'idtf'); case 5 saveas(gifti(H.patch),fullfile(pathname, filename),'vtk'); + case 6 + saveas(gifti(H.patch),fullfile(pathname, filename),'obj'); end end @@ -691,9 +730,10 @@ function myImageSections(obj,evt,H) %========================================================================== function myChangeGeometry(obj,evt,H) -[P, sts] = spm_select(1,'mesh','Select new geometry mesh'); +[P, sts] = spm_select([1, Inf],'mesh','Select new geometry mesh'); if ~sts, return; end G = gifti(P); +if numel(G) > 1, G = gifti(spm_mesh_join(G)); end if size(H.patch.Vertices,1) ~= size(G.vertices,1) error('Number of vertices must match.'); end @@ -748,7 +788,7 @@ function renderSlices(H,P,pls) [SPM,v] = spm_getSPM(struct('swd',p)); cd(swd); else - try, spm_vol(v); catch, v = gifti(v); end; + try, spm_vol(v); catch, v = gifti(v); end end end if isa(v,'gifti'), v = v.cdata; end diff --git a/spm_mesh_split.m b/spm_mesh_split.m index 9e0c71bc..c9cfe50a 100644 --- a/spm_mesh_split.m +++ b/spm_mesh_split.m @@ -1,16 +1,16 @@ function MS = spm_mesh_split(M, C) % Split a surface mesh into its connected components -% FUNCTION [MS] = spm_mesh_split(M, C) -% M - a [nx3] faces array or a patch structure -% C - a [nx1] vector containing labels for the connected components -% or a logical vector indicating vertices to keep +% FORMAT MS = spm_mesh_split(M, C) +% M - a [nx3] faces array or a patch structure +% C - a [nx1] vector containing labels for the connected components +% or a logical vector indicating vertices to keep % -% MS - a patch structure array +% MS - a patch structure array %__________________________________________________________________________ -% Copyright (C) 2010 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2010-2016 Wellcome Trust Centre for Neuroimaging % Guillaume Flandin -% $Id: spm_mesh_split.m 4035 2010-08-05 18:54:32Z guillaume $ +% $Id: spm_mesh_split.m 6911 2016-10-26 12:10:58Z guillaume $ if isnumeric(M), M = struct('faces',M); end diff --git a/spm_mesh_utils.mexa64 b/spm_mesh_utils.mexa64 index 8e79e359794bf0e420e05a3356d8e7dcf3abd5f1..faddbe3619afaa65a24230317e5914183ba8345b 100755 GIT binary patch delta 1713 zcmZ8ie{2&~9KUz%w(Fd`c3EldM3|E)Zf-!3Q8vH<7vJesHgUR`n4o{m5hVVzvaxLI z$gRNhs1{yGz$|eI!C<1YSe2qUI<|EkE>k2Df)WQ}IO#yLxj80T{l04%i9wZk)DOFa z&=|@!qY;YI9lX;Sa-|Pc%SCSNrr5($|M`+xFgL%s`XkniJ}`PF}A5CurqDxT2SfY1@~vf3xp!O(o) zPzeGiec!Mn=wS;cgZjN`0JTG`1|~d1&M|~YUD!7$1(}=L+KJkh&JX)dkIoOelpRU0ZagT34G#Wa#E$)l-XIi?h?!QOJxep16of%|1*nVy(4H|M7k=niK}xAoSIa zHE$P2QLK5w@kbT%I94ICdRD;hzQ#LP?L`WjmE9vdGkuth8yw@8jU$jDav!7(>dmQE zG3mu756c*i=hum^MaD%NKR;g_t5L{zS9VYBv|@5DneJzWK!BO89{*GWx zl{IC6V>Ft48RJ-dx;JjeWCWkTtzJdgGQyzfxL7+^NM;{k}iX! z!MUWsup4VxQA{!!y;RICIK%E20_Hn#EZta@VgfFIBO>lSILl_j3#3wmp{>#HP8nDj zYyKuSE81$k@SjA&IGCrvIXLIrEa=1kcWx5&X@;r&^>kNG9xbrv_~JYaXAjHqui3an zQw;bF09jkFAA&tK#WN+l0xw+(C$9(0F$WV8)Auq4T1|KAPSqNO`iuq?kYy50V?-II7| z#~_J9Zs@z{)&(2t+8~KuZJc1aJ_OFGW0++O+$kIx4fSKKT>tuSqc@LuVoX*CP!Hpv zkiYboj5_@axrqr(d%6A{0H-XBVPI`D6&$5#3#|F#_i#Vs6{j+imJ)_JyfEQ$)^{dj z^Cm1!`PlEx|58i7#QFfb!R2e;NKGbD>%%t#&<$I_NG}DSDND;woLP!1=Ig;VQGO z8~5-Jr@yXd>`xD*y>I@&WE$qPGT_gXJ;m_*6n+`hl2?jWQ8%nrp>26TAbNOVH>wZG zk8RFCm*|ltrIvapi{Q9=dVWcnr9Gv!Q(Iw~<-ymX8nkfgn-LBjC_H0E^|ZRkf!blU zo2*<5-3?k8R(t64q8uKL(%xrE`DIS}UU4CHmekq|;!wx}t?^to6x?0%JbE`YRN^qf RmxW$iUV=tKwiO3W{{gVX;WYpN delta 1636 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 diff --git a/spm_mesh_utils.mexw64 b/spm_mesh_utils.mexw64 index d22adf259ee1c7bf1afac33d49911fbb75c1b600..1a654fa30109f125e385966f2e96936b75083c32 100755 GIT binary patch delta 33 mcmZq3X~>!Ig2mw3)5wW$e3-8oGH$kJ{HX;N*leM5f)fA;kPgiN delta 33 mcmZq3X~>!Ig5?+M@$iXne3-R!88%xp{?q~sY_`xj!3hBSObzh> diff --git a/spm_mkdir.m b/spm_mkdir.m new file mode 100644 index 00000000..e5e7b4df --- /dev/null +++ b/spm_mkdir.m @@ -0,0 +1,33 @@ +function sts = spm_mkdir(varargin) +% Make new directory trees +% FORMAT sts = spm_mkdir(dir,...) +% dir - character array, or cell array of strings +% +% sts - true if all directories were successfully created or already +% existing, false otherwise. +%__________________________________________________________________________ +% Copyright (C) 2017 Wellcome Trust Centre for Neuroimaging + +% Guillaume Flandin +% $Id: spm_mkdir.m 7088 2017-06-01 16:18:44Z guillaume $ + + +sts = true; +if nargin > 0 + d1 = cellstr(varargin{1}); + for i=1:numel(d1) + if ~exist(spm_select('cpath',d1{i}),'dir') + status = mkdir(d1{i}); + sts = sts & status; + end + if nargin > 1 + d2 = cellstr(varargin{2}); + for j=1:numel(d2) + status = spm_mkdir(fullfile(d1{i},d2{j}),varargin{3:end}); + sts = sts & status; + end + end + end +else + error('Not enough input arguments.'); +end diff --git a/spm_mrf.mexa64 b/spm_mrf.mexa64 index 2d184dfa5278c64305247fedc546f6e5b0ffcca4..ea6f4a20131c74c1aca073a5e8e63e064d43bd32 100755 GIT binary patch delta 3779 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 Mc}{EQ>=TZE0}gEG!vFvP diff --git a/spm_mrf.mexmaci64 b/spm_mrf.mexmaci64 index 99addf5c6b1dc1cd5388fb617dea1ceeb098d4a2..7026ebf416b6d908a26a1464f731875be8ac580e 100755 GIT binary patch literal 13612 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 literal 13400 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 diff --git a/spm_mrf.mexw32 b/spm_mrf.mexw32 index fbe244f097a32cd3770355fac1f1937b2c07bb70..f023db85c3d08746b2771a32d34228d1d4212f5f 100755 GIT binary patch delta 5105 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 diff --git a/spm_mrf.mexw64 b/spm_mrf.mexw64 index 51d146e845d6fdbd16d89262e5fd49b9cd23676e..10c7f54e7c73872d34c67b63ae527913d25deb1e 100755 GIT binary patch delta 6304 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 diff --git a/spm_mvb.m b/spm_mvb.m index bc9c2d34..80f159ec 100644 --- a/spm_mvb.m +++ b/spm_mvb.m @@ -32,7 +32,7 @@ % many-to-one mapping, from voxel values or data features to a target % variable, using a parametric empirical or hierarchical Bayesian model. % This model is inverted using standard variational techniques, in this -% case expectation maximisation, to furnish the model evidence and the +% case Variational Laplace, to furnish the model evidence and the % conditional density of the model's parameters. This allows one to compare % different models or hypotheses about the mapping from functional or % structural anatomy to perceptual and behavioural consequences (or their @@ -69,7 +69,7 @@ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_mvb.m 5219 2013-01-29 17:07:07Z spm $ +% $Id: spm_mvb.m 7081 2017-05-27 19:36:09Z karl $ % defaults (use splits +/- one standard deviation by default) %-------------------------------------------------------------------------- diff --git a/spm_mvb_display.m b/spm_mvb_display.m index 5dc56bbf..827d9a13 100644 --- a/spm_mvb_display.m +++ b/spm_mvb_display.m @@ -1,23 +1,27 @@ function spm_mvb_display(MVB) -% model display for MVB +% Model display for MVB % FORMAT spm_mvb_display(MVB) % MVB - multivariate Bayes structure, select one if not provided %__________________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2007-2017 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_mvb_display.m 5219 2013-01-29 17:07:07Z spm $ +% $Id: spm_mvb_display.m 7162 2017-08-30 11:47:07Z guillaume $ -if nargin<1 - load(spm_select(1,'^MVB.*\.mat','Select MVB to display')) + +if ~nargin + [filename, sts] = spm_select(1,'^MVB.*\.mat','Select MVB to display'); + if ~sts, return; end + load(filename); end -% get figure +%-Get figure %-------------------------------------------------------------------------- Fmvb = spm_figure('GetWin','MVB'); spm_clf(Fmvb); +spm_figure('Focus',Fmvb); -% display specified model +%-Display specified model %========================================================================== M = MVB.M; XYZ = MVB.XYZ; @@ -26,14 +30,12 @@ function spm_mvb_display(MVB) X = MVB.X; Y = MVB.Y; -% model comparison and selection, relative to the null model +%-Model comparison and selection, relative to the null model %-------------------------------------------------------------------------- F = M.F(2:end) - M.F(1); P = exp(F); P = P./(P + 1); -figure(Fmvb) -%-------------------------------------------------------------------------- subplot(3,2,1) bar(F), hold on plot([0 length(F) + 1], [3 3],'r') @@ -55,7 +57,7 @@ function spm_mvb_display(MVB) title({'distribution of weights'}) -% Posterior probabilities +%-Posterior probabilities %-------------------------------------------------------------------------- P = 1 - spm_Ncdf(0,abs(M.qE),M.qC); str{1,1} = 'Posterior probabilities at maxima '; @@ -78,7 +80,7 @@ function spm_mvb_display(MVB) text(0,1/2,str,'FontSize',10) axis off -% maximium intensity projection +%-Maximum intensity projection %-------------------------------------------------------------------------- subplot(3,2,3) i = P > .5; @@ -86,12 +88,12 @@ function spm_mvb_display(MVB) axis image title(['PPM: ' MVB.name ' (' MVB.contrast ')']) -% residual forming matrix +%-Residual forming matrix %-------------------------------------------------------------------------- R = speye(size(X0,1)) - X0*pinv(X0); Ns = 1:size(X0,1); -% predictions and target (adjusted) +%-Predictions and target (adjusted) %-------------------------------------------------------------------------- X = R*X; P = R*Y*M.qE; @@ -116,3 +118,7 @@ function spm_mvb_display(MVB) ylabel('prediction') title({'observed and predicted contrast',str}) axis square, grid on + +%-Print +%========================================================================== +spm_print('',Fmvb); diff --git a/spm_mvb_ui.m b/spm_mvb_ui.m index d1fbdc50..968ba6af 100644 --- a/spm_mvb_ui.m +++ b/spm_mvb_ui.m @@ -1,5 +1,5 @@ function [MVB] = spm_mvb_ui(xSPM,SPM,MVB) -% multivariate Bayes (Bayesian decoding of a contrast) +% Multivariate Bayes (Bayesian decoding of a contrast) % FORMAT [MVB] = spm_mvb_ui(xSPM,SPM,MVB) % % Sets up, evaluates and saves an MVB structure: @@ -74,10 +74,10 @@ % Friston KJ, Frith CD, Frackowiak RS, Turner R. % Neuroimage. 1995 Jun;2(2):166-72. %__________________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2007-2017 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_mvb_ui.m 4770 2012-06-19 13:24:40Z guillaume $ +% $Id: spm_mvb_ui.m 7162 2017-08-30 11:47:07Z guillaume $ %-Get figure handles and set title @@ -86,8 +86,7 @@ spm_results_ui('Clear'); spm_input('!DeleteInputObj'); header = get(Finter,'Name'); -Fmvb = spm_figure('GetWin','MVB'); -spm_clf(Fmvb); +spm_clf(spm_figure('FindWin','MVB')); %-Get contrast: only the first line of F-contrast %-------------------------------------------------------------------------- @@ -131,12 +130,12 @@ [xY,XYZ,j] = spm_ROI(xY, XYZmm); -% Get explanatory variables (data) +%-Get explanatory variables (data) %-------------------------------------------------------------------------- XYZ = XYZmm(:,j); Y = spm_get_data(SPM.xY.VY,SPM.xVol.XYZ(:,j)); -% Check there are intracranial voxels +%-Check there are intracranial voxels %-------------------------------------------------------------------------- if isempty(Y) spm('alert*',{'No voxels in this VOI';'Please use a larger volume'},... @@ -162,7 +161,7 @@ sg = spm_input(str,'!+1','e',.5); end -% MVB is now specified +%-MVB is now specified %========================================================================== spm('Pointer','Watch') @@ -183,11 +182,11 @@ end X = X*c; -% serial correlations +%-Serial correlations %-------------------------------------------------------------------------- V = SPM.xVi.V; -% invert +%-Invert %========================================================================== VOX = diag(abs(SPM.xVol.M)); U = spm_mvb_U(Y,priors,X0,XYZ,VOX); @@ -200,7 +199,7 @@ M = spm_mvb(X,Y,X0,U,V,Ni,sg); M.priors = priors; -% assemble results +%-Assemble results %-------------------------------------------------------------------------- MVB.contrast = contrast; % contrast of interest MVB.name = name; % name @@ -221,11 +220,11 @@ MVB.priors = priors; % model (spatial prior) MVB.fSPM = fullfile(SPM.swd,'SPM.mat'); % SPM analysis (.mat file) -% display +%-Display %========================================================================== -spm_mvb_display(MVB) +if ~spm('CmdLine'), spm_mvb_display(MVB); end -% save +%-Save %-------------------------------------------------------------------------- save(fullfile(SPM.swd,[name '.mat']),'MVB', spm_get_defaults('mat.format')) assignin('base','MVB',MVB) diff --git a/spm_nlsi_N.m b/spm_nlsi_N.m index 975c06b8..c2e056f3 100644 --- a/spm_nlsi_N.m +++ b/spm_nlsi_N.m @@ -84,14 +84,14 @@ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_nlsi_N.m 6432 2015-05-09 12:58:12Z karl $ +% $Id: spm_nlsi_N.m 7143 2017-07-29 18:50:38Z karl $ % options %-------------------------------------------------------------------------- try, M.nograph; catch, M.nograph = 0; end try, M.Nmax; catch, M.Nmax = 64; end try, M.Gmax; catch, M.Gmax = 8; end -try, M.Hmax; catch, M.Hmax = 8; end +try, M.Hmax; catch, M.Hmax = 4; end % figure (unless disabled) %-------------------------------------------------------------------------- @@ -306,7 +306,6 @@ end - % EM %========================================================================== warning(sw); sw = warning('off','all'); @@ -322,6 +321,7 @@ % Optimize p: parameters of f(x,u,p) %========================================================================== +EP = []; for ip = 1:M.Nmax % time @@ -330,12 +330,17 @@ % predicted hidden states (x) and dxdp %---------------------------------------------------------------------- - [dxdp,x] = spm_diff(IS,Ep,M,U,1,{Vp}); + [dxdp,x] = spm_diff(IS,Ep,M,U,1,{Vp}); - % check for dissipative dynamics + % check for inital iterations and dissipative dynamics %---------------------------------------------------------------------- if all(isfinite(spm_vec(x))) Gmax = M.Gmax; + if ip < 8 + vg = -4; + else + vg = 2; + end else Gmax = 0; end @@ -374,7 +379,7 @@ end % Optimize F(h): parameters of iS(h) - %================================================================== + %================================================================== dgdb = [dgdp dgdg dgdu]; for ih = 1:M.Hmax @@ -423,7 +428,7 @@ % convergence %-------------------------------------------------------------- - if dFdh'*dh < 1e-2, break, end + if dFdh'*dh < exp(-2), break, end end @@ -447,13 +452,13 @@ % Conditional updates of parameters (g) %------------------------------------------------------------------ - dg = spm_dx(dFdgg,dFdg,{4}); + dg = spm_dx(dFdgg,dFdg,{vg}); Eg = spm_unvec(spm_vec(Eg) + Vg*dg,Eg); % convergence %------------------------------------------------------------------ dG = dFdg'*dg; - if ig > 1 && dG < 1e-2, break, end + if ig > 1 && dG < exp(-2), break, end end @@ -490,7 +495,7 @@ % decrease regularization %------------------------------------------------------------------ - v = min(v + 1/2,8); + v = min(v + 1/2,4); str = 'EM(+)'; % accept current estimates @@ -501,8 +506,8 @@ C.Eu = Eu; C.h = h; C.F = F; - C.L = L; - + C.L = L; + else % reset expansion point @@ -524,8 +529,11 @@ %====================================================================== dp = spm_dx(dFdpp,dFdp,{v}); Ep = spm_unvec(spm_vec(Ep) + Vp*dp,Ep); - + % diagnostic + %---------------------------------------------------------------------- + % EP(:,end + 1) = spm_vec(Ep); + % subplot times %---------------------------------------------------------------------- @@ -607,5 +615,9 @@ F = C.F; L = C.L; warning(sw); - + +% diagnostic +%-------------------------------------------------------------------------- +% save('spm_nlsi_N_Ep','EP') + return diff --git a/spm_orthviews.m b/spm_orthviews.m index 89fe06eb..2a7b9ed6 100644 --- a/spm_orthviews.m +++ b/spm_orthviews.m @@ -1,13 +1,14 @@ function varargout = spm_orthviews(action,varargin) % Display orthogonal views of a set of images -% FORMAT H = spm_orthviews('Image',filename[,position]) +% FORMAT H = spm_orthviews('Image',filename[,area[,F]]) % filename - name of image to display % area - position of image {relative} % [left, bottom, width, height] +% F - figure handle % H - handle for orthogonal sections % % FORMAT spm_orthviews('Reposition',centre) -% centre - X, Y & Z coordinates of centre voxel +% centre - X, Y & Z coordinates of centre voxel {mm} % % FORMAT spm_orthviews('Space'[,handle[,M,dim]]) % handle - the view to define the space by, optionally with extra @@ -18,8 +19,7 @@ % FORMAT H = spm_orthviews('Caption', handle, string, [Property, Value]) % handle - the view to which a caption should be added % string - the caption text to add -% optional: Property-Value pairs, e.g. 'FontWeight', 'Bold' -% +% Property,Value - optional, e.g. 'FontWeight', 'Bold' % H - the handle to the object whose String property has the caption % % FORMAT spm_orthviews('BB',bb) @@ -28,21 +28,21 @@ % hiX hiY hiZ] % % FORMAT spm_orthviews('MaxBB') -% Set the bounding box big enough to display the whole of all images +% Set the bounding box big enough to display the whole of all images. % % FORMAT spm_orthviews('Resolution'[,res]) % res - resolution (mm) -% Set the sampling resolution for all images. The effective resolution -% will be the minimum of res and the voxel sizes of all images. If no -% resolution is specified, the minimum of 1mm and the voxel sizes of the -% images is used. +% Set the sampling resolution for all images. The effective resolution will +% be the minimum of res and the voxel sizes of all images. If no resolution +% is specified, the minimum of 1mm and the voxel sizes of the images is +% used. % % FORMAT spm_orthviews('Zoom'[,fov[,res]]) % fov - half width of field of view (mm) % res - resolution (mm) -% Set the displayed part and sampling resolution for all images. The -% image display will be centered at the current crosshair position. The -% image region [xhairs-fov xhairs+fov] will be shown. +% Set the displayed part and sampling resolution for all images. The image +% display will be centered at the current crosshair position. The image +% region [xhairs-fov xhairs+fov] will be shown. % If no argument is given or fov == Inf, the image display will be reset to % "Full Volume". If fov == 0, the image will be zoomed to the bounding box % from spm_get_bbox for the non-zero voxels of the image. If fov is NaN, @@ -51,7 +51,7 @@ % Optionally, the display resolution can be set as well. % % FORMAT spm_orthviews('Redraw') -% Redraw the images +% Redraw the images. % % FORMAT spm_orthviews('Reload_mats') % Reload the voxel-world mapping matrices from the headers stored on disk, @@ -64,28 +64,28 @@ % Clear the orthogonal views % % FORMAT spm_orthviews('Pos') -% Return the co-ordinate of the crosshairs in millimetres in the -% standard space. +% Return the co-ordinate of the crosshairs in millimetres in the standard +% space. % % FORMAT spm_orthviews('Pos', i) -% Return the voxel co-ordinate of the crosshairs in the image in the -% ith orthogonal section. +% Return the voxel co-ordinate of the crosshairs in the image in the ith +% orthogonal section. % % FORMAT spm_orthviews('Xhairs','off') OR spm_orthviews('Xhairs') -% Disable the cross-hairs on the display +% Disable the cross-hairs on the display. % % FORMAT spm_orthviews('Xhairs','on') -% Enable the cross-hairs +% Enable the cross-hairs. % % FORMAT spm_orthviews('Interp',hld) -% Set the hold value to hld (see spm_slice_vol) +% Set the hold value to hld (see spm_slice_vol). % % FORMAT spm_orthviews('AddBlobs',handle,XYZ,Z,mat,name) -% Add blobs from a pointlist to the image specified by the handle(s) +% Add blobs from a pointlist to the image specified by the handle(s). % handle - image number to add blobs to % XYZ - blob voxel locations % Z - blob voxel intensities -% mat - matrix from voxels to millimeters of blob. +% mat - matrix from voxels to millimetres of blob % name - a name for this blob % This method only adds one set of blobs, and displays them using a split % colour table. @@ -106,15 +106,15 @@ % blobs print well. % % FORMAT spm_orthviews('AddColourBar',handle,blobno) -% Add colourbar for a specified blob set +% Add colourbar for a specified blob set. % handle - image number % blobno - blob number % % FORMAT spm_orthviews('RemoveBlobs',handle) -% Remove all blobs from the image specified by the handle(s) +% Remove all blobs from the image specified by the handle(s). % % FORMAT spm_orthviews('Addtruecolourimage',handle,filename,colourmap,prop,mx,mn) -% Add blobs from an image in true colour +% Add blobs from an image in true colour. % handle - image number to add blobs to [Default: 1] % filename - image containing blob data [Default: GUI input] % colourmap - colormap to display blobs in [Default: GUI input] @@ -148,26 +148,26 @@ % spm_orthviews('plugin_name', plugin_arguments). For detailed descriptions % of each plugin see help spm_orthviews/spm_ov_'plugin_name'. %__________________________________________________________________________ -% Copyright (C) 1996-2015 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 1996-2017 Wellcome Trust Centre for Neuroimaging % John Ashburner et al -% $Id: spm_orthviews.m 6656 2015-12-24 16:49:52Z guillaume $ +% $Id: spm_orthviews.m 7168 2017-09-19 10:24:02Z guillaume $ % The basic fields of st are: -% n - the number of images currently being displayed +% n - the number of images currently being displayed. % vols - a cell array containing the data on each of the % displayed images. % Space - a mapping between the displayed images and the % mm space of each image. % bb - the bounding box of the displayed images. -% centre - the current centre of the orthogonal views +% centre - the current centre of the orthogonal views. % callback - a callback to be evaluated on a button-click. -% xhairs - crosshairs off/on -% hld - the interpolation method -% fig - the figure that everything is displayed in +% xhairs - crosshairs off/on. +% hld - the interpolation method. +% fig - the figure that everything is displayed in. % mode - the position/orientation of the sagittal view. -% - currently always 1 +% (currently always 1) % % st.registry.hReg \_ See spm_XYZreg for documentation % st.registry.hMe / @@ -243,6 +243,7 @@ % callback handling. The order in which plugins are called is % undefined. + global st persistent zoomlist reslist @@ -251,13 +252,9 @@ if ~nargin, action = ''; end -if ~any(strcmpi(action,{'reposition','pos'})) - spm('Pointer','Watch'); -end - switch lower(action) case 'image' - if numel(varargin)>=3 + if numel(varargin) > 2 F = varargin{3}; else F = st.fig; @@ -271,13 +268,12 @@ end if isempty(st.bb), st.bb = maxbb; end resolution; - bbox; - cm_pos; + bbox(H); end varargout{1} = H; - mmcentre = mean(st.Space*[maxbb';1 1],2)'; + mmcentre = mean(st.Space*[st.bb';1 1],2)'; st.centre = mmcentre(1:3); - redraw_all + redraw_all; try, set(F, 'WindowScrollWheelFcn', @scroll_wheel); end @@ -320,7 +316,11 @@ redraw_all; case 'redraw' - redraw_all; + if isempty(varargin) + redraw_all; + else + redraw(varargin{1}); + end callback; if isfield(st,'registry') spm_XYZreg('SetCoords',st.centre,st.registry.hReg,st.registry.hMe); @@ -354,28 +354,23 @@ if isfield(st,'registry') spm_XYZreg('SetCoords',st.centre,st.registry.hReg,st.registry.hMe); end - cm_pos; case 'setcoords' st.centre = varargin{1}; st.centre = st.centre(:); redraw_all; callback; - cm_pos; case 'space' - if numel(varargin) < 1 + if isempty(varargin) st.Space = eye(4); st.bb = maxbb; - resolution; - bbox; - redraw_all; else space(varargin{:}); - resolution; - bbox; - redraw_all; end + resolution; + bbox; + redraw_all; case 'maxbb' st.bb = maxbb; @@ -541,8 +536,6 @@ end end -spm('Pointer','Arrow'); - %========================================================================== % function H = specify_image(img, h) @@ -897,24 +890,23 @@ function move(handle,pos) %========================================================================== function space(handle,M,dim) global st -if ~isempty(st.vols{handle}) - if nargin < 2 - M = st.vols{handle}.mat; - dim = st.vols{handle}.dim(1:3); - end - Mat = st.vols{handle}.premul(1:3,1:3)*M(1:3,1:3); - vox = sqrt(sum(Mat.^2)); - if det(Mat(1:3,1:3))<0, vox(1) = -vox(1); end - Mat = diag([vox 1]); - Space = (M)/Mat; - bb = [1 1 1; dim]; - bb = [bb [1;1]]; - bb = bb*Mat'; - bb = bb(:,1:3); - bb = sort(bb); - st.Space = Space; - st.bb = bb; +if isempty(st.vols{handle}), return; end +if nargin < 2 + M = st.vols{handle}.mat; + dim = st.vols{handle}.dim(1:3); end +Mat = st.vols{handle}.premul(1:3,1:3)*M(1:3,1:3); +vox = sqrt(sum(Mat.^2)); +if det(Mat(1:3,1:3))<0, vox(1) = -vox(1); end +Mat = diag([vox 1]); +Space = (M)/Mat; +bb = [1 1 1; dim]; +bb = [bb [1;1]]; +bb = bb*Mat'; +bb = bb(:,1:3); +bb = sort(bb); +st.Space = Space; +st.bb = bb; %========================================================================== @@ -986,15 +978,17 @@ function scroll_wheel(varargin) %========================================================================== % function bbox %========================================================================== -function bbox +function bbox(handles) global st +if ~nargin, handles = valid_handles; end + Dims = diff(st.bb)'+1; TD = Dims([1 2])'; CD = Dims([1 3])'; if st.mode == 0, SD = Dims([3 2])'; else SD = Dims([2 3])'; end -for i=valid_handles +for i=valid_handles(handles) H = ancestor(st.vols{i}.ax{1}.ax,{'figure','uipanel'}); un = get(H,'Units');set(H,'Units','Pixels'); @@ -1107,7 +1101,7 @@ function redraw(arg1) CM = inv(CM0*M); CD = Dims([1 3]); - if st.mode ==0 + if st.mode == 0 SM0 = [ 0 0 1 -bb(1,3)+1 0 1 0 -bb(1,2)+1 1 0 0 -cent(1) @@ -1127,331 +1121,325 @@ function redraw(arg1) imgt = spm_slice_vol(st.vols{i},TM,TD,st.hld)'; imgc = spm_slice_vol(st.vols{i},CM,CD,st.hld)'; imgs = spm_slice_vol(st.vols{i},SM,SD,st.hld)'; - ok = true; catch fprintf('Cannot access file "%s".\n', st.vols{i}.fname); fprintf('%s\n',getfield(lasterror,'message')); - ok = false; + continue; end - if ok - % get min/max threshold - if strcmp(st.vols{i}.window,'auto') - mn = -Inf; - mx = Inf; - else - mn = min(st.vols{i}.window); - mx = max(st.vols{i}.window); - end + + % get min/max threshold + if strcmp(st.vols{i}.window,'auto') + mn = -Inf; + mx = Inf; + else + mn = min(st.vols{i}.window); + mx = max(st.vols{i}.window); % threshold images imgt = max(imgt,mn); imgt = min(imgt,mx); imgc = max(imgc,mn); imgc = min(imgc,mx); imgs = max(imgs,mn); imgs = min(imgs,mx); - % compute intensity mapping, if histeq is available - if license('test','image_toolbox') == 0 - st.vols{i}.mapping = 'linear'; - end - switch st.vols{i}.mapping - case 'linear' - case 'histeq' - % scale images to a range between 0 and 1 - imgt1=(imgt-min(imgt(:)))/(max(imgt(:)-min(imgt(:)))+eps); - imgc1=(imgc-min(imgc(:)))/(max(imgc(:)-min(imgc(:)))+eps); - imgs1=(imgs-min(imgs(:)))/(max(imgs(:)-min(imgs(:)))+eps); - img = histeq([imgt1(:); imgc1(:); imgs1(:)],1024); - imgt = reshape(img(1:numel(imgt1)),size(imgt1)); - imgc = reshape(img(numel(imgt1)+(1:numel(imgc1))),size(imgc1)); - imgs = reshape(img(numel(imgt1)+numel(imgc1)+(1:numel(imgs1))),size(imgs1)); - mn = 0; - mx = 1; - case 'quadhisteq' - % scale images to a range between 0 and 1 - imgt1=(imgt-min(imgt(:)))/(max(imgt(:)-min(imgt(:)))+eps); - imgc1=(imgc-min(imgc(:)))/(max(imgc(:)-min(imgc(:)))+eps); - imgs1=(imgs-min(imgs(:)))/(max(imgs(:)-min(imgs(:)))+eps); - img = histeq([imgt1(:).^2; imgc1(:).^2; imgs1(:).^2],1024); - imgt = reshape(img(1:numel(imgt1)),size(imgt1)); - imgc = reshape(img(numel(imgt1)+(1:numel(imgc1))),size(imgc1)); - imgs = reshape(img(numel(imgt1)+numel(imgc1)+(1:numel(imgs1))),size(imgs1)); - mn = 0; - mx = 1; - case 'loghisteq' - sw = warning('off','MATLAB:log:logOfZero'); - imgt = log(imgt-min(imgt(:))); - imgc = log(imgc-min(imgc(:))); - imgs = log(imgs-min(imgs(:))); - warning(sw); - imgt(~isfinite(imgt)) = 0; - imgc(~isfinite(imgc)) = 0; - imgs(~isfinite(imgs)) = 0; - % scale log images to a range between 0 and 1 - imgt1=(imgt-min(imgt(:)))/(max(imgt(:)-min(imgt(:)))+eps); - imgc1=(imgc-min(imgc(:)))/(max(imgc(:)-min(imgc(:)))+eps); - imgs1=(imgs-min(imgs(:)))/(max(imgs(:)-min(imgs(:)))+eps); - img = histeq([imgt1(:); imgc1(:); imgs1(:)],1024); - imgt = reshape(img(1:numel(imgt1)),size(imgt1)); - imgc = reshape(img(numel(imgt1)+(1:numel(imgc1))),size(imgc1)); - imgs = reshape(img(numel(imgt1)+numel(imgc1)+(1:numel(imgs1))),size(imgs1)); - mn = 0; - mx = 1; - end - % recompute min/max for display - if strcmp(st.vols{i}.window,'auto') - mx = -inf; mn = inf; - end - if ~isempty(imgt) - tmp = imgt(isfinite(imgt)); - mx = max([mx max(max(tmp))]); - mn = min([mn min(min(tmp))]); - end - if ~isempty(imgc) - tmp = imgc(isfinite(imgc)); - mx = max([mx max(max(tmp))]); - mn = min([mn min(min(tmp))]); - end - if ~isempty(imgs) - tmp = imgs(isfinite(imgs)); - mx = max([mx max(max(tmp))]); - mn = min([mn min(min(tmp))]); - end - if mx==mn, mx=mn+eps; end - - if isfield(st.vols{i},'blobs') - if ~isfield(st.vols{i}.blobs{1},'colour') - % Add blobs for display using the split colourmap - scal = 64/(mx-mn); - dcoff = -mn*scal; - imgt = imgt*scal+dcoff; - imgc = imgc*scal+dcoff; - imgs = imgs*scal+dcoff; - - if isfield(st.vols{i}.blobs{1},'max') - mx = st.vols{i}.blobs{1}.max; + end + + % compute intensity mapping, if histeq is available + if license('test','image_toolbox') == 0 + st.vols{i}.mapping = 'linear'; + end + switch st.vols{i}.mapping + case 'linear' + case 'histeq' + % scale images to a range between 0 and 1 + imgt1=(imgt-min(imgt(:)))/(max(imgt(:)-min(imgt(:)))+eps); + imgc1=(imgc-min(imgc(:)))/(max(imgc(:)-min(imgc(:)))+eps); + imgs1=(imgs-min(imgs(:)))/(max(imgs(:)-min(imgs(:)))+eps); + img = histeq([imgt1(:); imgc1(:); imgs1(:)],1024); + imgt = reshape(img(1:numel(imgt1)),size(imgt1)); + imgc = reshape(img(numel(imgt1)+(1:numel(imgc1))),size(imgc1)); + imgs = reshape(img(numel(imgt1)+numel(imgc1)+(1:numel(imgs1))),size(imgs1)); + mn = 0; + mx = 1; + case 'quadhisteq' + % scale images to a range between 0 and 1 + imgt1=(imgt-min(imgt(:)))/(max(imgt(:)-min(imgt(:)))+eps); + imgc1=(imgc-min(imgc(:)))/(max(imgc(:)-min(imgc(:)))+eps); + imgs1=(imgs-min(imgs(:)))/(max(imgs(:)-min(imgs(:)))+eps); + img = histeq([imgt1(:).^2; imgc1(:).^2; imgs1(:).^2],1024); + imgt = reshape(img(1:numel(imgt1)),size(imgt1)); + imgc = reshape(img(numel(imgt1)+(1:numel(imgc1))),size(imgc1)); + imgs = reshape(img(numel(imgt1)+numel(imgc1)+(1:numel(imgs1))),size(imgs1)); + mn = 0; + mx = 1; + case 'loghisteq' + sw = warning('off','MATLAB:log:logOfZero'); + imgt = log(imgt-min(imgt(:))); + imgc = log(imgc-min(imgc(:))); + imgs = log(imgs-min(imgs(:))); + warning(sw); + imgt(~isfinite(imgt)) = 0; + imgc(~isfinite(imgc)) = 0; + imgs(~isfinite(imgs)) = 0; + % scale log images to a range between 0 and 1 + imgt1=(imgt-min(imgt(:)))/(max(imgt(:)-min(imgt(:)))+eps); + imgc1=(imgc-min(imgc(:)))/(max(imgc(:)-min(imgc(:)))+eps); + imgs1=(imgs-min(imgs(:)))/(max(imgs(:)-min(imgs(:)))+eps); + img = histeq([imgt1(:); imgc1(:); imgs1(:)],1024); + imgt = reshape(img(1:numel(imgt1)),size(imgt1)); + imgc = reshape(img(numel(imgt1)+(1:numel(imgc1))),size(imgc1)); + imgs = reshape(img(numel(imgt1)+numel(imgc1)+(1:numel(imgs1))),size(imgs1)); + mn = 0; + mx = 1; + end + % recompute min/max for display + if strcmp(st.vols{i}.window,'auto') + mx = -Inf; + mn = Inf; + end + tmp = imgt(isfinite(imgt)); + mx = max([mx max(tmp)]); + mn = min([mn min(tmp)]); + tmp = imgc(isfinite(imgc)); + mx = max([mx max(tmp)]); + mn = min([mn min(tmp)]); + tmp = imgs(isfinite(imgs)); + mx = max([mx max(tmp)]); + mn = min([mn min(tmp)]); + if mx==mn, mx = mn + eps; end + + if isfield(st.vols{i},'blobs') + if ~isfield(st.vols{i}.blobs{1},'colour') + % Add blobs for display using the split colourmap + scal = 64/(mx-mn); + dcoff = -mn*scal; + imgt = imgt*scal+dcoff; + imgc = imgc*scal+dcoff; + imgs = imgs*scal+dcoff; + + if isfield(st.vols{i}.blobs{1},'max') + mx = st.vols{i}.blobs{1}.max; + else + mx = max([eps maxval(st.vols{i}.blobs{1}.vol)]); + st.vols{i}.blobs{1}.max = mx; + end + if isfield(st.vols{i}.blobs{1},'min') + mn = st.vols{i}.blobs{1}.min; + else + mn = min([0 minval(st.vols{i}.blobs{1}.vol)]); + st.vols{i}.blobs{1}.min = mn; + end + + vol = st.vols{i}.blobs{1}.vol; + M = st.Space\st.vols{i}.premul*st.vols{i}.blobs{1}.mat; + tmpt = spm_slice_vol(vol,inv(TM0*M),TD,[0 NaN])'; + tmpc = spm_slice_vol(vol,inv(CM0*M),CD,[0 NaN])'; + tmps = spm_slice_vol(vol,inv(SM0*M),SD,[0 NaN])'; + + %tmpt_z = find(tmpt==0);tmpt(tmpt_z) = NaN; + %tmpc_z = find(tmpc==0);tmpc(tmpc_z) = NaN; + %tmps_z = find(tmps==0);tmps(tmps_z) = NaN; + + sc = 64/(mx-mn); + off = 65.51-mn*sc; + msk = find(isfinite(tmpt)); imgt(msk) = off+tmpt(msk)*sc; + msk = find(isfinite(tmpc)); imgc(msk) = off+tmpc(msk)*sc; + msk = find(isfinite(tmps)); imgs(msk) = off+tmps(msk)*sc; + + cmap = get(st.fig,'Colormap'); + if size(cmap,1)~=128 + figure(st.fig) + spm_figure('Colormap','gray-hot') + end + redraw_colourbar(i,1,[mn mx],(1:64)'+64); + elseif isstruct(st.vols{i}.blobs{1}.colour) + % Add blobs for display using a defined colourmap + + % colourmaps + gryc = (0:63)'*ones(1,3)/63; + + % scale grayscale image, not isfinite -> black + gimgt = scaletocmap(imgt,mn,mx,gryc,65); + gimgc = scaletocmap(imgc,mn,mx,gryc,65); + gimgs = scaletocmap(imgs,mn,mx,gryc,65); + gryc = [gryc; 0 0 0]; + cactp = 0; + + for j=1:numel(st.vols{i}.blobs) + % colourmaps + actc = st.vols{i}.blobs{j}.colour.cmap; + actp = st.vols{i}.blobs{j}.colour.prop; + + % get min/max for blob image + if isfield(st.vols{i}.blobs{j},'max') + cmx = st.vols{i}.blobs{j}.max; else - mx = max([eps maxval(st.vols{i}.blobs{1}.vol)]); - st.vols{i}.blobs{1}.max = mx; + cmx = max([eps maxval(st.vols{i}.blobs{j}.vol)]); end - if isfield(st.vols{i}.blobs{1},'min') - mn = st.vols{i}.blobs{1}.min; + if isfield(st.vols{i}.blobs{j},'min') + cmn = st.vols{i}.blobs{j}.min; else - mn = min([0 minval(st.vols{i}.blobs{1}.vol)]); - st.vols{i}.blobs{1}.min = mn; + cmn = -cmx; end - - vol = st.vols{i}.blobs{1}.vol; - M = st.Space\st.vols{i}.premul*st.vols{i}.blobs{1}.mat; + + % get blob data + vol = st.vols{i}.blobs{j}.vol; + M = st.Space\st.vols{i}.premul*st.vols{i}.blobs{j}.mat; tmpt = spm_slice_vol(vol,inv(TM0*M),TD,[0 NaN])'; tmpc = spm_slice_vol(vol,inv(CM0*M),CD,[0 NaN])'; tmps = spm_slice_vol(vol,inv(SM0*M),SD,[0 NaN])'; - - %tmpt_z = find(tmpt==0);tmpt(tmpt_z) = NaN; - %tmpc_z = find(tmpc==0);tmpc(tmpc_z) = NaN; - %tmps_z = find(tmps==0);tmps(tmps_z) = NaN; - - sc = 64/(mx-mn); - off = 65.51-mn*sc; - msk = find(isfinite(tmpt)); imgt(msk) = off+tmpt(msk)*sc; - msk = find(isfinite(tmpc)); imgc(msk) = off+tmpc(msk)*sc; - msk = find(isfinite(tmps)); imgs(msk) = off+tmps(msk)*sc; - - cmap = get(st.fig,'Colormap'); - if size(cmap,1)~=128 - figure(st.fig) - spm_figure('Colormap','gray-hot') - end - redraw_colourbar(i,1,[mn mx],(1:64)'+64); - elseif isstruct(st.vols{i}.blobs{1}.colour) - % Add blobs for display using a defined colourmap - - % colourmaps - gryc = (0:63)'*ones(1,3)/63; - - % scale grayscale image, not isfinite -> black - gimgt = scaletocmap(imgt,mn,mx,gryc,65); - gimgc = scaletocmap(imgc,mn,mx,gryc,65); - gimgs = scaletocmap(imgs,mn,mx,gryc,65); - gryc = [gryc; 0 0 0]; - cactp = 0; - - for j=1:numel(st.vols{i}.blobs) - % colourmaps - actc = st.vols{i}.blobs{j}.colour.cmap; - actp = st.vols{i}.blobs{j}.colour.prop; - - % get min/max for blob image - if isfield(st.vols{i}.blobs{j},'max') - cmx = st.vols{i}.blobs{j}.max; - else - cmx = max([eps maxval(st.vols{i}.blobs{j}.vol)]); - end - if isfield(st.vols{i}.blobs{j},'min') - cmn = st.vols{i}.blobs{j}.min; - else - cmn = -cmx; - end - - % get blob data - vol = st.vols{i}.blobs{j}.vol; - M = st.Space\st.vols{i}.premul*st.vols{i}.blobs{j}.mat; - tmpt = spm_slice_vol(vol,inv(TM0*M),TD,[0 NaN])'; - tmpc = spm_slice_vol(vol,inv(CM0*M),CD,[0 NaN])'; - tmps = spm_slice_vol(vol,inv(SM0*M),SD,[0 NaN])'; - - % actimg scaled round 0, black NaNs - topc = size(actc,1)+1; - tmpt = scaletocmap(tmpt,cmn,cmx,actc,topc); - tmpc = scaletocmap(tmpc,cmn,cmx,actc,topc); - tmps = scaletocmap(tmps,cmn,cmx,actc,topc); - actc = [actc; 0 0 0]; - - % combine gray and blob data to truecolour - if isnan(actp) - if j==1, imgt = gryc(gimgt(:),:); end - imgt(tmpt~=size(actc,1),:) = actc(tmpt(tmpt~=size(actc,1)),:); - if j==1, imgc = gryc(gimgc(:),:); end - imgc(tmpc~=size(actc,1),:) = actc(tmpc(tmpc~=size(actc,1)),:); - if j==1, imgs = gryc(gimgs(:),:); end - imgs(tmps~=size(actc,1),:) = actc(tmps(tmps~=size(actc,1)),:); - else - cactp = cactp + actp; - if j==1, imgt = actc(tmpt(:),:)*actp; else imgt = imgt + actc(tmpt(:),:)*actp; end - if j==numel(st.vols{i}.blobs), imgt = imgt + gryc(gimgt(:),:)*(1-cactp); end - if j==1, imgc = actc(tmpc(:),:)*actp; else imgc = imgc + actc(tmpc(:),:)*actp; end - if j==numel(st.vols{i}.blobs), imgc = imgc + gryc(gimgc(:),:)*(1-cactp); end - if j==1, imgs = actc(tmps(:),:)*actp; else imgs = imgs + actc(tmps(:),:)*actp; end - if j==numel(st.vols{i}.blobs), imgs = imgs + gryc(gimgs(:),:)*(1-cactp); end - end - if j==numel(st.vols{i}.blobs) - imgt = reshape(imgt,[size(gimgt) 3]); - imgc = reshape(imgc,[size(gimgc) 3]); - imgs = reshape(imgs,[size(gimgs) 3]); - end - - % colourbar - csz = size(st.vols{i}.blobs{j}.colour.cmap); - cdata = reshape(st.vols{i}.blobs{j}.colour.cmap, [csz(1) 1 csz(2)]); - redraw_colourbar(i,j,[cmn cmx],cdata); - end - - else - % Add full colour blobs - several sets at once - scal = 1/(mx-mn); - dcoff = -mn*scal; - - wt = zeros(size(imgt)); - wc = zeros(size(imgc)); - ws = zeros(size(imgs)); - - imgt = repmat(imgt*scal+dcoff,[1,1,3]); - imgc = repmat(imgc*scal+dcoff,[1,1,3]); - imgs = repmat(imgs*scal+dcoff,[1,1,3]); - - cimgt = zeros(size(imgt)); - cimgc = zeros(size(imgc)); - cimgs = zeros(size(imgs)); - - colour = zeros(numel(st.vols{i}.blobs),3); - for j=1:numel(st.vols{i}.blobs) % get colours of all images first - if isfield(st.vols{i}.blobs{j},'colour') - colour(j,:) = reshape(st.vols{i}.blobs{j}.colour, [1 3]); - else - colour(j,:) = [1 0 0]; - end + + % actimg scaled round 0, black NaNs + topc = size(actc,1)+1; + tmpt = scaletocmap(tmpt,cmn,cmx,actc,topc); + tmpc = scaletocmap(tmpc,cmn,cmx,actc,topc); + tmps = scaletocmap(tmps,cmn,cmx,actc,topc); + actc = [actc; 0 0 0]; + + % combine gray and blob data to truecolour + if isnan(actp) + if j==1, imgt = gryc(gimgt(:),:); end + imgt(tmpt~=size(actc,1),:) = actc(tmpt(tmpt~=size(actc,1)),:); + if j==1, imgc = gryc(gimgc(:),:); end + imgc(tmpc~=size(actc,1),:) = actc(tmpc(tmpc~=size(actc,1)),:); + if j==1, imgs = gryc(gimgs(:),:); end + imgs(tmps~=size(actc,1),:) = actc(tmps(tmps~=size(actc,1)),:); + else + cactp = cactp + actp; + if j==1, imgt = actc(tmpt(:),:)*actp; else imgt = imgt + actc(tmpt(:),:)*actp; end + if j==numel(st.vols{i}.blobs), imgt = imgt + gryc(gimgt(:),:)*(1-cactp); end + if j==1, imgc = actc(tmpc(:),:)*actp; else imgc = imgc + actc(tmpc(:),:)*actp; end + if j==numel(st.vols{i}.blobs), imgc = imgc + gryc(gimgc(:),:)*(1-cactp); end + if j==1, imgs = actc(tmps(:),:)*actp; else imgs = imgs + actc(tmps(:),:)*actp; end + if j==numel(st.vols{i}.blobs), imgs = imgs + gryc(gimgs(:),:)*(1-cactp); end end - %colour = colour/max(sum(colour)); - - for j=1:numel(st.vols{i}.blobs) - if isfield(st.vols{i}.blobs{j},'max') - mx = st.vols{i}.blobs{j}.max; - else - mx = max([eps max(st.vols{i}.blobs{j}.vol(:))]); - st.vols{i}.blobs{j}.max = mx; - end - if isfield(st.vols{i}.blobs{j},'min') - mn = st.vols{i}.blobs{j}.min; - else - mn = min([0 min(st.vols{i}.blobs{j}.vol(:))]); - st.vols{i}.blobs{j}.min = mn; - end - - vol = st.vols{i}.blobs{j}.vol; - M = st.Space\st.vols{i}.premul*st.vols{i}.blobs{j}.mat; - tmpt = spm_slice_vol(vol,inv(TM0*M),TD,[0 NaN])'; - tmpc = spm_slice_vol(vol,inv(CM0*M),CD,[0 NaN])'; - tmps = spm_slice_vol(vol,inv(SM0*M),SD,[0 NaN])'; - % check min/max of sampled image - % against mn/mx as given in st - tmpt(tmpt(:)mx) = mx; - tmpc(tmpc(:)>mx) = mx; - tmps(tmps(:)>mx) = mx; - tmpt = (tmpt-mn)/(mx-mn); - tmpc = (tmpc-mn)/(mx-mn); - tmps = (tmps-mn)/(mx-mn); - tmpt(~isfinite(tmpt)) = 0; - tmpc(~isfinite(tmpc)) = 0; - tmps(~isfinite(tmps)) = 0; - - cimgt = cimgt + cat(3,tmpt*colour(j,1),tmpt*colour(j,2),tmpt*colour(j,3)); - cimgc = cimgc + cat(3,tmpc*colour(j,1),tmpc*colour(j,2),tmpc*colour(j,3)); - cimgs = cimgs + cat(3,tmps*colour(j,1),tmps*colour(j,2),tmps*colour(j,3)); - - wt = wt + tmpt; - wc = wc + tmpc; - ws = ws + tmps; - cdata=permute(shiftdim((1/64:1/64:1)'* ... - colour(j,:),-1),[2 1 3]); - redraw_colourbar(i,j,[mn mx],cdata); + if j==numel(st.vols{i}.blobs) + imgt = reshape(imgt,[size(gimgt) 3]); + imgc = reshape(imgc,[size(gimgc) 3]); + imgs = reshape(imgs,[size(gimgs) 3]); end - - imgt = repmat(1-wt,[1 1 3]).*imgt+cimgt; - imgc = repmat(1-wc,[1 1 3]).*imgc+cimgc; - imgs = repmat(1-ws,[1 1 3]).*imgs+cimgs; - - imgt(imgt<0)=0; imgt(imgt>1)=1; - imgc(imgc<0)=0; imgc(imgc>1)=1; - imgs(imgs<0)=0; imgs(imgs>1)=1; + + % colourbar + csz = size(st.vols{i}.blobs{j}.colour.cmap); + cdata = reshape(st.vols{i}.blobs{j}.colour.cmap, [csz(1) 1 csz(2)]); + redraw_colourbar(i,j,[cmn cmx],cdata); end + else - scal = 64/(mx-mn); + % Add full colour blobs - several sets at once + scal = 1/(mx-mn); dcoff = -mn*scal; - imgt = imgt*scal+dcoff; - imgc = imgc*scal+dcoff; - imgs = imgs*scal+dcoff; - end - - set(st.vols{i}.ax{1}.d,'HitTest','off', 'Cdata',imgt); - set(st.vols{i}.ax{1}.lx,'HitTest','off',... - 'Xdata',[0 TD(1)]+0.5,'Ydata',[1 1]*(cent(2)-bb(1,2)+1)); - set(st.vols{i}.ax{1}.ly,'HitTest','off',... - 'Ydata',[0 TD(2)]+0.5,'Xdata',[1 1]*(cent(1)-bb(1,1)+1)); - - set(st.vols{i}.ax{2}.d,'HitTest','off', 'Cdata',imgc); - set(st.vols{i}.ax{2}.lx,'HitTest','off',... - 'Xdata',[0 CD(1)]+0.5,'Ydata',[1 1]*(cent(3)-bb(1,3)+1)); - set(st.vols{i}.ax{2}.ly,'HitTest','off',... - 'Ydata',[0 CD(2)]+0.5,'Xdata',[1 1]*(cent(1)-bb(1,1)+1)); - - set(st.vols{i}.ax{3}.d,'HitTest','off','Cdata',imgs); - if st.mode ==0 - set(st.vols{i}.ax{3}.lx,'HitTest','off',... - 'Xdata',[0 SD(1)]+0.5,'Ydata',[1 1]*(cent(2)-bb(1,2)+1)); - set(st.vols{i}.ax{3}.ly,'HitTest','off',... - 'Ydata',[0 SD(2)]+0.5,'Xdata',[1 1]*(cent(3)-bb(1,3)+1)); - else - set(st.vols{i}.ax{3}.lx,'HitTest','off',... - 'Xdata',[0 SD(1)]+0.5,'Ydata',[1 1]*(cent(3)-bb(1,3)+1)); - set(st.vols{i}.ax{3}.ly,'HitTest','off',... - 'Ydata',[0 SD(2)]+0.5,'Xdata',[1 1]*(bb(2,2)+1-cent(2))); - end - - if ~isempty(st.plugins) % process any addons - for k = 1:numel(st.plugins) - if isfield(st.vols{i},st.plugins{k}) - feval(['spm_ov_', st.plugins{k}], ... - 'redraw', i, TM0, TD, CM0, CD, SM0, SD); + + wt = zeros(size(imgt)); + wc = zeros(size(imgc)); + ws = zeros(size(imgs)); + + imgt = repmat(imgt*scal+dcoff,[1,1,3]); + imgc = repmat(imgc*scal+dcoff,[1,1,3]); + imgs = repmat(imgs*scal+dcoff,[1,1,3]); + + cimgt = zeros(size(imgt)); + cimgc = zeros(size(imgc)); + cimgs = zeros(size(imgs)); + + colour = zeros(numel(st.vols{i}.blobs),3); + for j=1:numel(st.vols{i}.blobs) % get colours of all images first + if isfield(st.vols{i}.blobs{j},'colour') + colour(j,:) = reshape(st.vols{i}.blobs{j}.colour, [1 3]); + else + colour(j,:) = [1 0 0]; + end + end + %colour = colour/max(sum(colour)); + + for j=1:numel(st.vols{i}.blobs) + if isfield(st.vols{i}.blobs{j},'max') + mx = st.vols{i}.blobs{j}.max; + else + mx = max([eps max(st.vols{i}.blobs{j}.vol(:))]); + st.vols{i}.blobs{j}.max = mx; + end + if isfield(st.vols{i}.blobs{j},'min') + mn = st.vols{i}.blobs{j}.min; + else + mn = min([0 min(st.vols{i}.blobs{j}.vol(:))]); + st.vols{i}.blobs{j}.min = mn; end + + vol = st.vols{i}.blobs{j}.vol; + M = st.Space\st.vols{i}.premul*st.vols{i}.blobs{j}.mat; + tmpt = spm_slice_vol(vol,inv(TM0*M),TD,[0 NaN])'; + tmpc = spm_slice_vol(vol,inv(CM0*M),CD,[0 NaN])'; + tmps = spm_slice_vol(vol,inv(SM0*M),SD,[0 NaN])'; + % check min/max of sampled image + % against mn/mx as given in st + tmpt(tmpt(:)mx) = mx; + tmpc(tmpc(:)>mx) = mx; + tmps(tmps(:)>mx) = mx; + tmpt = (tmpt-mn)/(mx-mn); + tmpc = (tmpc-mn)/(mx-mn); + tmps = (tmps-mn)/(mx-mn); + tmpt(~isfinite(tmpt)) = 0; + tmpc(~isfinite(tmpc)) = 0; + tmps(~isfinite(tmps)) = 0; + + cimgt = cimgt + cat(3,tmpt*colour(j,1),tmpt*colour(j,2),tmpt*colour(j,3)); + cimgc = cimgc + cat(3,tmpc*colour(j,1),tmpc*colour(j,2),tmpc*colour(j,3)); + cimgs = cimgs + cat(3,tmps*colour(j,1),tmps*colour(j,2),tmps*colour(j,3)); + + wt = wt + tmpt; + wc = wc + tmpc; + ws = ws + tmps; + cdata = permute(shiftdim((1/64:1/64:1)'* ... + colour(j,:),-1),[2 1 3]); + redraw_colourbar(i,j,[mn mx],cdata); + end + + imgt = repmat(1-wt,[1 1 3]).*imgt+cimgt; + imgc = repmat(1-wc,[1 1 3]).*imgc+cimgc; + imgs = repmat(1-ws,[1 1 3]).*imgs+cimgs; + + imgt(imgt<0)=0; imgt(imgt>1)=1; + imgc(imgc<0)=0; imgc(imgc>1)=1; + imgs(imgs<0)=0; imgs(imgs>1)=1; + end + else + scal = 64/(mx-mn); + dcoff = -mn*scal; + imgt = imgt*scal+dcoff; + imgc = imgc*scal+dcoff; + imgs = imgs*scal+dcoff; + end + + set(st.vols{i}.ax{1}.d,'HitTest','off', 'Cdata',imgt); + set(st.vols{i}.ax{1}.lx,'HitTest','off',... + 'Xdata',[0 TD(1)]+0.5,'Ydata',[1 1]*(cent(2)-bb(1,2)+1)); + set(st.vols{i}.ax{1}.ly,'HitTest','off',... + 'Ydata',[0 TD(2)]+0.5,'Xdata',[1 1]*(cent(1)-bb(1,1)+1)); + + set(st.vols{i}.ax{2}.d,'HitTest','off', 'Cdata',imgc); + set(st.vols{i}.ax{2}.lx,'HitTest','off',... + 'Xdata',[0 CD(1)]+0.5,'Ydata',[1 1]*(cent(3)-bb(1,3)+1)); + set(st.vols{i}.ax{2}.ly,'HitTest','off',... + 'Ydata',[0 CD(2)]+0.5,'Xdata',[1 1]*(cent(1)-bb(1,1)+1)); + + set(st.vols{i}.ax{3}.d,'HitTest','off','Cdata',imgs); + if st.mode == 0 + set(st.vols{i}.ax{3}.lx,'HitTest','off',... + 'Xdata',[0 SD(1)]+0.5,'Ydata',[1 1]*(cent(2)-bb(1,2)+1)); + set(st.vols{i}.ax{3}.ly,'HitTest','off',... + 'Ydata',[0 SD(2)]+0.5,'Xdata',[1 1]*(cent(3)-bb(1,3)+1)); + else + set(st.vols{i}.ax{3}.lx,'HitTest','off',... + 'Xdata',[0 SD(1)]+0.5,'Ydata',[1 1]*(cent(3)-bb(1,3)+1)); + set(st.vols{i}.ax{3}.ly,'HitTest','off',... + 'Ydata',[0 SD(2)]+0.5,'Xdata',[1 1]*(bb(2,2)+1-cent(2))); + end + + if ~isempty(st.plugins) % process any addons + for k = 1:numel(st.plugins) + if isfield(st.vols{i},st.plugins{k}) + feval(['spm_ov_', st.plugins{k}], ... + 'redraw', i, TM0, TD, CM0, CD, SM0, SD); end end end @@ -1504,7 +1492,7 @@ function redraw_colourbar(vh,bh,interval,cdata) for i=valid_handles for j=1:3 if ~isempty(obj) - if (st.vols{i}.ax{j}.ax == obj), + if (st.vols{i}.ax{j}.ax == obj) cp = get(obj,'CurrentPoint'); end end @@ -1568,7 +1556,7 @@ function redraw_colourbar(vh,bh,interval,cdata) end for k = 1:numel(pluginbase) pluginpath = fullfile(pluginbase{k},'spm_orthviews'); - if isdir(pluginpath) + if exist(pluginpath,'dir') == 7 pluginfiles = dir(fullfile(pluginpath,'spm_ov_*.m')); if ~isempty(pluginfiles) if ~isdeployed, addpath(pluginpath); end @@ -1623,7 +1611,7 @@ function redraw_colourbar(vh,bh,interval,cdata) % create context menu set(0,'CurrentFigure',st.fig); % contextmenu -item_parent = uicontextmenu; +item_parent = uicontextmenu('Callback',@(obj,evt) cm_pos); % contextsubmenu 0 item00 = uimenu(item_parent, 'Label','unknown image', 'UserData','filename'); @@ -1661,10 +1649,11 @@ function redraw_colourbar(vh,bh,interval,cdata) item2 = uimenu(item_parent,'Label','Crosshairs','Callback','spm_orthviews(''context_menu'',''Xhair'');','Checked',checked{2}); % contextsubmenu 3 -if st.Space == eye(4) - checked = {'off', 'on'}; -else + +if any(any(abs(st.Space - eye(4)) > 1e-4)) checked = {'on', 'off'}; +else + checked = {'off', 'on'}; end item3 = uimenu(item_parent,'Label','Orientation'); item3_1 = uimenu(item3, 'Label','World space', 'Callback','spm_orthviews(''context_menu'',''orientation'',3);','Checked',checked{2}); @@ -1699,21 +1688,21 @@ function redraw_colourbar(vh,bh,interval,cdata) % item5 = uimenu(item_parent,'Label','Position', 'Callback','spm_orthviews(''context_menu'',''position'');'); % contextsubmenu 6 -item6 = uimenu(item_parent,'Label','Image','Separator','on'); -item6_1 = uimenu(item6, 'Label','Window'); -item6_1_1 = uimenu(item6_1, 'Label','local'); -item6_1_1_1 = uimenu(item6_1_1, 'Label','auto', 'Callback','spm_orthviews(''context_menu'',''window'',2);'); -item6_1_1_2 = uimenu(item6_1_1, 'Label','manual', 'Callback','spm_orthviews(''context_menu'',''window'',1);'); -item6_1_1_3 = uimenu(item6_1_1, 'Label','percentiles', 'Callback','spm_orthviews(''context_menu'',''window'',3);'); -item6_1_2 = uimenu(item6_1, 'Label','global'); -item6_1_2_1 = uimenu(item6_1_2, 'Label','auto', 'Callback','spm_orthviews(''context_menu'',''window_gl'',2);'); -item6_1_2_2 = uimenu(item6_1_2, 'Label','manual', 'Callback','spm_orthviews(''context_menu'',''window_gl'',1);'); +item6 = uimenu(item_parent,'Label','Intensity','Separator','on'); +item6_1 = uimenu(item6, 'Label','Range'); +item6_1_1 = uimenu(item6_1, 'Label','This image'); +item6_1_1_1 = uimenu(item6_1_1, 'Label','Automatic', 'Callback','spm_orthviews(''context_menu'',''window'',2);'); +item6_1_1_2 = uimenu(item6_1_1, 'Label','Manual', 'Callback','spm_orthviews(''context_menu'',''window'',1);'); +item6_1_1_3 = uimenu(item6_1_1, 'Label','Percentiles', 'Callback','spm_orthviews(''context_menu'',''window'',3);'); +item6_1_2 = uimenu(item6_1, 'Label','All images'); +item6_1_2_1 = uimenu(item6_1_2, 'Label','Automatic', 'Callback','spm_orthviews(''context_menu'',''window_gl'',2);'); +item6_1_2_2 = uimenu(item6_1_2, 'Label','Manual', 'Callback','spm_orthviews(''context_menu'',''window_gl'',1);'); if license('test','image_toolbox') == 1 offon = {'off', 'on'}; checked = offon(strcmp(st.vols{volhandle}.mapping, ... {'linear', 'histeq', 'loghisteq', 'quadhisteq'})+1); - item6_2 = uimenu(item6, 'Label','Intensity mapping'); - item6_2_1 = uimenu(item6_2, 'Label','local'); + item6_2 = uimenu(item6, 'Label','Mapping'); + item6_2_1 = uimenu(item6_2, 'Label','This image'); item6_2_1_1 = uimenu(item6_2_1, 'Label','Linear', 'Checked',checked{1}, ... 'Callback','spm_orthviews(''context_menu'',''mapping'',''linear'');'); item6_2_1_2 = uimenu(item6_2_1, 'Label','Equalised histogram', 'Checked',checked{2}, ... @@ -1722,7 +1711,7 @@ function redraw_colourbar(vh,bh,interval,cdata) 'Callback','spm_orthviews(''context_menu'',''mapping'',''loghisteq'');'); item6_2_1_4 = uimenu(item6_2_1, 'Label','Equalised squared-histogram', 'Checked',checked{4}, ... 'Callback','spm_orthviews(''context_menu'',''mapping'',''quadhisteq'');'); - item6_2_2 = uimenu(item6_2, 'Label','global'); + item6_2_2 = uimenu(item6_2, 'Label','All images'); item6_2_2_1 = uimenu(item6_2_2, 'Label','Linear', 'Checked',checked{1}, ... 'Callback','spm_orthviews(''context_menu'',''mapping_gl'',''linear'');'); item6_2_2_2 = uimenu(item6_2_2, 'Label','Equalised histogram', 'Checked',checked{2}, ... @@ -1736,21 +1725,21 @@ function redraw_colourbar(vh,bh,interval,cdata) % contextsubmenu 7 item7 = uimenu(item_parent,'Label','Overlay'); item7_1 = uimenu(item7, 'Label','Add blobs'); -item7_1_1 = uimenu(item7_1, 'Label','local', 'Callback','spm_orthviews(''context_menu'',''add_blobs'',2);'); -item7_1_2 = uimenu(item7_1, 'Label','global', 'Callback','spm_orthviews(''context_menu'',''add_blobs'',1);'); +item7_1_1 = uimenu(item7_1, 'Label','This image', 'Callback','spm_orthviews(''context_menu'',''add_blobs'',2);'); +item7_1_2 = uimenu(item7_1, 'Label','All images', 'Callback','spm_orthviews(''context_menu'',''add_blobs'',1);'); item7_2 = uimenu(item7, 'Label','Add image'); -item7_2_1 = uimenu(item7_2, 'Label','local', 'Callback','spm_orthviews(''context_menu'',''add_image'',2);'); -item7_2_2 = uimenu(item7_2, 'Label','global', 'Callback','spm_orthviews(''context_menu'',''add_image'',1);'); +item7_2_1 = uimenu(item7_2, 'Label','This image', 'Callback','spm_orthviews(''context_menu'',''add_image'',2);'); +item7_2_2 = uimenu(item7_2, 'Label','All images', 'Callback','spm_orthviews(''context_menu'',''add_image'',1);'); item7_3 = uimenu(item7, 'Label','Add coloured blobs','Separator','on'); -item7_3_1 = uimenu(item7_3, 'Label','local', 'Callback','spm_orthviews(''context_menu'',''add_c_blobs'',2);'); -item7_3_2 = uimenu(item7_3, 'Label','global', 'Callback','spm_orthviews(''context_menu'',''add_c_blobs'',1);'); +item7_3_1 = uimenu(item7_3, 'Label','This image', 'Callback','spm_orthviews(''context_menu'',''add_c_blobs'',2);'); +item7_3_2 = uimenu(item7_3, 'Label','All images', 'Callback','spm_orthviews(''context_menu'',''add_c_blobs'',1);'); item7_4 = uimenu(item7, 'Label','Add coloured image'); -item7_4_1 = uimenu(item7_4, 'Label','local', 'Callback','spm_orthviews(''context_menu'',''add_c_image'',2);'); -item7_4_2 = uimenu(item7_4, 'Label','global', 'Callback','spm_orthviews(''context_menu'',''add_c_image'',1);'); +item7_4_1 = uimenu(item7_4, 'Label','This image', 'Callback','spm_orthviews(''context_menu'',''add_c_image'',2);'); +item7_4_2 = uimenu(item7_4, 'Label','All images', 'Callback','spm_orthviews(''context_menu'',''add_c_image'',1);'); item7_5 = uimenu(item7, 'Label','Remove blobs', 'Visible','off','Separator','on'); item7_6 = uimenu(item7, 'Label','Remove coloured blobs','Visible','off'); -item7_6_1 = uimenu(item7_6, 'Label','local', 'Visible','on'); -item7_6_2 = uimenu(item7_6, 'Label','global','Visible','on'); +item7_6_1 = uimenu(item7_6, 'Label','This image', 'Visible','on'); +item7_6_2 = uimenu(item7_6, 'Label','All images','Visible','on'); item7_7 = uimenu(item7, 'Label','Set blobs max', 'Visible','off'); for i=1:3 @@ -1775,7 +1764,6 @@ function addcontexts(handles) for ii = valid_handles(handles) addcontext(ii); end -spm_orthviews('reposition',spm_orthviews('pos')); %========================================================================== @@ -2052,17 +2040,17 @@ function c_menu(varargin) c_handle = findobj(findobj(st.vols{cm_handles(i)}.ax{1}.cm,'label','Overlay'),'Label','Remove blobs'); set(c_handle,'Visible','on'); delete(get(c_handle,'Children')); - item7_3_1 = uimenu(c_handle,'Label','local','Callback','spm_orthviews(''context_menu'',''remove_blobs'',2);'); + item7_3_1 = uimenu(c_handle,'Label','This image','Callback','spm_orthviews(''context_menu'',''remove_blobs'',2);'); if varargin{2} == 1, - item7_3_2 = uimenu(c_handle,'Label','global','Callback','spm_orthviews(''context_menu'',''remove_blobs'',1);'); + item7_3_2 = uimenu(c_handle,'Label','All images','Callback','spm_orthviews(''context_menu'',''remove_blobs'',1);'); end % Add options for setting maxima for blobs c_handle = findobj(findobj(st.vols{cm_handles(i)}.ax{1}.cm,'label','Overlay'),'Label','Set blobs max'); set(c_handle,'Visible','on'); delete(get(c_handle,'Children')); - uimenu(c_handle,'Label','local','Callback','spm_orthviews(''context_menu'',''setblobsmax'',2);'); + uimenu(c_handle,'Label','This image','Callback','spm_orthviews(''context_menu'',''setblobsmax'',2);'); if varargin{2} == 1 - uimenu(c_handle,'Label','global','Callback','spm_orthviews(''context_menu'',''setblobsmax'',1);'); + uimenu(c_handle,'Label','All images','Callback','spm_orthviews(''context_menu'',''setblobsmax'',1);'); end end redraw_all; @@ -2096,17 +2084,17 @@ function c_menu(varargin) c_handle = findobj(findobj(st.vols{cm_handles(i)}.ax{1}.cm,'label','Overlay'),'Label','Remove blobs'); set(c_handle,'Visible','on'); delete(get(c_handle,'Children')); - item7_3_1 = uimenu(c_handle,'Label','local','Callback','spm_orthviews(''context_menu'',''remove_blobs'',2);'); + item7_3_1 = uimenu(c_handle,'Label','This image','Callback','spm_orthviews(''context_menu'',''remove_blobs'',2);'); if varargin{2} == 1 - item7_3_2 = uimenu(c_handle,'Label','global','Callback','spm_orthviews(''context_menu'',''remove_blobs'',1);'); + item7_3_2 = uimenu(c_handle,'Label','All images','Callback','spm_orthviews(''context_menu'',''remove_blobs'',1);'); end % Add options for setting maxima for blobs c_handle = findobj(findobj(st.vols{cm_handles(i)}.ax{1}.cm,'label','Overlay'),'Label','Set blobs max'); set(c_handle,'Visible','on'); delete(get(c_handle,'Children')); - uimenu(c_handle,'Label','local','Callback','spm_orthviews(''context_menu'',''setblobsmax'',2);'); + uimenu(c_handle,'Label','This image','Callback','spm_orthviews(''context_menu'',''setblobsmax'',2);'); if varargin{2} == 1 - uimenu(c_handle,'Label','global','Callback','spm_orthviews(''context_menu'',''setblobsmax'',1);'); + uimenu(c_handle,'Label','All images','Callback','spm_orthviews(''context_menu'',''setblobsmax'',1);'); end end redraw_all; @@ -2246,9 +2234,10 @@ function c_menu(varargin) %========================================================================== % function cm_pos %========================================================================== -function cm_pos +function cm_pos(handles) global st -for i = 1:numel(valid_handles) +if ~nargin, handles = get_current_handle; end +for i=valid_handles(handles) if isfield(st.vols{i}.ax{1},'cm') set(findobj(st.vols{i}.ax{1}.cm,'UserData','pos_mm'),... 'Label',sprintf('mm: %.1f %.1f %.1f',spm_orthviews('pos'))); @@ -2274,7 +2263,7 @@ function c_menu(varargin) global st cm_handles = []; for i = valid_handles - cm_handles = [cm_handles st.vols{i}.ax{1}.cm]; + try, cm_handles = [cm_handles st.vols{i}.ax{1}.cm]; end end diff --git a/spm_orthviews/spm_ov_mesh.m b/spm_orthviews/spm_ov_mesh.m new file mode 100644 index 00000000..d5b3d527 --- /dev/null +++ b/spm_orthviews/spm_ov_mesh.m @@ -0,0 +1,261 @@ +function ret = spm_ov_mesh(varargin) +% Mesh tool - plugin for spm_orthviews +% +% This routine is a plugin to spm_orthviews. For general help about +% spm_orthviews and plugins type +% help spm_orthviews +% at the MATLAB prompt. +%__________________________________________________________________________ +% Copyright (C) 2017 Wellcome Trust Centre for Neuroimaging + +% Torben Lund, Guillaume Flandin & Christian Gaser +% $Id: spm_ov_mesh.m 7183 2017-10-09 15:26:47Z guillaume $ + + +switch lower(varargin{1}) + % Context menu and callbacks + case 'context_menu' + item0 = uimenu(varargin{3}, ... + 'Label', 'Mesh',... + 'UserData',... + struct('style','','width',1,'id',varargin{2})); + item1 = uimenu(item0,... + 'Label','Select mesh(es)...',... + 'Tag','menu',... + 'Callback',@(hObj,event) mesh_menu(hObj,event,varargin{2})); + item2 = uimenu(item0,... + 'Label','Options'); + item2_1 = uimenu(item2,... + 'Label','Line style...',... + 'UserData',struct('str','Line style', 'field','style'),... + 'Callback',@(hObj,event) mesh_options(hObj,event,item0)); + item2_2 = uimenu(item2,... + 'Label','Line width...',... + 'UserData',struct('str','Line width', 'field','width'),... + 'Callback',@(hObj,event) mesh_options(hObj,event,item0)); + ret = item0; + case 'display' + if nargin < 2 + varargin{2} = spm_input('Select image', '!+1', 'e'); + end + mesh_add(varargin{2:end}); + mesh_delete(varargin{2}); + mesh_display(varargin{2}); + case 'redraw' + mesh_redraw(varargin{2:end}); + otherwise +end + + +%========================================================================== +function mesh_options(hObj,event,hM) +Finter = spm_figure('FindWin', 'Interactive'); +spm_input('!DeleteInputObj',Finter); +UDm = get(hObj,'UserData'); +UDc = get(hM,'UserData'); +if isnumeric(UDc.(UDm.field)) + N = Inf; + T = 'e'; +else + N = Inf; + T = 's'; +end +if T == 's' && iscell(UDc.(UDm.field)) + UDc.(UDm.field) = ''; +end +UDc.(UDm.field) = spm_input(UDm.str, '!+1', T, UDc.(UDm.field), N); +if T == 's' + if ~isempty(strfind(UDc.(UDm.field),'{')) + UDc.(UDm.field) = eval(UDc.(UDm.field)); + end +end +set(hM,'UserData',UDc); +try, mesh_redraw(UDc.id); end + + +%========================================================================== +function mesh_menu(hObj,event,i,varargin) + +global st + +mesh_add(i); +mesh_delete(i); +mesh_display(i); + + +%========================================================================== +function mesh_add(i,g) + +global st + +try + m = st.vols{i}.mesh.meshes; +catch + m = []; +end + +if nargin < 2 + [g,sts] = spm_select([1 Inf],'mesh','Select mesh(es)...'); + if ~sts, st.vols{i}.mesh.meshes = m; return; end +end +g = gifti(g); +for j=1:numel(g) + if ~isfield(g(j),'vertices') || ~isfield(g(j),'faces') + error('Selected file must contain triangular meshes.'); + end +end + +st.vols{i}.mesh.meshes = [m, g]; + +hM = findobj(st.vols{i}.ax{1}.cm,'Label','Mesh'); +if numel(get(hM,'children')) < 3 + uimenu(hM,... + 'Label','Display 3D mesh(es)',... + 'Tag','tmp',... + 'Callback',@(hObj,event) mesh_render(i)); + uimenu(hM,... + 'Label','Remove mesh(es)',... + 'Tag','tmp',... + 'Callback',@(hObj,event) mesh_clear(i)); +end + + +%========================================================================== +function mesh_clear(i) + +global st + +mesh_delete(i); +st.vols{i} = rmfield(st.vols{i},'mesh'); +hM = findobj(st.vols{i}.ax{1}.cm,'Label','Mesh'); +set(findobj(hM,'Tag','menu'),'Label','Select mesh(es)'); +delete(findobj(get(hM,'Children'),'Tag','tmp')); + + +%========================================================================== +function mesh_display(i) + +global st + +if nargin < 1 + i = 1; +end +o = st.vols{i}.mesh.meshes; + +try + hM = findobj(st.vols{i}.ax{1}.cm,'Label','Mesh'); + set(findobj(hM,'Tag','menu'),'Label','Add mesh(es)'); + UD = get(hM,'UserData'); + linespec = UD.style; + linewidth = UD.width; + set(hM,'UserData',UD); +end +if ~iscell(linespec) + if ~isempty(linespec) + disp('Wrong Linestyle format please use {''linestyle1'',''linestyle2'',...}.'); + UD.style = ''; + set(hM,'UserData',UD); + end + + linespec = {'b-' 'g-' 'r-' 'c-' 'm-' 'y-' 'k-' 'w-' ... + 'b-.' 'g-.' 'r-.' 'c-.' 'm-.' 'y-.' 'k-.' 'w-.' ... + 'b--' 'g--' 'r--' 'c--' 'm--' 'y--' 'k--' 'w--' }; + if numel(o) <= 24 + linespec = linespec(1:numel(o)); + else + % If there are more than 24 surfaces plot them all in red + linespec = repmat({'r-'},1,numel(o)); + end +end +if numel(linespec) < numel(o) + disp('Meshes with unspecified line style are displayed in black.') + linespec(end+1:numel(o)) = {'k-'}; + UD.style = linespec; + set(hM,'UserData',UD); +end +if numel(linewidth) < numel(o) + linewidth(end+1:numel(o)) = linewidth(end); + UD.width = linewidth; + set(hM,'UserData',UD); +end + +% This requires more work: does not work in voxel space, ie handling of +% st.Space is incomplete +bb = st.bb; +is = inv(st.Space); +lh = {}; +for n=1:numel(o) + vert = (st.vols{i}.premul(1:3,:)*[o(n).vertices';ones(1,size(o(n).vertices,1))])'; + % 1 + set(st.vols{i}.ax{1}.ax,'NextPlot','add'); + s = spm_mesh_contour(... + struct('faces',o(n).faces,'vertices',vert),... + st.centre(3)); + for j=1:numel(s) + c = is*[s(j).xdata; s(j).ydata;ones(2,size(s(j).xdata,2))]; + c(2,:) = c(2,:)-bb(1,2)+1; + c(1,:) = c(1,:)-bb(1,1)+1; + lh{end+1} = plot(st.vols{i}.ax{1}.ax,c(1,:),c(2,:),... + linespec{n},'LineWidth',linewidth(n)); + end + % 2 + set(st.vols{i}.ax{2}.ax,'NextPlot','add'); + s = spm_mesh_contour(... + struct('faces',o(n).faces,'vertices',vert(:,[3 1 2])),... + st.centre(2)); + for j=1:numel(s) + c = is*[s(j).xdata;ones(1,size(s(j).xdata,2));s(j).ydata;ones(1,size(s(j).ydata,2))]; + c(3,:) = c(3,:)-bb(1,1)+1; + c(1,:) = c(1,:)-bb(1,3)+1; + lh{end+1} = plot(st.vols{i}.ax{2}.ax,c(3,:),c(1,:),... + linespec{n},'LineWidth',linewidth(n)); + end + % 3 + if st.mode == 0 + warning('Not handled.'); + else + set(st.vols{i}.ax{3}.ax,'NextPlot','add'); + s = spm_mesh_contour(... + struct('faces',o(n).faces,'vertices',vert(:,[2 3 1])),... + st.centre(1)); + for j=1:numel(s) + c = is*[ones(1,size(s(j).xdata,2));[s(j).xdata; s(j).ydata];ones(1,size(s(j).ydata,2))]; + c(2,:) = -c(2,:)+bb(2,2)+1; + c(3,:) = c(3,:)-bb(1,3)+1; + lh{end+1} = plot(st.vols{i}.ax{3}.ax,c(2,:),c(3,:),... + linespec{n},'LineWidth',linewidth(n)); + end + end +end + +set(cat(1,lh{:}),'HitTest','off'); + +st.vols{i}.mesh.handles = lh; + + +%========================================================================== +function mesh_redraw(i,varargin) %i, TM0, TD, CM0, CD, SM0, SD + +mesh_delete(i); +mesh_display(i); + + +%========================================================================== +function mesh_delete(i) + +global st + +try, delete(cat(1,st.vols{i}.mesh.handles{:})); end + + +%========================================================================== +function mesh_render(i) + +global st + +m = st.vols{i}.mesh.meshes; +for j=1:numel(m) + spm_mesh_render(m(j)); +end +% data cursor should be linked to orthviews through spm_XYZreg +% see spm_ovhelper_3Dreg.m diff --git a/spm_orthviews/spm_ov_movie.m b/spm_orthviews/spm_ov_movie.m index a09a922c..3ab3f390 100644 --- a/spm_orthviews/spm_ov_movie.m +++ b/spm_orthviews/spm_ov_movie.m @@ -15,10 +15,10 @@ % help spm_orthviews % at the MATLAB prompt. %__________________________________________________________________________ -% Copyright (C) 2012-2016 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2012-2017 Wellcome Trust Centre for Neuroimaging % Volkmar Glauche -% $Id: spm_ov_movie.m 6807 2016-06-10 12:58:35Z guillaume $ +% $Id: spm_ov_movie.m 7111 2017-06-16 09:01:09Z guillaume $ global st; if isempty(st) @@ -61,7 +61,7 @@ num2str(bb(dir,:), '%.1f %.1f'), 2); mstart(dir)=tmp(1); mend(dir)=tmp(2); - end; + end ds=spm_input('Step size (mm)', '!+1', 'e', '1', 1); d=mend-mstart; l=sqrt(d'*d); @@ -82,15 +82,15 @@ end else vh = []; - end; + end for k=1:numel(steps) spm_orthviews('reposition', mstart+steps(k)*d); for ci = 1:numel(vh) for ca = 1:3 M{ci,ca}(k) = getframe(st.vols{vh(ci)}.ax{ca}.ax); - end; - end; - end; + end + end + end spm('pointer', 'watch'); for ci = 1:numel(vh) for ca = 1:3 @@ -98,7 +98,7 @@ for cf = 1:numel(M{ci,ca}) fname = sprintf('%s-%02d-%1d-%03d.png',prefix,vh(ci),ca,cf); imwrite(frame2im(M{ci,ca}(cf)), fname, 'png'); - end; + end elseif domovie == 2 fname = sprintf('%s-%02d-%1d.avi',prefix,vh(ci),ca); if spm_check_version('matlab','7.10') > 0 @@ -108,19 +108,18 @@ close(writerObj); fname = writerObj.Filename; else - movie2avi(M{ci,ca},fname, 'compression','None'); + movie2avi(M{ci,ca},fname, 'compression','None'); %#ok end if ispc, cmd = 'winopen(''%s'')'; else, cmd = 'open(''%s'')'; end fprintf('Movie saved in %s\n',spm_file(fname,'link',cmd)); - end; - end; - end; + end + end + end spm('pointer', 'arrow'); spm_orthviews('reposition', opos); spm_input('!DeleteInputObj',Finter); otherwise fprintf('spm_orthviews(''movie'', ...): Unknown action %s', cmd); -end; - +end spm('pointer','arrow'); diff --git a/spm_orthviews/spm_ov_roi.m b/spm_orthviews/spm_ov_roi.m index 8eb19b5e..cb5417ea 100644 --- a/spm_orthviews/spm_ov_roi.m +++ b/spm_orthviews/spm_ov_roi.m @@ -90,7 +90,7 @@ % Copyright (C) 2012 Wellcome Trust Centre for Neuroimaging % Volkmar Glauche -% $Id: spm_ov_roi.m 4996 2012-10-11 18:28:37Z guillaume $ +% $Id: spm_ov_roi.m 6991 2017-01-19 13:09:51Z guillaume $ % Note: This plugin depends on the blobs set by spm_orthviews('addblobs',...) % They should not be removed while ROI tool is active and no other blobs be @@ -565,7 +565,7 @@ item18 = uimenu(item0, 'Label', 'Help', 'Callback', ... sprintf('spm_help(''%s'');', mfilename)); % add some stuff outside ROI tool menu - iorient = findobj(st.vols{volhandle}.ax{1}.cm, 'Label', 'Orientation'); + iorient = findobj(get(st.vols{volhandle}.ax{1}.cm,'Children'), 'flat', 'Label', 'Orientation'); item19 = uimenu(iorient, 'Label', 'ROI Space', 'Callback', ... sprintf('%s(''context_space'', %d);', mfilename, volhandle), ... 'Visible','off', 'Tag',sprintf('ROI_1_%d', volhandle)); @@ -643,16 +643,17 @@ case 'context_space' spm_orthviews('space', volhandle, ... - st.vols{volhandle}.roi.Vroi.mat, ... - st.vols{volhandle}.roi.Vroi.dim(1:3)); - iorient = get(findobj(0,'Label','Orientation'),'children'); - if iscell(iorient) - iorient = cell2mat(iorient); - end; - set(iorient, 'Checked', 'Off'); - ioroi = findobj(iorient, 'Label','ROI space'); - set(ioroi, 'Checked', 'On'); - return; + st.vols{volhandle}.roi.Vroi.mat, ... + st.vols{volhandle}.roi.Vroi.dim(1:3)); + iorient = get(findobj(get(st.vols{volhandle}.ax{1}.cm,'Children'), ... + 'flat', 'Label', 'Orientation'),'children'); + if iscell(iorient) + iorient = cell2mat(iorient); + end + set(iorient, 'Checked', 'Off'); + ioroi = findobj(iorient, 'Label','ROI Space'); + set(ioroi, 'Checked', 'On'); + return; case 'context_thresh' Finter = spm_figure('FindWin', 'Interactive'); diff --git a/spm_platform.m b/spm_platform.m index 75ef7cdd..ed2b90f8 100644 --- a/spm_platform.m +++ b/spm_platform.m @@ -13,7 +13,6 @@ % - 'user' - returns username % - 'host' - returns system's host name % - 'tempdir' - returns name of temp directory -% - 'drives' - returns string containing valid drive letters % - 'desktop' - returns whether or not the Desktop is in use % % FORMAT PlatFontNames = spm_platform('fonts') @@ -50,10 +49,10 @@ % Platform specific definitions are contained in the data structures at % the beginning of the init_platform subfunction at the end of this file. %__________________________________________________________________________ -% Copyright (C) 1999-2016 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 1999-2017 Wellcome Trust Centre for Neuroimaging % Matthew Brett -% $Id: spm_platform.m 6903 2016-10-12 11:36:41Z guillaume $ +% $Id: spm_platform.m 7205 2017-11-09 11:29:59Z guillaume $ %-Initialise @@ -92,8 +91,7 @@ case 'drives' %-Return drives %========================================================================== -warning('Use spm_select(''ListDrives'') instead.'); -varargout = {PLATFORM.drives}; +error('Use spm_select(''ListDrives'') instead.'); case 'tempdir' %-Return temporary directory %========================================================================== @@ -226,15 +224,6 @@ PLATFORM.host = strtok(PLATFORM.host,'.'); -%-Drives -%-------------------------------------------------------------------------- -PLATFORM.drives = ''; -if strcmp(PLATFORM.filesys,'win') - driveLett = spm_select('ListDrives'); - PLATFORM.drives = strrep(strcat(driveLett{:}),':',''); -end - - %-Fonts %-------------------------------------------------------------------------- switch comp diff --git a/spm_plot_convergence.m b/spm_plot_convergence.m index 065dc15c..0b6f697e 100644 --- a/spm_plot_convergence.m +++ b/spm_plot_convergence.m @@ -9,10 +9,10 @@ function spm_plot_convergence(action,varargin) % FORMAT spm_plot_convergence('Clear') % Clear the 'Interactive' window. %__________________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2008-2017 Wellcome Trust Centre for Neuroimaging % John Ashburner -% $Id: spm_plot_convergence.m 4147 2010-12-24 13:50:06Z guillaume $ +% $Id: spm_plot_convergence.m 7112 2017-06-16 11:30:37Z guillaume $ if ~nargin, action = 'Init'; end @@ -29,12 +29,10 @@ function spm_plot_convergence(action,varargin) if nargin > 2, arg2 = varargin{2}; else arg2 = 'Chi-squared'; end if nargin > 3, arg3 = varargin{3}; else arg3 = 'Iteration'; end pb = struct('pointer',get(Finter,'Pointer'),... - 'name', get(Finter,'Name'),... - 'buffer', get(Finter,'DoubleBuffer')); + 'name', get(Finter,'Name')); spm_plot_convergence('Clear'); set(Finter,'Pointer','watch'); set(Finter,'Name',pb.name); - set(Finter,'DoubleBuffer','on'); pb.ax = axes('Position',[0.15 0.1 0.8 0.75],... 'Box', 'on',... 'Parent', Finter); @@ -68,7 +66,6 @@ function spm_plot_convergence(action,varargin) if isstruct(pb) set(Finter,'Pointer', pb.pointer); set(Finter,'Name', pb.name); - set(Finter,'DoubleBuffer',pb.buffer); end % Error diff --git a/spm_powell.m b/spm_powell.m index e9fa4d32..3c382337 100644 --- a/spm_powell.m +++ b/spm_powell.m @@ -15,10 +15,10 @@ % Method is based on Powell's optimisation method described in % Numerical Recipes (Press, Flannery, Teukolsky & Vetterling). %__________________________________________________________________________ -% Copyright (C) 2001-2011 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2001-2017 Wellcome Trust Centre for Neuroimaging % John Ashburner -% $Id: spm_powell.m 4423 2011-08-04 16:28:51Z guillaume $ +% $Id: spm_powell.m 7112 2017-06-16 11:30:37Z guillaume $ p = p(:); @@ -32,7 +32,7 @@ for i=1:length(p) ft = f; [p,junk,f] = min1d(p,xi(:,i),func,f,tolsc,varargin{:}); - if abs(ft-f) > del, + if abs(ft-f) > del del = abs(ft-f); ibig = i; end @@ -121,7 +121,7 @@ d = -pol(2)/(2*pol(3)+eps); % A very conservative constraint on the displacement - if d > (1+gold)*(t(3).p-t(2).p), + if d > (1+gold)*(t(3).p-t(2).p) d = (1+gold)*(t(3).p-t(2).p); end u.p = t(2).p+d; @@ -199,7 +199,7 @@ eps2 = 2*eps*abs(t(1).p)+eps; if abs(d) > abs(ppd)/2 || u.p < brk(1)+eps2 || u.p > brk(2)-eps2 || pol(3)<=0 % if criteria are not met, then golden search into the larger part - if t(1).p >= 0.5*(brk(1)+brk(2)), + if t(1).p >= 0.5*(brk(1)+brk(2)) d = gold1*(brk(1)-t(1).p); else d = gold1*(brk(2)-t(1).p); @@ -252,11 +252,9 @@ function min1d_plot(action,arg1,arg2,arg3) min1dplot = struct('pointer',get(fg,'Pointer'),... 'name', get(fg,'Name'),... - 'ax', [],... - 'buffer', get(fg,'DoubleBuffer')); + 'ax', []); min1d_plot('Clear'); set(fg,'Pointer','Watch'); - set(fg,'DoubleBuffer','on'); min1dplot.ax = axes('Position', [0.15 0.1 0.8 0.75],... 'Box', 'on',... 'Parent', fg); @@ -292,7 +290,6 @@ function min1d_plot(action,arg1,arg2,arg3) if ishandle(min1dplot.ax), delete(min1dplot.ax); end set(fg,'Pointer',min1dplot.pointer); set(fg,'Name',min1dplot.name); - set(fg,'DoubleBuffer',min1dplot.buffer); end spm_figure('Clear',fg); drawnow; diff --git a/spm_preproc8.m b/spm_preproc8.m index 73ad6d52..0cd4917a 100644 --- a/spm_preproc8.m +++ b/spm_preproc8.m @@ -71,7 +71,9 @@ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % John Ashburner -% $Id: spm_preproc8.m 6798 2016-05-20 11:53:33Z john $ +% $Id: spm_preproc8.m 7172 2017-09-21 16:31:30Z john $ + +wp_reg = 1; % Bias wp towards 1 Affine = obj.Affine; tpm = obj.tpm; @@ -434,7 +436,7 @@ vr(:,:,k) = (mom2(:,:,k) - mom1(:,k)*mom1(:,k)'/mom0(k) + N*vr0)/(mom0(k)+N); % US eq. 25 end for k1=1:Kb - wp(k1) = (sum(mom0(lkp==k1)) + 1)/(mgm(k1) + Kb); % bias the solution towards 1 + wp(k1) = (sum(mom0(lkp==k1)) + wp_reg*1)/(mgm(k1) + wp_reg*Kb); % bias the solution towards 1 end wp = wp/sum(wp); @@ -492,7 +494,7 @@ end clear cr end - wp = (sum(chan(1).hist)+1)./(mgm+Kb); + wp = (sum(chan(1).hist)+wp_reg*1)./(mgm+wp_reg*Kb); wp = wp/sum(wp); my_fprintf('Hist:\t%g\t%g\t%g\n', ll,llr,llrb); diff --git a/spm_preproc_write8.m b/spm_preproc_write8.m index e59d275f..fa379236 100644 --- a/spm_preproc_write8.m +++ b/spm_preproc_write8.m @@ -1,11 +1,11 @@ -function [cls,M1] = spm_preproc_write8(res,tc,bf,df,mrf,cleanup,bb,vx) +function [cls,M1] = spm_preproc_write8(res,tc,bf,df,mrf,cleanup,bb,vx,odir) % Write out VBM preprocessed data -% FORMAT [cls,M1] = spm_preproc_write8(res,tc,bf,df,mrf,cleanup,bb,vx) +% FORMAT [cls,M1] = spm_preproc_write8(res,tc,bf,df,mrf,cleanup,bb,vx,odir) %__________________________________________________________________________ % Copyright (C) 2008-2016 Wellcome Trust Centre for Neuroimaging % John Ashburner -% $Id: spm_preproc_write8.m 6881 2016-09-19 09:48:54Z john $ +% $Id: spm_preproc_write8.m 7202 2017-11-08 12:30:01Z john $ % Prior adjustment factor. % This is a fudge factor to weaken the effects of the tissue priors. The @@ -20,31 +20,32 @@ else Kb = size(res.intensity(1).lik,2); end -N = numel(res.image); +N = numel(res.image); if nargin<2, tc = true(Kb,4); end % native, import, warped, warped-mod if nargin<3, bf = false(N,2); end % field, corrected if nargin<4, df = false(1,2); end % inverse, forward if nargin<5, mrf = 1; end % MRF parameter if nargin<6, cleanup = 1; end % Run the ad hoc cleanup +if nargin<7, bb = NaN(2,3); end % Default to TPM bounding box +if nargin<8, vx = NaN; end % Default to TPM voxel size +if nargin<9, odir = []; end % Output directory % Read essentials from tpm (it will be cleared later) tpm = res.tpm; -if ~isstruct(tpm) || ~isfield(tpm, 'bg1'), +if ~isstruct(tpm) || ~isfield(tpm, 'bg1') tpm = spm_load_priors8(tpm); end -d1 = size(tpm.dat{1}); -d1 = d1(1:3); -M1 = tpm.M; +d1 = size(tpm.dat{1}); +d1 = d1(1:3); +M1 = tpm.M; % Define orientation and field of view of any "normalised" space % data that may be generated (wc*.nii, mwc*.nii, rc*.nii & y_*.nii). -if nargin>=7 && any(isfinite(bb(:))) +if any(isfinite(bb(:))) || any(isfinite(vx)) % If a bounding box is supplied, combine this with the closest % bounding box derived from the dimensions and orientations of % the tissue priors. - if nargin<7, bb = NaN(2,3); end % Default to TPM bounding box - if nargin<8, vx = NaN; end % Default to TPM voxel size [bb1,vx1] = spm_get_bbox(tpm.V(1), 'old'); bb(~isfinite(bb)) = bb1(~isfinite(bb)); if ~isfinite(vx), vx = abs(prod(vx1))^(1/3); end @@ -78,6 +79,7 @@ [pth,nam] = fileparts(res.image(1).fname); +if ~isempty(odir) && ischar(odir), pth = odir; end ind = res.image(1).n; d = res.image(1).dim(1:3); @@ -94,6 +96,7 @@ % Need to fix writing of bias fields or bias corrected images, when the data used are 4D. [pth1,nam1] = fileparts(res.image(n).fname); + if ~isempty(odir) && ischar(odir), pth1 = odir; end chan(n).ind = res.image(n).n; if bf(n,2) @@ -151,7 +154,6 @@ do_defs = do_cls | do_defs; if do_defs if df(1) - [pth,nam] =fileparts(res.image(1).fname); Ndef = nifti; Ndef.dat = file_array(fullfile(pth,['iy_', nam, '.nii']),... [res.image(1).dim(1:3),1,3],... @@ -200,12 +202,9 @@ if exist('Ndef','var') % Write out the deformation to file, adjusting it so mapping is % to voxels (voxels in image to mm in TPM) - tmp = M1(1,1)*t1 + M1(1,2)*t2 + M1(1,3)*t3 + M1(1,4); - Ndef.dat(:,:,z,1,1) = tmp; - tmp = M1(2,1)*t1 + M1(2,2)*t2 + M1(2,3)*t3 + M1(2,4); - Ndef.dat(:,:,z,1,2) = tmp; - tmp = M1(3,1)*t1 + M1(3,2)*t2 + M1(3,3)*t3 + M1(3,4); - Ndef.dat(:,:,z,1,3) = tmp; + Ndef.dat(:,:,z,1,1) = M1(1,1)*t1 + M1(1,2)*t2 + M1(1,3)*t3 + M1(1,4); + Ndef.dat(:,:,z,1,2) = M1(2,1)*t1 + M1(2,2)*t2 + M1(2,3)*t3 + M1(2,4); + Ndef.dat(:,:,z,1,3) = M1(3,1)*t1 + M1(3,2)*t2 + M1(3,3)*t3 + M1(3,4); end if exist('y','var') @@ -217,7 +216,7 @@ if do_cls % Generate variable Q if tissue classes are needed - %msk = (f==0) | ~isfinite(f); + msk = any((f==0) | ~isfinite(f),3); if isfield(res,'mg') % Parametric representation of intensity distributions @@ -232,7 +231,9 @@ s = s + b{k1}; end for k1=1:Kb - q(:,:,k1) = sum(q1(:,:,lkp==k1),3).*(b{k1}./s); + tmp = sum(q1(:,:,lkp==k1),3); + tmp(msk) = 1e-3; + q(:,:,k1) = tmp.*(b{k1}./s); end else % Nonparametric representation of intensity distributions @@ -281,7 +282,6 @@ spm_progress_bar('init',nmrf_its,['MRF: Working on ' nam],'Iterations completed'); G = ones([Kb,1],'single')*mrf; vx2 = 1./single(sum(res.image(1).mat(1:3,1:3).^2)); - %save PQG P Q G tiss Kb x3 ind for iter=1:nmrf_its spm_mrf(P,Q,G,vx2); spm_progress_bar('set',iter); @@ -291,7 +291,7 @@ if cleanup % Use an ad hoc brain cleanup procedure - if size(P,4)>5 + if size(P,4)>3 P = clean_gwc(P,cleanup); else warning('Cleanup not done.'); @@ -339,7 +339,6 @@ mat0 = R\mat; % Voxel-to-world of original image space - [pth,nam] = fileparts(res.image(1).fname); fwhm = max(vx./sqrt(sum(res.image(1).mat(1:3,1:3).^2))-1,0.01); for k1=1:size(tc,1) if tc(k1,2) @@ -628,7 +627,6 @@ cp = ((cp>th).*(slices{1}+slices{2}+slices{3}))>th; slices{3} = slices{3}.*cp; end - slices{5} = slices{5}+1e-4; % Add a little to the soft tissue class tot = zeros(size(bp))+eps; for k1=1:size(P,4) tot = tot + slices{k1}; @@ -638,3 +636,4 @@ end end spm_progress_bar('Clear'); + diff --git a/spm_print.m b/spm_print.m index 92424602..a9b7dd12 100644 --- a/spm_print.m +++ b/spm_print.m @@ -9,15 +9,15 @@ % FORMAT spm_print(job) % Run a batch print job (see spm_cfg_print) %__________________________________________________________________________ -% Copyright (C) 1994-2016 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 1994-2017 Wellcome Trust Centre for Neuroimaging % John Ashburner -% $Id: spm_print.m 6894 2016-09-30 16:48:46Z spm $ +% $Id: spm_print.m 7018 2017-02-15 13:36:48Z guillaume $ %-Shortcut for list of graphics file formats available %-------------------------------------------------------------------------- -if nargin > 0 && isequal(lower(varargin{1}),'format') +if nargin > 0 && ischar(varargin{1}) && strcmpi(varargin{1},'format') [varargout{1:nargout}] = print_format(varargin{2:end}); return; end @@ -77,17 +77,26 @@ return; end +%-Check valid renderer +% 'OpenGL' is not a valid renderer in -nodisplay mode. Normally, MATLAB +% warns and uses 'zbuffer' if one tries to set 'OpenGL' in this case. +% However, sometimes this setting is not passed properly to the +% user-visible properties of the figure, and the 'Renderer' property is +% empty. This causes problems when printing, so it is better to set any +% invalid 'Renderer' setting to 'zbuffer'. +%-------------------------------------------------------------------------- +validrend = set(F, 'Renderer'); +if ~any(strcmpi(get(F, 'Renderer'), validrend)) + set(F, 'Renderer','zbuffer'); +end + %-Print %========================================================================== try if ismember('-dfig',opts.opt) saveas(F, fname, 'fig'); else - if isdeployed - deployprint(F, fname, opts.opt{:}); - else - print(F, fname, opts.opt{:}); - end + print(F, fname, opts.opt{:}); end catch disp('Print error: nothing has been printed.'); diff --git a/spm_progress_bar.m b/spm_progress_bar.m index a593b61f..f8223ebd 100644 --- a/spm_progress_bar.m +++ b/spm_progress_bar.m @@ -17,10 +17,10 @@ function spm_progress_bar(action,varargin) % FORMAT spm_progress_bar('Clear') % Clear the 'Interactive' window. %__________________________________________________________________________ -% Copyright (C) 1996-2015 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 1996-2017 Wellcome Trust Centre for Neuroimaging % John Ashburner -% $Id: spm_progress_bar.m 6383 2015-03-19 17:20:41Z guillaume $ +% $Id: spm_progress_bar.m 7112 2017-06-16 11:30:37Z guillaume $ persistent pbar; @@ -40,12 +40,10 @@ function spm_progress_bar(action,varargin) if nargin > 4, arg4 = varargin{4}; else arg4 = ' '; end if any(arg4 == 't'), interp = 'tex'; else interp = 'none'; end pb = struct('pointer',get(Finter,'Pointer'),... - 'name', get(Finter,'Name'),... - 'buffer', get(Finter,'DoubleBuffer')); + 'name', get(Finter,'Name')); spm_progress_bar('Clear'); set(Finter,'Pointer','watch'); set(Finter,'Name',pb.name); - set(Finter,'DoubleBuffer','on'); % no effect since R2013a if ischar(arg2), arg2 = repmat({arg2},1,numel(arg1)); end if ischar(arg3), arg3 = repmat({arg3},1,numel(arg1)); end @@ -131,9 +129,8 @@ function spm_progress_bar(action,varargin) if isempty(Finter), pbar = []; return; end spm_figure('Clear',Finter); if isstruct(pbar) - set(Finter,'Pointer', pbar.pointer); - set(Finter,'Name', pbar.name); - set(Finter,'DoubleBuffer',pbar.buffer); + set(Finter,'Pointer', pbar.pointer); + set(Finter,'Name', pbar.name); end pbar = []; drawnow; diff --git a/spm_project.mexmaci64 b/spm_project.mexmaci64 index efbfba2069864a1e69a99e1a230a0667a2175bc3..deed030a88f7b46819780fe9c58b162734e723a1 100755 GIT binary patch literal 13176 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 PVRFGP$xCi5Kp^}FQ~|vT literal 13272 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 delta 32 lcmZn&X$YC{f#v_+n9zw|e3)|mHajssk^}QMYbe~{1OWRS4r>4a diff --git a/spm_provenance.m b/spm_provenance.m index 3dca016d..a05e9d78 100644 --- a/spm_provenance.m +++ b/spm_provenance.m @@ -32,10 +32,10 @@ % p.hadMember(collection,entity) % p.bundle(id,b) %__________________________________________________________________________ -% Copyright (C) 2013-2015 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2013-2017 Wellcome Trust Centre for Neuroimaging % Guillaume Flandin -% $Id: spm_provenance.m 6903 2016-10-12 11:36:41Z guillaume $ +% $Id: spm_provenance.m 7057 2017-04-13 16:45:49Z guillaume $ %-Properties @@ -658,6 +658,28 @@ function addItem(obj,varargin) end end end + % remove trailing colon + for n=1:numel(node) + if iscell(node{n}) + for k=1:numel(node{n}) + if isstruct(node{n}{k}) + if isfield(node{n}{k},'value') && node{n}{k}.value(end) == ':' + node{n}{k}.value = node{n}{k}.value(1:end-1); + elseif isfield(node{n}{k},'id') && node{n}{k}.id(end) == ':' + node{n}{k}.id = node{n}{k}.id(1:end-1); + end + else + if node{n}{k}(end) == ':' + node{n}{k} = node{n}{k}(1:end-1); + end + end + end + else + if node{n}(end) == ':' + node{n} = node{n}(1:end-1); + end + end + end % serialize node str = [str o o sprintf('{\n')]; for j=1:size(node,1) @@ -828,7 +850,7 @@ function addItem(obj,varargin) attr = obj.stack{j}{end}; if ~isempty(attr) url_ann = sprintf('http://annot/ann%d',annn); - attrlist = []; + attrlist = ''; for k=1:2:numel(attr) attribute = attr{k}; literal = attr{k+1}; diff --git a/spm_read_vols.m b/spm_read_vols.m index 9b7b37ba..0408ff16 100644 --- a/spm_read_vols.m +++ b/spm_read_vols.m @@ -1,38 +1,39 @@ -function [Y,XYZ] = spm_read_vols(V,mask) +function [Y,XYZmm] = spm_read_vols(V,mask) % Read in entire image volumes -% FORMAT [Y,XYZ] = spm_read_vols(V,mask) -% V - vector of mapped image volumes to read in (from spm_vol) -% mask - implicit zero mask? +% FORMAT [Y,XYZmm] = spm_read_vols(V,mask) +% V - vector of mapped image volumes to read in (from spm_vol) +% mask - implicit zero mask? % -% Y - 4D matrix of image data, fourth dimension indexes images -% XYZ - 3xn matrix of XYZ locations returned (in mm) +% Y - 4D matrix of image data, fourth dimension indexes images +% XYZmm - 3xn matrix of XYZ locations returned {mm} %__________________________________________________________________________ % % For image data types without a representation of NaN (see spm_type), % implicit zero masking can be used. If mask is set, then zeros are % treated as masked, and returned as NaN. %__________________________________________________________________________ -% Copyright (C) 1999-2013 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 1999-2016 Wellcome Trust Centre for Neuroimaging % Andrew Holmes -% $Id: spm_read_vols.m 5731 2013-11-04 18:11:44Z guillaume $ +% $Id: spm_read_vols.m 6918 2016-11-02 14:33:11Z guillaume $ %-Argument checks %-------------------------------------------------------------------------- -if nargin<2, mask = 0; end -if nargin<1, error('insufficient arguments'), end +if nargin<2, mask = false; end spm_check_orientations(V); %-Read in image data %-------------------------------------------------------------------------- -n = numel(V); %-#images -Y = zeros([V(1).dim(1:3),n]); %-image data matrix +n = numel(V); %-#images +Y = zeros([V(1).dim(1:3),n]); %-image data matrix -for i=1:n, for p=1:V(1).dim(3) - Y(:,:,p,i) = spm_slice_vol(V(i),spm_matrix([0 0 p]),V(i).dim(1:2),0); -end, end +for i=1:n + for p=1:V(1).dim(3) + Y(:,:,p,i) = spm_slice_vol(V(i),spm_matrix([0 0 p]),V(i).dim(1:2),0); + end +end %-Apply implicit zero mask for image datatypes without a NaNrep %-------------------------------------------------------------------------- @@ -48,12 +49,10 @@ %-------------------------------------------------------------------------- if n==1, Y=Y(:,:,:,1); end -%-Compute XYZ co-ordinates (if required) +%-Compute XYZmm co-ordinates (if required) %-------------------------------------------------------------------------- -if nargout>1 - [R,C,P] = ndgrid(1:V(1).dim(1),1:V(1).dim(2),1:V(1).dim(3)); - RCP = [R(:)';C(:)';P(:)']; - clear R C P - RCP(4,:) = 1; - XYZ = V(1).mat(1:3,:)*RCP; +if nargout > 1 + [R,C,P] = ndgrid(1:V(1).dim(1),1:V(1).dim(2),1:V(1).dim(3)); + RCP = [R(:)';C(:)';P(:)';ones(1,numel(R))]; + XYZmm = V(1).mat(1:3,:)*RCP; end diff --git a/spm_realign.m b/spm_realign.m index 81192d16..1d1664a2 100644 --- a/spm_realign.m +++ b/spm_realign.m @@ -83,13 +83,13 @@ % RSJ (1995) Spatial registration and normalization of images Hum. Brain % Map. 2:165-189 %__________________________________________________________________________ -% Copyright (C) 1994-2013 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 1994-2017 Wellcome Trust Centre for Neuroimaging % John Ashburner -% $Id: spm_realign.m 6070 2014-06-26 20:53:39Z guillaume $ +% $Id: spm_realign.m 7141 2017-07-26 09:05:05Z guillaume $ -SVNid = '$Rev: 6070 $'; +SVNid = '$Rev: 7141 $'; %-Say hello %-------------------------------------------------------------------------- @@ -97,12 +97,6 @@ %-Parameters & Arguments %========================================================================== -if ~nargin - error('Not enough input arguments.'); -end -if nargin > 2 - error('Too many input arguments.'); -end %-Flags %-------------------------------------------------------------------------- @@ -128,13 +122,13 @@ P(cellfun(@isempty,P)) = []; if ~isempty(flags.PW) && ischar(flags.PW), flags.PW = spm_vol(flags.PW); end -if isempty(P), warning('Nothing to do'); return; end +if isempty(P), warning('Nothing to do.'); end %-Perform realignment %========================================================================== if numel(P)==1 P{1} = realign_series(P{1}, flags); -else +elseif numel(P) > 1 Ptmp = P{1}(1); for s=2:numel(P) Ptmp = [Ptmp ; P{s}(1)]; @@ -417,16 +411,22 @@ %========================================================================== function V = smooth_vol(P,hld,wrp,fwhm) % Convolve the volume in memory -s = sqrt(sum(P.mat(1:3,1:3).^2)).^(-1)*(fwhm/sqrt(8*log(2))); +vx = sqrt(sum(P.mat(1:3,1:3).^2)); +s = vx.^(-1)*(fwhm/sqrt(8*log(2))); x = round(6*s(1)); x = -x:x; y = round(6*s(2)); y = -y:y; z = round(6*s(3)); z = -z:z; -x = exp(-(x).^2/(2*(s(1)).^2)); -y = exp(-(y).^2/(2*(s(2)).^2)); -z = exp(-(z).^2/(2*(s(3)).^2)); -x = x/sum(x); -y = y/sum(y); -z = z/sum(z); + +x = spm_smoothkern(fwhm/vx(1),x,1); +y = spm_smoothkern(fwhm/vx(2),y,1); +z = spm_smoothkern(fwhm/vx(3),z,1); + +%x = exp(-(x).^2/(2*(s(1)).^2)); +%y = exp(-(y).^2/(2*(s(2)).^2)); +%z = exp(-(z).^2/(2*(s(3)).^2)); +%x = x/sum(x); +%y = y/sum(y); +%z = z/sum(z); i = (length(x) - 1)/2; j = (length(y) - 1)/2; diff --git a/spm_regions.m b/spm_regions.m index 1eb74268..0224b1cb 100644 --- a/spm_regions.m +++ b/spm_regions.m @@ -47,10 +47,10 @@ % be extracted from xY.y, and will be the same as the [adjusted] data % returned by the plotting routine (spm_graph.m) for the same contrast. %__________________________________________________________________________ -% Copyright (C) 1999-2015 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 1999-2016 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_regions.m 6436 2015-05-14 10:05:27Z guillaume $ +% $Id: spm_regions.m 6923 2016-11-04 15:35:12Z guillaume $ %-Shortcut for VOI display @@ -153,7 +153,7 @@ if isempty(xY.XYZmm) warning('Empty region.'); - Y = []; + [Y, xY.y, xY.u, xY.v, xY.s, xY.X0] = deal([]); return; end diff --git a/spm_reml.m b/spm_reml.m index 6c6eba88..6d69a45f 100644 --- a/spm_reml.m +++ b/spm_reml.m @@ -1,20 +1,19 @@ -function [V,h,Ph,F,Fa,Fc] = spm_reml(YY,X,Q,N,D,t,hE,hP) +function [V,h,Ph,F,Fa,Fc] = spm_reml(YY,X,Q,N,t,hE,hP) % ReML estimation of [improper] covariance components from y*y' -% FORMAT [C,h,Ph,F,Fa,Fc] = spm_reml(YY,X,Q,N,D,t,hE,hP); +% FORMAT [C,h,Ph,F,Fa,Fc] = spm_reml(YY,X,Q,N,t,hE,hP) % % YY - (m x m) sample covariance matrix Y*Y' {Y = (m x N) data matrix} % X - (m x p) design matrix % Q - {1 x q} covariance components % -% N - number of samples (default 1) -% D - Flag for positive-definite scheme (default 0) -% t - regularisation (default 4) -% hE - hyperprior (default 0) -% hP - hyperprecision (default 1e-16) +% N - number of samples [default: 1] +% t - regularisation [default: 4] +% hE - hyperprior [default: 0] +% hP - hyperprecision [default: exp(-8)] % % C - (m x m) estimated errors = h(1)*Q{1} + h(2)*Q{2} + ... -% h - (q x 1) ReML hyperparameters h -% Ph - (q x q) conditional precision of h +% h - (q x 1) posterior expectation of h +% Ph - (q x q) posterior precision of h % % F - [-ve] free energy F = log evidence = p(Y|X,Q) = ReML objective % @@ -35,21 +34,20 @@ % spm_sp_reml: for sparse patterns (c.f., ARD) % %__________________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2002-2017 Wellcome Trust Centre for Neuroimaging % John Ashburner & Karl Friston -% $Id: spm_reml.m 5223 2013-02-01 11:56:05Z ged $ - - +% $Id: spm_reml.m 7178 2017-10-02 18:12:16Z karl $ + + % check defaults %-------------------------------------------------------------------------- -try, N; catch, N = 1; end % assume a single sample if not specified -try, K; catch, K = 32; end % default number of iterations -try, D; catch, D = 0; end % default checking -try, t; catch, t = 4; end % default regularisation -try, hE; catch, hE = 0; end % default hyperprior -try, hP; catch, hP = 1e-16; end % default hyperprecision - +try, N; catch, N = 1; end % assume a single sample if not specified +try, K; catch, K = 32; end % default number of iterations +try, t; catch, t = 4; end % default regularisation +try, hE; catch, hE = 0; end % default hyperprior +try, hP; catch, hP = exp(-8); end % default hyperprecision + % catch NaNs %-------------------------------------------------------------------------- W = Q; @@ -58,12 +56,12 @@ for i = 1:length(Q) Q{i} = Q{i}(q,q); end - + % dimensions %-------------------------------------------------------------------------- n = length(Q{1}); m = length(Q); - + % ortho-normalise X %-------------------------------------------------------------------------- if isempty(X) @@ -71,51 +69,32 @@ else X = spm_svd(X(q,:),0); end - + % initialise h and specify hyperpriors %========================================================================== h = zeros(m,1); +d = false(n,1); for i = 1:m - h(i,1) = any(diag(Q{i})); + q = diag(Q{i}); + h(i,1) = any(q & ~d); + d = d | q; end +h = double(h); hE = sparse(m,1) + hE; hP = speye(m,m)*hP; dF = Inf; -D = 8*(D > 0); - - + % ReML (EM/VB) %-------------------------------------------------------------------------- for k = 1:K - + % compute current estimate of covariance %---------------------------------------------------------------------- C = sparse(n,n); for i = 1:m C = C + Q{i}*h(i); end - - % positive [semi]-definite check - %---------------------------------------------------------------------- - for i = 1:D - if min(real(eig(full(C)))) < 0 - - % increase regularisation and re-evaluate C - %-------------------------------------------------------------- - t = t - 1; - h = h - dh; - dh = spm_dx(dFdhh,dFdh,{t}); - h = h + dh; - C = sparse(n,n); - for i = 1:m - C = C + Q{i}*h(i); - end - else - break - end - end - - + % E-step: conditional covariance cov(B|y) {Cq} %====================================================================== iC = spm_inv(C); @@ -125,60 +104,60 @@ else Cq = sparse(0); end - + % M-step: ReML estimate of hyperparameters %====================================================================== - + % Gradient dF/dh (first derivatives) %---------------------------------------------------------------------- P = iC - iCX*Cq*iCX'; U = speye(n) - P*YY/N; for i = 1:m - + % dF/dh = -trace(dF/diC*iC*Q{i}*iC) %------------------------------------------------------------------ PQ{i} = P*Q{i}; dFdh(i,1) = -spm_trace(PQ{i},U)*N/2; - + end - + % Expected curvature E{dF/dhh} (second derivatives) %---------------------------------------------------------------------- for i = 1:m for j = i:m - + % dF/dhh = -trace{P*Q{i}*P*Q{j}} %-------------------------------------------------------------- dFdhh(i,j) = -spm_trace(PQ{i},PQ{j})*N/2; dFdhh(j,i) = dFdhh(i,j); - + end end - + % add hyperpriors %---------------------------------------------------------------------- e = h - hE; dFdh = dFdh - hP*e; dFdhh = dFdhh - hP; - + % Fisher scoring: update dh = -inv(ddF/dhh)*dF/dh %---------------------------------------------------------------------- dh = spm_dx(dFdhh,dFdh,{t}); h = h + dh; - + % predicted change in F - increase regularisation if increasing %---------------------------------------------------------------------- pF = dFdh'*dh; if pF > dF - t = t - 1; + t = max(t - 1, -8); else - t = t + 1/4; + t = min(t + 1/4,8); end - % revert to SPD checking, if near phase-transition + % if near phase-transition start again with more precise priors %---------------------------------------------------------------------- - if ~isfinite(pF) || abs(pF) > 1e6 - [V,h,Ph,F,Fa,Fc] = spm_reml(YY,X,Q,N,1,t - 2); + if ~isfinite(pF) || norm(dh,'inf') > 1e6 + [V,h,Ph,F,Fa,Fc] = spm_reml(YY,X,Q,N,t,0,hP(1)*2); return else dF = pF; @@ -187,48 +166,81 @@ % Convergence (1% change in log-evidence) %====================================================================== fprintf('%s %-23d: %10s%e [%+3.2f]\n',' ReML Iteration',k,'...',full(pF),t); - + % final estimate of covariance (with missing data points) %---------------------------------------------------------------------- if dF < 1e-1, break, end end - + % re-build predicted covariance %========================================================================== V = 0; for i = 1:m V = V + W{i}*h(i); end - -% check V is positive semi-definite (if not already checked) + +% check V is positive semi-definite and parameters have been identified %========================================================================== -if ~D - if min(eig(V)) < 0 - [V,h,Ph,F,Fa,Fc] = spm_reml(YY,X,Q,N,1,2,hE(1),hP(1)); - return +Ph = -dFdhh; +if ((min(eig(full(V))) < 0) || log(condest(Ph)) > 16) && t > -4 + + % Bayesian model reduction (successive removal of parameters) + %---------------------------------------------------------------------- + iQ = []; + qE = h; + pC = inv(hP); + qC = inv(Ph); + for i = 1:m + rC = pC; + rC(i,:) = 0; + rC(:,i) = 0; + [F,sE,sC] = spm_log_evidence_reduce(qE,qC,hE,pC,hE,rC); + + % Remove redundant covariance components + %------------------------------------------------------------------ + if F > 2 + qE = sE; + qC = sC; + pC = rC; + else + iQ = [iQ,i]; + end + end + if nargout > 3 + [V,qE,qP,F,Fa,Fc] = spm_reml(YY,X,Q(iQ),N,t,0,hP(1)*2); + else + [V,qE,qP] = spm_reml(YY,X,Q(iQ),N,t,0,hP(1)*2); end + + % Replace redundant covariance components + %---------------------------------------------------------------------- + h = hE; + h(iQ) = qE; + Ph = hP; + Ph(iQ,iQ) = qP; + + return end - + % log evidence = ln p(y|X,Q) = ReML objective = F = trace(R'*iC*R*YY)/2 ... %-------------------------------------------------------------------------- -Ph = -dFdhh; if nargout > 3 - - % tr(hP*inv(Ph)) - nh + tr(pP*inv(Pp)) - np (pP = 0) + + % tr(hP*inv(Ph)) - nh (complexity KL cost of parameters = 0) %---------------------------------------------------------------------- - Ft = trace(hP*inv(Ph)) - length(Ph) - length(Cq); - + Ft = trace(hP/Ph) - length(Ph); + % complexity - KL(Ph,hP) %---------------------------------------------------------------------- - Fc = Ft/2 + e'*hP*e/2 + spm_logdet(Ph*inv(hP))/2 - N*spm_logdet(Cq)/2; - + Fc = Ft/2 + e'*hP*e/2 + spm_logdet(Ph/hP)/2; + % Accuracy - ln p(Y|h) %---------------------------------------------------------------------- Fa = Ft/2 - trace(C*P*YY*P)/2 - N*n*log(2*pi)/2 - N*spm_logdet(C)/2; - + % Free-energy %---------------------------------------------------------------------- F = Fa - Fc; - + end diff --git a/spm_reml_A.m b/spm_reml_A.m index ff623963..6b9e995e 100644 --- a/spm_reml_A.m +++ b/spm_reml_A.m @@ -1,6 +1,6 @@ function [C,h,Ph,F,Fa,Fc] = spm_reml_A(YY,X,Q,N,hE,hC,V) % ReML estimation of covariance components from y*y' - factored components -% FORMAT [C,h,Ph,F,Fa,Fc] = spm_reml_A(YY,X,Q,N,[hE,hC,V]); +% FORMAT [C,h,Ph,F,Fa,Fc] = spm_reml_A(YY,X,Q,N,[hE,hC,V]) % % YY - (m x m) sample covariance matrix Y*Y' {Y = (m x N) data matrix} % X - (m x p) design matrix @@ -32,10 +32,10 @@ % spm_sp_reml: for sparse patterns (c.f., ARD) % %__________________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2010-2017 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_reml_A.m 4805 2012-07-26 13:16:18Z karl $ +% $Id: spm_reml_A.m 7192 2017-10-18 14:59:01Z guillaume $ % assume a single sample if not specified @@ -171,13 +171,13 @@ Ph = -dFdhh; if nargout > 3 - % tr(hP*inv(Ph)) - nh + tr(pP*inv(Pp)) - np (pP = 0) + % tr(hP*inv(Ph)) - nh (complexity KL cost of parameters = 0) %---------------------------------------------------------------------- - Ft = trace(hP/Ph) - length(Ph) - length(Cq); + Ft = trace(hP/Ph) - length(Ph); % complexity - KL(Ph,hP) %---------------------------------------------------------------------- - Fc = Ft/2 + e'*hP*e/2 + spm_logdet(Ph/hP)/2 - N*spm_logdet(Cq)/2; + Fc = Ft/2 + e'*hP*e/2 + spm_logdet(Ph/hP)/2; % Accuracy - ln p(Y|h) %---------------------------------------------------------------------- diff --git a/spm_reml_sc.m b/spm_reml_sc.m index 94d7cfef..f4254965 100644 --- a/spm_reml_sc.m +++ b/spm_reml_sc.m @@ -1,6 +1,6 @@ -function [C,h,Ph,F,Fa,Fc] = spm_reml_sc(YY,X,Q,N,hE,hC,V) +function [C,h,Ph,F,Fa,Fc,Eh,Ch,hE,hC] = spm_reml_sc(YY,X,Q,N,hE,hC,V) % ReML estimation of covariance components from y*y' - proper components -% FORMAT [C,h,Ph,F,Fa,Fc] = spm_reml_sc(YY,X,Q,N,[hE,hC,V]); +% FORMAT [C,h,Ph,F,Fa,Fc,Eh,Ch,hE,hC] = spm_reml_sc(YY,X,Q,N,[hE,hC,V]) % % YY - (m x m) sample covariance matrix Y*Y' {Y = (m x N) data matrix} % X - (m x p) design matrix @@ -15,6 +15,11 @@ % h - (q x 1) ReML hyperparameters h % Ph - (q x q) conditional precision of log(h) % +% hE - prior expectation of log scale parameters +% hC - prior covariances of log scale parameters +% Eh - posterior expectation of log scale parameters +% Ch - posterior covariances of log scale parameters +% % F - [-ve] free energy F = log evidence = p(Y|X,Q) = ReML objective % % Fa - accuracy @@ -23,7 +28,7 @@ % Performs a Fisher-Scoring ascent on F to find MAP variance parameter % estimates. NB: uses weakly informative log-normal hyperpriors. % See also spm_reml for an unconstrained version that allows for negative -% hyperparameters +% hyperparameters. % %__________________________________________________________________________ % @@ -34,10 +39,10 @@ % spm_sp_reml: for sparse patterns (c.f., ARD) % %__________________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2007-2017 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_reml_sc.m 4805 2012-07-26 13:16:18Z karl $ +% $Id: spm_reml_sc.m 7192 2017-10-18 14:59:01Z guillaume $ % assume a single sample if not specified @@ -191,7 +196,7 @@ else % eliminate redundant components (automatic selection) %------------------------------------------------------------------ - as = find(h > -16); + as = find(h > hE); as = as(:)'; end end @@ -201,13 +206,13 @@ Ph = -dFdhh; if nargout > 3 - % tr(hP*inv(Ph)) - nh + tr(pP*inv(Pp)) - np (pP = 0) + % tr(hP*inv(Ph)) - nh (complexity KL cost of parameters = 0) %---------------------------------------------------------------------- - Ft = trace(hP/Ph) - length(Ph) - length(Cq); + Ft = trace(hP/Ph) - length(Ph); % complexity - KL(Ph,hP) %---------------------------------------------------------------------- - Fc = Ft/2 + e'*hP*e/2 + spm_logdet(Ph/hP)/2 - N*spm_logdet(Cq)/2; + Fc = Ft/2 + e'*hP*e/2 + spm_logdet(Ph/hP)/2; % Accuracy - ln p(Y|h) %---------------------------------------------------------------------- @@ -219,6 +224,16 @@ end +% priors and posteriors of log parameters (with scaling) +%-------------------------------------------------------------------------- +if nargout > 7 + + hE = hE + log(sY) - log(sh); + hC = spm_inv(hP); + Eh = h + log(sY) - log(sh); + Ch = spm_inv(Ph); + +end % return exp(h) hyperpriors and rescale %-------------------------------------------------------------------------- diff --git a/spm_render_vol.mexmaci64 b/spm_render_vol.mexmaci64 index 47cce538f07a22e211676a22b0e50cfe716cff33..8e0518d0c0f9da5e422cf36feee3ba85dfd5e28b 100755 GIT binary patch literal 186104 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


q0Ne00x}amMEytc8{)?bP{ZDZ`HVzxKy&^D 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 TJ7b1Sm0{<|h$eM0H(&h+fdKJ$ literal 199432 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 Rd#%vDPZ+!%Be!8h{ue%S5a9p- diff --git a/spm_slice_vol.mexw32 b/spm_slice_vol.mexw32 index 1410517a9d3dcf31fa5e8bd10ec77bc5866895fe..1c176e5008f5f8884dd703926e17e62ac32a958c 100755 GIT binary patch delta 12822 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 BsxJTl delta 12471 zcmd^FdwfjS_Mbh;$f!v&2qp=U$Am~c&STzZ<|IW(RU$DYT%xFwQf>4mUd2R{w8o(H zv<7{6v?%qSBJEX%s6?wC<+jmGNIiNFQBs0XmEYQDW+bEXyH%fG|M|`5v-UZA?X~w_ z`@0@{&pD@{T2fFgSzH_K`2G4&k>^(}5=XT{QjtiGM51&zvvnZX2K9`;U5G?tfg^`z zeB-^ktF_&c$PC;gUAT!TT0AR&+b)h4^Re6xq!AnaxXY*u>ch1bPeWrJR`G_w(7T}` zk*&g(e6R4Jw6Gpov*mdq>1O_93+`F@aPjmO+&Z~QtZ%_xl(WPgiAa?5eiV}PGeEJz zgECvDbTHos?rjxSe*E3rB2iTz>2g~=eK+AQUvrx?w;nHkUc&vWbwt?n&}dB#Sxz5F zI8az`nWL}`l}|*2`2-1fqjipWzdx7V=6j1RSz${FDZC@jXKg9+s^mypx-7$%+HtTg zU0QfWTGdgRVN3BJY?IrP6u=J|45OsmlCg|*aC!#6yc+AJ$}XLI=XF2&@nAI~ zf5F0k#ZTHzY8(a3<5k9D`;(61QD)zW#$g~_{~|0e4)l&sQB=<;l|d z2_DXzI$OVbH*1KORX_L8C(yUB2Ia3GH3EQ7=XKl?Mdx5X2FcCoWy$r>D&hxn`xG7G zDuBoT>uy5>B&RHXg>d6v&BSPEt z+5DinCG-Yg6V(jQ;+ObvacI}{$>Q^UxH$FH^vL3ebMrzY6nn5vHFrEZmB3AwHMx%O z#O)1L1b-|j>}{;&E{3KJTqP`wKYj=DYAr0J_*QVyAs8}~PXNJ8TRqk`&P?j1XY*GGdcr(nl{#BR>uKl=^ztH3V5IY%a9dhPhP9uZKYOd80RXer2XCF@AH0>#ISzxE2k*b;$5U9W z;xu1)Fs`^VxTq7rXRfN?t32k+IQ&1Mc>=7QqdiO8Q6v0A70udr}H_FESn+k&F%xI1l!!lIXZ+qM{JN zO@cCxTL@(&w-rhScLGW|cO%Lq$VVX^XO6~_`B27j_UH(Z+!Y-WDfnQx+o9!U{X%f& zg=`TC_}A#LJJv;avxH#1^J)dXZL_7eR9TJ;SXmkT$y)bfWyO`kVi#s1IDYJ_gT>Y> zp;Mx}lbPQIg0PYzXK>Lo*wy%zo}T{DGcuh|!BsFSfR({paQ_Rqf5SDHlsYJ%2t8iE z3?lBF(U2cw=G)^gL!}tv19;W}xYrTf>+5UW(U>q=10Br#kJo&~g0NT#7F&b|KNw<5 zJ)UJ<^f9cM_vgZuF>U8V574!^AwMvu01NiN#$_nG1SH}6uxs2LWlzgJ@GSn~RXl*d zEgO`OxnnDx?~CX2`mr6>n#Hel%N5o`7-jJ`Zw=+eW%0A!HKw1miC2rk19ODHdR=G+ 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 diff --git a/spm_slice_vol.mexw64 b/spm_slice_vol.mexw64 index 14db01b188ba708d48032cca464187463788c2a6..d36368a3d95b49712f957ddb3a01679d3c31b07b 100755 GIT binary patch delta 40 tcmZp;!PantZNdu{sb^0kC%*AvuKL2*Y|XgcnvwD5EU@5qi8+if_yKm$5q$sv delta 40 tcmZp;!PantZNdu{73R;O6W{nSuTW!Zwr1RJ&B%Cj7Fck*#2m&K`~XSO4?q9_ diff --git a/spm_sp_reml.m b/spm_sp_reml.m index 6f3f55e3..6f557377 100644 --- a/spm_sp_reml.m +++ b/spm_sp_reml.m @@ -1,4 +1,4 @@ -function [C,h,Ph,F,Fa,Fc] = spm_sp_reml(YY,X,Q,N,hE); +function [C,h,Ph,F,Fa,Fc] = spm_sp_reml(YY,X,Q,N,hE) % ReML estimation of covariance components from y*y' (for sparse patterns) % FORMAT [C,h,Ph,F,Fa,Fc] = spm_sp_reml(YY,X,Q,N); % @@ -18,7 +18,7 @@ % Fc - complexity (F = Fa - Fc) % % Performs a Fisher-Scoring ascent on F to find ReML variance parameter -% estimates,. using uninformative hyperpriors (this is effectively an ARD +% estimates, using uninformative hyperpriors (this is effectively an ARD % scheme). The specification of components differs from spm_reml and % spm_reml_sc. % @@ -31,10 +31,10 @@ % spm_sp_reml: for sparse patterns (c.f., ARD) % %__________________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2006-2017 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_sp_reml.m 5892 2014-02-23 11:00:16Z karl $ +% $Id: spm_sp_reml.m 7192 2017-10-18 14:59:01Z guillaume $ % assume a single sample if not specified %-------------------------------------------------------------------------- @@ -125,7 +125,7 @@ % pre-compute bases %-------------------------------------------------------------------------- -[n s] = size(q); +[n,s] = size(q); qq = cell(s,1); for i = 1:s qq{i} = q(:,i)*q(:,i)'; @@ -217,13 +217,13 @@ Ph(as,as) = Ph(as,as) - dFdhh; if nargout > 3 - % tr(hP*inv(Ph)) - nh + tr(pP*inv(Pp)) - np (pP = 0) + % tr(hP*inv(Ph)) - nh (complexity KL cost of parameters = 0) %---------------------------------------------------------------------- - Ft = trace(hP*inv(Ph)) - length(Ph) - length(Cq); + Ft = trace(hP*inv(Ph)) - length(Ph); % complexity - KL(Ph,hP) %---------------------------------------------------------------------- - Fc = Ft/2 + e'*hP*e/2 + spm_logdet(Ph*inv(hP))/2 - N*spm_logdet(Cq)/2; + Fc = Ft/2 + e'*hP*e/2 + spm_logdet(Ph*inv(hP))/2; % Accuracy - ln p(Y|h) %---------------------------------------------------------------------- diff --git a/spm_spm.m b/spm_spm.m index 35b1e7c8..e6fa27b1 100644 --- a/spm_spm.m +++ b/spm_spm.m @@ -268,10 +268,10 @@ % Copyright (C) 1994-2016 Wellcome Trust Centre for Neuroimaging % Karl Friston & Guillaume Flandin -% $Id: spm_spm.m 6842 2016-07-28 09:02:10Z guillaume $ +% $Id: spm_spm.m 7120 2017-06-20 11:30:30Z spm $ -SVNid = '$Rev: 6842 $'; +SVNid = '$Rev: 7120 $'; %-Say hello %-------------------------------------------------------------------------- @@ -333,11 +333,13 @@ if any(ismember(name,'SurfaceID')) metadata = metadata(ismember(name,'SurfaceID')); metadata = {metadata.name, metadata.value}; + elseif isfield(g,'faces') && ~isempty(g.faces) + metadata = {'SurfaceID', VY(1).fname}; else error('SurfaceID not found in GIfTI''s metadata.'); end if isempty(spm_file(metadata{2},'path')) - metadata{2} = fullfile(spm_file(VY(1).fname,'path'),metadata{2}); + metadata{2} = fullfile(spm_file(VY(1).fname,'path'),metadata{2}); end SPM.xVol.G = metadata{2}; else diff --git a/spm_standalone.m b/spm_standalone.m index f06e8dec..7f3ca9e4 100644 --- a/spm_standalone.m +++ b/spm_standalone.m @@ -1,46 +1,114 @@ function spm_standalone(varargin) -% A function to be compiled, which will run a standalone SPM. +% Gateway function for standalone SPM % -% See MATLAB Compiler: http://www.mathworks.com/products/compiler/ -% See also config/spm_make_standalone.m +% References: +% +% SPM Standalone: https://en.wikibooks.org/wiki/SPM/Standalone +% MATLAB Compiler: http://www.mathworks.com/products/compiler/ +% +% See also: config/spm_make_standalone.m %__________________________________________________________________________ -% Copyright (C) 2010-2016 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2010-2017 Wellcome Trust Centre for Neuroimaging % Guillaume Flandin -% $Id: spm_standalone.m 6862 2016-08-25 14:42:19Z guillaume $ +% $Id: spm_standalone.m 7035 2017-03-14 12:21:54Z guillaume $ -[v,r] = spm('Ver'); -fprintf('%s (%s): %s\n',v,r,spm('Dir')); if ~nargin, action = ''; else action = varargin{1}; end +if strcmpi(action,'run') + warning('"Run" is deprecated: use "Batch".'); + action = 'batch'; +end + exit_code = 0; switch lower(action) - case {'batch', 'run'} + case {'','pet','fmri','eeg','quit'} %---------------------------------------------------------------------- - spm('asciiwelcome'); - %spm('defaults','fmri'); + spm(varargin{:}); + + case {'-h','--help'} + %---------------------------------------------------------------------- + cmd = lower(spm('Ver')); + fprintf([... + '%s - Statistical Parametric Mapping\n',... + 'http://www.fil.ion.ucl.ac.uk/spm/\n',... + '\n'],... + upper(cmd)); + fprintf([... + 'Usage: %s [ fmri | eeg | pet ]\n',... + ' %s COMMAND [arg...]\n',... + ' %s [ -h | --help | -v | --version ]\n',... + '\n',... + 'Commands:\n',... + ' batch Run a batch job\n',... + ' script Execute a script\n',... + ' function Execute a function\n',... + ' eval Evaluate a MATLAB expression\n',... + ' [NODE] Run a specified batch node\n',... + '\n',... + 'Options:\n',... + ' -h, --help Print usage statement\n',... + ' -v, --version Print version information\n',... + '\n',... + 'Run ''%s [NODE] help'' for more information on a command.\n'],... + cmd, cmd, cmd, cmd); + + case {'-v','--version'} + %---------------------------------------------------------------------- + spm_banner; + + case 'batch' + %---------------------------------------------------------------------- + inputs = varargin(2:end); + flg = ismember(inputs,'--silent'); + if any(flg) + quiet = true; + inputs = inputs(~flg); + else + quiet = false; + end + flg = ismember(inputs,'--modality'); + if any(flg) + idx = find(flg); + try + modality = inputs{idx+1}; + catch + error('Syntax is: --modality .'); + end + inputs([idx idx+1]) = []; + else + modality = 'fmri'; + end + flg = ismember(inputs,'--cmdline'); + if any(flg) + cmdline = true; + inputs = inputs(~flg); + else + cmdline = false; + end + spm_banner(~quiet); + spm('defaults',modality); + spm_get_defaults('cmdline',cmdline); spm_jobman('initcfg'); - if nargin == 1 + if isempty(inputs) h = spm_jobman; waitfor(h,'Visible','off'); else - %spm_get_defaults('cmdline',true); - for i=2:nargin - try - spm_jobman('run',varargin{i}); - catch - fprintf('Execution failed: %s', varargin{i}); - end + try + spm_jobman('run', inputs{:}); + catch + fprintf('Execution failed: %s\n', inputs{1}); + exit_code = 1; end end spm('Quit'); case 'script' %---------------------------------------------------------------------- - spm('asciiwelcome'); + spm_banner; assignin('base','inputs',varargin(3:end)); try if nargin > 1 @@ -54,7 +122,7 @@ function spm_standalone(varargin) case 'function' %---------------------------------------------------------------------- - spm('asciiwelcome'); + spm_banner; if nargin == 1 fcn = spm_input('function name','!+1','s',''); else @@ -66,9 +134,30 @@ function spm_standalone(varargin) exit_code = 1; end - otherwise + case 'eval' %---------------------------------------------------------------------- - spm(varargin{:}); + spm_banner; + if nargin == 1 + expr = spm_input('expression to evaluate','!+1','s',''); + else + expr = varargin{2}; + end + try + eval(expr); + catch + exit_code = 1; + end + + otherwise % cli + %---------------------------------------------------------------------- + %spm('defaults','fmri'); + %spm_get_defaults('cmdline',true); + spm_jobman('initcfg'); + try + spm_cli(varargin{:}); + catch + exit_code = 1; + end end @@ -91,3 +180,15 @@ function spm_standalone(varargin) exit(exit_code); end + + +%========================================================================== +function spm_banner(verbose) +% Display text banner +if nargin && ~verbose, return; end +[vspm,rspm] = spm('Ver'); +tlkt = ver(spm_check_version); +if isdeployed, mcr = ' (standalone)'; else mcr = ''; end +fprintf('%s, version %s%s\n',vspm,rspm,mcr); +fprintf('%s, version %s\n',tlkt.Name,version); +spm('asciiwelcome'); diff --git a/spm_tests.m b/spm_tests.m index 8693c596..6b60f568 100644 --- a/spm_tests.m +++ b/spm_tests.m @@ -2,33 +2,34 @@ % Unit Testing Framework % FORMAT results = spm_tests(name,value,...) % name,value - pairs of optional parameter names and values: -% verbose: verbosity level of test run progress report [default: 2] -% display: display test results [default: false] -% coverage: display code coverage [default: false] -% tag: test tag selector [default: '', ie all tests] -% tap: save a Test Anything Protocol (TAP) file [default: false] -% test: name of function to test [default: '', ie all tests] +% verbose: verbosity level of test run progress report [default: 2] +% display: display test results [default: false] +% coverage: display code coverage [default: false] +% cobertura: save code coverage results in the Cobertura XML format [default: false] +% tag: test tag selector [default: '', ie all tests] +% tap: save a Test Anything Protocol (TAP) file [default: false] +% test: name of function to test [default: '', ie all tests] % % results - TestResult array containing information describing the % result of running the test suite. %__________________________________________________________________________ -% Copyright (C) 2015-2016 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2015-2017 Wellcome Trust Centre for Neuroimaging % Guillaume Flandin -% $Id: spm_tests.m 6876 2016-09-15 10:27:19Z guillaume $ +% $Id: spm_tests.m 7109 2017-06-15 11:15:23Z guillaume $ if spm_check_version('matlab','8.3') < 0 error('Unit Tests require MATLAB R2014a or above.'); end -SVNid = '$Rev: 6876 $'; +SVNid = '$Rev: 7109 $'; SPMid = spm('FnBanner',mfilename,SVNid); %-Input parameters %-------------------------------------------------------------------------- options = struct('verbose',2, 'display',false, 'coverage',false, ... - 'tag', '', 'tap',false, 'test',''); + 'cobertura',false, 'tag', '', 'tap',false, 'test',''); if nargin if isstruct(varargin{1}) fn = fieldnames(varargin{1}); @@ -66,7 +67,12 @@ 'No tests found for %s',options.test{i}); continue end - suite = [suite TestSuite.fromFile(mtest)]; + suite = [suite, TestSuite.fromFile(mtest)]; + % if i==1 + % suite = TestSuite.fromFile(mtest); + % else + % suite(i) = TestSuite.fromFile(mtest); + % end end end if ~isempty(options.tag) @@ -88,6 +94,15 @@ runner.addPlugin(plugin); end +if options.cobertura + d = getenv('WORKSPACE'); + if isempty(d), d = spm('Dir'); end + coberturaFile = fullfile(d,'spm_CoverageResults.xml'); + plugin = CodeCoveragePlugin.forFolder(spm('Dir'),... + 'Producing',codecoverage.CoberturaFormat(coberturaFile)); + runner.addPlugin(plugin); +end + if options.tap d = getenv('WORKSPACE'); if isempty(d), d = spm('Dir'); end diff --git a/spm_unlink.mexmaci64 b/spm_unlink.mexmaci64 index 6a4ad102e0bf9076689b2726de8ac4bc3e498061..e5793bb81662f8ecdc794692c1d78ac5ff0f7b11 100755 GIT binary patch literal 8768 zcmeHNO>7%Q6rN3+<_Ck_DpHHmiVY%FAd#C$RHRjlyupcV;Z`Yef20xyCt1f9{z>+y zI2DITZKN8MDu^?e9=Ic+9*{th0yHN`f5ZjU1Aj^dh;VCrV0qu}th07x#Ic8Y%ItgJ z%zNL?yctWgGx_fEpZ~NmrtD&jwNr^uQCk^XA`N+#N?!|OoTo=Gq}{6e2Lgg3FmW=X zVS7Xy=aycvwjCS!wx0IdeiAOgySLo|7K4y;)3T?`T2&+8ooBqJ7la3}QuC&<3cl_B zfsg0(!kli9UnAc`!Iu&oz?7D4+0nmg(=zge&h7Y}<4!=l~CK4Bd(PT+i{Wktyn4ZDap71mB&C?CRit%R5*`oX)WO8 zua71g>jb=hUpX%oxVccADi`>iWi;jU>9Amf{la|ubBbPYUda3xUqlcM!kGj($cO&n zci{`hnV`aXDtY?#(RkATO{l^{@G*g7VqoA2uD|CQTXf$^e&BB>eSowts>)c7z%|lX zBcMV1L&6=TS9^$n^ix#EsRRYSD0pWxxkm9~N!Ph_6T*A;e6m!&QGMn1^-s0$|M=*0 zhToApw2n^3Iy>1*J|+zbQNef+i+B4HGv+c@?nog&Rjfp37D#(7|HEGo2JG~&5Rt-; z*row?lbF|;-jZX563Zu#Dzt^)paBg1 zFuL?h`1*%rrj}10qv~ul{M=P{Xs13HxSy*2wRwZk)m7_l*zc2_tbPsiV=_m=H&cDi zl}D=GlU$CsI$4rh{5On+Zzi0CvrZ1y--wx}80aMF-}l2i;Ge2Gn^u_oZd$SSFqP+4}NnTC$}HgkFa`S-GOx!);cWo^1+v|&cphQtaQ1o7Bi&&!Xv>&gnzr)g5*x_U;fbNo+j&Eu z$;{<1>4u5=pCY1!0|oJ!27J-OwZ7nxi~MW&od%4Kp%H_?OL2!CxO;-6lr**oXaK z=9}-E`F=C^n>m<2`@_xax7rzttY?gMAax>L+`!l@G|9b4ed`$GJexY66|P_w51LHc zz+`}7ZL*qk*O+pfZCB!*rj8-M`HGPpm1Uu#>~yQixiekKTV?LJ)%?Kf@#VYx*1Kd7 z*^w524vE(s->Bo-C39T1SvkJ55^qq}D_cQ=qJUt07#J@aQuZ>) zs^42RPnOIAFPUT3f8Y(r{75xLWC!?L2KEb_8$~{5=PHJ>gY$b);vJW9WYZc^vWci$~^gaYAB;7P?Ier z9+UQz1S6c*^?V=ftw`tIFaI$#b3r?5j=!nC&CuWMWb8v|%r_fGBB6CfiTbDiIE`g3X&_!Mb`5Te*T^ z^NE~W+*2;)D^m$9h*DnF-*%i447}~QoEzwHRa}&QZ9Cgjb!-|RCC4p{?%thvxHWK9 zoM0;wh#Mar`1!yU2OJk{H)aM-={V{ zqo2^9)t~$JN~ZR6YT)|PzDBzC%R&Ry>DrZa?dyeisaPM{>YX0c+yhie2RqV}(7N|! zX6B2I)ZRbck22@B?IJ&i|IB>#<8*!ht0*q)N49irEVkne3IsOn!5Cu9&%YwHtLge- z(ZgR$?;tLLb_=vITs-DMdOyKN(d+$GxiPSqL5W!03!TQ#TAaJ(d9=4> zsC)>{#qTkiMsbVpd5}Dx3D0idqmkzW;o0kZddTyZ@Er3!TgWpjJQ?3}6Kc^R4+>(J zw@qq|91snO_SH&ge@7`2_dQgmGt6e>TLl7RbDb zw|6v9^9X#@-%tNw1dz+rh(v^S#m}yb(oA%=MQH@**GK8_G1K(hwK1|JLH(N1g34!^WR|rS20RZBB4FCWD delta 32 lcmZoLX)u}ag5}uXPoWdv_%MlgZMI^}5(4u#uMm!40|5MT4xa!3 diff --git a/spm_unlink.mexw64 b/spm_unlink.mexw64 index d1679beb7c6fee459aa0f37d47de942a8e75cb7d..d60de1b852c69382320f0ef33cdcc5387a1d274d 100755 GIT binary patch delta 33 mcmZp$X|S2_fJOb;)5wWWe3%cjFm5(xWE2JqY_ is available for download % msg - string describing outcome, that would otherwise be displayed. %__________________________________________________________________________ -% Copyright (C) 2010-2016 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2010-2017 Wellcome Trust Centre for Neuroimaging % Guillaume Flandin -% $Id: spm_update.m 6905 2016-10-20 15:00:48Z guillaume $ +% $Id: spm_update.m 7218 2017-11-16 10:03:14Z guillaume $ vspm = spm('Ver'); @@ -63,7 +63,7 @@ error('SPM cannot be found in MATLAB path.'); end if ~strcmp(v,vspm), error('Your SPM version is %s and not %s',v,vspm); end -rs = [6225 6470 6685 6906]; +rs = [6225 6470 6685 6906 7219]; if isnan(r), r = rs(1); end if floor(r) == str2double(vspm(4:end)) try diff --git a/spm_voronoi.mexmaci64 b/spm_voronoi.mexmaci64 index 956b0c5b9d175f1c22da2d2e0db637b0c8f753e6..e0802e33e222dffac05c7c4128eedf3d9f254523 100755 GIT binary patch literal 13980 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 TIpB@$4LEaOGq)(mb4L1Kdc@O_ literal 14016 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 Z8F?U5Tb_i}vX4Of>{DlhzXhdf{|inuj647U diff --git a/spm_voronoi.mexw32 b/spm_voronoi.mexw32 index 49b58a04584d49020e377b7d767811ba27500589..67e97f3588298b2a499a20e057d634352ef505d7 100755 GIT binary patch delta 33 mcmZojX-Jvyf@P!hv&e~We3(t77&lup{*(a=Y_^a)Aq)WUrww8N delta 33 mcmZojX-Jvyg5~z#PoWdv_%JWJ#<1C%@uv(}V6%nX31I*zz7Vqj diff --git a/spm_voronoi.mexw64 b/spm_voronoi.mexw64 index 65c73ced1376e9c19634c81664b58357de6b1d0e..3204f992d19970b568d89bd102261717c731f037 100755 GIT binary patch delta 32 lcmZoDXegNQfkpq>)5wWme3+!XHajsMQULQeb13}~1pxF<4hR4M delta 32 lcmZoDXegNQfrV*bOz6ZfK1^#rY<6NiqyXk`=1}?}3IOc-4SfIr diff --git a/spm_wft.m b/spm_wft.m index eeb84c94..332facab 100644 --- a/spm_wft.m +++ b/spm_wft.m @@ -4,31 +4,26 @@ % s - (t X n) time-series % k - Frequencies (cycles per window) % n - window length -% C - coefficents (complex) +% C - (w X t X n) coefficents (complex) %__________________________________________________________________________ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_wft.m 5219 2013-01-29 17:07:07Z spm $ - - -% transpose so that time runs down columns -%-------------------------------------------------------------------------- -if size(s,1) < size(s,2); s = s'; end +% $Id: spm_wft.m 6977 2016-12-24 17:48:44Z karl $ % window function (Hanning) %-------------------------------------------------------------------------- -[N,M] = size(s); +[T,N] = size(s); h = 0.5*(1 - cos(2*pi*(1:n)/(n + 1))); h = h'/sum(h); -C = zeros(length(k),N,M); +C = zeros(length(k),T,N); % spectral density %-------------------------------------------------------------------------- for i = 1:length(k) - W = exp(-1j*(2*pi*k(i)*(0:(N - 1))/n))'; - for j = 1:M + W = exp(-1j*(2*pi*k(i)*(0:(T - 1))/n))'; + for j = 1:N w = conv(full(s(:,j)).*W,h); - C(i,:,j) = w((1:N) + n/2); + C(i,:,j) = w((1:T) + n/2); end end diff --git a/src/shoot_diffeo3d.c b/src/shoot_diffeo3d.c index 0ed1ff48..8d38a951 100644 --- a/src/shoot_diffeo3d.c +++ b/src/shoot_diffeo3d.c @@ -1,4 +1,4 @@ -/* $Id: shoot_diffeo3d.c 6137 2014-08-19 12:43:11Z john $ */ +/* $Id: shoot_diffeo3d.c 6945 2016-11-22 10:29:18Z john $ */ /* (c) John Ashburner (2011) */ #include @@ -633,7 +633,7 @@ void push(mwSize dm[], mwSize m, mwSize n, float def[], float pf[], float po[], { double x, y, z; - if (mxIsFinite(pf[i])) + if (mxIsFinite(pf[i]) && mxIsFinite(px[i]) && mxIsFinite(py[i]) && mxIsFinite(pz[i])) { x = px[i]-1.0; /* Subtract 1 because of MATLAB indexing */ y = py[i]-1.0; @@ -826,7 +826,7 @@ void pushc(mwSize dm[], mwSize m, mwSize n, float def[], float pf[], float po[], { double x, y, z; - if (mxIsFinite(pf[i])) + if (mxIsFinite(pf[i]) && mxIsFinite(px[i]) && mxIsFinite(py[i]) && mxIsFinite(pz[i])) { mwSize o000, o100, o010, o110, o001, o101, o011, o111; float w000, w100, w010, w110, w001, w101, w011, w111; @@ -949,7 +949,7 @@ void pushc_grads(mwSize dmo[], mwSize dm[], float def[], float J[], float pf[], for(i0=0; i0 @@ -14,9 +14,10 @@ static void choldc(int n, double a[], double p[]) int i, j, k; double sm, sm0; - sm0 = 1e-16; + sm0 = 1e-40; for(i=0; i @@ -521,9 +521,9 @@ void relax_le(mwSize dm[], float a[], float b[], double s[], int nit, float u[]) wz001 = -2*mu-lam; w2 = 0.25*mu+0.25*lam; - wx000 = wx000*1.00001 + 1e-6; +/* wx000 = wx000*1.00001 + 1e-6; wy000 = wy000*1.00001 + 1e-6; - wz000 = wz000*1.00001 + 1e-6; + wz000 = wz000*1.00001 + 1e-6; */ if (dm[0]==1) { @@ -1333,9 +1333,9 @@ void relax_all(mwSize dm[], float a[], float b[], double s[], int nit, float u[] wz001 = -2*mu-lam + w001/v2; w2 = 0.25*mu+0.25*lam; - wx000 = wx000*1.00001 + 1e-6; +/* wx000 = wx000*1.00001 + 1e-6; wy000 = wy000*1.00001 + 1e-6; - wz000 = wz000*1.00001 + 1e-6; + wz000 = wz000*1.00001 + 1e-6; */ if (dm[0]<=2) { diff --git a/src/spm_field.c b/src/spm_field.c index d6231d91..b3c4a9e9 100644 --- a/src/spm_field.c +++ b/src/spm_field.c @@ -1,4 +1,4 @@ -/* $Id: spm_field.c 6772 2016-04-19 10:21:41Z john $ */ +/* $Id: spm_field.c 7130 2017-07-04 17:43:49Z john $ */ /* (c) John Ashburner (2007) */ #include "mex.h" @@ -74,7 +74,9 @@ static void fmg_mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray * t[0] = param[0]*param[0]; t[1] = param[1]*param[1]; t[2] = param[2]*param[2]; - param[3]+= (param[5]*(6*(t[0]*t[0]+t[1]*t[1]+t[2]*t[2]) + 8*(t[0]*t[1]+t[0]*t[2]+t[1]*t[2]))+param[4]*2*(t[0]+t[1]+t[2]))*1.2e-7; + + param[3]+= (param[5]*(6*(t[0]*t[0]+t[1]*t[1]+t[2]*t[2]) + 8*(t[0]*t[1]+t[0]*t[2]+t[1]*t[2]))+param[4]*2*(t[0]+t[1]+t[2]))*4e-7; + if (nrhs==4) { diff --git a/src/spm_jsonread.c b/src/spm_jsonread.c index a1caf211..901fe9b7 100644 --- a/src/spm_jsonread.c +++ b/src/spm_jsonread.c @@ -1,5 +1,5 @@ /* - * $Id: spm_jsonread.c 6891 2016-09-29 13:38:25Z guillaume $ + * $Id: spm_jsonread.c 7190 2017-10-17 11:22:43Z spm $ * Guillaume Flandin */ @@ -31,6 +31,17 @@ mxArray *mexCallMATLABWithTrap(int nlhs, mxArray *plhs[], int nrhs, mxArray *prh #endif */ +#if defined(_WIN32) || defined(_WIN64) + #define strcasecmp _stricmp +#endif + +static enum jsonrepsty { + JSON_REPLACEMENT_STYLE_NOP, + JSON_REPLACEMENT_STYLE_UNDERSCORE, + JSON_REPLACEMENT_STYLE_HEX, + JSON_REPLACEMENT_STYLE_DELETE +} ReplacementStyle; + static int should_convert_to_array(const mxArray *pm) { size_t i, j, n, nfields; mxClassID cat; @@ -66,7 +77,11 @@ static int should_convert_to_array(const mxArray *pm) { d = (mwSize *)mxGetDimensions(mxGetCell(pm, i)); for (j = 0; j < ndims; j++) { if (dim[j] != d[j]) { - return 0; + if ( !( (cat == mxDOUBLE_CLASS) + && (mxGetNumberOfElements(mxGetCell(pm, i)) <= 1) + && (mxGetNumberOfElements(mxGetCell(pm, 0)) <= 1) ) ) { + return 0; + } } } if (cat == mxSTRUCT_CLASS) { @@ -75,12 +90,20 @@ static int should_convert_to_array(const mxArray *pm) { return 0; } for (j = 0; j < nfields; j++) { - if (mxGetFieldNumber(mxGetCell(pm, 0), mxGetFieldNameByNumber(mxGetCell(pm, i), j)) == -1) { + if (mxGetFieldNumber(mxGetCell(pm, 0), mxGetFieldNameByNumber(mxGetCell(pm, i), j)) != j) { return 0; } } } } + if (cat == mxDOUBLE_CLASS) { + for (i = 0; i < n; i++) { + if (mxGetNumberOfElements(mxGetCell(pm, i)) == 0) { + mxDestroyArray(mxGetCell(pm, i)); + mxSetCell((mxArray *)pm, i, mxCreateDoubleScalar(mxGetNaN())); + } + } + } return 1; } @@ -123,27 +146,164 @@ static int setup_for_cell2mat(mxArray *pm) { static int create_struct(char *js, jsmntok_t *tok, mxArray **mx); static char * get_string(char *js, int start, int end) { - js[end] = '\0'; + int i, j; + for (i = start, j = start; j < end; i++, j++) { + if (js[j] == '\\') { + switch (js[j+1]) { + case '"': + case '\\': + case '/': + js[i] = js[++j]; + break; + case 'b': + js[i] = '\b'; j++; + break; + case 'f': + js[i] = '\f'; j++; + break; + case 'n': + js[i] = '\n'; j++; + break; + case 'r': + js[i] = '\r'; j++; + break; + case 't': + js[i] = '\t'; j++; + break; + case 'u': + /* four-hex-digits */ + js[i] = 'X'; j+=5; + break; + default: + mexPrintf("Unexpected backslash escape."); + } + } + else { + if (i != j) js[i] = js[j]; + } + } + js[i] = '\0'; + js[end] = '\0'; /* not necessary sensu stricto */ return js + start; } -static void valid_fieldname(char **field) { - char *f = *field; - while (f[0] != '\0') { - if ( ((f[0] >= '0') && (f[0] <= '9')) - || ((f[0] >= 'a') && (f[0] <= 'z')) - || ((f[0] >= 'A') && (f[0] <= 'Z'))) { +static char * valid_fieldname_underscore(char *field) { + /* matlab.lang.makeValidName + with ReplacementStyle == 'underscore' and Prefix == 'x' */ + char *re = field, *wr = field; + int beg = 1; + while (re[0] != '\0') { + if ((re[0] == 32) || (re[0] == 9)) { /* ' ' or \t */ + if (re[1] == '\0') { + break; + } + else if ((beg != 1) && (re[1] >= 'a') && (re[1] <= 'z')) { + re[1] -= 32; /* 'a'-'A' */ + } + re++; + } + else { + if ( ((re[0] >= '0') && (re[0] <= '9')) + || ((re[0] >= 'a') && (re[0] <= 'z')) + || ((re[0] >= 'A') && (re[0] <= 'Z'))) { + if (re != wr) { wr[0] = re[0]; } + wr++; + } + else { + if (ReplacementStyle == JSON_REPLACEMENT_STYLE_UNDERSCORE) { + wr[0] = '_'; wr++; + } + } + re++; + beg = 0; + } + } + wr[0] = '\0'; + if ( (field[0] == '\0') || (field[0] == '_') + || ((field[0] >= '0') && (field[0] <= '9')) ) { + field = field - 1; + field[0] = 'x'; + } + return field; +} + +static char * valid_fieldname_hex(char *field) { + /* matlab.lang.makeValidName + with ReplacementStyle == 'hex' and Prefix == 'x' */ + char *re = field, *wr = NULL, *ret = NULL, *str = NULL; + int sts, beg = 1; + size_t len = 4*strlen(field)+2; /* 'x' + all '0x??' + \0 */ + mxArray *mx = NULL, *ma = NULL; + ret = (char *)malloc(len); + wr = ret; + if (! (((re[0] >= 'a') && (re[0] <= 'z')) + || ((re[0] >= 'A') && (re[0] <= 'Z'))) ) { + wr[0] = 'x'; wr++; + } + while (re[0] != '\0') { + if ((re[0] == 32) || (re[0] == 9)) { /* ' ' or \t */ + if (re[1] == '\0') { + break; + } + else if ((beg != 1) && (re[1] >= 'a') && (re[1] <= 'z')) { + re[1] -= 32; /* 'a'-'A' */ + } + re++; } else { - f[0] = '_'; + if ( ((re[0] >= 'a') && (re[0] <= 'z')) + || ((re[0] >= 'A') && (re[0] <= 'Z')) + || ((((re[0] >= '0') && (re[0] <= '9')) + || (re[0] == '_')) && !beg) ) { + wr[0] = re[0]; wr++; + } + else { + /* could also use sprintf(wr,"%02X",re[0]) + but might call unicode2native in the future */ + wr[0] = '0'; wr++; + wr[0] = 'x'; wr++; + wr[0] = re[0]; + wr[1] = '\0'; + ma = mxCreateString((const char *)wr); + sts = mexCallMATLAB(1, &mx, 1, &ma, "dec2hex"); + if (sts != 0) { + mexErrMsgTxt("Cannot convert to hexadecimal representation."); + } + mxDestroyArray(ma); + str = mxArrayToString(mx); + mxDestroyArray(mx); + wr[0] = str[0]; wr++; + wr[0] = str[1]; wr++; + mxFree(str); + } + re++; + beg = 0; } - f++; } - if ( (*field[0] == '_') - || ((*field[0] >= '0') && (*field[0] <= '9')) ) { - *field = *field - 1; - *field[0] = 'x'; + wr[0] = '\0'; + return ret; +} + +static char * valid_fieldname(char *field, int *need_free) { + switch (ReplacementStyle) { + case JSON_REPLACEMENT_STYLE_NOP: + /* nop */ + *need_free = 0; + break; + case JSON_REPLACEMENT_STYLE_UNDERSCORE: + case JSON_REPLACEMENT_STYLE_DELETE: + field = valid_fieldname_underscore(field); + *need_free = 0; + break; + case JSON_REPLACEMENT_STYLE_HEX: + field = valid_fieldname_hex(field); + *need_free = 1; + break; + default: + mexErrMsgTxt("Unknown ReplacementStyle."); + break; } + return field; } static int primitive(char *js, jsmntok_t *tok, mxArray **mx) { @@ -220,7 +380,7 @@ static int array(char *js, jsmntok_t *tok, mxArray **mx) { } static int object(char *js, jsmntok_t *tok, mxArray **mx) { - int i, j, k; + int i, j, k, need_free = 0; mxArray *ma = NULL; char *field = NULL; if (tok->size == 0) { @@ -229,7 +389,7 @@ static int object(char *js, jsmntok_t *tok, mxArray **mx) { } for (i = 0, j = 0, k = 0; i < tok->size; i++) { field = get_string(js, (tok+1+j)->start, (tok+1+j)->end); /* check it is a JSMN_STRING */ - valid_fieldname(&field); + field = valid_fieldname(field, &need_free); j++; if (i == 0) { *mx = mxCreateStructMatrix(1, 1, 1, (const char**)&field); @@ -246,6 +406,7 @@ static int object(char *js, jsmntok_t *tok, mxArray **mx) { if (k == -1) mexErrMsgTxt("mxAddField()"); } + if (need_free) { free(field); } j += create_struct(js, tok+1+j, &ma); mxSetFieldByNumber(*mx, 0, k, ma); } @@ -341,19 +502,57 @@ static char * get_data(const mxArray * mx, size_t * jslen) { void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { char *js = NULL; - size_t jslen = 0; + const char *field = NULL; + size_t i, jslen = 0, nfields; jsmntok_t *tok = NULL; + mxArray *mx = NULL; + char *repsty = NULL; /* Validate input arguments */ if (nrhs == 0) { mexErrMsgTxt("Not enough input arguments."); } - else if (nrhs > 1) { + else if (nrhs > 2) { mexErrMsgTxt("Too many input arguments."); } if (!mxIsChar(prhs[0])) { mexErrMsgTxt("Input must be a string."); } + ReplacementStyle = JSON_REPLACEMENT_STYLE_UNDERSCORE; + if (nrhs > 1) { + if (!mxIsStruct(prhs[1])){ + mexErrMsgTxt("Input must be a struct."); + } + nfields = mxGetNumberOfFields(prhs[1]); + for (i = 0; i < nfields; i++) { + field = mxGetFieldNameByNumber(prhs[1], i); + if (!strcasecmp(field,"replacementStyle")) { + mx = mxGetFieldByNumber(prhs[1],0,i); + if (mx != NULL) { + repsty = mxArrayToString(mx); + if (!strcasecmp(repsty,"nop")) { + ReplacementStyle = JSON_REPLACEMENT_STYLE_NOP; + } + else if (!strcasecmp(repsty,"underscore")) { + ReplacementStyle = JSON_REPLACEMENT_STYLE_UNDERSCORE; + } + else if (!strcasecmp(repsty,"hex")) { + ReplacementStyle = JSON_REPLACEMENT_STYLE_HEX; + } + else if (!strcasecmp(repsty,"delete")) { + ReplacementStyle = JSON_REPLACEMENT_STYLE_DELETE; + } + else { + mexErrMsgTxt("Unknown replacementStyle."); + } + mxFree(repsty); + } + } + else { + mexErrMsgTxt("Unknown optional parameter."); + } + } + } /* Get JSON data as char array */ js = get_data(prhs[0], &jslen); diff --git a/src/spm_mrf.c b/src/spm_mrf.c index 21825641..83226fef 100644 --- a/src/spm_mrf.c +++ b/src/spm_mrf.c @@ -1,4 +1,4 @@ -/* $Id: spm_mrf.c 4873 2012-08-30 19:06:26Z john $ */ +/* $Id: spm_mrf.c 7172 2017-09-21 16:31:30Z john $ */ /* (c) John Ashburner (2010) */ #include "mex.h" @@ -42,7 +42,7 @@ static void mrf1(mwSize dm[], unsigned char q[], float p[], float G[], float w[] for(i0=i0start; i0 Right */ { - float se; + float se, mx; unsigned char *qq = NULL; /* Pointers to current voxel in first volume */ @@ -101,41 +101,31 @@ static void mrf1(mwSize dm[], unsigned char q[], float p[], float G[], float w[] /* Weights are in the form of a matrix, shared among all voxels. */ float *g; - se = 0.0; for(k=0, g=G; kmx) mx = e[k]; + + se = 0.0; + for(k=0; kR2 +b_reduced = BMA.Cp(:,2); +expected = logical([0 0 0 0 1 0]); +testCase.assertTrue(all(b_reduced(~expected) < 1e-4)); +testCase.assertTrue(all(b_reduced(expected) > 1e-4)); + +% ------------------------------------------------------------------------- +function data_path = get_data_path() + +data_path = fullfile( spm('Dir'), 'tests', ... + 'data', 'fMRI', 'simulated_2region'); \ No newline at end of file diff --git a/tests/test_spm_dcm_loo.m b/tests/test_spm_dcm_loo.m index 1b0adb6d..84350ea8 100644 --- a/tests/test_spm_dcm_loo.m +++ b/tests/test_spm_dcm_loo.m @@ -3,7 +3,7 @@ %__________________________________________________________________________ % Copyright (C) 2016 Wellcome Trust Centre for Neuroimaging -% $Id: test_spm_dcm_loo.m 6771 2016-04-18 14:10:58Z peter $ +% $Id: test_spm_dcm_loo.m 7102 2017-06-08 12:56:06Z peter $ tests = functiontests(localfunctions); @@ -13,8 +13,8 @@ function test_loo_group(testCase) data_path = get_data_path(); -% Subjects to include -s = [11:14 15:18]; +% Reduce number of subjects to increase performance +s = [1:6 24:30]; % Load first level DCMs GCM = load(fullfile(data_path,'models','GCM_simulated.mat')); @@ -41,8 +41,8 @@ function test_loo_group_null(testCase) data_path = get_data_path(); -% Subjects to include -s = [11:14 15:18]; +% Reduce number of subjects to increase performance +s = [1:6 24:30]; % Load first level DCMs GCM = load(fullfile(data_path,'models','GCM_simulated.mat')); @@ -69,8 +69,8 @@ function test_loo_continuous_null(testCase) data_path = get_data_path(); -% Subjects to include -s = [11:14 15:18]; +% Reduce number of subjects to increase performance +s = [1:6 24:30]; % Load first level DCMs GCM = load(fullfile(data_path,'models','GCM_simulated.mat')); diff --git a/tests/test_spm_dcm_peb.m b/tests/test_spm_dcm_peb.m new file mode 100644 index 00000000..40b6257a --- /dev/null +++ b/tests/test_spm_dcm_peb.m @@ -0,0 +1,97 @@ +function tests = test_spm_dcm_peb +% Unit Tests for test_spm_dcm_peb +%__________________________________________________________________________ +% Copyright (C) 2016 Wellcome Trust Centre for Neuroimaging + +% $Id: test_spm_dcm_peb.m 7050 2017-03-29 15:44:54Z peter $ + +tests = functiontests(localfunctions); + +% ------------------------------------------------------------------------- +function test_peb(testCase) + +data_path = get_data_path(); + +% Load first level DCMs +GCM = load(fullfile(data_path,'models','GCM_simulated.mat')); +GCM = GCM.GCM; +nm = size(GCM,2); + +% Prepare group level design matrix +X = load(fullfile(data_path,'design_matrix.mat')); +X = X.X; + +ns = size(X,1); +X = [ones(ns,1) X]; +nx = size(X,2); + +% Number of free DCM parameters expected in full model +np = 6; + +% Estimate PEB +PEB = spm_dcm_peb(GCM, X); + +% Check output sizes +testCase.assertEqual(size(PEB,2), nm); +testCase.assertEqual(size(PEB(1).Xnames,2), nx); +testCase.assertEqual(size(PEB(1).Ep,2), nx); +testCase.assertEqual(size(PEB(1).Ep,1), np); +testCase.assertEqual(size(PEB(1).Pnames,1), np); +testCase.assertEqual(size(PEB(1).Pind,1), np); +testCase.assertEqual(size(PEB(1).Ce), [np np]); +testCase.assertEqual(size(PEB(1).Cp), [np*nx np*nx]); + +% % Save test PEB for other tests +% %save(fullfile(data_path,'PEB_test.mat'),'PEB'); +% ------------------------------------------------------------------------- +function test_precision_def(testCase) +% Tests different configurations of precision components + +data_path = get_data_path(); + +% Load first level DCMs +GCM = load(fullfile(data_path,'models','GCM_simulated.mat')); +GCM = GCM.GCM; + +% Get the indices of free parameters +q = spm_find_pC(GCM{1},{'A','B'}); + +% Prepare group level design matrix +X = load(fullfile(data_path,'design_matrix.mat')); +X = X.X; +ns = size(X,1); +X = [ones(ns,1) X]; +M.X = X; + +% Estimate PEB (single precision component) +M.Q = 'single'; +PEB = spm_dcm_peb(GCM(:,1), M); +testCase.assertEqual(length(PEB.Eh), 1); +testCase.assertEqual(length(PEB.Ch), 1); + +% Estimate PEB (one precision component per parameter) +M.Q = 'all'; +PEB = spm_dcm_peb(GCM(:,1), M); +testCase.assertEqual(length(PEB.Eh), length(q)); +testCase.assertEqual(length(PEB.Ch), length(q)); + +% Estimate PEB (one precision component per field) +M.Q = 'fields'; +PEB = spm_dcm_peb(GCM(:,1), M); +testCase.assertEqual(length(PEB.Eh), 2); +testCase.assertEqual(length(PEB.Ch), 2); + +% Estimate PEB (manual precision component definition) +np = size(GCM{1}.M.pC,1); +Q{1} = sparse(q(1:2),q(1:2),[1 1],np,np); +Q{2} = sparse(q(3:6),q(3:6),[1 1 1 1],np,np); +M.Q = Q; +PEB = spm_dcm_peb(GCM(:,1), M); +testCase.assertEqual(length(PEB.Eh), 2); +testCase.assertEqual(length(PEB.Ch), 2); + +% ------------------------------------------------------------------------- +function data_path = get_data_path() + +data_path = fullfile( spm('Dir'), 'tests', ... + 'data', 'fMRI', 'simulated_2region'); \ No newline at end of file diff --git a/tests/test_spm_dcm_peb_bmc_fam.m b/tests/test_spm_dcm_peb_bmc_fam.m new file mode 100644 index 00000000..178b7fbc --- /dev/null +++ b/tests/test_spm_dcm_peb_bmc_fam.m @@ -0,0 +1,66 @@ +function tests = test_spm_dcm_peb_bmc_fam +% Unit Tests for test_spm_dcm_peb_bmc +%__________________________________________________________________________ +% Copyright (C) 2016 Wellcome Trust Centre for Neuroimaging + +% $Id: test_spm_dcm_peb_bmc_fam.m 6946 2016-11-23 15:26:29Z peter $ + +tests = functiontests(localfunctions); + +% ------------------------------------------------------------------------- +function test_peb_bmc(testCase) + +data_path = get_data_path(); + +% Load +GCM = load(fullfile(data_path,'models','GCM_simulated.mat')); +PEB = load(fullfile(data_path,'PEB_test.mat')); +GCM = GCM.GCM; +PEB = PEB.PEB; + +% Model comparison +[BMA,BMR] = spm_dcm_peb_bmc(PEB(1),GCM(1,:)); + +% Family 1: model 1 (full) and model 2 (fwd modulation) +% Family 2: model 3 (bwd) and model 4 (bwd modulation) +families = [1 1 2 2]; + +% Model comparison under families +[BMA,fam] = spm_dcm_peb_bmc_fam(BMA,BMR,families); + +% ------------------------------------------------------------------------- +% Should be equal priors as families were balanced +Nm = size(GCM,2); +testCase.assertEqual([0.5 0.5], fam.family.prior) +testCase.assertTrue(all(fam.model.prior(:) == 1/(Nm*Nm))); + +% Family 1 and model 2 should win +testCase.assertTrue(fam.family.post(1,1) > 0.9); +testCase.assertTrue(fam.model.Pw(2) > 0.9); +testCase.assertTrue(fam.model.Px(2) > 0.9); + +% ------------------------------------------------------------------------- +% Run again with unbalanced families +families = [1 1 1 2]; +[BMA,fam] = spm_dcm_peb_bmc_fam(BMA,BMR,families); + +% Families should have equal priors +testCase.assertEqual([0.5 0.5], fam.family.prior); + +% Model joint prior matrix should sum to 1 +testCase.assertEqual(1, sum(fam.model.prior(:))); + +% Models within each family should have same total prior probability +family_total_prior = []; +for f = 1:2 + p = (fam.model.prior(families == f,families == f)); + family_total_prior(f) = sum(p(:)); +end +testCase.assertTrue(... + all(family_total_prior(:) - family_total_prior(1) < 1e-10)); + +% ------------------------------------------------------------------------- +function data_path = get_data_path() + +data_path = fullfile( spm('Dir'), 'tests', ... + 'data', 'fMRI', 'simulated_2region'); \ No newline at end of file diff --git a/tests/test_spm_dcm_simulate.m b/tests/test_spm_dcm_simulate.m index 0b1a0133..d0480d9b 100644 --- a/tests/test_spm_dcm_simulate.m +++ b/tests/test_spm_dcm_simulate.m @@ -3,7 +3,7 @@ %__________________________________________________________________________ % Copyright (C) 2016 Wellcome Trust Centre for Neuroimaging -% $Id: test_spm_dcm_simulate.m 6865 2016-08-31 16:49:57Z guillaume $ +% $Id: test_spm_dcm_simulate.m 6954 2016-11-28 11:57:12Z peter $ tests = functiontests(localfunctions); @@ -129,6 +129,52 @@ function test_simulate_snr_var(testCase) testCase.assertTrue(p >= 0.05); end +% ------------------------------------------------------------------------- +function test_simulate_Ce(testCase) +% Test simulation based on fixed noise variance +data_path = get_data_path(); + +% Load DCMs +GCM = load(fullfile(data_path,'GCM_simulated.mat')); +GCM = GCM.GCM; + +% Simulate data +noise_var = [1 2]; +gen_idx = 1; + +for i = 1:length(GCM) + GCM{i}.Ce = noise_var'; +end + +rng('default');rng(1); +%st = randn('state'); +%randn('state',100); +[GCM,gen] = spm_dcm_simulate(GCM, 'Ce', noise_var, gen_idx); +%randn('state',st); + +ns = size(GCM,1); + +% Gather actual SNR +actual_var = []; +for s = 1:ns + DCM_gen = gen{s}; + + signal = DCM_gen.y; + noise = DCM_gen.Y.y - signal; + + actual_var(s,:) = var(noise); +end + +nr = size(actual_var,2); % Number of regions + +% Check that there isn't significant evidence that the SNR deviated from +% the expected value (one-sample ttest) +for n = 1:nr + data = actual_var(:,n); + p = one_sample_tt(data,noise_var(n)); + testCase.assertTrue(p >= 0.05); +end + % ------------------------------------------------------------------------- function p = one_sample_tt(data,mu) % One sample t-test diff --git a/tests/test_spm_jsonread.m b/tests/test_spm_jsonread.m index 8dfe6182..bb7df19a 100644 --- a/tests/test_spm_jsonread.m +++ b/tests/test_spm_jsonread.m @@ -1,9 +1,9 @@ function tests = test_spm_jsonread % Unit Tests for spm_jsonread %__________________________________________________________________________ -% Copyright (C) 2015-2016 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2015-2017 Wellcome Trust Centre for Neuroimaging -% $Id: test_spm_jsonread.m 6869 2016-09-12 16:11:01Z guillaume $ +% $Id: test_spm_jsonread.m 7077 2017-05-23 09:13:10Z guillaume $ tests = functiontests(localfunctions); @@ -26,7 +26,13 @@ function test_jsonread_all_types(testCase) % JSON Data Type | MATLAB Data Type -% null | empty double, [] +% null, in numeric arrays | NaN +json = '[1, 2, null, 4]'; +exp = [1; 2; NaN; 4]; +act = spm_jsonread(json); +%testCase.verifyTrue(isequaln(exp, act)); + +% null, in nonnumeric arrays| empty double [] json = '{"null": null}'; exp = struct('null',[]); act = spm_jsonread(json); @@ -63,6 +69,16 @@ function test_jsonread_all_types(testCase) act = spm_jsonread(json); testCase.verifyTrue(isequal(exp, act)); +json = '{"object": {"field 1": 1, "field two": 2, " field Three ": 3}}'; +exp = struct('object',struct('field1',1,'fieldTwo',2,'fieldThree',3)); +act = spm_jsonread(json); +testCase.verifyTrue(isequal(exp, act)); + +json = '{"object": {"": 1}}'; +exp = struct('object',struct('x',1)); +act = spm_jsonread(json); +testCase.verifyTrue(isequal(exp, act)); + % Array, when elements are | cell array % of different data types | json = '{"array": ["a", 1]}'; @@ -104,6 +120,15 @@ function test_jsonread_all_types(testCase) act = spm_jsonread(json); testCase.verifyTrue(isequal(exp, act)); +% Array of objects, when | cell array of +% all objects have the |scalar structures +% same set of names | +% but different order +json = '{"structarray": [{"a":1,"b":2},{"b":3,"a":4}]}'; +exp = struct('structarray',{{struct('a',1,'b',2);struct('b',3,'a',4)}}); +act = spm_jsonread(json); +testCase.verifyTrue(isequal(exp, act)); + % empty struct json = '{"a":"aa","b":{},"c":"cc"}'; exp = struct('a','aa','b',struct(),'c','cc'); diff --git a/tests/test_spm_jsonwrite.m b/tests/test_spm_jsonwrite.m index 3e319d86..0243d01e 100644 --- a/tests/test_spm_jsonwrite.m +++ b/tests/test_spm_jsonwrite.m @@ -1,9 +1,9 @@ function tests = test_spm_jsonwrite % Unit Tests for spm_jsonwrite %__________________________________________________________________________ -% Copyright (C) 2016 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2016-2017 Wellcome Trust Centre for Neuroimaging -% $Id: test_spm_jsonwrite.m 6863 2016-08-30 14:56:27Z guillaume $ +% $Id: test_spm_jsonwrite.m 7108 2017-06-15 10:36:29Z guillaume $ tests = functiontests(localfunctions); @@ -21,13 +21,22 @@ function test_jsonwrite_object(testCase) function test_jsonwrite_all_types(testCase) exp = []; act = spm_jsonread(spm_jsonwrite(exp)); -testCase.verifyTrue(isequal(act, struct('exp',exp))); +testCase.verifyTrue(isequal(exp, act)); exp = [true;false]; act = spm_jsonread(spm_jsonwrite(exp)); -testCase.verifyTrue(isequal(act, struct('exp',exp))); +testCase.verifyTrue(isequal(exp, act)); + +exp = struct('a',''); +act = spm_jsonread(spm_jsonwrite(exp)); +testCase.verifyTrue(isequal(exp, act)); -str = reshape(1:9,3,3); -exp = '{"str":[[1,4,7],[2,5,8],[3,6,9]]}'; -act = spm_jsonwrite(str); +str = struct('str',reshape(1:9,3,3)); +exp = spm_jsonread('{"str":[[1,4,7],[2,5,8],[3,6,9]]}'); +act = spm_jsonread(spm_jsonwrite(str)); testCase.verifyTrue(isequal(act, exp)); + +str = [1,2,NaN,3,Inf]; +exp = spm_jsonread('[1,2,null,3,null]'); +act = spm_jsonread(spm_jsonwrite(str)); +testCase.verifyTrue(isequaln(act, exp)); diff --git a/tests/test_spm_mesh_contour.m b/tests/test_spm_mesh_contour.m new file mode 100644 index 00000000..195ffd57 --- /dev/null +++ b/tests/test_spm_mesh_contour.m @@ -0,0 +1,21 @@ +function tests = test_spm_mesh_contour +% Unit Tests for spm_mesh_contour +%__________________________________________________________________________ +% Copyright (C) 2017 Wellcome Trust Centre for Neuroimaging + +% $Id: test_spm_mesh_contour.m 7183 2017-10-09 15:26:47Z guillaume $ + +tests = functiontests(localfunctions); + + +function test_spm_mesh_contour_(testCase) +M = gifti(fullfile(spm('Dir'),'canonical','cortex_20484.surf.gii')); +S = spm_mesh_contour(M,mean(M.vertices(:,3))); + +% at least two hemispheres +exp = 2; +act = numel(S); +testCase.verifyGreaterThanOrEqual(act, exp); + +% all surfaces are closed +testCase.verifyFalse(any([S.isopen])); diff --git a/tests/test_spm_mesh_normals.m b/tests/test_spm_mesh_normals.m new file mode 100644 index 00000000..fe079682 --- /dev/null +++ b/tests/test_spm_mesh_normals.m @@ -0,0 +1,17 @@ +function tests = test_spm_mesh_normals +% Unit Tests for spm_mesh_normals +%__________________________________________________________________________ +% Copyright (C) 2016 Wellcome Trust Centre for Neuroimaging + +% $Id: test_spm_mesh_normals.m 6955 2016-11-30 11:40:52Z guillaume $ + +tests = functiontests(localfunctions); + + +function test_spm_mesh_normals_1(testCase) +M = spm_mesh_polyhedron('tetrahedron'); + +t = triangulation(M.faces,M.vertices); +exp = -double(t.vertexNormal); +act = spm_mesh_normals(M, true); +testCase.verifyEqual(act, exp ,'AbsTol', 10*eps); diff --git a/tests/test_spm_run_dcm_bms.m b/tests/test_spm_run_dcm_bms.m new file mode 100644 index 00000000..ff49ab32 --- /dev/null +++ b/tests/test_spm_run_dcm_bms.m @@ -0,0 +1,248 @@ +function tests = test_spm_run_dcm_bms +% Unit Tests for config/spm_run_dcm_bms. Tests are provided with and +% without evidence for a particular model with artificially generated free +% energies. Additionally, tests are included using real DCM files for +% software testing. +%__________________________________________________________________________ +% Copyright (C) 2015 Wellcome Trust Centre for Neuroimaging + +% $Id: test_spm_run_dcm_bms.m 7103 2017-06-08 14:39:32Z peter $ + +tests = functiontests(localfunctions); + +function setup(testCase) +% Prepare output directory +out_dir = get_output_dir(); + +% Delete existing files if they exist +if exist(fullfile(out_dir,'BMS.mat'),'file') + delete(fullfile(out_dir,'BMS.mat')); +end +if exist(fullfile(out_dir,'F.mat'),'file') + delete(fullfile(out_dir,'F.mat')); +end + +% ------------------------------------------------------------------------- +function test_ffx_fmri_dcm(testCase) +% Tests that the BMS can run on an fMRI DCM (model 2 should win) + +models_path = fullfile( spm('Dir'), 'tests', ... + 'data', 'fMRI', 'simulated_2region', 'models'); + +% Select DCMs (2 per subject) +P1 = spm_select('FPList',models_path,'DCM_.*_m1\.mat$'); +P2 = spm_select('FPList',models_path,'DCM_.*_m2\.mat$'); +P = [cellstr(P1) cellstr(P2)]; + +% Run FFX BMS +run_bms_dcm_files('FFX', P); + +% Check +load(fullfile(get_output_dir(), 'BMS.mat')); +testCase.assertTrue(BMS.DCM.ffx.model.post(2) > 0.99); +% ------------------------------------------------------------------------- +function test_ffx_csd_dcm(testCase) +% Tests that the BMS can run on a CSD DCM + +models_path = fullfile( spm('Dir'), 'tests', ... + 'data', 'MEEG'); + +% Select DCMs (2 per subject) +P1 = spm_select('FPList',models_path,'DCM_CSD.mat'); +P2 = spm_select('FPList',models_path,'DCM_CSD.mat'); +P = [cellstr(P1) cellstr(P2)]; + +% Run FFX BMS +run_bms_dcm_files('FFX', P); + +% Check +load(fullfile(get_output_dir(), 'BMS.mat')); +testCase.assertTrue(BMS.DCM.ffx.model.post(2) == 0.5); +% ------------------------------------------------------------------------- +function test_rfx_no_evidence(testCase) +% Tests RFX BMS in the context of equal model probabilities + +% Setup +import matlab.unittest.constraints.* +rng('default'); +rng(1); + +n = 20; % Subjects +models = 4; % Models per subject + +% Frequency of each model in the group +r = [0.25 0.25 0.25 0.25]; + +num_subjects_per_model = n .* r; + +% Build subjects x models matrix of model assignments +m = []; +for model = 1:models + row = zeros(1,models); + row(model) = 1; + + m = [m; repmat(row, num_subjects_per_model(model), 1)]; +end + +% Free energy of the generative model in each subject +mean_F = -10; +std_F = 0.5; +F_gen = mean_F + std_F .* randn(sum(m(:) > 0),1); + +% Build free energy matrix (mean -13, STD 1) +F = -13 + randn(n,4); +F(m > 0) = F_gen; +save('output/F.mat','F'); + +% Run +run_bms_Fmatrix('RFX'); + +load('output/BMS.mat'); + +% Check expected frequencies are within 10% +actual = BMS.DCM.rfx.model.exp_r; +testCase.verifyThat(actual, IsEqualTo(r, 'Within', AbsoluteTolerance(0.1) ) ); + +% Test BOR +actual = BMS.DCM.rfx.model.bor; +testCase.verifyThat(actual, IsGreaterThanOrEqualTo(0.9 ) ); + +% ------------------------------------------------------------------------- +function test_rfx_strong_evidence(testCase) +% Tests RFX BMS in the context of an effect + +% Setup +import matlab.unittest.constraints.* +rng('default'); +rng(1); + +n = 20; % Subjects +models = 4; % Models per subject + +% Frequency of each model in the group +r = [0.60 0.20 0.15 0.05]; + +num_subjects_per_model = n .* r; + +% Build subjects x models matrix of model assignments +m = []; +for model = 1:models + row = zeros(1,models); + row(model) = 1; + + m = [m; repmat(row, num_subjects_per_model(model), 1)]; +end + +% Free energy of the generative model in each subject +mean_F = -10; +std_F = 0.5; +F_gen = mean_F + std_F .* randn(sum(m(:) > 0),1); + +% Build free energy matrix (mean -13, STD 1) +F = -13 + randn(n,4); +F(m > 0) = F_gen; +save('output/F.mat','F'); + +% Run +run_bms_Fmatrix('RFX'); + +load('output/BMS.mat'); + +% Check expected frequencies are within 10% +actual = BMS.DCM.rfx.model.exp_r; +testCase.verifyThat(actual, IsEqualTo(r, 'Within', AbsoluteTolerance(0.1) ) ); + +% Test BOR +actual = BMS.DCM.rfx.model.bor; +testCase.verifyThat(actual, IsLessThanOrEqualTo(0.1 ) ); + +% ------------------------------------------------------------------------- +function test_ffx_strong_evidence(testCase) +% Tests FFX in the context of strong evidence + +import matlab.unittest.constraints.* + +% Free energies for model 1 and model 2 +F = [-10.3 -10.3 -10.3 -10.3 -10.3; + -9.7 -9.7 -9.7 -9.7 -9.7]'; +save('output/F.mat','F'); + +% Run +run_bms_Fmatrix('FFX'); + +% Check +load('output/BMS.mat'); +actual_group_log_bf = BMS.DCM.ffx.SF - min(BMS.DCM.ffx.SF); +actual_PP = BMS.DCM.ffx.model.post(2); + +testCase.verifyThat(actual_group_log_bf(2), ... + IsEqualTo(3, 'Within', AbsoluteTolerance(0.01) ) ); + +testCase.verifyThat(actual_PP, ... + IsEqualTo(0.95, 'Within', AbsoluteTolerance(0.01))); + +% ------------------------------------------------------------------------- +function test_ffx_no_evidence(testCase) +% Tests FFX in the context of no evidence + +import matlab.unittest.constraints.* + +% Free energies for model 1 and model 2 +F = [-10 -10 -10 -10 -10 + -10 -10 -10 -10 -10]'; +save('output/F.mat','F'); + +% Run +run_bms_Fmatrix('FFX'); + +% Check +load('output/BMS.mat'); +actual_group_log_bf = BMS.DCM.ffx.SF - min(BMS.DCM.ffx.SF); +actual_PP = BMS.DCM.ffx.model.post(2); + +testCase.verifyThat(actual_group_log_bf(2), ... + IsEqualTo(0, 'Within', AbsoluteTolerance(0.01) ) ); + +testCase.verifyThat(actual_PP, ... + IsEqualTo(0.5, 'Within', AbsoluteTolerance(0.01))); + +% ------------------------------------------------------------------------- +function run_bms_Fmatrix(method) +% Run BMS using saved log evidence matrix +clear matlabbatch; +matlabbatch{1}.spm.dcm.bms.inference.dir = {'output'}; +matlabbatch{1}.spm.dcm.bms.inference.sess_dcm = {}; +matlabbatch{1}.spm.dcm.bms.inference.model_sp = {''}; +matlabbatch{1}.spm.dcm.bms.inference.load_f = {'output/F.mat'}; +matlabbatch{1}.spm.dcm.bms.inference.method = method; +matlabbatch{1}.spm.dcm.bms.inference.family_level.family_file = {''}; +matlabbatch{1}.spm.dcm.bms.inference.bma.bma_no = 0; +matlabbatch{1}.spm.dcm.bms.inference.verify_id = 1; +spm_jobman('run',matlabbatch); +% ------------------------------------------------------------------------- +function run_bms_dcm_files(method, P) +% Run BMS using DCM .mat files +% +% P - subjects x models cell array + +clear matlabbatch; +matlabbatch{1}.spm.dcm.bms.inference.dir = cellstr(get_output_dir()); +matlabbatch{1}.spm.dcm.bms.inference.model_sp = {''}; +matlabbatch{1}.spm.dcm.bms.inference.load_f = {''}; +matlabbatch{1}.spm.dcm.bms.inference.method = method; +matlabbatch{1}.spm.dcm.bms.inference.family_level.family_file = {''}; +matlabbatch{1}.spm.dcm.bms.inference.bma.bma_no = 0; +matlabbatch{1}.spm.dcm.bms.inference.verify_id = 0; + +for s = 1:size(P,1) + matlabbatch{1}.spm.dcm.bms.inference.sess_dcm{s}.dcmmat = P(s,:)'; +end +spm_jobman('run',matlabbatch); + +% ------------------------------------------------------------------------- +function out_dir = get_output_dir() +% Returns the directory for output files and creates it if needed +out_dir = fullfile( spm('Dir'), 'tests', 'output'); +if ~exist(out_dir,'file') + mkdir(out_dir); +end diff --git a/toolbox/DARTEL/spm_dartel_norm_fun.m b/toolbox/DARTEL/spm_dartel_norm_fun.m index af146ac4..60598482 100644 --- a/toolbox/DARTEL/spm_dartel_norm_fun.m +++ b/toolbox/DARTEL/spm_dartel_norm_fun.m @@ -35,13 +35,25 @@ % Copyright (C) 2009 Wellcome Trust Centre for Neuroimaging % John Ashburner -% $Id: spm_dartel_norm_fun.m 5668 2013-10-03 18:34:18Z guillaume $ +% $Id: spm_dartel_norm_fun.m 7182 2017-10-06 10:37:31Z christophe $ -% Hard coded stuff, that should maybe be customisable -K = 6; -tpm = fullfile(spm('Dir'),'tpm','TPM.nii'); +% If there is no passed tpm field (ie the default behaviour), then use the default. +if isfield(job,'tpm') + tpm = job.tpm.fn; + K = job.tpm.k; +else + K = 6; + tpm = fullfile(spm('Dir'),'tpm','TPM.nii'); +end Mmni = spm_get_space(tpm); +% Check if output path is specified +if isfield(job,'output') + output = job.output; +else + output = []; +end + % Dartel template if ~isempty(job.template{1}) Nt = nifti(job.template{1}); @@ -63,10 +75,10 @@ msk = ~isfinite(vox); vox(msk) = vox0(msk); msk = ~isfinite(bb); bb(msk) = bb0(msk); - + bb = sort(bb); vox = abs(vox); - + % Adjust bounding box slightly - so it rounds to closest voxel. bb(:,1) = round(bb(:,1)/vox(1))*vox(1); bb(:,2) = round(bb(:,2)/vox(2))*vox(2); @@ -104,7 +116,7 @@ mat_intent = 'Aligned'; end fprintf('\n'); - + if isfield(job.data,'subjs') % Re-order data %------------------------------------------------------------------ @@ -121,7 +133,7 @@ else subj = job.data.subj; end - + % Loop over subjects %---------------------------------------------------------------------- out = cell(1,numel(subj)); @@ -129,9 +141,9 @@ % Spatially normalise data from this subject [pth,nam,ext] = fileparts(subj(i).flowfield{1}); fprintf('** "%s" **\n', nam); - out{i} = deal_with_subject(subj(i).flowfield,subj(i).images,K, mat,dim,M,job.preserve,job.fwhm,mat_intent); + out{i} = deal_with_subject(subj(i).flowfield,subj(i).images,K,mat,dim,M,job.preserve,job.fwhm,mat_intent,output); end - + if isfield(job.data,'subjs'), out1 = out; out = cell(numel(subj),numel(subjs.images)); @@ -142,10 +154,11 @@ end end end +end %__________________________________________________________________________ %__________________________________________________________________________ -function out = deal_with_subject(Pu,PI,K,mat,dim,M,jactransf,fwhm,mat_intent) +function out = deal_with_subject(Pu,PI,K,mat,dim,M,jactransf,fwhm,mat_intent,output) % Generate deformation, which is the inverse of the usual one (it is for "pushing" % rather than the usual "pulling"). This deformation is affine transformed to @@ -166,11 +179,12 @@ oM = zeros(4,4); out = cell(1,numel(PI)); for m=1:numel(PI), - + % Generate headers etc for output images %---------------------------------------------------------------------- [pth,nam,ext,num] = spm_fileparts(PI{m}); NI = nifti(fullfile(pth,[nam ext])); + pth = get_output_path(pth,output); NO = NI; if jactransf, if fwhm==0, @@ -201,16 +215,16 @@ out{m} = NO.dat.fname; NO.extras = []; create(NO); - + % Smoothing settings vx = sqrt(sum(mat(1:3,1:3).^2)); krn = max(fwhm./vx,0.1); - + % Loop over volumes within the file %---------------------------------------------------------------------- fprintf('%s',nam); drawnow; for j=1:size(NI.dat,4), - + % Check if it is a Dartel "imported" image to normalise if sum(sum((NI.mat - NU.mat ).^2)) < 0.0001 && ... sum(sum((NI.mat0 - NU.mat0).^2)) < 0.0001, @@ -230,7 +244,7 @@ M0 = M1(:,:,j); end end - + M = NU.mat0\M0; dm = [size(NI.dat),1,1,1,1]; if ~all(dm(1:3)==odm) || ~all(M(:)==oM(:)), @@ -246,7 +260,7 @@ end odm = dm(1:3); oM = M; - + % Write the warped data for this time point. %------------------------------------------------------------------ for k=1:size(NI.dat,5), @@ -271,4 +285,34 @@ end fprintf('\n'); drawnow; end +end %__________________________________________________________________________ + +%__________________________________________________________________________ +function pth = get_output_path(pth,output) + +% Generate desired output path. +if ~isempty(output) + switch output.option + case 'same' + % no change to output path + case 'allin' + % put everythin the same predefined folder + pth = output.outDir; + case 'subjspec' + % keep per-subject organisation in predefined folder + % and create it if necessary + l_fsep = strfind(pth,filesep); + lp_fsep = [0 l_fsep length(pth)+1]; + dn_subj = pth(lp_fsep(end-1)+1:lp_fsep(end)-1); + pth = fullfile(output.outDir,dn_subj); + otherwise + % inconsistent specification -> no change to output path + fprintf('\nWrong output path specification, use input data path.'); + end + if ~exist(pth,'dir'), mkdir(pth); end +end + +end +%__________________________________________________________________________ + diff --git a/toolbox/DARTEL/spm_dartel_template.m b/toolbox/DARTEL/spm_dartel_template.m index 03bcfdf3..ecfe4dee 100644 --- a/toolbox/DARTEL/spm_dartel_template.m +++ b/toolbox/DARTEL/spm_dartel_template.m @@ -7,7 +7,7 @@ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % John Ashburner -% $Id: spm_dartel_template.m 4064 2010-09-03 12:57:10Z john $ +% $Id: spm_dartel_template.m 7182 2017-10-06 10:37:31Z christophe $ code = 2; st = job.settings; @@ -17,6 +17,13 @@ NF = struct('NI',[],'vn',[1 1]); NF(n1,n2) = struct('NI',[],'vn',[1 1]); +% Check if output path is specified +if isfield(job,'output') + output = job.output; +else + output = []; +end + for i=1:n1, if numel(job.images{i}) ~= n2, error('Incompatible number of images'); @@ -37,6 +44,7 @@ tname = deblank(job.settings.template); for i=1:n2, [pth,nam,ext] = fileparts(NU(i).dat.fname); + pth = get_output_path(pth,output,'subject'); if ~isempty(tname), NU(i).dat.fname = fullfile(pth,['u_' nam '_' tname '.nii']); else @@ -127,6 +135,7 @@ NG = NF(1,1).NI; NG.descrip = sprintf('Avg of %d', n2); [tdir,nam,ext] = fileparts(job.images{1}{1}); + tdir = get_output_path(tdir,output,'darteltemplates'); NG.dat.fname = fullfile(tdir,[tname, '_0.nii']); NG.dat.dim = [dm n1]; NG.dat.dtype = 'float32-le'; @@ -210,6 +219,7 @@ n1 = numel(job.images); n2 = numel(job.images{1}); [tdir,nam,ext] = fileparts(job.images{1}{1}); +tdir = get_output_path(tdir,output,'darteltemplates'); tname = deblank(job.settings.template); out.template = cell(numel(job.settings.param),1); if ~isempty(tname), @@ -221,6 +231,7 @@ out.files = cell(n2,1); for j=1:n2, [pth,nam,ext,num] = spm_fileparts(job.images{1}{j}); + pth = get_output_path(pth,output,'subject'); if ~isempty(tname), fname = fullfile(pth,['u_' nam '_' tname '.nii']); else @@ -229,3 +240,39 @@ out.files{j} = fname; end; +end +%__________________________________________________________________________ + +%__________________________________________________________________________ +function pth = get_output_path(pth,output,dtype) + +% Generate desired output path. + +if ~isempty(output) + switch output.option + case 'same' + % no change to output path + case 'allin' + % put everythin the same predefined folder + pth = output.outDir; + case 'subjspec' + % keep per-subject organisation in predefined folder + % and create it if necessary + switch dtype + case 'subject' % get subject's directory name + l_fsep = strfind(pth,filesep); + lp_fsep = [0 l_fsep length(pth)+1]; + dn_out = pth(lp_fsep(end-1)+1:lp_fsep(end)-1); + case 'darteltemplates' + dn_out = 'DartelTemplates'; + end + pth = fullfile(output.outDir,dn_out); + otherwise + % inconsistent specification -> no change to output path + fprintf('\nWrong output path specification, use input data path.\n'); + end + if ~exist(pth,'dir'), mkdir(pth); end +end + +end +%__________________________________________________________________________ \ No newline at end of file diff --git a/toolbox/DARTEL/spm_dartel_warp.m b/toolbox/DARTEL/spm_dartel_warp.m index 5fe5ff13..5e4997df 100644 --- a/toolbox/DARTEL/spm_dartel_warp.m +++ b/toolbox/DARTEL/spm_dartel_warp.m @@ -7,7 +7,7 @@ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % John Ashburner -% $Id: spm_dartel_warp.m 4064 2010-09-03 12:57:10Z john $ +% $Id: spm_dartel_warp.m 7182 2017-10-06 10:37:31Z christophe $ code = 2; st = job.settings; @@ -16,6 +16,13 @@ NF = struct('NI',[],'vn',[1 1]); NF(n1,n2) = struct('NI',[],'vn',[1 1]); +% Check if output path is specified +if isfield(job,'output') + output = job.output; +else + output = []; +end + for i=1:n1, if numel(job.images{i}) ~= n2, error('Incompatible number of images'); @@ -44,13 +51,13 @@ vn = NF(j,i).vn; f(:,:,:,j) = single(NF(j,i).NI.dat(:,:,:,vn(1),vn(2))); end - f(~isfinite(f)) = 0; [pth,nam,ext] = fileparts(NF(1,i).NI.dat.fname); fprintf('*** %s ***\n', nam); NU = NF(1,i).NI; [pth,nam,ext] = fileparts(NU.dat.fname); + pth = get_output_path(pth,output); NU.dat.fname = fullfile(pth,['u_' nam '.nii']); NU.dat.dim = [dm 1 3]; NU.dat.dtype = 'float32-le'; @@ -97,7 +104,38 @@ out.files = cell(n2,1); for j=1:n2, [pth,nam,ext,num] = spm_fileparts(job.images{1}{j}); + pth = get_output_path(pth,output); fname = fullfile(pth,['u_' nam '.nii']); out.files{j} = fname; end; +end +%__________________________________________________________________________ + +%__________________________________________________________________________ +function pth = get_output_path(pth,output) + +% Generate desired output path. +if ~isempty(output) + switch output.option + case 'same' + % no change to output path + case 'allin' + % put everythin the same predefined folder + pth = output.outDir; + case 'subjspec' + % keep per-subject organisation in predefined folder + % and create it if necessary + l_fsep = strfind(pth,filesep); + lp_fsep = [0 l_fsep length(pth)+1]; + dn_subj = pth(lp_fsep(end-1)+1:lp_fsep(end)-1); + pth = fullfile(output.outDir,dn_subj); + otherwise + % inconsistent specification -> no change to output path + fprintf('\nWrong output path specification, use input data path.\n'); + end + if ~exist(pth,'dir'), mkdir(pth); end +end + +end +%__________________________________________________________________________ diff --git a/toolbox/DARTEL/tbx_cfg_dartel.m b/toolbox/DARTEL/tbx_cfg_dartel.m index bac2b382..9f4738c4 100644 --- a/toolbox/DARTEL/tbx_cfg_dartel.m +++ b/toolbox/DARTEL/tbx_cfg_dartel.m @@ -4,7 +4,7 @@ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % John Ashburner -% $Id: tbx_cfg_dartel.m 6522 2015-08-14 18:55:42Z john $ +% $Id: tbx_cfg_dartel.m 7155 2017-08-17 10:55:05Z john $ if ~isdeployed, addpath(fullfile(spm('dir'),'toolbox','DARTEL')); end @@ -1152,12 +1152,12 @@ dartel.tag = 'dartel'; dartel.name = 'Dartel Tools'; dartel.help = { - 'This toolbox is based around the ``A Fast Diffeomorphic Registration Algorithm'''' paper/* \cite{ashburner07} */. The idea is to register images by computing a ``flow field'''', which can then be ``exponentiated'''' to generate both forward and backward deformations. Currently, the software only works with images that have isotropic voxels, identical dimensions and which are in approximate alignment with each other. One of the reasons for this is that the approach assumes circulant boundary conditions, which makes modelling global rotations impossible. Another reason why the images should be approximately aligned is because there are interactions among the transformations that are minimised by beginning with images that are already almost in register. This problem could be alleviated by a time varying flow field, but this is currently computationally impractical.' + 'This toolbox is based around the ``A Fast Diffeomorphic Registration Algorithm'''' paper/* \cite{ashburner07} */. The idea is to register images by computing a ``flow field'''', which can then be ``exponentiated'''' to generate both forward and backward deformations. Currently, the software only works with images that have isotropic voxels, identical dimensions and which are in approximate alignment with each other. One of the reasons for this is that the approach assumes periodic boundary conditions, which makes modelling global rotations impossible. Another reason why the images should be approximately aligned is because there are interactions among the transformations that are minimised by beginning with images that are already almost in register. This problem could be alleviated by a time varying flow field, but this is currently computationally impractical.' 'Because of these limitations, images should first be imported. This involves taking the ``*_seg_sn.mat'''' files produced by the segmentation code of SPM5, and writing out rigidly transformed versions of the tissue class images, such that they are in as close alignment as possible with the tissue probability maps. Rigidly transformed original images can also be generated, with the option to have skull-stripped versions.' 'The next step is the registration itself. This can involve matching single images together, or it can involve the simultaneous registration of e.g. GM with GM, WM with WM and 1-(GM+WM) with 1-(GM+WM) (when needed, the 1-(GM+WM) class is generated implicitly, so there is no need to include this class yourself). This procedure begins by creating a mean of all the images, which is used as an initial template. Deformations from this template to each of the individual images are computed, and the template is then re-generated by applying the inverses of the deformations to the images and averaging. This procedure is repeated a number of times.' 'Finally, warped versions of the images (or other images that are in alignment with them) can be generated. ' '' - 'This toolbox is not yet seamlessly integrated into the SPM package. Eventually, the plan is to use many of the ideas here as the default strategy for spatial normalisation. The toolbox may change with future updates. There will also be a number of other (as yet unspecified) extensions, which may include a variable velocity version (related to LDDMM). Note that the Fast Diffeomorphism paper only describes a sum of squares objective function. The multinomial objective function is an extension, based on a more appropriate model for aligning binary data to a template.' + 'This toolbox is not yet seamlessly integrated into the SPM package. Eventually, the plan is to use many of the ideas here as the default strategy for spatial normalisation. The toolbox may change with future updates. There will also be a number of other (as yet unspecified) extensions, which may include a variable velocity version (related to LDDMM). Note that the Fast Diffeomorphism paper only describes a sum of squares objective function. The multinomial objective function is an extension, based on a more appropriate model for aligning binary data to a template/* \cite{john_averageshape} */.' }'; dartel.values = {initial warp warp1 nrm crt_warped jacdet crt_iwarped popnorm kernfun }; %dartel.num = [0 Inf]; diff --git a/toolbox/DEM/ADEM_sample_image.m b/toolbox/DEM/ADEM_sample_image.m index d67042ad..a4554d8b 100644 --- a/toolbox/DEM/ADEM_sample_image.m +++ b/toolbox/DEM/ADEM_sample_image.m @@ -25,7 +25,7 @@ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: ADEM_sample_image.m 6901 2016-10-08 13:21:41Z karl $ +% $Id: ADEM_sample_image.m 6932 2016-11-16 12:11:01Z karl $ % retinotopic predictions @@ -33,7 +33,6 @@ global STIM if nargin < 3 s = 0; - o = spm_softmax(o(:)); for i = 1:numel(o) s = s + o(i)*ADEM_sample_image(STIM.H{i},V,STIM.R); end diff --git a/toolbox/DEM/DEMO_MDP_maze.m b/toolbox/DEM/DEMO_MDP_maze.m new file mode 100644 index 00000000..8a0caa9d --- /dev/null +++ b/toolbox/DEM/DEMO_MDP_maze.m @@ -0,0 +1,429 @@ +function MDP = DEMO_MDP_maze +% Demo of mixed continuous and discrete state space modelling +%__________________________________________________________________________ +% +% this demonstration of active inference focuses on navigation and planning +% in a fairly complicated maze. The idea is to demonstrate how epistemic +% foraging and goal (target) directed behaviour are integrated in the +% minimisation of expected free energy. In this illustration, and 8 x 8 +% maze is learned through novelty driven evidence accumulation – to learn +% the likelihood mapping between hidden states (locations in the maze) and +% outcomes (whether the current location is open or closed). This +% accumulated experience is then used to plan a path from a start to an end +% (target location) under a task set specified by prior preferences over +% locations. These priors are based upon a simple diffusion (CF backwards +% induction) heuristic that specifies subgoals. The subgoals (i.e., +% locations) contain the most paths from the target within the horizon of +% the current policy. +% +% we will first illustrate the novelty driven epistemic foraging that +% efficiently scans the maze to learn its structure. We then simulate +% planning of(shortest path) trajectory to the targetunder the assumption +% the maze has been previously learned. Finally, we consider exploration +% under prior preferences to simulate bbehaviour when both epistemic and +% goal directed imperatives are in play. The focus on this demo is on +% behavioural responses and electrophysiological responses over moves. +% +% a key aspect of this formulation is the hierarchical decomposition of +% goal directed behaviour into subgoals that are within the horizon of a +% limited policy – here, to moves that correspond to a trial. The prior +% preferences then contextualise each policy or trial to ensure that the +% ultimate goal is achieved. +% +% see also: spm_MPD_VB_X.m +%__________________________________________________________________________ +% Copyright (C) 2005 Wellcome Trust Centre for Neuroimaging + +% Karl Friston +% $Id: DEMO_MDP_maze.m 7003 2017-02-02 18:22:56Z karl $ + +% set up and preliminaries: first level +%-------------------------------------------------------------------------- +rng('default') + +% generative model at the sensory level (DEM): continuous states +%========================================================================== +% the generative model has two outcome modalities; namely, what (open +% versus closed) and where (the current location in a maze). These outcomes +% are generated from a single hidden factor (location), where the structure +% of the maze is encoded in the likelihood of observation mapping (that can +% be learned through experience). Allowable actions include for moves (up, +% down, left, right) and staying at the current location. These induce five +% transition matrices that play the role of empirical priors. Finally, +% prior preferences are based upon allowable transitions (that are function +% of learned accumulated likelihood), which are used to define attractive +% locations within the horizon of two-move policies. These priors implement +% a task set and are returned by a subfunction below: spm_maze_cost +%-------------------------------------------------------------------------- +label.factor = {'where'}; +label.modality = {'what','where'}; +label.outcome{1} = {'open','closed'}; + +MAZE = [... + 1 1 1 1 1 1 1 1; + 1 0 0 0 0 0 0 1; + 1 1 1 0 1 1 0 1; + 1 1 0 0 0 1 0 1; + 1 1 0 1 0 0 0 1; + 1 1 0 1 1 1 0 1; + 1 0 0 0 0 0 0 1; + 1 0 1 1 1 1 1 1]; +END = sub2ind(size(MAZE),5,5); % goal or target location +START = sub2ind(size(MAZE),8,2); % first or start location + +% prior beliefs about initial states: D +%-------------------------------------------------------------------------- +D{1} = zeros(numel(MAZE),1); +Ns = numel(D{1}); + +% probabilistic mapping from hidden states to outcomes: A +%-------------------------------------------------------------------------- +A{1} = [1 - MAZE(:), MAZE(:)]'; % what +A{2} = eye(Ns,Ns); % where +Ng = numel(A); +for g = 1:Ng + No(g) = size(A{g},1); +end + +% controlled transitions: B (up, down, left, right, stay) +%-------------------------------------------------------------------------- +u = [1 0; -1 0; 0 1; 0 -1; 0 0]; % allowable actions +nu = size(u,1); % number of actions +B{1} = zeros(Ns,Ns,nu); +[n,m] = size(MAZE); +for i = 1:n + for j = 1:m + + % allowable transitions from state s to state ss + %------------------------------------------------------------------ + s = sub2ind([n,m],i,j); + for k = 1:nu + try + ss = sub2ind([n,m],i + u(k,1),j + u(k,2)); + B{1}(ss,s,k) = 1; + catch + B{1}(s, s,k) = 1; + end + end + end +end + +% allowable policies (2 moves): V +%-------------------------------------------------------------------------- +V = []; +for i = 1:nu + for j = 1:nu + V(:,end + 1) = [i;j]; + end +end + +% priors: (negative cost) C: +%-------------------------------------------------------------------------- +for g = 1:Ng + C{g} = zeros(No(g),1); +end + +% basic MDP structure +%-------------------------------------------------------------------------- +mdp.V = V; % allowable policies +mdp.A = A; % observation model or likelihood +mdp.B = B; % transition probabilities +mdp.C = C; % preferred outcomes +mdp.D = D; % prior over initial states + +mdp.label = label; +mdp.alpha = 64; +mdp.tau = 8; +mdp = spm_MDP_check(mdp); + + +% exploratory (32 trial) sequence (no experience or task set) +%========================================================================== +% These simulations use a subroutine (spm_maze_search) to perform recursive +% variational inversions of the active inference scheme under different +% levels of experience and prior preferences +%-------------------------------------------------------------------------- +SDP = spm_maze_search(mdp,32,START,END,0,0); + +% show results - behavioural +%-------------------------------------------------------------------------- +spm_figure('GetWin','Figure 1'); clf +spm_maze_plot(SDP,END) + +% show results - electrophysiological +%-------------------------------------------------------------------------- +spm_figure('GetWin','Figure 2'); clf +spm_MDP_VB_LFP(SDP); + +% exploratory (8 trial) sequence (with experience and task set) +%========================================================================== +MDP = spm_maze_search(mdp,8,START,END,128,1); + +% show results in terms of path +%-------------------------------------------------------------------------- +spm_figure('GetWin','Figure 3'); clf +spm_maze_plot(MDP,END) + +% and implicit subgoals +%-------------------------------------------------------------------------- +for i = 1:8 + subplot(8,2,(i - 1)*2 + 2); + c = softmax(MDP(i).C{2}(:,1)); + imagesc(spm_unvec(c,MAZE)) + axis image off, title(sprintf('%s %i','Trial',i)) +end + +% evidence accumulation under task set +%========================================================================== +MDP = mdp; +for i = 1:4 + + % return to start + %---------------------------------------------------------------------- + MDP = spm_maze_search(MDP(end),8,START,END,0,1); + + % show results in terms of path + %---------------------------------------------------------------------- + spm_figure('GetWin',sprintf('%s %i','Search',i)); clf + spm_maze_plot(MDP,END) + + % and electrophysiological responses + %---------------------------------------------------------------------- + spm_figure('GetWin',sprintf('%s %i','Responses',i)); clf + spm_MDP_VB_game(MDP(1:8)); + subplot(6,1,3), set(gca,'YLim',[-1 1]/3); + subplot(6,1,4), set(gca,'YLim',[0 1]); + +end + +% in silico psychophysical experiment +%========================================================================== +% Here, we return to the exploratory simulation above and probe each level +% of experience by asking the subject to execute a path to target. The +% behaviour is then assessed in terms of the latency with which the target +% will go is required – and the number of mistakes or exploratory +% excursions into closed locations. +%-------------------------------------------------------------------------- +N = []; +M = []; +T = []; +for i = 1:2:numel(SDP) + + % execute path to target with increasing experience + %---------------------------------------------------------------------- + MDP = spm_maze_search(SDP(i),8,START,END,0,1); + + % record behaviour + %---------------------------------------------------------------------- + s = spm_cat({MDP.s}); s(3:3:end) = []; + s = [s,END]; + N = [N,find(s == END,1)]; % latency + M = [M,sum(MAZE(s))]; % mistakes + T = [T,i/2]; % exposure to maze + +end + +% show results +%-------------------------------------------------------------------------- +spm_figure('GetWin','Figure 4'); clf +subplot(2,1,1), bar([M;N]'), xlabel('Exposure (seconds)'), axis square +title('Performance','FontSize',16),legend({'Mistakes','Latency'}) + +return + + + +function MDP = spm_maze_search(mdp,N,START,END,alpha,beta) +% FORMAT MDP = spm_maze_search(mdp,N,START,END,alpha,beta) +% mdp - MDP structure +% N - number of trials (i.e., policies: default 8) +% START - index of intial state (default 1) +% END - index of target state (default 1) +% alpha - prior concentration parameter for likelihood (default 128) +% beta - precision of prior preference (default 0) +% +% MDP - MDP structure array + +% preliminaries +%-------------------------------------------------------------------------- +try, N; catch, N = 8; end +try, START; catch, START = 1; end +try, END; catch, END = 1; end +try, alpha; catch, alpha = 128; end +try, beta; catch, beta = 0; end + +% initialise concentration parameters: a (if unspecified) +%-------------------------------------------------------------------------- +if ~isfield(mdp,'a') + mdp.a{1} = ones(size(mdp.A{1}))/8 + mdp.A{1}*alpha; + mdp.a{2} = mdp.A{2}*128; +end +if ~isfield(mdp,'o') + mdp.o = []; +end +if ~isfield(mdp,'u') + mdp.u = []; +end +mdp.s = START; + +% Evaluate a sequence of eye movements +%========================================================================== + +for i = 1:N + + % Evaluate preferred states (subgoals) on the basis of current beliefs + %---------------------------------------------------------------------- + mdp.C{2} = spm_maze_cost(mdp,END)*beta; + + % proceed with subsequent trial + %---------------------------------------------------------------------- + MDP(i) = spm_MDP_VB_X(mdp); + mdp = MDP(i); + mdp.s = mdp.s(:,end); + mdp.D{1} = MDP(i).X{1}(:,end); + mdp.o = []; + mdp.u = []; + +end + +return + + +function C = spm_maze_cost(MDP,END) +% Evaluate subgoals using +%========================================================================== +START = MDP.s(1); +if isfield(MDP,'a') + Q = MDP.a{1}; +else + Q = MDP.A{1}; +end +Q = Q/diag(sum(Q)); +Q = Q(1,:); % open states +P = diag(Q)*any(MDP.B{1},3); % allowable transitions +ns = length(Q); % number of states +X = zeros(ns,1);X(START) = 1; % initial state +Y = zeros(ns,1);Y(END) = 1; % target state + + +% Preclude transitions to closed states and evaluate graph Laplacian +%-------------------------------------------------------------------------- +P = P - diag(diag(P)); +P = P - diag(sum(P)); +P = expm(P); + +% evaluate (negative) cost as a path integral conjunctions +%-------------------------------------------------------------------------- +for t = 1:size(MDP.V,1) + X = P*X; +end +X = X > exp(-3); +C = log(X.*(P*Y) + exp(-32)); + +return + + + +function spm_maze_plot(MDP,END) +% illustrate search graphically +%-------------------------------------------------------------------------- +A = spm_vec(MDP(1).A{1}(1,:)); +ns = numel(A); +ni = sqrt(ns); +A = reshape(A,ni,ni); +subplot(2,2,1), imagesc(A), axis image +title('Scanpath','fontsize',16); + +% Cycle of the trials +%-------------------------------------------------------------------------- +h = []; +MS = {}; +MC = {}; +for p = 1:numel(MDP) + + % current beliefs and preferences: A likelihood + %---------------------------------------------------------------------- + if isfield(MDP,'a') + Q = MDP(p).a{1}; + else + Q = MDP(p).A{1}; + end + Q = Q/diag(sum(Q)); + Q = Q(1,:); + a = reshape(Q(:),ni,ni); + subplot(2,2,2), imagesc(a), axis image + title('Likelihood','fontsize',16); + + % current beliefs and preferences: B transitions + %---------------------------------------------------------------------- + try + b = diag(Q)*any(MDP(p).B{1},3); + catch + b = diag(Q)*any(MDP(p).B{1},3); + end + subplot(2,2,4), imagesc(-b), axis image + title('Allowable transitions','fontsize',16); + + % current beliefs and preferences: C preferences + %---------------------------------------------------------------------- + C = MDP(p).C{2}(:,1); + C = spm_softmax(C); + C = reshape(C,ni,ni); + subplot(2,2,3), imagesc(C), axis image + title('Preferences','fontsize',16); + try + [i,j] = ind2sub([ni,ni],MDP(p).s(1)); hold on + plot(j,i,'.','MarkerSize',32,'Color','g'); + [i,j] = ind2sub([ni,ni],END); + plot(j,i,'.','MarkerSize',32,'Color','r'); hold off + end + + % cycle over short-term searches + %---------------------------------------------------------------------- + subplot(2,2,1),hold on + s = MDP(p).s; + for t = 1:numel(s) + + % location + %------------------------------------------------------------------ + [i,j] = ind2sub([ni,ni],s(t)); + h(end + 1) = plot(j,i,'.','MarkerSize',32,'Color','r'); + try + set(h(end - 1),'Color','m','MarkerSize',16); + j = [get(h(end - 1),'Xdata'), get(h(end),'Xdata')]; + i = [get(h(end - 1),'Ydata'), get(h(end),'Ydata')]; + plot(j,i,':r'); + end + + % save + %------------------------------------------------------------------ + if numel(MS) + MS(end + 1) = getframe(gca); + else + MS = getframe(gca); + end + + end + + % save + %---------------------------------------------------------------------- + subplot(2,2,3) + if numel(MC) + MC(end + 1) = getframe(gca); + else + MC = getframe(gca); + end + +end + +% save movie +%-------------------------------------------------------------------------- +subplot(2,2,1) +xlabel('click axis for movie') +set(gca,'Userdata',{MS,16}) +set(gca,'ButtonDownFcn','spm_DEM_ButtonDownFcn') + +subplot(2,2,3) +xlabel('click axis for movie') +set(gca,'Userdata',{MC,16}) +set(gca,'ButtonDownFcn','spm_DEM_ButtonDownFcn') diff --git a/toolbox/DEM/DEM_I3_and_TS.m b/toolbox/DEM/DEM_I3_and_TS.m new file mode 100644 index 00000000..8123d953 --- /dev/null +++ b/toolbox/DEM/DEM_I3_and_TS.m @@ -0,0 +1,283 @@ +function DEM_I3_and_TS +%-------------------------------------------------------------------------- +% This routine is a phenomenological examination of the relationship +% between conditional mutual information (i.e.,expected intrinsic mutual +% information and the exponential divergence of trajectories as the +% Rayleigh parameter of a Lorenz attractoris increased (through a pitchfork +% bifurcation and subsequent (subcritical) Hopf bifurcation. The +% (stochastic) Lorentz system is integrated for different values of the +% relay (control) parameter. The nonequilibrium steady-state density is +% then estimated by bidding into a discrete state space; while the +% bifurcations are characterised in terms of the maximal Lyapunov exponent. +% The key thing to observe is the increase in conditional mutual +% information following the Hopf bifurcation and implicit exponential +% divergence of trajectories. This is scored by the maximal Lyapunov +% exponent crossing zero. + + +% generative model +%========================================================================== % switch for demo +spm_figure('GetWin','DEM'); clf + +% flow and Jacobian functions +%-------------------------------------------------------------------------- +f = @(x,v,P,G) v(:) + [-P(1) P(1) 0; P(3) -1 -x(1); x(2) 0 P(2)]*x/64; +Df = @(x,v,P,G) [-P(1) P(1) 0; P(3) -1 -x(1); x(2) 0 P(2)]/64 + ... + [0 0 0; -x(3) 0 0; 0 x(1) 0]/64; + +% model with initial states +%-------------------------------------------------------------------------- +G.x = [1; 1; 24]; +G.f = f; + +% set up +%-------------------------------------------------------------------------- +b = 32; % number of bins for density estimation +T = 2^18; % length of trajectory +W = 32; % precision of intrinsic fluctuations +P = exp((-16:32)*log(32)/32); % Rayleigh parameter range +for k = 1:length(P) + + % integrated timeseries + %---------------------------------------------------------------------- + U.u = randn(T + 256,3)/W; + Pk = [10; -8/3; P(k)]; + t = spm_int_L(Pk,G,U); + + % remove intial transients + %---------------------------------------------------------------------- + t = t(256:end,:); + t = t(1:T,:); + tt{k} = t; + + + % sample density + %---------------------------------------------------------------------- + for i = 1:3 + t(:,i) = t(:,i) - min(t(:,i)); + t(:,i) = (b - 2)*t(:,i)/max(t(:,i)); + end + t = t + 1; + p = zeros(b,b,b) + 1/T; + S = 0; + for i = 1:T + + % accumulate in bins + %------------------------------------------------------------------ + j = round(t(i,:)); + p(j(1),j(2),j(3)) = p(j(1),j(2),j(3)) + 1; + + % Lyapunov exponents + %------------------------------------------------------------------ + dfdx = Df(tt{k}(i,:)',zeros(1,3)',Pk); + S = S + sort(real(eig(dfdx,'nobalance')),'descend'); + + end + p = p/sum(p(:)); + pp{k} = p; + + % mutual informations of sample density + %---------------------------------------------------------------------- + [I,Ii,Ie] = spm_self_entropy(p); + MI(1,k) = I; + MI(2,k) = Ii; + MI(3,k) = Ie; + LE(:,k) = S/T; + + % plot mutual informations + %---------------------------------------------------------------------- + subplot(3,2,3) + semilogx(P(1:k),MI(1,:),'b:',P(1:k),MI(2,:),'b',P(1:k),MI(3,:),'b-.') + axis square xy + title('Self mutual information','Fontsize',16) + xlabel('Control parameter'),ylabel('MI3 (nats)'),drawnow + + % plot maximal Lyapunov exponent + %---------------------------------------------------------------------- + subplot(3,2,4) + semilogx(P(1:k),LE(1,:),'b') + axis square xy + title('Lyapunov exponent','Fontsize',16) + xlabel('Control parameter'),ylabel('MI3 (nats)'),drawnow + +end + +% lines and thresholds +%-------------------------------------------------------------------------- +j = find(LE(1,:) > 0,1); +j = P(j); +subplot(3,2,3) +hold on, plot([j j],[ 0 3],':'), hold off +hold on, plot([1 1],[ 0 3],':'), hold off +legend({'Ir','Ii','Ie'}) +subplot(3,2,4) +hold on, plot([j j],[-1 1]*0.03,':'), hold off +hold on, plot([1 1],[-1 1]*0.03,':'), hold off +hold on, plot(P,zeros(size(P)),'--'), hold off + + +% illustrated lectures and ergodic density +%-------------------------------------------------------------------------- +j = [8 38 length(P)]; +for i = 1:length(j) + + % exemplar trajectory (plot) + %---------------------------------------------------------------------- + subplot(3,3,i) + t = tt{j(i)}; + plot(t(1:1024,2),t(1:1024,3),'k') + axis square xy + title('trajectory','Fontsize',16) + axis([-30 30 -5 60]) + + % image format + %---------------------------------------------------------------------- + subplot(3,3,6 + i) + p = pp{j(i)}; + imagesc(1-squeeze(sum(p,2))'),axis xy square + title('Marginal density','Fontsize',16) + ylabel('State'), xlabel('State') + +% subplot(3,3,6 + i) +% [W,S,X,beta] = spm_power_law(t'); +% plot(W,S,'b.',W,X*beta,'b','LineWidth',1) +% title(sprintf('alpha = %-2.2f',beta(2)),'FontSize',16) +% ylabel('Log power'), xlabel('Log frequency') +% axis square, axis xy, spm_axis tight + + +end + +return + + +function [I,Ii,Ie] = spm_self_entropy(pSxH) +% FORMAT [I,Ii,Ie] = spm_self_entropy(pSxH) +% mutual informations +% G = Ge - Gi +% E[Gi] = I(H,S'|S) +% E[Ge] = I(H,S) +% E[G] = I(H,S',S) = I + +% size of probability distribution array +%-------------------------------------------------------------------------- +n = size(pSxH); + +% evaluate joint density and posterior +%-------------------------------------------------------------------------- +pH = squeeze(sum(pSxH,1)); +pS = sum(sum(sum(pSxH,2),3),4); +pHS = pSxH; +for i = 1:n(1) + pHS(i,:,:,:) = pSxH(i,:,:,:)/sum(pSxH(i,:)); +end +pSH = spm_norm(pSxH); +pS = pS(:); +pH = pH(:); + +% entropies and probabilities +%-------------------------------------------------------------------------- +for j = 1:n(1) + ph = squeeze(pHS(j,:,:,:)); + ps = pSH(:,:)*ph(:); + psxh = spm_unnorm(pSH,ph); + + psxh = psxh(:); + ps = ps(:); + ph = ph(:); + + % intrinsic (mutual information) and extrinsic (cost) + %---------------------------------------------------------------------- + Gi(j,1) = psxh'*log(psxh + eps) - ps'*log(ps) - ph'*log(ph); + Ge(j,1) = ph'*(log(ph) - log(pH)); +end + +% expected values +%-------------------------------------------------------------------------- +I = pS'*(Ge - Gi); +Ii = pS'*Gi; +Ie = pS'*Ge; + +return + +function A = spm_norm(A) +% normalisation of a probability transition matrix (columns) +%-------------------------------------------------------------------------- +for i = 1:size(A,2) + for j = 1:size(A,3) + for k = 1:size(A,4) + for l = 1:size(A,5) + S = sum(A(:,i,j,k,l),1); + if S > 0 + A(:,i,j,k,l) = A(:,i,j,k,l)/S; + else + A(:,i,j,k,l) = 1/size(A,1); + end + end + end + end +end + +function A = spm_unnorm(A,B) +% a normalisation of a probability transition matrix (columns) +%-------------------------------------------------------------------------- +for i = 1:size(A,2) + for j = 1:size(A,3) + for k = 1:size(A,4) + for l = 1:size(A,5) + if size(B,1) > 1 + A(:,i,j,k,l) = A(:,i,j,k,l)*B(i,j,k,l); + else + A(:,i,j,k,l) = A(:,i,j,k,l)*B(1,i,j,k,l); + end + end + end + end +end + +function D = spm_Kaplan_Yorke(LE) +% FORMAT Kaplan Yorke estimate of dimensional complexity +%-------------------------------------------------------------------------- +L = real(LE); +for i = 1:size(L,2) + l = sort(L(:,i),'descend'); + j = find(cumsum(l) > 0,1); + if isempty(j), j = 0; end + D(i) = j + sum(l(1:j))/abs(l(j + 1)); +end + + + +function [W,S,X,beta] = spm_power_law(x) +% FORMAT spm_power_law(x) + +% illustrate power law scaling +%-------------------------------------------------------------------------- +N = floor(log2(size(x,2))); +s = abs(fft(x(1,:)')).^2; +w = (1:2^12)'; +W = w; +S = s(w + 1); + +S = decimate(log(S),N - 4); +W = log(decimate(W,N - 4)); +X = [ones(size(W)),W]; + +% plot part of trajectory +%-------------------------------------------------------------------------- +[~,i] = max(abs(diff(spm_conv(x(1,:),2^(N - 8))))); +nn = 2^10; +i = (-nn:nn) + i; +i = i(i > 0 & i < size(x,2)); + +% estimate exponent (alpha) +%-------------------------------------------------------------------------- +[~,~,beta] = spm_ancova(X,[],S,[0;1]); + +% plot +%-------------------------------------------------------------------------- +% plot(W,S,'b.',W,X*beta,'b','LineWidth',1) +% title(sprintf('alpha = %-2.2f',beta(2)),'FontSize',16) +% ylabel('Log power'), xlabel('Log frequency') +% axis square, axis xy, spm_axis tight + diff --git a/toolbox/DEM/DEM_birdsong.m b/toolbox/DEM/DEM_birdsong.m index d98b8b9c..9448c1f1 100644 --- a/toolbox/DEM/DEM_birdsong.m +++ b/toolbox/DEM/DEM_birdsong.m @@ -1,12 +1,12 @@ function [S] = DEM_birdsong(file) -% Creates basis set for sounds +% Create basis set for sounds % FORMAT [S] = DEM_birdsong(file) % % file - .wav file % % S.U - h x 3 basis functions (Hz) % S.V - 3 x n basis functions (seconds) -% S.Hz - s x 1 frwuencies (Hz) +% S.Hz - s x 1 frequencies (Hz) % % Bird Song demo: These simple loads a .wav file of a real bird-song; and % approximates the ensuing spectrogram with in terms of three @@ -14,41 +14,44 @@ % illustrating DEM_demo_sequences %__________________________________________________________________________ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging - + % Karl Friston -% $Id: DEM_birdsong.m 4136 2010-12-09 22:22:28Z guillaume $ - +% $Id: DEM_birdsong.m 7111 2017-06-16 09:01:09Z guillaume $ + % load bird song %========================================================================== -try - [Y,FS] = wavread(file); -catch - [Y,FS] = wavread('lebi3'); +if ~nargin + file = fullfile(fileparts(mfilename('fullpath')),'lebi3.wav'); end - +if spm_check_version('matlab','8.0') > 0 + [Y,FS] = audioread(file); +else + [Y,FS] = wavread(file); %#ok +end + Y = Y(1:2^15); T = length(Y)/FS; % duration (seconds) - + Nm = 3; % number of frequency modes cpw = 4; % minimum cycles per window -pst = [1:length(Y)]/FS; % peristimulus time (seconds) -Hz = [1:64]*4000/64; % frequencies +pst = (1:length(Y))/FS; % peristimulus time (seconds) +Hz = (1:64)*4000/64; % frequencies k = cpw*Hz/Hz(1); n = cpw*FS/Hz(1); - + % windowed Fourier transform %-------------------------------------------------------------------------- -C = spm_wft(Y,k,n); +C = spm_wft(Y(:),k,n); C = spm_conv(C,8,1); Y = spm_iwft(C,k,n); - + % SVD %-------------------------------------------------------------------------- U = spm_svd(C*C'); U = U(:,1:Nm); V = U'*C; c = U*V; - + % reconstituted sound %-------------------------------------------------------------------------- y = spm_iwft(c,k,n); @@ -59,8 +62,8 @@ S.U = U; S.V = V; S.Hz = Hz; - - + + % Graphics %========================================================================== subplot(2,2,1) @@ -69,21 +72,20 @@ xlabel('Time (sec)') ylabel('Frequency (Hz)') title('(with three modes') - + % set sound data %-------------------------------------------------------------------------- h = get(gca,'Children'); set(h(1),'Userdata',{Y,FS}) set(h(1),'ButtonDownFcn','spm_DEM_ButtonDownFcn') - - + subplot(2,2,2) imagesc(pst,Hz,abs(c)) axis xy xlabel('Time (sec)') ylabel('Frequency (Hz)') title('spectrogram') - + % set sound data %-------------------------------------------------------------------------- h = get(gca,'Children'); @@ -96,7 +98,7 @@ plot(Hz,U) xlabel('Frequency (Hz)') title('Frequency modes') - + subplot(2,2,4) plot(pst,V) xlabel('Time (sec)') diff --git a/toolbox/DEM/DEM_cells.m b/toolbox/DEM/DEM_cells.m new file mode 100644 index 00000000..87edaa4d --- /dev/null +++ b/toolbox/DEM/DEM_cells.m @@ -0,0 +1,213 @@ +function DEM = DEM_cells + +% This demo illustrates self organisation in an ensemble of (sixteen) cells +% using the same principles described in DEM_morphogenesis, using a simpler +% generative model. Overall, the dynamics of these simulations show how one +% can prescribe a point attractor for each constituent of an ensemble that +% endows the ensemble with a point attractor to which the ensemble +% converges. In this example, we consider the special case where the point +% attractor is itself a Markov blanket. In other words, cells come to +% acquire dependencies, in terms of intracellular signalling, that conform +% to a simple Markov blanket with intrinsic or internal cells, surrounded +% by active cells that are, in turn, surrounded by sensory cells. This +% organisation rests upon intracellular signals and active inference using +% generalised (second-order) variational filtering. In brief, the hidden +% causes driving action (migration and signalling) are expectations about +% cell type. These expectations are optimised using sensory signals; +% namely, the signals generated by other cells. By equipping each cell with +% prior beliefs about what it would sense if it was a particular cell type +% (i.e., internal, active or sensory), the act (i.e., move and signal) so +% that they behave and infer their role in an ensemble of cells that itself +% has a Markov blanket. In a DEM_cell_cell.m, we use this first-order +% scheme to simulate hierarchical emergence of Markov blankets; i.e., +% ensembles of cells that can be one of three types at the local level; +% independently of their role at the global level. +%__________________________________________________________________________ +% Copyright (C) 2017 Wellcome Trust Centre for Neuroimaging + +% Karl Friston +% $Id: DEM_cells.m 7150 2017-08-08 19:57:33Z karl $ + +% preliminaries +%-------------------------------------------------------------------------- +clear global +rng('default') +N = 32; % duration of process + +% generative process and model +%========================================================================== +M(1).E.d = 1; % approximation order +M(1).E.n = 2; % embedding order +M(1).E.s = 1; % smoothness +M(1).E.dt = 2; % time step + +% Target morphology +%========================================================================== +n = [1 6 9]; % internal, active and sensory +r = [0 1 3]; % radial distance from centre +pos = []; % position +typ = []; % cell type +for j = 1:length(n) + for i = 1:n(j) + pos(:,end + 1) = r(j)*[sin(2*pi*i/n(j));cos(2*pi*i/n(j))]; + typ(j,end + 1) = 1; + end +end + +% Target sensation - given the canonical location and types +%-------------------------------------------------------------------------- +sen = foxhound(pos,typ); +for i = 1:3 + P.sen(:,i) = mean(sen(:,find(typ(i,:))),2); +end + +% check the predicted sensations are sufficiently orthogonal for inference +%-------------------------------------------------------------------------- +disp(P.sen) + +% initialise expectations and action +%-------------------------------------------------------------------------- +v = typ/2 + randn(size(typ))/8; % states (identity) % predicted sensations +a.pos = pos/2 + randn(size(pos))/8; % chemotaxis +a.sec = spm_softmax(v); % secretion +g = Mg([],v,P); + +n = sum(n); % number of cells +ns(1) = size(g.sec,1); % number of secretions +ns(2) = size(g.sen,1); % number of sensations +na(1) = size(a.pos,1); % number of positions +na(2) = size(a.sec,1); % number of secretions + +% restriction matrix (ensuring action is strictly local) +%-------------------------------------------------------------------------- +In = eye(n,n); +R = spm_cat({kron(In,ones(ns(1),na(1))) kron(In,ones(ns(1),na(2))); + kron(In,ones(ns(2),na(1))) kron(In,ones(ns(2),na(2)))}); + +% level 1 of generative process +%-------------------------------------------------------------------------- +G(1).g = @(x,v,a,P) Gg(x,v,a,P); +G(1).v = Gg([],[],a,a); +G(1).V = exp(16); % precision (noise) +G(1).U = exp(-2); % precision (action) +G(1).R = R; % rate matrix +G(1).pE = a; % form (action) +G(1).aP = exp(-8); % precision (action) + + +% level 2; causes (action) +%-------------------------------------------------------------------------- +G(2).a = spm_vec(a); % endogenous cause (action) +G(2).v = 0; % exogenous cause +G(2).V = exp(16); + + +% generative model +%========================================================================== + +% level 1 of the generative model: +%-------------------------------------------------------------------------- +M(1).g = @(x,v,P) Mg([],v,P); +M(1).v = g; +M(1).V = exp(4); % precision of sensations +M(1).pE = P; + +% level 2: +%-------------------------------------------------------------------------- +M(2).v = v; +M(2).V = exp(-4); % prior precision of identity + +% hidden cause and prior identity expectations (and time) - none +%-------------------------------------------------------------------------- +U = zeros(n*3,N); +C = zeros(1,N); + +% assemble model structure +%-------------------------------------------------------------------------- +DEM.M = M; +DEM.G = G; +DEM.C = C; +DEM.U = U; + +% solve +%========================================================================== +DEM = spm_ADEM(DEM); +spm_DEM_qU(DEM.qU,DEM.pU); + + +% Graphics +%========================================================================== + +% Evolution +% -------------------------------------------------------------------------- +subplot(2,2,2) +for t = 1:N + v = spm_unvec(DEM.qU.a{2}(:,t),a); + c = spm_unvec(DEM.qU.v{2}(:,t),DEM.M(2).v); + for i = 1:n + x = v.pos(1,i); + y = v.pos(2,i); + R = spm_softmax(c(:,i),2); + plot(x,y,'o','markersize',4,'markeredgecolor',[0 0 0],'markerfacecolor',R); hold on + if t == N + plot(x,y,'o','markersize',10,'markeredgecolor',[0 0 0],'markerfacecolor',R); hold on + end + end + title ('Self-organisation','fontsize',15); + xlabel('position'); + ylabel('position'); + axis([-1 1 -1 1]*r(end)) + axis equal off, drawnow +end + +% subroutines +%========================================================================== + +% Generating sensations: self signalling and extracellular signalling +%-------------------------------------------------------------------------- +function g = Gg(x,v,a,P) + +a = spm_unvec(a,P); % action +g.sec = a.sec; % secretion +g.sen = foxhound(a.pos,a.sec); % sensation + +return + +% Generating predictions based on expectations about subtype +%-------------------------------------------------------------------------- +function g = Mg(x,v,P) + +p = spm_softmax(v); % expected identity +g.sec = p; % secretion +g.sen = P.sen*p; % sensation + +return + +% Sensed signals that decay as a Gaussian function of distance +%-------------------------------------------------------------------------- +function sen = foxhound(x,y) + +% sen = sensation +% x = position +% y = cell or signal type (internal, active sensory) + +[m,n] = size(y); % number of signals and cells +sen = zeros(m,n); % extracellular signals +k = 2; % spatial decay constant +for i = 1:n + for j = 1:n + + % distance + %------------------------------------------------------------------ + d = x(:,i) - x(:,j); + d = d'*d; + + % signal sensed + %------------------------------------------------------------------ + if i ~= j + sen(:,i) = sen(:,i) + exp(-k*d)*y(:,j); + end + + end +end +return diff --git a/toolbox/DEM/DEM_cells_cells.m b/toolbox/DEM/DEM_cells_cells.m new file mode 100644 index 00000000..ce97531e --- /dev/null +++ b/toolbox/DEM/DEM_cells_cells.m @@ -0,0 +1,345 @@ +function DEM = DEM_cells_cells + +% This demo is a hierarchical extension of DEM_cell.m, where we have 16 +% ensembles comprising 16 cells. Each cell has a generative model (i.e., +% prior beliefs) about its local and global cell type (i.e., internal, +% active or sensory). Given posterior beliefs about its role at the local +% and global level, the cell (or ensmeble) can predict the local and +% global intracellular signals it would expect to receive. The ensemble of +% ensembles then converges to a point attractor; where the ensemble has a +% Markov blanket and each element of the ensemble comprises a cell that is +% itself a Markov blanket. The focus of this simulation is how the local +% level couples to the global level and vice versa. For simplicity (and +% computational expediency) we only model one ensemble at the local level +% and assume that the remaining ensembles conform to the same (local) +% dynamics. This is effectively a mean field approximation where +% expectations of a cell in the first ensemble about its global type are +% coupled to the corresponding expectations and the ensemble level, and +% vice versa. The results of this simulation are provided in the form of a +% movie and graphs. The figure legend for which is included in the code +% below.m. +% +% In this example, we have used the same generative model at both levels to +% exploit the self similar hierarchical structure that emerges. However, we +% could have used different generative models at the global and local +% levels to simulate the morphogenesis of particular organelles that have a +% different form from their constituent cellular ensembles. +%__________________________________________________________________________ +% Copyright (C) 2017 Wellcome Trust Centre for Neuroimaging + +% Karl Friston +% $Id: DEM_cells_cells.m 7150 2017-08-08 19:57:33Z karl $ + + +% preliminaries +%-------------------------------------------------------------------------- +clear global +rng('default') +N = 32; % duration of process + +% generative process and model +%========================================================================== +M(1).E.d = 1; % approximation order +M(1).E.n = 2; % embedding order +M(1).E.s = 1; % smoothness +M(1).E.dt = 2; % time step + +% Target morphology (for both levels) +%========================================================================== +n = [1 6 9]; % internal, active and sensory +r = [0 1 3]; % radial distance from centre +pos = []; % position +typ = []; % cell type +for j = 1:length(n) + for i = 1:n(j) + pos(:,end + 1) = r(j)*[sin(2*pi*i/n(j));cos(2*pi*i/n(j))]; + typ(j,end + 1) = 1; + end +end + +% Target sensation - given the canonical location and types +%-------------------------------------------------------------------------- +sen = foxhound(pos,typ); +for i = 1:3 + P.sen(:,i) = mean(sen(:,find(typ(i,:))),2); +end + +% check the predicted sensations are sufficiently orthogonal for inference +%-------------------------------------------------------------------------- +disp(P.sen) + +% initialise expectations and action +%-------------------------------------------------------------------------- +v = typ/2 + randn(size(typ))/8; % states (identity) % predicted sensations +a.pos = pos/2 + randn(size(pos))/8; % chemotaxis +a.sec = spm_softmax(v); % secretion + +% restriction matrix (ensuring action is strictly local) +%-------------------------------------------------------------------------- +n = sum(n); % total number of cells +In = eye(n,n); +R = spm_cat({kron(In,ones(3,2)) kron(In,ones(3,3))}); +R = kron(ones(2,1),R); + + +% duplicate expectations and actions +%========================================================================== +aa.l = a; % local action +aa.g = a; % global action +aa.c = a; % global action of 1st ensemble +vv.l = v; % local hidden states +vv.g = v; % global hidden states +vv.c = v; % local global hidden states +R = kron(speye(3,3),R); % augment restriction + +% level 1 of generative process +%-------------------------------------------------------------------------- +G(1).g = @(x,v,a,P) Gg(x,v,a,P); +G(1).v = Gg([],[],aa,aa); +G(1).V = exp(16); % precision (noise) +G(1).U = exp(-2); % precision (action) +G(1).R = R; % rate matrix +G(1).pE = aa; % form (action) +G(1).aP = exp(-8); % precision (action) + +% level 2; causes (action) +%-------------------------------------------------------------------------- +G(2).a = spm_vec(aa); % endogenous cause (action) +G(2).v = 0; % exogenous cause +G(2).V = exp(16); + +% generative model +%========================================================================== + +% level 1 of the generative model: +%-------------------------------------------------------------------------- +M(1).g = @(x,v,P) Mg([],v,P); +M(1).v = Mg([],vv,P); +M(1).V = exp(4); % precision of sensations +M(1).pE = P; + +% level 2: +%-------------------------------------------------------------------------- +M(2).v = vv; +M(2).V = exp(-4); % prior precision of identity + +% hidden cause and prior identity expectations (and time)- none +%-------------------------------------------------------------------------- +U = zeros(spm_length(M(2).v),N); +C = zeros(spm_length(G(2).v),N); + +% assemble model structure +%-------------------------------------------------------------------------- +DEM.M = M; +DEM.G = G; +DEM.C = C; +DEM.U = U; + +% solve +%========================================================================== +DEM = spm_ADEM(DEM); +spm_DEM_qU(DEM.qU,DEM.pU); + +% Free energy +%-------------------------------------------------------------------------- +subplot(2,2,3), plot(-DEM.J) +title('Free energy','Fontsize',16) +xlabel('time'), ylabel('Free energy') +axis square + + +% Graphics +%========================================================================== + +% Evolution +% ------------------------------------------------------------------------- +spm_figure('GetWin','Figure 1'); clf +for t = 1:N + + % mmorphogenesis + %---------------------------------------------------------------------- + subplot(2,1,1) + v = spm_unvec(DEM.qU.a{2}(:,t),DEM.G(1).pE); + c = spm_unvec(DEM.qU.v{2}(:,t),DEM.M(2).v); + for i = 1:n + for j = 1:n + x = v.g.pos(1,i) + v.l.pos(1,j)/8; + y = v.g.pos(2,i) + v.l.pos(2,j)/8; + cl = spm_softmax(c.l(:,j),2); + cg = spm_softmax(c.g(:,i),2); + plot(x,y,'o','markersize',16,... + 'LineWidth',1,... + 'markeredgecolor',cg), hold on + plot(x,y,'.','markersize',16,... + 'color',cl) + end + end + axis([-1 1 -1 1]*r(end)) + axis equal, box off, drawnow, hold off + + % movie + %---------------------------------------------------------------------- + Mov(t) = getframe(gca); + + % differentiation: local, global and local expectations about global + %---------------------------------------------------------------------- + subplot(2,3,4) + for i = 1:n + col = spm_softmax(c.l(:,i),2); + plot(i,t,'.','markersize',16,'color',col), hold on, axis([0 n 0 N]) + end + + subplot(2,3,5) + for i = 1:n + col = spm_softmax(c.g(:,i),2); + plot(i,t,'.','markersize',16,'color',col), hold on, axis([0 n 0 N]) + end + + subplot(2,3,6) + for i = 1:n + col = spm_softmax(c.c(:,i),2); + plot(i,t,'.','markersize',16,'color',col), hold on, axis([0 n 0 N]) + end + +end + +% labels and movie +%-------------------------------------------------------------------------- +subplot(2,1,1) +set(gca,'Userdata',{Mov,8}) +set(gca,'ButtonDownFcn','spm_DEM_ButtonDownFcn') +title({'Self-organisation and differentiation';'(left click for movie)'},'FontSize',16) +xlabel('position'), ylabel('position') + +subplot(2,3,4) +title('local expectations','Fontsize',16) +xlabel('cell'), ylabel('time'), box off, hold off + +subplot(2,3,5) +title('global expectations','Fontsize',16) +xlabel('cell'), ylabel('time'), box off, hold off + +subplot(2,3,6) +title('local about global','Fontsize',16) +xlabel('cell'), ylabel('time'), box off, hold off + +% Figure legend: +% +% This figure shows the (final) results of self organisation of an ensemble +% of cells, where each constituent of the ensemble is itself a local +% ensemble. In this example, there are 16 cells at both the global (higher) +% and local (lower) level. The upper panel shows the final disposition of +% the ensemble (of ensembles) in terms of the location of cells, and their +% differentiation (shown in colour: internal – red, active – green and +% sensory – blue). Note that there are no external states because the +% external states comprise the Markov blankets of other ensembles. Here, +% each cell is coded with two colours. The central colour corresponds to +% expectations about the type of cell in question at the local level, while +% the peripheral circle encodes expectations at the global level. The key +% thing to observe here is the emergence of a Markov blanket at both +% levels. This reflects a particular independency structure, where internal +% cells do not influence sensory (i.e. surface) cells, in virtue of their +% separation by active cells. This separation induces conditional +% independence, because of the limited range of intracellular signals (that +% fall off with a Gaussian function of Euclidean distance). The lower +% panels show the same results in a simpler format; namely, the evolution +% of subtype expectations (i.e., differentiation) at the local (left), and +% global (middle) level. The lower right panel shows the expectations of a +% single ensemble (the first) about its role at the global level. Here, the +% first ensemble is the internal state. Note the differentiation on both a +% local and global level; while local expectations about the cells’ role +% the global level converge to the same (in general) type. In these +% simulations, we used a time step of two units (of arbitrary time) and a +% second order variational filtering scheme (heuristically, this is a +% second order generalisation of extended Kalman filtering) with hidden +% states corresponding to unknown identity in terms of cell type at the +% local and global level. Please see above for more details. +%========================================================================== + + +% subroutines +%========================================================================== + +% Generating sensations (self-signalling and extracellular signals) +%-------------------------------------------------------------------------- +function g = Gg(x,v,a,P) + +a = spm_unvec(a,P); % action +n = size(a.l.pos,2); % number of cells + +% local level +%-------------------------------------------------------------------------- +g.l.sec = a.l.sec; % secretion +g.l.sen = foxhound(a.l.pos,a.l.sec); % sensation + +% global level +%-------------------------------------------------------------------------- +g.g.sec = a.g.sec; % secretion +g.g.sen = foxhound(a.g.pos,a.g.sec); % sensation + +% global to local coupling +%-------------------------------------------------------------------------- +g.c.sec = a.c.sec; % secretion +g.c.sen = g.g.sen(:,1)*ones(1,n); % sensation + +% local to global coupling +%-------------------------------------------------------------------------- +g.g.sec(:,1) = mean(g.c.sec,2); +g.g.sen(:,1) = mean(g.c.sen,2); + +return + +% Generating predictionsof cell signalling and extracellular signals +%-------------------------------------------------------------------------- +function g = Mg(x,v,P) + +% local level +%-------------------------------------------------------------------------- +p = spm_softmax(v.l); % expected identity +g.l.sec = p; % secretion +g.l.sen = P.sen*p; % sensation + +% global level +%-------------------------------------------------------------------------- +p = spm_softmax(v.g); % expected identity +g.g.sec = p; % secretion +g.g.sen = P.sen*p; % sensation + +% local predictions of global signals +%-------------------------------------------------------------------------- +p = spm_softmax(v.c); % expected identity +g.c.sec = p; % secretion +g.c.sen = P.sen*p; % sensation + + +return + +% Sensed signals +%-------------------------------------------------------------------------- +function sen = foxhound(x,y) +% sen = sensation +% x = position +% y = cell type + +[m,n] = size(y); +sen = zeros(m,n); +k = 2; +for i = 1:n + for j = 1:n + + % distance between cells (local) or ensembles (global) + %------------------------------------------------------------------ + d = x(:,i) - x(:,j); + d = d'*d; + + % signal sensed + %------------------------------------------------------------------ + if i ~= j + sen(:,i) = sen(:,i) + exp(-k*d)*y(:,j); + end + + end +end + +return + diff --git a/toolbox/DEM/DEM_demo.fig b/toolbox/DEM/DEM_demo.fig index 01cdfcae56f2cf0352c7492178a37119b2d66fa9..7e96bc3f281359b49f0867823794d7a0925d5a59 100644 GIT binary patch literal 30544 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�gxC-7$gPa2Z@4&K$4e6u*a~cFe4ZUrU5gB z>B6jGTCgWDLzo@x5zHK>53_-3!z^LOFnh2%*aWNtwgPK{Ex-m~Tku1$8CVbe4Ez}U z6l??rfi=LU3nJZjx+S^=y2TDy?V0RZkqpS&NJb(Y z6MZr?m7-s|@6qb>qvZ2X=eb9xFYbixXC08vW~+y=4wlk1bZVU5&QfJ|Hoh@Cp>ax+ zrOM=txIU}O7pX9KKsFnwerlVgO7D!In59-feVEmC(^;B)R$u+pEUSygS(;*2T>Vrp ztBcCHj(isRa!;NwQgRSP(J&piN6Qx}IJiXG0EpX@S`351^8j{pcWd?b!%}Q&Wif0j?xl2dR?jj{F z-$pAeLFk6uf{rk1#fUc;-v_+GyP?OSU3tA7$gHDKgi|n2B;^0sE{UO+(Eq_|Kflw) z@X?TsJ5GlEYAjQX73@swy!kpVBvJdfI)4vLQsC#az?x4}9H_zwuyT0dFE3eBf=vB_up z%NscGvr3H^$UaUvN0-)YelGBOdl2P`8DF{}G|t;kTo#`q!-;jF2Vym-zZZ#Z$#e3%V-$TX>Z9a+TE+$J%^VZn0=~ hHr1%-7q5Gv`G<}PXpN@2#%P&QE(Q`3pid_K{|6rRP?G=v literal 28768 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 z%0A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 YwBf;LF0PeGiMJI)vQ3E04XX$L2WV{T-2eap diff --git a/toolbox/DEM/DEM_demo.m b/toolbox/DEM/DEM_demo.m index 11fe7697..13457352 100644 --- a/toolbox/DEM/DEM_demo.m +++ b/toolbox/DEM/DEM_demo.m @@ -22,7 +22,7 @@ % Edit the above text to modify the response to help DEM_demo -% Last Modified by GUIDE v2.5 03-Sep-2016 16:56:31 +% Last Modified by GUIDE v2.5 10-Aug-2017 21:42:47 % Begin initialization code - DO NOT EDIT gui_Singleton = 1; @@ -56,7 +56,7 @@ function DEM_demo_OpeningFcn(hObject, eventdata, handles, varargin) handles.output = hObject; % default paper -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/The%20free-energy%20principle%20A%20unified%20brain%20theory.pdf'; +handles.web = 'The free-energy principle A unified brain theory'; % Display PDF image axes5_CreateFcn(hObject, eventdata, handles); @@ -97,7 +97,10 @@ function run_demo_Callback(hObject, handles, file) % --- Executes on button press in pushbutton131. function pushbutton131_Callback(hObject, eventdata, handles) -try, web(handles.web,'-browser'); end +try, + url = strcat('http://www.fil.ion.ucl.ac.uk/~karl/',handles.web); + web(url,'-browser','-notoolbar'); +end % --- Executes on button press in pushbutton51. @@ -131,92 +134,92 @@ function pushbutton93_Callback(hObject, eventdata, handles) % --- Executes on button press in pushbutton1. function pushbutton1_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Variational%20free%20energy%20and%20the%20Laplace%20approximation.pdf'; +handles.web = 'Variational free energy and the Laplace approximation'; run_demo_Callback(hObject, handles, 'DEM_demo_GLM') % --- Executes on button press in pushbutton2. function pushbutton2_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Variational%20free%20energy%20and%20the%20Laplace%20approximation.pdf'; +handles.web = 'Variational free energy and the Laplace approximation'; run_demo_Callback(hObject, handles, 'DEM_demo_PEB') % --- Executes on button press in pushbutton4. function pushbutton4_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Hierarchical%20Models%20in%20the%20Brain.pdf'; +handles.web = 'Hierarchical Models in the Brain'; run_demo_Callback(hObject, handles, 'DEM_demo_factor_analysis') % --- Executes on button press in pushbutton5. function pushbutton5_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/DEM%20A%20variational%20treatment%20of%20dynamic%20systems.pdf'; +handles.web = 'DEM A variational treatment of dynamic systems'; run_demo_Callback(hObject, handles, 'DEM_demo_OU') % --- Executes on button press in pushbutton6. function pushbutton6_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Hierarchical%20Models%20in%20the%20Brain.pdf'; +handles.web = 'Hierarchical Models in the Brain'; run_demo_Callback(hObject, handles, 'DEM_demo_convolution') % --- Executes on button press in pushbutton7. function pushbutton7_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/DEM%20A%20variational%20treatment%20of%20dynamic%20systems.pdf'; +handles.web = 'DEM A variational treatment of dynamic systems'; run_demo_Callback(hObject, handles, 'DEM_demo_EM') % --- Executes on button press in pushbutton8. function pushbutton8_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/DEM%20A%20variational%20treatment%20of%20dynamic%20systems.pdf'; +handles.web = 'DEM A variational treatment of dynamic systems'; run_demo_Callback(hObject, handles, 'DEM_demo_DEM') % --- Executes on button press in pushbutton9. function pushbutton9_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/DEM%20A%20variational%20treatment%20of%20dynamic%20systems.pdf'; +handles.web = 'DEM A variational treatment of dynamic systems'; run_demo_Callback(hObject, handles, 'DEM_demo_filtering') % --- Executes on button press in pushbutton10. function pushbutton10_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/DEM%20A%20variational%20treatment%20of%20dynamic%20systems.pdf'; +handles.web = 'DEM A variational treatment of dynamic systems'; run_demo_Callback(hObject, handles, 'DEM_demo_Lorenz') % --- Executes on button press in pushbutton11. function pushbutton11_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Dynamic%20causal%20modelling.pdf'; +handles.web = 'Dynamic causal modelling'; run_demo_Callback(hObject, handles, 'DEM_demo_hdm') % --- Executes on button press in pushbutton12. function pushbutton12_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/DEM%20A%20variational%20treatment%20of%20dynamic%20systems.pdf'; +handles.web = 'DEM A variational treatment of dynamic systems'; run_demo_Callback(hObject, handles, 'DEM_demo_double_well') % --- Executes on button press in pushbutton3. function pushbutton3_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Variational%20filtering.pdf'; +handles.web = 'Variational filtering'; run_demo_Callback(hObject, handles, 'DEM_demo_DFP') % --- Executes on button press in pushbutton14. function pushbutton14_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Variational%20filtering.pdf'; +handles.web = 'Variational filtering'; run_demo_Callback(hObject, handles, 'DFP_demo_double_well') % --- Executes on button press in pushbutton15. function pushbutton15_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Cortical%20circuits%20for%20perceptual%20inference.pdf'; +handles.web = 'Cortical circuits for perceptual inference'; run_demo_Callback(hObject, handles, 'DEM_demo_song_priors') % --- Executes on button press in pushbutton37. function pushbutton37_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Predictive%20coding%20under%20the%20free-energy%20principle.pdf'; +handles.web = 'Predictive coding under the free-energy principle'; run_demo_Callback(hObject, handles, 'DEM_demo_song_inference') % --- Executes on button press in pushbutton38. function pushbutton38_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Cortical%20circuits%20for%20perceptual%20inference.pdf'; +handles.web = 'Cortical circuits for perceptual inference'; run_demo_Callback(hObject, handles, 'DEM_demo_song_omission') % --- Executes on button press in pushbutton40. function pushbutton40_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Learning%20and%20inference%20in%20the%20brain.pdf'; +handles.web = 'Learning and inference in the brain'; run_demo_Callback(hObject, handles, 'DEM_demo_face_inference') % --- Executes on button press in pushbutton41. function pushbutton41_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Attractors%20in%20song.pdf'; +handles.web = 'Attractors in song'; run_demo_Callback(hObject, handles, 'DEM_demo_MMN') % --- Executes on button press in pushbutton42. @@ -226,67 +229,67 @@ function pushbutton42_Callback(hObject, eventdata, handles) % --- Executes on button press in pushbutton44. function pushbutton44_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Action%20and%20behavior%20A%20free-energy%20formulation.pdf'; +handles.web = 'Action and behavior A free-energy formulation'; run_demo_Callback(hObject, handles, 'ADEM_visual') % --- Executes on button press in pushbutton45. function pushbutton45_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Action%20and%20behavior%20A%20free-energy%20formulation.pdf'; +handles.web = 'Action and behavior A free-energy formulation'; run_demo_Callback(hObject, handles, 'ADEM_motor') % --- Executes on button press in pushbutton46. function pushbutton46_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Reinforcement%20Learning%20or%20Active%20Inference.pdf'; +handles.web = 'Reinforcement Learning or Active Inference'; run_demo_Callback(hObject, handles, 'ADEM_learning') % --- Executes on button press in pushbutton47. function pushbutton47_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Action%20and%20behavior%20A%20free-energy%20formulation.pdf'; +handles.web = 'Action and behavior A free-energy formulation'; run_demo_Callback(hObject, handles, 'ADEM_lorenz') % --- Executes on button press in pushbutton48. function pushbutton48_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Action%20and%20behavior%20A%20free-energy%20formulation.pdf'; +handles.web = 'Action and behavior A free-energy formulation'; run_demo_Callback(hObject, handles, 'ADEM_reaching') % --- Executes on button press in pushbutton49. function pushbutton49_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Free%20Energy%20Value%20and%20Attractors.pdf'; +handles.web = 'Free Energy Value and Attractors'; run_demo_Callback(hObject, handles, 'ADEM_lorenz_entropy') % --- Executes on button press in pushbutton50. function pushbutton50_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Free%20Energy%20Value%20and%20Attractors.pdf'; +handles.web = 'Free Energy Value and Attractors'; run_demo_Callback(hObject, handles, 'ADEM_mountaincar_loss') % --- Executes on button press in pushbutton80. function pushbutton80_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Policies%20and%20Priors.pdf'; +handles.web = 'Policies and Priors'; run_demo_Callback(hObject, handles, 'ADEM_SHC_demo') % --- Executes on button press in pushbutton81. function pushbutton81_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Free%20Energy%20Value%20and%20Attractors.pdf'; +handles.web = 'Free Energy Value and Attractors'; run_demo_Callback(hObject, handles, 'ADEM_lorenz_surprise') % --- Executes on button press in pushbutton83. function pushbutton83_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Generalised%20Filtering.pdf'; +handles.web = 'Generalised Filtering'; run_demo_Callback(hObject, handles, 'DEM_demo_LAP') % --- Executes on button press in pushbutton84. function pushbutton84_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Generalised%20Filtering.pdf'; +handles.web = 'Generalised Filtering'; run_demo_Callback(hObject, handles, 'DEM_demo_hdm_LAP') % --- Executes on button press in pushbutton91. function pushbutton91_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Attention%20uncertainty%20and%20free-energy.pdf'; +handles.web = 'Attention uncertainty and free-energy'; run_demo_Callback(hObject, handles, 'DEM_demo_Posner') % --- Executes on button press in pushbutton92. function pushbutton92_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Policies%20and%20Priors.pdf'; +handles.web = 'Policies and Priors'; run_demo_Callback(hObject, handles, 'ADEM_cost_SHC') % --- Executes on button press in pushbutton94. @@ -296,288 +299,288 @@ function pushbutton94_Callback(hObject, eventdata, handles) % --- Executes on button press in pushbutton96. function pushbutton96_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Action%20understanding%20and%20active%20inference.pdf'; +handles.web = 'Action understanding and active inference'; run_demo_Callback(hObject, handles, 'ADEM_observe') % --- Executes on button press in pushbutton97. function pushbutton97_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Network%20discovery%20with%20DCM.pdf'; +handles.web = 'Network discovery with DCM'; run_demo_Callback(hObject, handles, 'DEM_demo_DCM_LAP') % --- Executes on button press in pushbutton98. function pushbutton98_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Dynamic%20modeling%20of%20neuronal%20responses%20in%20fMRI%20using%20cubature%20Kalman%20filtering.pdf'; +handles.web = 'Dynamic modeling of neuronal responses in fMRI using cubature Kalman filtering'; run_demo_Callback(hObject, handles, 'DEM_demo_convolution_LAP') % --- Executes on button press in pushbutton99. function pushbutton99_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Dynamic%20modeling%20of%20neuronal%20responses%20in%20fMRI%20using%20cubature%20Kalman%20filtering.pdf'; +handles.web = 'Dynamic modeling of neuronal responses in fMRI using cubature Kalman filtering'; run_demo_Callback(hObject, handles, 'DEM_demo_lorenz_LAP') % --- Executes on button press in pushbutton100. function pushbutton100_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Dynamic%20modeling%20of%20neuronal%20responses%20in%20fMRI%20using%20cubature%20Kalman%20filtering.pdf'; +handles.web = 'Dynamic modeling of neuronal responses in fMRI using cubature Kalman filtering'; run_demo_Callback(hObject, handles, 'DEM_demo_doublewell_LAP') % --- Executes on button press in pushbutton101. function pushbutton101_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Dynamic%20modeling%20of%20neuronal%20responses%20in%20fMRI%20using%20cubature%20Kalman%20filtering.pdf'; +handles.web = 'Dynamic modeling of neuronal responses in fMRI using cubature Kalman filtering'; run_demo_Callback(hObject, handles, 'DEM_demo_hdm_SCK') % --- Executes on button press in pushbutton102. function pushbutton102_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Action%20understanding%20and%20active%20inference.pdf'; +handles.web = 'Action understanding and active inference'; run_demo_Callback(hObject, handles, 'ADEM_writing') % --- Executes on button press in pushbutton103. function pushbutton103_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Free%20energy%20and%20dendritic%20self-organization.pdf'; +handles.web = 'Free energy and dendritic self-organization'; run_demo_Callback(hObject, handles, 'DEM_demo_dendrite') % --- Executes on button press in pushbutton104. function pushbutton104_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Free-energy%20and%20illusions%20the%20Cornsweet%20effect.pdf'; +handles.web = 'Free-energy and illusions the Cornsweet effect'; run_demo_Callback(hObject, handles, 'DEM_demo_Cornsweet') % --- Executes on button press in pushbutton105. function pushbutton105_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Smooth%20Pursuit%20and%20Visual%20Occlusion.pdf'; +handles.web = 'Smooth Pursuit and Visual Occlusion'; run_demo_Callback(hObject, handles, 'ADEM_pursuit') % --- Executes on button press in pushbutton117. function pushbutton117_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Dopamine%20Affordance%20and%20Active%20Inference.pdf'; +handles.web = 'Dopamine Affordance and Active Inference'; run_demo_Callback(hObject, handles, 'ADEM_cued_response') % --- Executes on button press in pushbutton118. function pushbutton118_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Attractors%20in%20song.pdf'; +handles.web = 'Attractors in song'; run_demo_Callback(hObject, handles, 'DEM_demo_MMN_deviance') % --- Executes on button press in pushbutton119. function pushbutton119_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Bayesian%20State%20Estimation%20Using%20Generalized%20Coordinates.pdf'; +handles.web = 'Bayesian State Estimation Using Generalized Coordinates'; run_demo_Callback(hObject, handles, 'DEM_demo_contact_lens') % --- Executes on button press in pushbutton120. function pushbutton120_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Bayesian%20State%20Estimation%20Using%20Generalized%20Coordinates.pdf'; +handles.web = 'Bayesian State Estimation Using Generalized Coordinates'; run_demo_Callback(hObject, handles, 'DEM_demo_GF_and_KF') % --- Executes on button press in pushbutton121. function pushbutton121_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Active%20inference%20and%20agency%20optimal%20control%20without%20cost%20functions.pdf'; +handles.web = 'Active inference and agency optimal control without cost functions'; run_demo_Callback(hObject, handles, 'spm_MDP_mountain_car') % --- Executes on button press in pushbutton122. function pushbutton122_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Perceptions%20as%20hypotheses%20saccades%20as%20experiments.pdf'; +handles.web = 'Perceptions as hypotheses saccades as experiments'; run_demo_Callback(hObject, handles, 'ADEM_salience') % --- Executes on button press in pushbutton123. function pushbutton123_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Perception%20and%20self-organized%20instability.pdf'; +handles.web = 'Perception and self-organized instability'; run_demo_Callback(hObject, handles, 'DEM_demo_SOC') % --- Executes on button press in pushbutton124. function pushbutton124_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Smooth%20Pursuit%20and%20Visual%20Occlusion.pdf'; +handles.web = 'Active inference, eye movements and oculomotor delays'; run_demo_Callback(hObject, handles, 'ADEM_occulomotor_delays') % --- Executes on button press in pushbutton125. function pushbutton125_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Smooth%20Pursuit%20and%20Visual%20Occlusion.pdf'; +handles.web = 'Smooth Pursuit and Visual Occlusion'; run_demo_Callback(hObject, handles, 'ADEM_occlusion') % --- Executes on button press in pushbutton126. function pushbutton126_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Generalised%20Filtering.pdf'; +handles.web = 'Generalised Filtering'; run_demo_Callback(hObject, handles, 'DEM_demo_ALAP') % --- Executes on button press in pushbutton127. function pushbutton127_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Active%20inference%20sensory%20attenuation%20and%20illusions.pdf'; +handles.web = 'Active inference sensory attenuation and illusions'; run_demo_Callback(hObject, handles, 'ALAP_demo_attenuation') % --- Executes on button press in pushbutton128. function pushbutton128_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Observing%20the%20Observer%20I.pdf'; +handles.web = 'Observing the Observer I'; run_demo_Callback(hObject, handles, 'spm_meta_model') % --- Executes on button press in pushbutton129. function pushbutton129_Callback(hObject, eventdata, handles) -handles.web = ''; +handles.web = 'Predictive Coding or Evidence Accumulation'; run_demo_Callback(hObject, handles, 'DEM_evidence_accumulation') % --- Executes on button press in pushbutton130. function pushbutton130_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Active%20inference%20and%20agency%20optimal%20control%20without%20cost%20functions.pdf'; +handles.web = 'The anatomy of choice active inference and agency'; run_demo_Callback(hObject, handles, 'spm_MDP_offer') % --- Executes on button press in pushbutton132. function pushbutton132_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Life%20as%20we%20know%20it.pdf'; +handles.web = 'Life as we know it'; run_demo_Callback(hObject, handles, 'FEP_Manifold') % --- Executes on button press in pushbutton133. function pushbutton133_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/The%20anatomy%20of%20choice%20active%20inference%20and%20agency.pdf'; +handles.web = 'The anatomy of choice active inference and agency'; run_demo_Callback(hObject, handles, 'spm_MDP_trust') % --- Executes on button press in pushbutton134. function pushbutton134_Callback(hObject, eventdata, handles) -handles.web = ''; +handles.web = 'A DCM for resting state fMRI'; run_demo_Callback(hObject, handles, 'DEM_demo_induced_fMRI') % --- Executes on button press in pushbutton142. function pushbutton142_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/The%20anatomy%20of%20choice%20active%20inference%20and%20agency.pdf'; +handles.web = 'Active Inference, Evidence Accumulation, and the Urn Task'; run_demo_Callback(hObject, handles, 'spm_MDP_urn') % --- Executes on button press in pushbutton143. function pushbutton143_Callback(hObject, eventdata, handles) -handles.web = ''; +handles.web = 'Network discovery with large DCMs'; run_demo_Callback(hObject, handles, 'DEM_demo_large_fMRI') % --- Executes on button press in pushbutton144. function pushbutton144_Callback(hObject, eventdata, handles) -handles.web = ''; +handles.web = 'On nodes and modes in resting state fMRI'; run_demo_Callback(hObject, handles, 'DEM_demo_connectivity_fMRI') % --- Executes on button press in pushbutton145. function pushbutton145_Callback(hObject, eventdata, handles) -handles.web = ''; +handles.web = 'On nodes and modes in resting state fMRI'; run_demo_Callback(hObject, handles, 'DEM_demo_modes_fMRI') % --- Executes on button press in pushbutton146. function pushbutton146_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Dynamic%20modeling%20of%20neuronal%20responses%20in%20fMRI%20using%20cubature%20Kalman%20filtering.pdf'; +handles.web = 'Dynamic modeling of neuronal responses in fMRI using cubature Kalman filtering'; run_demo_Callback(hObject, handles, 'DEM_demo_hdm_SCK') % --- Executes on button press in pushbutton147. function pushbutton147_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Generalised%20Filtering.pdf'; +handles.web = 'Generalised Filtering'; run_demo_Callback(hObject, handles, 'DEM_demo_convolution_LAP') % --- Executes on button press in pushbutton148. function pushbutton148_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Dynamic%20modeling%20of%20neuronal%20responses%20in%20fMRI%20using%20cubature%20Kalman%20filtering.pdf'; +handles.web = 'Dynamic modeling of neuronal responses in fMRI using cubature Kalman filtering'; run_demo_Callback(hObject, handles, 'DEM_demo_lorenz_LAP') % --- Executes on button press in pushbutton149. function pushbutton149_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Dynamic%20modeling%20of%20neuronal%20responses%20in%20fMRI%20using%20cubature%20Kalman%20filtering.pdf'; +handles.web = 'Dynamic modeling of neuronal responses in fMRI using cubature Kalman filtering'; run_demo_Callback(hObject, handles, 'DEM_demo_doublewell_LAP') % --- Executes on button press in pushbutton150. function pushbutton150_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Attention%20uncertainty%20and%20free-energy.pdf'; +handles.web = 'Cerebral Hierarchies, predictive processing, precision and the pulvinar'; run_demo_Callback(hObject, handles, 'DEM_demo_texture') % --- Executes on button press in pushbutton151. function pushbutton151_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Predictive%20coding%20under%20the%20free-energy%20principle.pdf'; +handles.web = 'A Duet for one'; run_demo_Callback(hObject, handles, 'DEM_demo_duet') % --- Executes on button press in pushbutton152. function pushbutton152_Callback(hObject, eventdata, handles) % --- Executes on button press in pushbutton133. -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/The%20anatomy%20of%20choice%20active%20inference%20and%20agency.pdf'; +handles.web = 'Active inference and epistemic value'; run_demo_Callback(hObject, handles, 'DEM_demo_MDP_maze') % --- Executes on button press in pushbutton153. function pushbutton153_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Post%20hoc%20Bayesian%20model%20selection.pdf'; +handles.web = 'Post hoc Bayesian model selection'; run_demo_Callback(hObject, handles, 'DEM_demo_Bayesian_Model_Reduction') % --- Executes on button press in pushbutton154. function pushbutton154_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Life%20as%20we%20know%20it.pdf'; +handles.web = 'Knowing ones place'; run_demo_Callback(hObject, handles, 'DEM_morphogenesis') % --- Executes on button press in pushbutton155. function pushbutton155_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Policies%20and%20Priors.pdf'; +handles.web = 'Active Inference and Learning in the Cerebellum'; run_demo_Callback(hObject, handles, 'ADEM_eyeblink') % --- Executes on button press in pushbutton156. function pushbutton156_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Post%20hoc%20Bayesian%20model%20selection.pdf'; +handles.web = 'Post hoc Bayesian model selection'; run_demo_Callback(hObject, handles, 'DEMO_SLR') % --- Executes on button press in pushbutton157. function pushbutton157_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Post%20hoc%20Bayesian%20model%20selection.pdf'; +handles.web = 'Post hoc Bayesian model selection'; run_demo_Callback(hObject, handles, 'DEMO_BMR_PEB') % --- Executes on button press in pushbutton158. function pushbutton158_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Post%20hoc%20Bayesian%20model%20selection.pdf'; +handles.web = 'Bayesian model reduction and empirical Bayes for group (DCM) studies'; run_demo_Callback(hObject, handles, 'DEMO_GROUP_PEB') % --- Executes on button press in pushbutton159. function pushbutton159_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/spm/doc/papers/sjk_aibf.pdf'; +handles.web = 'Anatomically informed basis functions'; run_demo_Callback(hObject, handles, 'DEM_spatial_deconvolution') % --- Executes on button press in pushbutton160. function pushbutton160_Callback(hObject, eventdata, handles) -handles.web = ''; +handles.web = 'Computational Nosology'; run_demo_Callback(hObject, handles, 'DEM_demo_ontology') % --- Executes on button press in pushbutton161. function pushbutton161_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Active%20inference%20and%20epistemic%20value.pdf'; +handles.web = 'Active inference and epistemic value'; run_demo_Callback(hObject, handles, 'DEM_demo_MDP_habits') % --- Executes on button press in pushbutton162. function pushbutton162_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Active%20inference%20and%20epistemic%20value.pdf'; +handles.web = 'Computational Phenotyping in Psychiatry'; run_demo_Callback(hObject, handles, 'DEM_demo_MDP_fit') % --- Executes on button press in pushbutton163. function pushbutton163_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Active%20inference%20and%20epistemic%20value.pdf'; +handles.web = 'Active inference and learning'; run_demo_Callback(hObject, handles, 'DEM_demo_MDP_X') % --- Executes on button press in pushbutton168. function pushbutton168_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Active%20inference%20and%20epistemic%20value.pdf'; +handles.web = 'Scene Construction,Visual Foraging and Active Inference'; run_demo_Callback(hObject, handles, 'DEM_demo_MDP_search') % --- Executes on button press in pushbutton169. function pushbutton169_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Active%20inference%20and%20epistemic%20value.pdf'; +handles.web = 'Scene Construction,Visual Foraging and Active Inference'; run_demo_Callback(hObject, handles, 'DEM_demo_MDP_reading') % --- Executes on button press in pushbutton170. function pushbutton170_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Active%20inference%20and%20epistemic%20value.pdf'; +handles.web = 'Active inference and epistemic value'; run_demo_Callback(hObject, handles, 'DEM_demo_MDP_rule') % --- Executes on button press in pushbutton197. function pushbutton197_Callback(hObject, eventdata, handles) -handles.web = ''; +handles.web = 'Empirical Bayes for DCM A Group Inversion Scheme'; run_demo_Callback(hObject, handles, 'DEMO_BMR_PEB') % --- Executes on button press in pushbutton198. function pushbutton198_Callback(hObject, eventdata, handles) -handles.web = ''; +handles.web = 'Empirical Bayes for DCM A Group Inversion Scheme'; run_demo_Callback(hObject, handles, 'DEMO_GROUP_PEB') % --- Executes on button press in pushbutton199. function pushbutton199_Callback(hObject, eventdata, handles) -handles.web = ''; +handles.web = 'Bayesian model reduction and empirical Bayes for group (DCM) studies'; run_demo_Callback(hObject, handles, 'DEMO_DCM_PEB') % --- Executes on button press in pushbutton200. function pushbutton200_Callback(hObject, eventdata, handles) -handles.web = ''; +handles.web = 'Bayesian model reduction and empirical Bayes for group (DCM) studies'; run_demo_Callback(hObject, handles, 'DEMO_DCM_PEB_FIT') % --- Executes on button press in pushbutton201. function pushbutton201_Callback(hObject, eventdata, handles) -handles.web = ''; +handles.web = 'Comparing dynamic causal models'; run_demo_Callback(hObject, handles, 'DEMO_BAYES_FACTORS') % --- Executes on button press in pushbutton202. @@ -587,21 +590,77 @@ function pushbutton202_Callback(hObject, eventdata, handles) % --- Executes on button press in pushbutton203. function pushbutton203_Callback(hObject, eventdata, handles) -handles.web = ''; +handles.web = 'Bayesian model selection for group studies'; run_demo_Callback(hObject, handles, 'DEMO_BMR_PEB') % --- Executes on button press in pushbutton210. function pushbutton210_Callback(hObject, eventdata, handles) -handles.web = ''; +handles.web = 'Bayesian model reduction and empirical Bayes for group (DCM) studies'; run_demo_Callback(hObject, handles, 'DEM_demo_fMRI_PEB') % --- Executes on button press in pushbutton211. function pushbutton211_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Active%20inference%20and%20epistemic%20value.pdf'; +handles.web = 'Active inference and epistemic value'; run_demo_Callback(hObject, handles, 'DEM_MDP_decision') - % --- Executes on button press in pushbutton212. function pushbutton212_Callback(hObject, eventdata, handles) -handles.web = 'http://www.fil.ion.ucl.ac.uk/~karl/Active%20inference%20and%20epistemic%20value.pdf'; +handles.web = ''; run_demo_Callback(hObject, handles, 'DEM_demo_MDP_DEM') + +% --- Executes on button press in pushbutton213. +function pushbutton213_Callback(hObject, eventdata, handles) +handles.web = 'Computational Phenotyping in Psychiatry'; +run_demo_Callback(hObject, handles, 'DEM_demo_MDP_fit_fields') + +% --- Executes on button press in pushbutton214. +function pushbutton214_Callback(hObject, eventdata, handles) +handles.web = 'Active inference and epistemic value'; +run_demo_Callback(hObject, handles, 'DEMO_MDP_maze') + +% --- Executes on button press in pushbutton215. +function pushbutton215_Callback(hObject, eventdata, handles) +handles.web = 'Life as we know it'; +run_demo_Callback(hObject, handles, 'FEP_fluctuations') + + +% --- Executes on button press in pushbutton216. +function pushbutton216_Callback(hObject, eventdata, handles) +handles.web = 'Life as we know it'; +run_demo_Callback(hObject, handles, 'FEP_MB_demo') + + +% --- Executes on button press in pushbutton217. +function pushbutton217_Callback(hObject, eventdata, handles) +handles.web = 'Knowing ones place'; +run_demo_Callback(hObject, handles, 'DEM_cells_cells') + + +% --- Executes on button press in pushbutton218. +function pushbutton218_Callback(hObject, eventdata, handles) +handles.web = 'Knowing ones place'; +run_demo_Callback(hObject, handles, 'DEM_cells') + + +% --- Executes on button press in pushbutton219. +function pushbutton219_Callback(hObject, eventdata, handles) +handles.web = 'Life as we know it'; +run_demo_Callback(hObject, handles, 'DEM_self_MI_a') + + +% --- Executes on button press in pushbutton220. +function pushbutton220_Callback(hObject, eventdata, handles) +handles.web = 'Life as we know it'; +run_demo_Callback(hObject, handles, 'DEM_self_MI_c') + + +% --- Executes on button press in pushbutton221. +function pushbutton221_Callback(hObject, eventdata, handles) +handles.web = 'Life as we know it'; +run_demo_Callback(hObject, handles, 'DEM_I3_and_TS') + + +% --- Executes on button press in pushbutton222. +function pushbutton222_Callback(hObject, eventdata, handles) +handles.web = 'Life as we know it'; +run_demo_Callback(hObject, handles, 'FEP_physics') diff --git a/toolbox/DEM/DEM_demo_MDP_DEM.m b/toolbox/DEM/DEM_demo_MDP_DEM.m index ef726b08..37870efc 100644 --- a/toolbox/DEM/DEM_demo_MDP_DEM.m +++ b/toolbox/DEM/DEM_demo_MDP_DEM.m @@ -1,59 +1,67 @@ function MDP = DEM_demo_MDP_DEM -% Demo of active inference for visual salience +% Demo of mixed continuous and discrete state space modelling %__________________________________________________________________________ % -% This routine provide simulations of reading to demonstrate deep temporal -% generative models. It builds upon the scene construction simulations to -% equip the generative model with a second hierarchical level. In effect, -% this creates an agent that can accumulate evidence at the second level -% based upon epistemic foraging at the first. In brief, the agent has to -% categorise a sentence or narrative into one of two categories (happy or -% sad), where it entertains six possible sentences. Each sentence comprises -% four words, which are themselves constituted by two pictures or graphemes -% These are the same visual outcomes used in previous illustrations of -% scene construction and saccadic searches. +% This routine illustrates the combination of discrete and continuous +% state space models for active inference. In this example, the lowest +% level of a hierarchical Markov decision process (used to illustrate +% evidence accumulation during reading in related simulations) is equipped +% with a continuous time and state space dynamical model at the lowest +% level. This allows one to model both the categorical belief updates +% using belief propagation and the continuous belief updates using +% Bayesian filtering within the same model and associated inversion +% scheme. % -% Here, the agent has policies at two levels. The second level policy (with -% just one step into the future) allows it to either look at the next word -% or stay on the current page and make a decision. Concurrently, a first -% level policy entails one of four saccadic eye movements to each quadrant -% of the current page, where it will sample a particular grapheme. +% The key contribution of this scheme is the message passing or belief +% propagation between the lowest discrete state (MDP) level and the +% highest level of the continuous state (DCM) models. In brief, during +% inversion, posterior beliefs about hidden causes of observable +% (continuous) inputs provide (probabilistic or posterior) outcomes for the +% (categorical) MDP scheme. In return, the posterior predictive density +% over outcomes of the MDP scheme specify priors on the hidden causes. In +% this example, these priors determine the salient locations to which the +% synthetic agent saccades. These saccades sample discriminative visual +% information that resolves uncertainty about the content of the local +% visual scene. Posterior expectations about the content then play the role +% of observations for higher (categorical) levels. % -% This provides a rough simulation of reading – that can be made more -% realistic by terminating first level active inference, when there can be -% no further increase in expected free energy (i.e., all uncertainty about -% the current word has been resolved). The subsequent inferred hidden -% states then become the outcome for the level above. +% Note that the priors from the MDP levels are time invariant (i.e., the +% attracting location of the saccade does not change during each saccadic +% epoch). Similarly, the posterior beliefs are over attributes that do +% not change during the saccadic sampling (i.e., the hidden cause of +% visual input at the attracting location). This underwrites a separation +% of temporal scales that is recapitulated at higher levels of the +% categorical model. The implementation of these schemes is as general as +% we could make it. The code below illustrates how one links MDP schemes +% to DPM schemes in a generic way through hidden causes. % -% To illustrate the schemes biological plausibility, one can change the -% agent’s prior beliefs and repeat the reading sequence under violations of -% either local (whether the graphemes are flipped vertically) or globally -% (whether the sentence is surprising) expectations. This produces a -% mismatch negativity (MMN) under local violations) and a MMN with a -% P300 with global violations. +% More details about each level of the model are provided in line as +% annotated descriptions. % -% see also: DEM_demo_MDP_habits.m and spm_MPD_VB_X.m +% see also: spm_MPD_VB_X.m %__________________________________________________________________________ % Copyright (C) 2005 Wellcome Trust Centre for Neuroimaging - + % Karl Friston -% $Id: DEM_demo_MDP_DEM.m 6901 2016-10-08 13:21:41Z karl $ - +% $Id: DEM_demo_MDP_DEM.m 7003 2017-02-02 18:22:56Z karl $ + % set up and preliminaries: first level -%========================================================================== -% There are two outcome modalities (what and where), encoding one of 4 cues -% and one of 4 locations. The hidden states have four factors; -% corresponding to context (three words), where (the 4 locations) -% and two further factors modelling invariance. There are no specific prior -% preferences at this level, which means behaviour is purely epistemic. %-------------------------------------------------------------------------- - rng('default') pth = fileparts(mfilename('fullpath')); -% generative model at the sensory level (DTM): continuous states +% generative model at the sensory level (DEM): continuous states %========================================================================== +% This level of model specification concerns the sampling of continuous +% data; here, visual stimuli encoded in a global structure (STIM). This is +% a generic specification that allows one to place various stimuli in the +% visual field – with user-specified parameters for sampling. The hidden +% causes of this generative model correspond to one attracting location +% and the content or stimulus that will be sampled at that location. The +% dynamics or hidden states in this level of the model are simple: the +% attracting location simply attracts the point of foveal fixation. + % memory map images and get hypotheses %-------------------------------------------------------------------------- @@ -66,12 +74,12 @@ % set-up: %-------------------------------------------------------------------------- dim = 32; % dimension of visual sample -nb = 4; % number of basis functions +nb = 6; % number of basis functions ns = nb*nb; % number of sensory channels STIM.W = 1/2; % foveal sampling width STIM.R = ones(dim,dim); % retinal precision STIM.B = spm_dctmtx(dim,nb); % Basis functions (CRFs) -STIM.A = 4; % Attenuation (spotlight) +STIM.A = 4; % Attenuation (spotlight) % and locations %-------------------------------------------------------------------------- @@ -85,28 +93,20 @@ % mapping from outputs of higher (discrete) level to (hidden) causes %========================================================================== -% true causes for every combination of discrete states +% true causes (U) and priors (C) for every combination of discrete states %-------------------------------------------------------------------------- -N = 16; % length of data sequence +N = 24; % length of data sequence nh = length(STIM.H); % number of hypotheses nl = length(STIM.L); % number of locations for i = 1:nh for j = 1:nl - c = [STIM.L{j}; sparse(i,1,4,nh,1)]; - demi.C{i,j} = c*ones(1,N); - end -end - -% priors over hidden causes, conditioned on discrete states -%-------------------------------------------------------------------------- -for i = 1:nh - for j = 1:nl - u = [STIM.L{j}; sparse(i,1,4,nh,1)]; + c = [STIM.L{j}; sparse(i,1,1,nh,1)]; + u = [STIM.L{j}; sparse(i,1,1,nh,1)]; demi.U{i,j} = u*ones(1,N); + demi.C{i,j} = c*ones(1,N); end end - % evaluate true and priors over causes given discrete states %-------------------------------------------------------------------------- o = [4,1]; @@ -122,18 +122,17 @@ % hidden states %-------------------------------------------------------------------------- x = [0;0]; % oculomotor angle -v.x = [8;0]; % equilibrium point +v.x = [8;0]; % fixed (attracting) point v.h = sparse(nh,1); % hypothesis g = @ADEM_sample_image; % level 1: Displacement dynamics and mapping to sensory/proprioception %-------------------------------------------------------------------------- -M(1).f = @(x,v,P) (v.x - x)/4; +M(1).f = @(x,v,P) (v.x - x)/8; M(1).g = @(x,v,P) spm_vec(x,g(x - v.x,v.h)); M(1).x = x; % hidden states -M(1).V = [exp(4) exp(4) ones(1,ns)*8]; % error precision (g) -M(1).W = exp(4); % error precision (f) - +M(1).V = 8; % error precision (g) +M(1).W = 8; % error precision (f) % level 2: %-------------------------------------------------------------------------- @@ -168,28 +167,48 @@ %-------------------------------------------------------------------------- DEM = spm_MDP_DEM(DEM,demi,O,o); -% overlay true values +% arrays (of functions) for graphics (in spm_MDP_plot) +%-------------------------------------------------------------------------- +DEM.label{1} = @(x,v,P) g(x - v.x,v.h); +DEM.label{2} = @(x,v,P) 1 - sparse(ceil(x(1)*2 + 16),ceil(x(2)*2 + 16),1,32,32); + +% overlay true values on the results of Bayesian filtering %-------------------------------------------------------------------------- spm_figure('GetWin','Figure 1'); spm_DEM_qU(DEM.qU,DEM.pU) +% show movies of sampling of continuous observations at this level +%-------------------------------------------------------------------------- spm_figure('GetWin','Figure 2'); spm_dem_mdp_movie(DEM) drawnow -% return - -% first level (lexical) + +% second level (discrete: lexical) %========================================================================== - +% There are two outcome modalities (what and where), encoding one of 4 cues +% and one of 4 locations. The hidden states have four factors; +% corresponding to context (three words), where (the 4 locations) +% and two further factors modelling invariance. There are no specific prior +% preferences at this level, which means behaviour is purely epistemic. +%-------------------------------------------------------------------------- +label.factor = {'what','where','flip','flip'}; +label.name{1} = {'flee','feed','wait'}; +label.name{2} = {'-','+'}; +label.name{3} = {'-','+'}; + +label.modality = {'what','where'}; +label.outcome{1} = {'null','bird','seed','cat'}; +label.outcome{2} = {'1','2','3','4'}; + + % prior beliefs about initial states %-------------------------------------------------------------------------- D{1} = [1 1 1]'; % what: {'flee','feed','wait'} D{2} = [1 0 0 0]'; % where: {'1',...,'4'} D{3} = [8 1]'; % flip(ud): {'no','yes'} -D{4} = [9 1]'; % flip(rl): {'no','yes'} - - +D{4} = [8 1]'; % flip(rl): {'no','yes'} + % probabilistic mapping from hidden states to outcomes: A %-------------------------------------------------------------------------- Nf = numel(D); @@ -230,22 +249,22 @@ end end end - + % controlled transitions: B{f} for each factor %-------------------------------------------------------------------------- for f = 1:Nf B{f} = eye(Ns(f)); end - + % controllable fixation points: move to the k-th location %-------------------------------------------------------------------------- for k = 1:Ns(2) B{2}(:,:,k) = 0; B{2}(k,:,k) = 1; end - - -% MDP Structure + + +% MDP structure for this level (and subordinate DEM level) %-------------------------------------------------------------------------- mdp.T = 3; % number of updates mdp.A = A; % observation model @@ -253,18 +272,20 @@ mdp.D = D; % prior over initial states mdp.DEM = DEM; mdp.demi = demi; - -mdp.Aname = {'what','where'}; -mdp.Bname = {'what','where','flip','flip'}; + +mdp.label = label; +mdp.Aname = label.modality; +mdp.Bname = label.factor; mdp.alpha = 64; mdp.chi = 1/32; - + clear A B D - + MDP = spm_MDP_check(mdp); clear mdp - -% set up and preliminaries: first level + + +% Third level (discrete: semantic) %========================================================================== % There are three outcome modalities (what, where and feedback), encoding % one of three cues (i.e., words) in one of 4 locations. The hidden states @@ -273,16 +294,29 @@ % third hidden factor corresponds to the categorical decision. A priori, % the agent prefers to solicit correct feedback. %-------------------------------------------------------------------------- - -% second level (semantic) -%========================================================================== - +label.factor = {'story','where','decision'}; +label.name{1} = {... + 'flee wait feed wait' + 'wait wait wait feed' + 'wait flee wait feed' + 'flee wait feed flee' + 'wait wait wait flee' + 'wait flee wait flee'}; +label.name{2} = {'1st','2nd','3rd','4th'}; +label.name{3} = {'null','happy','sad'}; + +label.modality = {'picture','where','feedback'}; +label.outcome{1} = {'flee','feed','wait'}; +label.outcome{2} = {'1','2','3','4'}; +label.outcome{3} = {'null','right','wrong'}; + + % prior beliefs about initial states (in terms of counts_: D and d %-------------------------------------------------------------------------- D{1} = [1 1 1 1 1 1]'; % what: {'story 1',...,'story 6'} D{2} = [1 0 0 0]'; % where: {'1',...,'4'} D{3} = [1 0 0]'; % report: {'null','happy','sad'} - + % probabilistic mapping from hidden states to outcomes: A %-------------------------------------------------------------------------- Nf = numel(D); @@ -328,31 +362,31 @@ for g = 1:Ng No(g) = size(A{g},1); end - + % controlled transitions: B{f} for each factor %-------------------------------------------------------------------------- for f = 1:Nf B{f} = eye(Ns(f)); end - + % control states B(2): where {'stay' or 'proceed'} %-------------------------------------------------------------------------- B{2}(:,:,1) = spm_speye(Ns(2),Ns(2), 0); B{2}(:,:,2) = spm_speye(Ns(2),Ns(2),-1); B{2}(end,end,2) = 1; - + % control states B(3): report {'null,'happy','sad'} %-------------------------------------------------------------------------- for k = 1:Ns(3) B{3}(:,:,k) = 0; B{3}(k,:,k) = 1; end - + % allowable policies (specified as the next action) U %-------------------------------------------------------------------------- U(1,1,:) = [1 2 1]'; % move to next page U(1,2,:) = [1 1 2]'; % stay on current page and report happy U(1,3,:) = [1 1 3]'; % stay on current page and report sad - + % priors: (utility) C %-------------------------------------------------------------------------- for g = 1:Ng @@ -360,12 +394,14 @@ end C{3}(2,:) = 0; % the agent expects to be right C{3}(3,:) = -4; % and not wrong - -% MDP Structure + +% MDP structure for this level (and subordinate MDP level) +% including links from outcomes at the current level to states of level +% below. This complete the specification of the mixed hierarchical model %-------------------------------------------------------------------------- mdp.MDP = MDP; mdp.link = sparse(1,1,1,numel(MDP.D),Ng); - + mdp.T = 5; % number of moves mdp.U = U; % allowable policies mdp.A = A; % observation model @@ -373,66 +409,63 @@ mdp.C = C; % preferred outcomes mdp.D = D; % prior over initial states mdp.s = [1 1 1]'; % initial state - -mdp.Aname = {'picture','where','feedback'}; -mdp.Bname = {'story','where','decision'}; + +mdp.label = label; mdp.alpha = 64; mdp = spm_MDP_check(mdp); - - -% illustrate a single trial + + +% invert this model of sentence reading %========================================================================== MDP = spm_MDP_VB_X(mdp); - -% show belief updates (and behaviour) + +% show belief updates (and behaviour) over trials %-------------------------------------------------------------------------- spm_figure('GetWin','Figure 3'); clf spm_MDP_VB_trial(MDP); - -% illustrate phase-precession and responses + +% illustrate phase-precession and electrophysiological responses %-------------------------------------------------------------------------- spm_figure('GetWin','Figure 4'); clf -spm_MDP_VB_LFP(MDP,[],1); subplot(3,1,3) -spm_MDP_search_plot(MDP) +spm_MDP_VB_LFP(MDP,[],1); +subplot(3,1,3), spm_MDP_search_plot(MDP) - -% illustrate evidence accumulation and perceptual synthesis (movie) +% electrophysiological responses over MDP levels %-------------------------------------------------------------------------- spm_figure('GetWin','Figure 5'); clf -spm_MDP_search_percept(MDP) - +spm_MDP_VB_ERP(MDP,1); +subplot(4,1,4), spm_MDP_search_plot(MDP) -% electrophysiological responses +% illustrate evidence accumulation and perceptual synthesis (movie) %-------------------------------------------------------------------------- spm_figure('GetWin','Figure 6'); clf -spm_MDP_VB_ERP(MDP,1); -subplot(4,1,4) -spm_MDP_search_plot(MDP) +spm_MDP_search_percept(MDP) + +% movie of expected states and outcomes at all levels +%-------------------------------------------------------------------------- +subplot(2,1,2) +spm_MDP_plot(MDP) + -spm_figure('GetWin','Figure 7'); -spm_dem_mdp_movie(MDP.mdp(4).dem) - return - - - - + + + + function spm_MDP_search_plot(MDP) % illustrate visual search graphically %-------------------------------------------------------------------------- - + % locations on page and of page %-------------------------------------------------------------------------- x = [0 0;0 1;1 0;1 1]; y = [1 0;2 0;3 0;4 0]*3; r = [-1,1]/2; - + % load images %-------------------------------------------------------------------------- load MDP_search_graphics -null = zeros(size(bird)) + 1; - - + % plot cues %-------------------------------------------------------------------------- cla; @@ -464,7 +497,7 @@ function spm_MDP_search_plot(MDP) X(end + 1,:) = y(MDP.o(2,p),:) + x(MDP.mdp(p).o(2,i),:); end end - + % Smooth and plot eye movements %-------------------------------------------------------------------------- for j = 1:2 @@ -474,8 +507,8 @@ function spm_MDP_search_plot(MDP) i = 1:(size(T,1) - 8); plot(T(i,1),T(i,2),'b ','LineWidth',1) plot(X(:,1),X(:,2),'r.','MarkerSize',16) - - + + function spm_MDP_search_percept(MDP) % illustrates visual expectations with a movie %-------------------------------------------------------------------------- @@ -484,20 +517,19 @@ function spm_MDP_search_percept(MDP) axis image ij, axis([2 14 -2 2]), subplot(4,1,2) axis image ij, axis([2 14 -2 2]), hold on - + % locations on page and of page %-------------------------------------------------------------------------- x = [0 0;0 1;1 0;1 1]; y = [1 0;2 0;3 0;4 0]*3; r = [-1,1]/2; s = r*(1 + 1/4); - - + + % load images %-------------------------------------------------------------------------- load MDP_search_graphics -null = zeros(size(bird)) + 1; - + mdp = MDP.mdp(1); try d = mdp.D; @@ -508,7 +540,7 @@ function spm_MDP_search_percept(MDP) for f = 1:Nf Ns(f) = numel(d{f}); end - + % plot posterior beliefs %-------------------------------------------------------------------------- M = []; @@ -619,7 +651,7 @@ function spm_MDP_search_percept(MDP) end end end - + % save movie %-------------------------------------------------------------------------- set(gca,'Userdata',{M,16}) diff --git a/toolbox/DEM/DEM_demo_MDP_fit_fields.m b/toolbox/DEM/DEM_demo_MDP_fit_fields.m new file mode 100644 index 00000000..984fbd13 --- /dev/null +++ b/toolbox/DEM/DEM_demo_MDP_fit_fields.m @@ -0,0 +1,315 @@ +function DCM = DEM_demo_MDP_fit_fields +% Demo of active inference for visual salience +%__________________________________________________________________________ +% +% This routine uses active inference for Markov decision processes to +% illustrate epistemic foraging in the context of visual searches. Here, +% the agent has to categorise scenes on the basis of the relative position +% of various cues. Crucially, the agent can only sample one cue or location +% at a time and therefore has to accumulate evidence for competing +% hypotheses. This rests upon resolving uncertainty about which scene or +% hypothesis is in play through the minimisation of expected free energy. +% +% When the agent become sufficiently confident about the underlying scene, +% it then makes a saccade to a choice location - to obtain feedback (right +% or wrong). The agent prefers to be right and does not expect to be +% wrong. We first illustrate a single trial in terms of behaviour and +% electrophysiological responses. We then consider sequences of trials and +% how one can recover prior preferences by inverting a model of observed +% responses (and cues). +% +% see also: DEM_demo_MDP_habits.m and spm_MPD_VB_X.m +%__________________________________________________________________________ +% Copyright (C) 2005 Wellcome Trust Centre for Neuroimaging + +% Karl Friston +% $Id: DEM_demo_MDP_fit_fields.m 6939 2016-11-20 13:33:56Z karl $ + + + +% create MDP structure of this paradigm +%========================================================================== + +% add prior preferences (and alpha) for this subject +%-------------------------------------------------------------------------- +P.C = log([2,1/4]); % log scaling for preferences +P.alpha = log(16); % log scaling for alpha +mdp = spm_MDP_gen(P); + +% An example trial: +%-------------------------------------------------------------------------- +SDP = spm_MDP_VB_X(mdp); + +% Illustrate belief updates (and behaviour) +%-------------------------------------------------------------------------- +spm_figure('GetWin','Figure 1'); clf +spm_MDP_VB_trial(SDP); + +% and phase-precession and responses +%-------------------------------------------------------------------------- +spm_figure('GetWin','Figure 2'); clf +spm_MDP_VB_LFP(SDP,[],1); + + +% generate a sequence of trials +%========================================================================== +% use an efficient experimental design with all three categories presented +% with and without horizontal flipping (see spm_MDP_create below) +%-------------------------------------------------------------------------- +s = []; +for i = 1:3 + for j = 1:2 + k = ones(4,1); + k(1) = i; + k(4) = j; + s(:,end + 1) = k; + end +end + +for i = 1:size(s,2) + MDP(i) = mdp; % create structure array + MDP(i).s = s(:,i); % context +end + +% solve sequence to get stimuli {MDP.o} and choices {MDP.u} +%-------------------------------------------------------------------------- +MDP = spm_MDP_VB_X(MDP); + + + +% Invert to recover parameters (preferences and precision) +%========================================================================== +% Computational phenotyping entails the estimation of subject specific +% priors (and other parameters) that best explain observed choices (under +% experimentally determined observations). This is done by using a Newton +% scheme and Variational Laplace, based on a log likelihood. The log +% likelihood of choices or actions is determined by the posterior +% distribution over choices. This log likelihood is returned by an +% auxiliary function: spm_MDP_L. The parameterisation of a subject's prior +% beliefs is specified with another auxiliary function that is configured +% for any particular experiment: spm_MDP_field. This function sets the +% requisite fields in the MDP scheme (usually MDP.C) as a function of +% user-specified parameters, whose priors are M.pE and M.pC. in the example +% spm_MDP_field subfunction below, we have used to parameters to scale +% preferences about outcomes and where to look, and a third parameter to +% set alpha - the precision with which an action is selected from posterior +% beliefs about action. By design, we expect the first parameter (about +% preferred outcomes to be about one and alpha to be about two. As there +% were no preferences about a speeded response used, during the generation +% of the simulated data, we expect the second parameter to be negative +% (because it is a log scaling parameter). + + +% response model priors (usually prior preferences in MDP) +%-------------------------------------------------------------------------- +pE.C = [0,0]; % log scaling for preferences +pE.alpha = 0; % log scaling for alpha +pC = eye(spm_length(pE))/32; % shrinkage priors + +% complete model specification +%-------------------------------------------------------------------------- +DCM.M.G = @spm_MDP_gen; % parameterisation of MDP (see below) +DCM.M.L = @spm_MDP_L; % log-likelihood function +DCM.M.pE = pE; % prior expectations +DCM.M.pC = pC; % prior covariances +DCM.U = {MDP.o}; % trial specification (stimuli) +DCM.Y = {MDP.u}; % responses (action or choices) + +% model inversion with Variational Laplace +%-------------------------------------------------------------------------- +[Ep,Cp,F] = spm_nlsi_Newton(DCM.M,DCM.U,DCM.Y); + +% Store posterior densities and log evidnce (free energy) +%-------------------------------------------------------------------------- +DCM.Ep = Ep; +DCM.Cp = Cp; +DCM.F = F; + +% superimpose true values on posterior estimates +%-------------------------------------------------------------------------- +p = spm_vec(P); +subplot(2,2,1),hold on; plot(p(1),p(2),'.g','MarkerSize',32); hold off +subplot(2,2,4),hold on; plot(p, '.g','MarkerSize',16); hold off + +return + + +function MDP = spm_MDP_gen(pE) +% auxiliary function for creating MDP models +% FORMAT MDP = spm_MDP_gen(pE) +% pE - subject specific parameters +% MDP - MDP structure for simulating choice behaviour +% +% This subfunction fills in the parameter fields of a MDP using free +% parameters specified in pE +%__________________________________________________________________________ +% +% In this example, an agent has to categorise a scene that comprises +% potential cues at four peripheral locations, starting from a central +% fixation point. This involves a form of scene construction, in which the +% relationship between various cues determines the category of scene. In +% brief, the scene always contains a bird and seed, or bird and a cat. If +% the bird is next to the seed or the cat, then the scene is categorised as +% feed or flee respectively. Conversely, if the seed is in an opposite +% diagonal location, the category is wait. The particular positions of the +% cues are irrelevant, the important attribute are there relationships. +% This means hidden states have to include some spatial mappings that +% induce invariances to spatial transformations. These are reflections +% around the horizontal and vertical axes. +% +% There are two outcome modalities (what and where), encoding one of six +% cues and one of eight locations (there are three extra locations that +% provide feedback about the respective decision). The hidden states +% have four factors; corresponding to context (the three categories), where +% (the eight locations) and two further factors modelling invariance +%-------------------------------------------------------------------------- + +% prior beliefs about initial states (in terms of counts_: D and d +%-------------------------------------------------------------------------- +D{1} = [1 1 1]'; % what: {'flee','feed','wait'} +D{2} = [1 0 0 0 0 0 0 0]'; % where: {'start','1',...,'4','flee','feed','wait'} +D{3} = [1 1]'; % flip(ud): {'no','yes'} +D{4} = [1 1]'; % flip(rl): {'no','yes'} + +% probabilistic mapping from hidden states to outcomes: A +%-------------------------------------------------------------------------- +Nf = numel(D); +for f = 1:Nf + Ns(f) = numel(D{f}); +end +No = [6 8]; +Ng = numel(No); +for g = 1:Ng + A{g} = zeros([No(g),Ns]); +end +for f1 = 1:Ns(1) + for f2 = 1:Ns(2) + for f3 = 1:Ns(3) + for f4 = 1:Ns(4) + + % location of cues for this hidden state + %---------------------------------------------------------- + if f1 == 1, a = {'bird','cat' ;'null','null'}; end + if f1 == 2, a = {'bird','seed';'null','null'}; end + if f1 == 3, a = {'bird','null';'null','seed'}; end + + % flip cues according to hidden (invariants) states + %---------------------------------------------------------- + if f3 == 2, a = flipud(a); end + if f4 == 2, a = fliplr(a); end + + % what: A{1} {'null','bird,'seed','cat','right','wrong'} + %========================================================== + if f2 == 1 + + % at fixation location + %---------------------------------------------------------- + A{1}(1,f1,f2,f3,f4) = true; + + elseif f2 > 1 && f2 < 6 + + % saccade to cue location + %---------------------------------------------------------- + A{1}(1,f1,f2,f3,f4) = strcmp(a{f2 - 1},'null'); + A{1}(2,f1,f2,f3,f4) = strcmp(a{f2 - 1},'bird'); + A{1}(3,f1,f2,f3,f4) = strcmp(a{f2 - 1},'seed'); + A{1}(4,f1,f2,f3,f4) = strcmp(a{f2 - 1},'cat'); + + elseif f2 > 5 + + % saccade choice location + %------------------------------------------------------ + A{1}(5,f1,f2,f3,f4) = (f2 - 5) == f1; + A{1}(6,f1,f2,f3,f4) = (f2 - 5) ~= f1; + + end + + % where: A{2} {'start','1',...,'4','flee','feed','wait'} + %---------------------------------------------------------- + A{2}(f2,f1,f2,f3,f4) = 1; + + end + end + end +end +for g = 1:Ng + A{g} = double(A{g}); +end + +% controlled transitions: B{f} for each factor +%-------------------------------------------------------------------------- +for f = 1:Nf + B{f} = eye(Ns(f)); +end + +% controllable fixation points: move to the k-th location +%-------------------------------------------------------------------------- +for k = 1:Ns(2) + B{2}(:,:,k) = 0; + B{2}(k,:,k) = 1; +end + +% plus a bespoke state action (reading) policy +%-------------------------------------------------------------------------- +B{2}(:,:,end + 1) = [ ... + 0 0 0 0 1 1 1 1 + 1 0 0 0 0 0 0 0 + 0 1 0 0 0 0 0 0 + 0 0 1 0 0 0 0 0 + 0 0 0 1 0 0 0 0 + 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0]; + + +% allowable policies (here, specified as the next action) U +%-------------------------------------------------------------------------- +Np = size(B{2},3); +U = ones(1,Np,Nf); +U(:,:,2) = 1:Np; + + +% priors over policies (with a slight preference for reading) +%-------------------------------------------------------------------------- +E = ones(Np,1); +E(end) = 1 + 1/8; + + +% priors: (utility) C +%-------------------------------------------------------------------------- +T = 5; +C{1} = zeros(6,T); +C{2} = zeros(8,T); + +% patterns of preferences +%-------------------------------------------------------------------------- +C{1}(5,:) = 1; % the agent expects to be right +C{1}(6,:) = -2; % and not wrong +C{2}(1:5,3) = -1; % make tardy sampling costly +C{2}(1:5,4) = -2; % make tardy sampling costly +C{2}(1:5,5) = -3; % make tardy sampling costly + +% scale by parameters +%-------------------------------------------------------------------------- +C{1} = C{1}*exp(pE.C(1)); +C{2} = C{2}*exp(pE.C(2)); + + +% MDP Structure +%========================================================================== +MDP.T = T; % number of moves +MDP.U = U; % allowable policies +MDP.A = A; % observation model +MDP.B = B; % transition probabilities +MDP.C = C; % preferred outcomes +MDP.D = D; % prior over initial states +MDP.E = E; % prior over initial states +MDP.s = [1 1 1 1]'; % initial state (flee) +MDP.o = [1 1]'; % initial outcome + +MDP.Aname = {'what','where'}; +MDP.Bname = {'what','where','flip','flip'}; + +% alpha +%-------------------------------------------------------------------------- +MDP.alpha = exp(pE.alpha); diff --git a/toolbox/DEM/DEM_demo_MDP_maze.m b/toolbox/DEM/DEM_demo_MDP_maze.m index 60a01cdc..96124f22 100644 --- a/toolbox/DEM/DEM_demo_MDP_maze.m +++ b/toolbox/DEM/DEM_demo_MDP_maze.m @@ -1,5 +1,5 @@ function MDP = DEM_demo_MDP_maze -% Demo of active inference for trust games +% Demo of active inference for epistemic foraging %__________________________________________________________________________ % % This routine uses the Markov decision process formulation of active @@ -37,7 +37,7 @@ % Copyright (C) 2005 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: DEM_demo_MDP_maze.m 6235 2014-10-12 10:03:05Z karl $ +% $Id: DEM_demo_MDP_maze.m 6975 2016-12-18 20:27:00Z karl $ % set up and preliminaries %========================================================================== diff --git a/toolbox/DEM/DEM_demo_MDP_search.m b/toolbox/DEM/DEM_demo_MDP_search.m index e7cdcae8..6a2fde63 100644 --- a/toolbox/DEM/DEM_demo_MDP_search.m +++ b/toolbox/DEM/DEM_demo_MDP_search.m @@ -30,7 +30,7 @@ % Copyright (C) 2005 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: DEM_demo_MDP_search.m 6848 2016-07-30 10:36:29Z karl $ +% $Id: DEM_demo_MDP_search.m 6938 2016-11-20 12:48:07Z karl $ % set up and preliminaries %========================================================================== @@ -155,9 +155,7 @@ C{2} = zeros(No(2),T); C{1}(5,:) = 2; % the agent expects to be right C{1}(6,:) = -4; % and not wrong - -% C{2} = zeros(8,6); % priors for a speedy reaction time -% C{2}(1:5,4:end) = -4; % make tardy sampling costly +C{2}(1:5,4:end) = -4; % make tardy sampling costly % MDP Structure - this will be used to generate arrays for multiple trials diff --git a/toolbox/DEM/DEM_evidence_accumulation.m b/toolbox/DEM/DEM_evidence_accumulation.m index 5ddb2bfe..102dc5ff 100644 --- a/toolbox/DEM/DEM_evidence_accumulation.m +++ b/toolbox/DEM/DEM_evidence_accumulation.m @@ -1,151 +1,90 @@ -function DEM_evidence_accumulation +function DEM = DEM_evidence_accumulation % Saccadic eye movements under active inference: %__________________________________________________________________________ -% This demo illustrates exploration or visual search in terms of optimality -% principles based on straightforward ergodic or allostatic principles. -% In other words, to maintain the constancy of our external milieu, it is -% sufficient to expose ourselves to predicted and predictable stimuli. -% Being able to predict what is currently seen also enables us to predict -% fictive sensations that we will experience from another viewpoint. This -% provides a principled way in which to explore and sample the world for -% example with visual searches using saccadic eye movements. These -% theoretical considerations are remarkably consistent with a number -% of compelling heuristics; most notably the Infomax principle or the -% principle of minimum redundancy, signal detection theory and recent -% formulations of salience in terms of Bayesian surprise. The example -% here uses saliency (the posterior precision associated with fictive -% sampling of sensory data) to simulate saccadic eye movements under -% active inference. +% This demo illustrates evidence accumulation (and responses) using a very +% simple generative model. In this model, there are three hidden states +% corresponding to right motion, no motion and left motion – as registered +% uniformly over 16 visual channels. Motion is slowly introduced, which +% moves the hidden states to one of the unstable fixed points; thereby +% inducing proprioceptive predictions that cause a motor response. The +% generative model is as minimal as possible and is based on generalised +% Lotka-Volterra dynamics to emulate a dynamic form of winner takes all. In +% other words, the only prior beliefs of this generative model are that the +% world can be in one of a number of (unstable) states. Evidence is +% accumulated slowly because the input is noisy (and is assigned a low +% precision). This reveals the evidence accumulation dynamics that drive +% action, when inference is sufficiently confident. These dynamics are +% formally equivalent to the race or drift diffusion dynamics in normative +% (descriptive) formulations of evidence accumulation. %__________________________________________________________________________ % Copyright (C) 2011 Wellcome Trust Centre for Neuroimaging - + % Karl Friston -% $Id: DEM_evidence_accumulation.m 6587 2015-11-02 10:29:49Z karl $ - - +% $Id: DEM_evidence_accumulation.m 7176 2017-09-26 19:02:39Z karl $ + + % hidden causes and states %========================================================================== % x - hidden states: -% o(1) - oculomotor angle -% o(2) - oculomotor angle -% x(1) - relative amplitude of visual hypothesis 1 -% x(2) - relative amplitude of visual hypothesis 2 -% x(3) - ... +% x(1) - log likelihood of hypothesis 1 (e.g. moving right) +% x(2) - log likelihood of hypothesis 2 (e.g. not moving) +% x(3) - log likelihood of hypothesis 3 (e.g. moving left) % -% v - hidden causes +% v - hidden causes (none for model and moving left for process) % % g - sensations: -% g(1) - oculomotor angle (proprioception - x) -% g(2) - oculomotor angle (proprioception - y) +% g(1) - looking to the left (proprioception) % g(3) - retinal input - channel 1 % g(4) - retinal input - channel 2 % g(5) - ... %-------------------------------------------------------------------------- - - + + % generative model %========================================================================== M(1).E.s = 1/2; % smoothness -M(1).E.n = 4; % order of +M(1).E.n = 3; % order of M(1).E.d = 1; % generalised motion - -% level 1: Displacement dynamics and mapping to sensory/proprioception + +% level 1: mmulti-stable dynamics generating signal over all channels %-------------------------------------------------------------------------- -M(1).f = inline('([1 - sum(exp(x)) - (x + log(3))/32 - [0; 1; 0]*v])/32','x','v','P'); -M(1).g = inline('[ [-1 0 1]*spm_phi(16*(exp(x) - 1)); [-1 0 1]*exp(x) + zeros(16,1)]','x','v','P'); +M(1).f = @(x,v,P)(1 - sum(exp(x)) - (x + log(3))/32)/64; +M(1).g = @(x,v,P)[[-1 0 1]*spm_phi(16*(exp(x) - 1)); [-1 0 1]*exp(x) + zeros(16,1)]; M(1).x = -log(3)*[1; 1; 1]; % hidden states M(1).V = [0 (zeros(1,16) + exp(-4))]; % error precision (g) -M(1).W = exp(32); % error precision (f) -% M(1).xP = exp(2); % error precision (f) - -% level 2: -%-------------------------------------------------------------------------- -M(2).v = 0; % priors -M(2).V = exp(8); - - +M(1).W = exp(8); % error precision (f) + + % generative process %========================================================================== - - + % first level %-------------------------------------------------------------------------- -G(1).g = inline('[a; v + zeros(16,1)]','x','v','a','P'); -G(1).V = [exp(8) zeros(1,16) + exp(-2)]; % error precision -G(1).U = [1 zeros(1,16)]; % motor gain - +G(1).g = @(x,v,a,P)[a; v + zeros(16,1)]'; +G(1).V = [exp(8) zeros(1,16) + exp(2)]; % error precision +G(1).U = [exp(0) zeros(1,16)]; % motor gain + % second level %-------------------------------------------------------------------------- G(2).v = 0; % exogenous forces G(2).a = 0; % action forces G(2).V = exp(16); - - + + % generate and invert %========================================================================== N = 32; % length of data sequence -pst = (1:N); % perstimulus time (bins) - +pst = (1:N); % peristimulus time (bins) + DEM.G = G; DEM.M = M; -DEM.C = spm_phi(((1:N) - N/4)*32/N); -DEM.U = sparse(1,N); - -DEM = spm_ADEM(DEM); +DEM.C = spm_phi(((1:N) - N/4)*32/N); % stimulus motion + +DEM = spm_ADEM(DEM); spm_DEM_qU(DEM.qU,DEM.pU) - + +% plot exponential transform of posterior estimates of hidden states +%-------------------------------------------------------------------------- subplot(2,2,2) -spm_plot_ci(DEM.qU.x,DEM.qU.S,pst,3,'exp'), hold on -plot(pst,exp(DEM.qU.x{1}),'LineWidth',1), hold off -axis([1 N 0 2]) -axis square - - - - - - - -return - - - - % (k) trial - %---------------------------------------------------------------------- - for k = 1:8 - - % solve and save saccade - %------------------------------------------------------------------ - DEM = spm_ADEM(DEM); - DEM = spm_ADEM_update(DEM); - - % overlay true values - %------------------------------------------------------------------ - spm_DEM_qU(DEM.qU,DEM.pU) - - % compute salience - %------------------------------------------------------------------ - [S L] = spm_salience_map(DEM.M,nr); - - % optimise prior belief - %------------------------------------------------------------------ - S = (S - min(S)).*(1 - R); - [i j] = max(S); - DEM.U = L(:,j)*ones(1,N); - DEM.S = reshape(S,nr,nr); - - % inhibition of return (IOR) - %------------------------------------------------------------------ - D = exp(-sum((L - L(:,j)*ones(1,nr*nr)).^2)/(2*s*s))'; - R = a*R + D; - - % store - %------------------------------------------------------------------ - ADEM{k} = DEM; - - end - - % save - %---------------------------------------------------------------------- - save ADEM_saccades ADEM - +spm_plot_ci(DEM.qU.x{1},DEM.qU.S,pst,(1:3),'exp'), hold on +axis([1 N 0 2]), axis square diff --git a/toolbox/DEM/DEM_morphogenesis.m b/toolbox/DEM/DEM_morphogenesis.m index a0f95665..5f603b68 100644 --- a/toolbox/DEM/DEM_morphogenesis.m +++ b/toolbox/DEM/DEM_morphogenesis.m @@ -23,7 +23,7 @@ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: DEM_morphogenesis.m 6801 2016-05-29 19:18:06Z karl $ +% $Id: DEM_morphogenesis.m 7145 2017-07-31 13:57:39Z karl $ % preliminaries @@ -35,7 +35,7 @@ % generative process and model %========================================================================== -M(1).E.d = 2; % approximation order +M(1).E.d = 1; % approximation order M(1).E.n = 2; % embedding order M(1).E.s = 1; % smoothness diff --git a/toolbox/DEM/DEM_self_MI_a.m b/toolbox/DEM/DEM_self_MI_a.m new file mode 100644 index 00000000..ad372383 --- /dev/null +++ b/toolbox/DEM/DEM_self_MI_a.m @@ -0,0 +1,337 @@ +function DEM_self_MI_a +%-------------------------------------------------------------------------- +% Routine to produce graphics illustrating self relative entropy or mutual +% information. A low self mutual information induces anomalous diffusion +% and itinerancy with power law scaling (i.e., self similar dynamics). This +% example uses a fixed form (quadratic) likelihood and optimises the density +% over over hidden states to minimise self mutual information explicitly. +% +% In this example where is just one Markov blanket states and one hidden +% state to illustrate noise phase symmetry breaking as self mutual +% information decreases. The subroutines illustrate the relationship +% between self mutual information, intrinsic mutual information and +% extrinsic cost. + + +% set up +%-------------------------------------------------------------------------- +rng('default'), clf + +n = 64; % number of bins +S = (1:n)'/n; % domain of states +dt = 1; % time step for solution +N = 16; % 2^N solution + +% likelihood – mapping from hidden states to sensory states - A +%-------------------------------------------------------------------------- +v = @(s) ((s*3/2).^2)/512 + 1/512; +m = @(s) ((s - 1/2)*3/2).^2 + 1/8; +for i = 1:n + for j = 1:n + A(:,j) = exp(-(S - m(j/n)).^2/v(j/n)); + end +end +A = A/diag(sum(A)); % likelihood +lnpH = log(hanning(n))/2; % hidden states) + +% subroutine to illustrate the decomposition of (relative) self entropy +%========================================================================== +% spm_G_check(A,lnpH); + +% progressively optimise mutual information w.r.t. hidden states +%========================================================================== +ni = [1 7 8]; % batches of iterations +for g = 1:3 + for i = 1:ni(g) + + % evaluate self entropy for current hidden states + %------------------------------------------------------------------ + [G,Gi,Ge] = spm_G(A,lnpH); + + % evaluate joint density and marginals + %------------------------------------------------------------------ + pH = spm_softmax(lnpH); + pS = A*pH; + pSxH = A*diag(pH); + pSxH = pSxH/sum(sum(pSxH)); + + % mutual informations + %------------------------------------------------------------------ + MIi(g) = pS'*Gi; + MIe(g) = pS'*Ge; + MI3(g) = pS'*G ; + H(g) = pS'*(-log(pS)); + C(g) = H(g) - MI3(g); + + % Optimise marginal w.r.t. second-order mutual information + %------------------------------------------------------------------ + % dp = spm_diff(@spm_MI2,A,lnpH,2); + + % Optimise marginal w.r.t. third-order mutual information + %------------------------------------------------------------------ + dp = spm_diff(@spm_MI3,A,lnpH,2); + + % update marginal over hidden states + %------------------------------------------------------------------ + lnpH = log(spm_softmax(lnpH + dp(:)*8)); + + % graphics + %------------------------------------------------------------------ + subplot(3,2,1), imagesc(1 - A) + title('Likelihood','FontSize',16) + xlabel('Hidden states'), ylabel('Blanket states') + axis square, axis xy + + subplot(3,2,2), bar([MIe;MIi;H;C;MI3]') + title('Mutual information','FontSize',16) + xlabel('Iteration'),ylabel('Mutual information') + axis square, axis xy, + legend({'extrinsic','intrinsic','entropy','conditional','self-entropy'}) + set(gca,'XTickLabel',ni) + + subplot(3,3,g + 3), imagesc(1 - pSxH) + j = sum(ni(1:(g - 1))) + i; + title(sprintf('Iteration %i',j),'FontSize',16) + xlabel('Hidden states'), ylabel('Blanket states') + axis square, axis xy + + hold on + tS = spm_softmax(-G); + plot(pH*n*n/8,'k') + plot(pS*n*n/8,(1:n),'r') + plot(tS*n*n/8,(1:n),'r:') + hold off + drawnow + + end + + % illustrate dynamics + %====================================================================== + + % flow + %---------------------------------------------------------------------- + G = eye(2,2); % amplitude of random fluctuations + Q = [0 -1;1 0]/4; % solenoidal flow + [gh,gs] = gradient(log(pSxH)); % gradients + f = [gh(:),gs(:)]*(G - Q); % flow + fh = spm_unvec(f(:,1),gh); + fs = spm_unvec(f(:,2),gs); + [gi,gj] = meshgrid(1:n,1:n); + i = 1:8:n; + + subplot(3,2,5), hold off, quiver(gi(i,i),gj(i,i),fh(i,i),fs(i,i),'k') + title('Flow and trajectories','FontSize',16) + xlabel('Hidden states'), ylabel('Blanket states') + axis square, axis xy + + + % solve for a particular trajectory + %---------------------------------------------------------------------- + [~,k] = max(pSxH(:)); + [p,q] = ind2sub([n,n],k); + x = [q;p]; + for t = 1:(2^N) + x(:,t) = max(1,min(n,x(:,t))); + k = sub2ind([n,n],round(x(2,t)),round(x(1,t))); + dx = f(k,:)' + sqrt(G/2)*randn(2,1); + x(:,t + 1) = x(:,t) + dx*dt; + end + + % illustrate power law scaling + %---------------------------------------------------------------------- + s = abs(fft(x(1,:)')).^2; + w = (1:2^12)'; + W = w; + S = s(w + 1); + + S = decimate(log(S),N - 4); + W = log(decimate(W,N - 4)); + X = [ones(size(W)),W]; + + % plot part of trajectory + %---------------------------------------------------------------------- + [~,i] = max(abs(diff(spm_conv(x(1,:),2^(N - 8))))); + nn = 2^10; + i = (-nn:nn) + i; + i = i(i > 0 & i < size(x,2)); + hold on, plot(x(1,i),x(2,i),'b'), hold off + axis([1,n,1,n]),drawnow + + % estimate exponent (alpha) + %---------------------------------------------------------------------- + [~,~,beta] = spm_ancova(X,[],S,[0;1]); + + % plot + %---------------------------------------------------------------------- + if g == 3 + subplot(3,2,6), plot(W,S,'b.',W,X*beta,'b','LineWidth',1) + elseif g == 1 + subplot(3,2,6), plot(W,S - 2,'c.'), hold on + else + subplot(3,2,6), plot(W,S - 4,'m.'), hold on + end + title(sprintf('alpha = %-2.2f',beta(2)),'FontSize',16) + ylabel('Log power'), xlabel('Log frequency') + axis square, axis xy, spm_axis tight + +end + +return + +% subroutines +%========================================================================== + +function [G,Gi,Ge] = spm_G(A,lnpH) +% FORMAT [G,Gi,Ge] = spm_G(A,lnpH) +% G = Ge - Gi % self entropy (extrinsic cost - intrinsic MI) +% E[Gi] = I(H,S'|S) % conditional MI +% E[Ge] = I(H,S) % (second-order) MI +% E[G] = I(H,S',S) % (third order) MI + +% evaluate marginal over hidden states +%-------------------------------------------------------------------------- +n = size(A,2); +pH = spm_softmax(lnpH); + +% evaluate joint density and posterior +%-------------------------------------------------------------------------- +pSxH = A*diag(pH); +pSxH = pSxH/sum(sum(pSxH)); +pHS = pSxH'/diag(sum(pSxH,2) + eps); + +% entropies and probabilities +%-------------------------------------------------------------------------- +for j = 1:n + ph = pHS(:,j); + ps = A*ph; + psxh = A*diag(ph); + psxh = psxh/sum(sum(psxh)); + psxh = psxh(:); + + % intrinsic MI minus KL (extrinsic cost) + %---------------------------------------------------------------------- + Gi(j,1) = psxh'*log(psxh + eps) - ps'*log(ps) - ph'*log(ph); + Ge(j,1) = ph'*(log(ph) - log(pH)); +end + +% self entropy +%-------------------------------------------------------------------------- +G = Ge - Gi; + +return + +function MI2 = spm_MI2(A,lnpH) + +% evaluate marginal over hidden states +%-------------------------------------------------------------------------- +pH = spm_softmax(lnpH); +pS = A*pH; + +% evaluate joint density and posterior +%-------------------------------------------------------------------------- +pSxH = A*diag(pH); +pSxH = pSxH/sum(sum(pSxH)); + +% second-order mutual information +%-------------------------------------------------------------------------- +pSxH = pSxH(:); +MI2 = pSxH'*log(pSxH + eps) - pS'*log(pS) - pH'*log(pH); + +return + +function MI3 = spm_MI3(A,lnpH) + +% evaluate marginal over hidden states +%-------------------------------------------------------------------------- +pH = spm_softmax(lnpH); +pS = A*pH; + +% (negative) third order (self) mutual information +%-------------------------------------------------------------------------- +MI3 = - pS'*spm_G(A,lnpH); + + +function [G,Gi,Ge] = spm_G_check(A,lnpH) +% FORMAT [G,Gi,Ge] = spm_G(A,lnpH) +% A - likelihhod p(S|H) +% pnpH - log prior log(p(H)) +% +% G = Ge - Gi % self entropy (extrinsic cost - intrinsic MI) +% E[Gi] = I(H,S'|S) % conditional MI +% E[Ge] = I(H,S) % (second-order) MI +% E[G] = I(H,S',S) = I(S,S') % (third order) MI = self entropy + +% evaluate marginal over hidden states +%-------------------------------------------------------------------------- +n = size(A,2); +pH = spm_softmax(lnpH); + +% evaluate joint density and posterior +%-------------------------------------------------------------------------- +pSxH = A*diag(pH); +pSxH = pSxH/sum(sum(pSxH)); +pHS = pSxH'/diag(sum(pSxH,2) + eps); +pS = sum(pSxH,2); + +% entropies and probabilities +%-------------------------------------------------------------------------- +for j = 1:n + ph = pHS(:,j); + ps = A*ph; + psxh = A*diag(ph); + psxh = psxh/sum(sum(psxh)); + psxhxS(:,:,j) = psxh*pS(j); + + % intrinsic MI minus KL (extrinsic cost) + %---------------------------------------------------------------------- + Gi(j,1) = psxh(:)'*log(psxh(:) + eps) - ps'*log(ps) - ph'*log(ph); + Ge(j,1) = ph'*(log(ph) - log(pH)); + + Gp(j,1) = ps'*log(ps) + ph'*log(ph) + ph'*log(ph)... + - psxh(:)'*log(psxh(:)) - ph'*log(pH); + Gp(j,1) = ps'*log(ps) + ph'*log(ph) - psxh(:)'*log(pSxH(:)); + +end + +% self entropy and its various forms +%-------------------------------------------------------------------------- +G = Ge - Gi; + +% intrinsic and extrinsic expected surprises (and prior) +%-------------------------------------------------------------------------- +IsHIS = Gi'*pS; +IHS = Ge'*pS; +IsHS = G'*pS; + +% underlying probability distributions +%-------------------------------------------------------------------------- +psxh = squeeze(sum(psxhxS,3)); +psxS = squeeze(sum(psxhxS,2)); +pHxS = squeeze(sum(psxhxS,1)); +ps = sum(psxh,2); + +% and entropies +%-------------------------------------------------------------------------- +HsHS = -psxhxS(:)'*log(psxhxS(:)); +HS = -pS'*log(pS); +Hs = -ps'*log(ps); +HH = -pH'*log(pH); +HsH = -psxh(:)'*log(psxh(:)); +HsS = -psxS(:)'*log(psxS(:)); +HHS = -pHxS(:)'*log(pHxS(:)); + +% equivalent formulation of self entropy in terms of entropy +%-------------------------------------------------------------------------- +I3 = HsHS + Hs + HH + HS - HsH - HHS - HsS; +I3 = Hs + HS - HsS; +HsHS = HsH + HHS - HH; + +subplot(3,1,1) +bar([IsHIS IHS IsHS 0 HS (HsS - HS) I3]) +str = {'I(H,s|S)','I(H,S)','I(S,s)',' ','H(s)','H(s|S)','I(S,s)'}; +set(gca,'XTickLabel',str) +title('Self entropy and information') + +return + + diff --git a/toolbox/DEM/DEM_self_MI_b.m b/toolbox/DEM/DEM_self_MI_b.m new file mode 100644 index 00000000..9091aacd --- /dev/null +++ b/toolbox/DEM/DEM_self_MI_b.m @@ -0,0 +1,221 @@ +function DEM_self_MI_b +%-------------------------------------------------------------------------- +% Routine to produce graphics illustrating self relative entropy or mutual +% information. A low self mutual information induces anomalous diffusion +% and itinerancy with power law scaling (i.e., self similar dynamics). This +% example reduces the KL divergence between a density with low expected +% self entropy and the density produced by hidden states. +% +% In this example where is just one Markov blanket states and one hidden +% state to illustrate noise phase symmetry breaking as self mutual +% information decreases. The subroutines illustrate the relationship +% between self mutual information, intrinsic mutual information and +% extrinsic cost. + +% set up +%-------------------------------------------------------------------------- +rng('default'), clf + +n = 64; % number of bins +S = (1:n)'/n; % domain of states +dt = 1; % time step for solution +N = 20; % 2^N solution + +% likelihood – mapping from hidden states to sensory states - A +%-------------------------------------------------------------------------- +v = @(s) ((1 - s).^2)/32 + 1/512; +m = @(s) s.^2 + 1/8; +for i = 1:n + for j = 1:n + A(:,j) = exp(-(S - m(j/n)).^2/v(j/n)); + end +end +A = A/diag(sum(A)); % likelihood + +% initial probability density over hidden states +%-------------------------------------------------------------------------- +lnpH = log(hanning(n))*2; + +% progressively optimise mutual information w.r.t. hidden states +%========================================================================== +ni = [1 7 8]; % number of iterations (batches) +for g = 1:3 + for i = 1:ni(g) + + % evaluate self mutual information for current hidden states + %------------------------------------------------------------------ + [G,Gi,Ge] = spm_G(A,lnpH); + + % evaluate joint density and marginals + %------------------------------------------------------------------ + pH = spm_softmax(lnpH); + pS = A*pH; + pSxH = A*diag(pH); + pSxH = pSxH/sum(sum(pSxH)); + + % mutual informations + %------------------------------------------------------------------ + MIi(g) = pS'*Gi; + MI2(g) = pS'*Ge; + MI3(g) = G; + H(g) = pS'*(-log(pS)); + + % Optimise marginal w.r.t. KL divergence + %------------------------------------------------------------------ + dp = spm_diff(@spm_KL,A,lnpH,2); + + % update marginal over hidden states + %------------------------------------------------------------------ + lnpH = log(spm_softmax(lnpH + dp(:)*16)); + + + % graphics + %================================================================== + subplot(3,2,1), imagesc(1 - A) + title('Likelihood','FontSize',16) + xlabel('Hidden states'), ylabel('Blanket states') + axis square, axis xy + + subplot(3,2,2), bar([MIi;MI2;MI3;H]') + title('Mutual information','FontSize',16) + xlabel('Iteration'),ylabel('Mutual information') + axis square, axis xy, legend({'iMI','MI2','MI3','H'}) + set(gca,'XTickLabel',ni) + + subplot(3,3,g + 3), imagesc(1 - pSxH) + j = sum(ni(1:(g - 1))) + i; + title(sprintf('Iteration %i',j),'FontSize',16) + xlabel('Hidden states'), ylabel('Blanket states') + axis square, axis xy + + hold on + tS = spm_softmax((Gi - Ge)*4); + plot(pH*n*n/8,'k') + plot(pS*n*n/8,(1:n),'r') + plot(tS*n*n/8,(1:n),'r:') + hold off + drawnow + + end + + % illustrate dynamics + %====================================================================== + + % flow + %---------------------------------------------------------------------- + G = eye(2,2); % amplitude of random fluctuations + Q = [0 -1;1 0]/4; % solenoidal flow + [gh,gs] = gradient(log(pSxH)); % gradients + f = [gh(:),gs(:)]*(G - Q); % flow + fh = spm_unvec(f(:,1),gh); + fs = spm_unvec(f(:,2),gs); + [gi,gj] = meshgrid(1:n,1:n); + i = 1:8:n; + + subplot(3,2,5), hold off, quiver(gi(i,i),gj(i,i),fh(i,i),fs(i,i),'k') + title('Flow and trajectories','FontSize',16) + xlabel('Hidden states'), ylabel('Blanket states') + axis square, axis xy + + + % solve for a particular trajectory + %---------------------------------------------------------------------- + [~,k] = max(pSxH(:)); + [p,q] = ind2sub([n,n],k); + x = [q;p]; + for t = 1:(2^N) + x(:,t) = max(1,min(n,x(:,t))); + k = sub2ind([n,n],round(x(2,t)),round(x(1,t))); + dx = f(k,:)' + sqrt(G/2)*randn(2,1); + x(:,t + 1) = x(:,t) + dx*dt; + end + + % illustrate power law scaling + %---------------------------------------------------------------------- + s = abs(fft(x(1,:)')).^2; + w = (1:2^12)'; + W = w; + S = s(w + 1); + + S = decimate(log(S),N - 4); + W = log(decimate(W,N - 4)); + X = [ones(size(W)),W]; + + % plot part of trajectory + %---------------------------------------------------------------------- + [~,i] = max(abs(diff(spm_conv(x(1,:),2^(N - 8))))); + nn = 2^10; + i = (-nn:nn) + i; + i = i(i > 0 & i < size(x,2)); + hold on, plot(x(1,i),x(2,i),'b'), hold off + axis([1,n,1,n]),drawnow + + % estimate exponent (alpha) + %---------------------------------------------------------------------- + [~,~,beta] = spm_ancova(X,[],S,[0;1]); + + % plot + %---------------------------------------------------------------------- + if g == 3 + subplot(3,2,6), plot(W,S,'b.',W,X*beta,'b','LineWidth',1) + elseif g == 1 + subplot(3,2,6), plot(W,S - 2,'c.'), hold on + else + subplot(3,2,6), plot(W,S - 4,'m.'), hold on + end + title(sprintf('alpha = %-2.2f',beta(2)),'FontSize',16) + ylabel('Log power'), xlabel('Log frequency') + axis square, axis xy, spm_axis tight + +end + +return + + +function [I3,Gi,Ge] = spm_G(A,lnpH) +% target distribution: intrinsic MI minus KL +% G = Ge - Gi +% E[Gi] = I(H,S'|S) +% E[Ge] = I(H,S) +% E[G] = I(H,S',S) + +% evaluate marginals and joint density +%-------------------------------------------------------------------------- +n = size(A,2); +pH = spm_softmax(lnpH); +pS = A*pH; +pSxH = A*diag(pH); +pSxH = pSxH/sum(sum(pSxH)); +pHS = pSxH'/diag(sum(pSxH,2) + eps); + + +% entropies and probabilities +%-------------------------------------------------------------------------- +for j = 1:n + ph = pHS(:,j); + ps = A*ph; + psxh = A*diag(ph); + psxh = psxh/sum(sum(psxh)); + psxh = psxh(:); + + % intrinsic MI minus KL + %---------------------------------------------------------------------- + Gi(j,1) = psxh'*log(psxh + eps) - ps'*log(ps) - ph'*log(ph); + Ge(j,1) = ph'*(log(ph) - log(pH)); +end +I3 = pS'*(Ge - Gi); + +return + + +function G = spm_KL(A,lnpH) + +% KL divergence between density over blanket states spm_softmax((Gi - Ge)) +%-------------------------------------------------------------------------- +pH = spm_softmax(lnpH); +lnpH = log(pH); +[G,Gi,Ge] = spm_G(A,lnpH); +pS = spm_softmax((Gi - Ge)); +G = pS'*(log(pS) - log(A*pH)); + + diff --git a/toolbox/DEM/DEM_self_MI_c.m b/toolbox/DEM/DEM_self_MI_c.m new file mode 100644 index 00000000..5011284c --- /dev/null +++ b/toolbox/DEM/DEM_self_MI_c.m @@ -0,0 +1,221 @@ +function DEM_self_MI_c +%-------------------------------------------------------------------------- +% Routine to produce graphics illustrating self relative entropy or mutual +% information. A low self mutual information induces anomalous diffusion +% and itinerancy with power law scaling (i.e., self similar dynamics). This +% example uses a fixed fixed format marginal over hidden states (with a +% Hanning window) and optimises the likelihood mapping. +% +% In this example where is just one Markov blanket states and one hidden +% state to illustrate noise phase symmetry breaking as self mutual +% information decreases. The subroutines illustrate the relationship +% between self mutual information, intrinsic mutual information and +% extrinsic cost. + +% set up +%-------------------------------------------------------------------------- +rng('default'), clf + +n = 64; % number of bins +S = (1:n)'/n; % domain of states +dt = 1; % time step for solution +N = 20; % 2^N solution + +% likelihood – mapping from hidden states to sensory states - A +%-------------------------------------------------------------------------- +v = @(s) ((s*3/2).^2)/256 + 1/512; +m = @(s) ((s - 1/2)*3/2).^2 + 1/8; +for i = 1:n + for j = 1:n + A(:,j) = exp(-(S - m(j/n)).^2/v(j/n)); + end +end +A = A/diag(sum(A)); % likelihood +pH = spm_softmax(log(hanning(n))); % marginal over hidden states +lnpH = log(pH); +lnA = log(A); + + +% progressively optimise mutual information w.r.t. hidden states +%========================================================================== +ni = [1 7 8]; +for g = 1:3 + for i = 1:ni(g) + + % evaluate high order mutual information for current hidden states + %------------------------------------------------------------------ + [~,Gi,Ge] = spm_G(lnA,lnpH); + + % Optimise marginal w.r.t. third order mutual information + %------------------------------------------------------------------ + dp = spm_diff(@spm_G,lnA,lnpH,1); + + % update marginal over hidden states + %------------------------------------------------------------------ + lnA(:) = log(spm_softmax(lnA(:) + dp(:)*128)); + + % evaluate joint density and marginals + %------------------------------------------------------------------ + A = spm_softmax(lnA); + pS = A*pH; + pSxH = A*diag(pH); + pSxH = pSxH/sum(sum(pSxH)); + + % mutual informations + %------------------------------------------------------------------ + MIi(g) = pS'*Gi; + MI2(g) = pS'*Ge; + MI3(g) = pS'*(Ge - Gi); + H(g) = pS'*(-log(pS)); + + % graphics + %------------------------------------------------------------------ + subplot(3,2,1), imagesc(1 - A) + title('Likelihood','FontSize',16) + xlabel('Hidden states'), ylabel('Blanket states') + axis square, axis xy + + subplot(3,2,2), bar([MIi;MI2;MI3;H]') + title('Mutual information','FontSize',16) + xlabel('Iteration'),ylabel('Mutual information') + axis square, axis xy, legend({'iMI','MI2','MI3','H'}) + set(gca,'XTickLabel',ni) + + subplot(3,3,g + 3), imagesc(1 - pSxH) + j = sum(ni(1:(g - 1))) + i; + title(sprintf('Iteration %i',j),'FontSize',16) + xlabel('Hidden states'), ylabel('Blanket states') + axis square, axis xy + + hold on + tS = spm_softmax((Gi - Ge)); + plot(pH*n*n/8,'k') + plot(pS*n*n/8,(1:n),'r') + plot(tS*n*n/8,(1:n),'r:') + hold off + drawnow + + % convergence + %------------------------------------------------------------------ + if norm(dp,'inf') < 1e-4, break, end + + + + end + + % illustrate dynamics + %====================================================================== + + % flow + %---------------------------------------------------------------------- + G = eye(2,2); % amplitude of random fluctuations + Q = [0 -1;1 0]/4; % solenoidal flow + [gh,gs] = gradient(log(pSxH)); % gradients + f = [gh(:),gs(:)]*(G - Q); % flow + fh = spm_unvec(f(:,1),gh); + fs = spm_unvec(f(:,2),gs); + [gi,gj] = meshgrid(1:n,1:n); + i = 1:8:n; + + subplot(3,2,5), hold off, quiver(gi(i,i),gj(i,i),fh(i,i),fs(i,i),'k') + title('Flow and trajectories','FontSize',16) + xlabel('Hidden states'), ylabel('Blanket states') + axis square, axis xy + + + % solve for a particular trajectory + %---------------------------------------------------------------------- + [~,k] = max(pSxH(:)); + [p,q] = ind2sub([n,n],k); + x = [q;p]; + for t = 1:(2^N) + x(:,t) = max(1,min(n,x(:,t))); + k = sub2ind([n,n],round(x(2,t)),round(x(1,t))); + dx = f(k,:)' + sqrt(G/2)*randn(2,1); + x(:,t + 1) = x(:,t) + dx*dt; + end + + % illustrate power law scaling + %---------------------------------------------------------------------- + s = abs(fft(x(1,:)')).^2; + w = (1:2^12)'; + W = w; + S = s(w + 1); + + S = decimate(log(S),N - 4); + W = log(decimate(W,N - 4)); + X = [ones(size(W)),W]; + + % plot part of trajectory + %---------------------------------------------------------------------- + [~,i] = max(abs(diff(spm_conv(x(1,:),2^(N - 8))))); + nn = 2^10; + i = (-nn:nn) + i; + i = i(i > 0 & i < size(x,2)); + hold on, plot(x(1,i),x(2,i),'b'), hold off + axis([1,n,1,n]),drawnow + + % estimate exponent (alpha) + %---------------------------------------------------------------------- + [~,~,beta] = spm_ancova(X,[],S,[0;1]); + + % plot + %---------------------------------------------------------------------- + if g == 3 + subplot(3,2,6), plot(W,S,'b.',W,X*beta,'b','LineWidth',1) + elseif g == 1 + subplot(3,2,6), plot(W,S - 2,'c.'), hold on + else + subplot(3,2,6), plot(W,S - 4,'m.'), hold on + end + title(sprintf('alpha = %-2.2f',beta(2)),'FontSize',16) + ylabel('Log power'), xlabel('Log frequency') + axis square, axis xy, spm_axis tight + +end + +return + + +function [MI3,Gi,Ge] = spm_G(lnA,lnpH) +% FORMAT [MI3,Gi,Ge] = spm_G(lnA,lnpH) +% intrinsic MI minus KL +% G = Gi - Ge +% E[Gi] = I(H,S'|S) +% E[Ge] = I(H,S) +% E[G] = I(H,S',S) = MI3 + +% evaluate marginal over hidden states +%-------------------------------------------------------------------------- +n = size(lnA,2); +A = spm_softmax(lnA); +pH = spm_softmax(lnpH); +pS = A*pH; + +% evaluate joint density and posterior +%-------------------------------------------------------------------------- +pSxH = A*diag(pH); +pSxH = pSxH/sum(sum(pSxH)); +pHS = pSxH'/diag(sum(pSxH,2) + eps); + +% entropies and probabilities +%-------------------------------------------------------------------------- +for j = 1:n + ph = pHS(:,j); + ps = A*ph; + psxh = A*diag(ph); + psxh = psxh/sum(sum(psxh)); + psxh = psxh(:); + + % intrinsic MI minus KL + %---------------------------------------------------------------------- + Gi(j,1) = psxh'*log(psxh + eps) - ps'*log(ps) - ph'*log(ph); + Ge(j,1) = ph'*(log(ph) - log(pH)); +end +MI3 = pS'*(Gi - Ge); + +return + + + + diff --git a/toolbox/DEM/DEM_spatial_deconvolution.m b/toolbox/DEM/DEM_spatial_deconvolution.m index 0c1287c8..d526e093 100644 --- a/toolbox/DEM/DEM_spatial_deconvolution.m +++ b/toolbox/DEM/DEM_spatial_deconvolution.m @@ -2,7 +2,7 @@ % FORMAT DEM_spatial_deconvolution %-------------------------------------------------------------------------- % This (toy) demonstration routine illustrates spatiotemporal -% deconvolution of regional responses from imagine time-series. The +% deconvolution of regional responses from imaging time-series. The % generative model assumes the data are generated by a small number of % anatomical parcels that are smoothly displaced. The resulting data are % then convolved spatially with a smoothly varying spatial kernel. The smooth @@ -16,7 +16,7 @@ % Copyright (C) 2010 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: DEM_spatial_deconvolution.m 6432 2015-05-09 12:58:12Z karl $ +% $Id: DEM_spatial_deconvolution.m 6975 2016-12-18 20:27:00Z karl $ % parcellation scheme (U) (make an atlas on the fly) diff --git a/toolbox/DEM/FEP_MB_demo.m b/toolbox/DEM/FEP_MB_demo.m new file mode 100644 index 00000000..be1b760b --- /dev/null +++ b/toolbox/DEM/FEP_MB_demo.m @@ -0,0 +1,492 @@ +function FEP_MB_demo +% This routine illustrates a hierarchical decomposition of Markov blankets +% (of Markov blankets). It rests upon the dual operators of finding a +% partition (a Markov partition) and then using an adiabatic dimensional +% reduction (using the eigensolution of the Markov blanket). In brief, this +% means the states of particles at the next level become mixtures of the +% Markov blanket of particles at the level below. +% +% The ensuing hierarchical decomposition is illustrated in terms of +% Jacobians and locations in a scaling space (evaluated using the graph +% Laplacian). This demonstration uses a fictive Jacobian that is created by +% hand – or the equivalent Jacobian of a synthetic soup (i.e., active +% matter) +% +%__________________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% Karl Friston +% $Id: FEP_MB_demo.m 7176 2017-09-26 19:02:39Z karl $ + +SOUP = 1; +if SOUP + % default settings + %---------------------------------------------------------------------- + rng('default') + + % Demo of synchronization manifold using coupled Lorenz attractors + %====================================================================== + N = 128; % number of (Lorenz) oscillators + T = 512; % number of time bins + dt = 1/32; % time interval + + % parameters + %---------------------------------------------------------------------- + P.k = 1 - exp(-rand(1,N)*4); % variations in temporal scale + P.d = 1/8; % amplitude of random fluctuations + + % states + %---------------------------------------------------------------------- + x.p = randn(2,N)*4; % microstates (position) + x.v = zeros(2,N); % microstates (velocity) + x.q = randn(3,N)/32; % microstates (states) + u = zeros(1,T); % exogenous fluctuations + + + % generate an dynamics from initial conditions + %====================================================================== + spm_figure('GetWin','Markov blanket');clf, subplot(2,1,1) + + [Q,X,V,A,x] = spm_soup(x,u,P,T,dt,1); + j = (T - 64:T); + J = spm_soup(Q(:,:,j),X(:,:,j),V(:,:,j),P); + A = mean(J,3); + + mm = spm_zeros(x); + mm.q(3,:) = 1; + + m = [1 4 1 1]; % number of internal states + jj = cell(4,1); % eligible internal states + jj{1} = spm_vec(mm); % eligible internal states + +else + + % create an adjacency matrix or Jacobian based upon a lattice + %====================================================================== + + % within blanket coupling (intrinsic) + %---------------------------------------------------------------------- + n = 2; + m = 3; + Jii = spm_cat({[], eye(n,n), spm_speye(n,m); + randn(n,n)/8, [], []; + [], spm_speye(m,n), (randn(m,m)/8 - eye(m,m))}); + + + % between blanket coupling (extrinsic) + %---------------------------------------------------------------------- + Jij = spm_cat({[], zeros(n,n), zeros(n,m); + randn(n,n), [], []; + [], zeros(m,n), zeros(m,m)}); + + + % an ensemble of blankets + %---------------------------------------------------------------------- + D = 2; % distance for seperation + N = 8; % size of lattice + [I,J] = ndgrid(1:N,1:N); % locations + for i = 1:numel(I) + for j = 1:numel(J) + d = sqrt( (I(i) - I(j))^2 + (J(i) - J(j))^2 ); + if i == j + A{i,j} = Jii; + elseif d < D + A{i,j} = Jij; + else + A{i,j} = zeros(size(Jij)); + end + end + end + + m = [3 2 1 1]; % number of internal states + jj = cell(4,1); % eligible internal states + +end + +clear J +J{1} = spm_cat(A); +z{1} = num2cell(1:length(J{1})); + + +% hierarchal decomposition +%========================================================================== +N = 3; % number of hierarchical scales +x = {}; % indices of states of partitions +u = {}; % locations of partitions +y = {}; % indices of partitions +for i = 1:N + + % Markov blanket (particular) partition + %---------------------------------------------------------------------- + spm_figure('getwin',sprintf('Markov level %i',i)); + + [x{i},u{i},y{i}] = spm_Markov_blanket(J{i},z{i},m(i),jj{i}); + + % dimension reduction (eliminating internal states) + %---------------------------------------------------------------------- + if i < N + [J{i + 1},z{i + 1}] = spm_A_reduce(J{i},x{i}); + end + + % plot partition (in subordinate embedding dimensions) + %---------------------------------------------------------------------- + if i > 1 + + subplot(3,2,1) + nx = size(x{i},2); + [bol,col,msz] = spm_MB_col(nx); + j = i - 1; + for k = 1:nx + ui = spm_vec(y{j}([1,2],y{i}{1,k})); plot(u{j}(ui,1),u{j}(ui,2),'.','color',bol{k},'MarkerSize',msz), hold on + ui = spm_vec(y{j}([1,2],y{i}{2,k})); plot(u{j}(ui,1),u{j}(ui,2),'.','color',bol{k},'MarkerSize',msz), hold on + ui = spm_vec(y{j}([1,2],y{i}{3,k})); plot(u{j}(ui,1),u{j}(ui,2),'.','color',col{k},'MarkerSize',msz), hold on + end + axis square + title('Blanket states','Fontsize',16) + + end + +end + +return + +% subroutines +%========================================================================== + +% Adiabatic dimension reduction +%========================================================================== +function [J,z,y] = spm_A_reduce(J,x,T) +% FORMAT [J,z,y] = spm_A_reduce(J,x,T) +% reduction of Markovian partition +% J - Jacobian (x) +% x - {3 x n} particular partition of states +% N - relative eigenvalue threshold to retain eigenvectors [default: 4] +% +% J - Jacobian (z) +% z - {1 x n} partition of states at the next level +% y - {1 x n} partition of states at the current level +%__________________________________________________________________________ + +% preliminaries +%-------------------------------------------------------------------------- +nx = size(x,2); % number of partitions +if nargin < 3 + T = 8; % adiabatic threshold +end + +% reduction +%-------------------------------------------------------------------------- +for i = 1:nx + + % Lyapunov exponents (eigensolution) for this partition + %---------------------------------------------------------------------- + y{i} = spm_vec(x(1:2,i)); + Jii = full(J(y{i},y{i})); + [e,s] = eig(Jii); + [d,j] = sort(real(diag(s)),'descend'); + + % Adiabatic threshold + %---------------------------------------------------------------------- + n(i) = sum(d > -T); + v{i} = e(:,j(1:n(i))); + u{i} = pinv(v{i}); + +end +for i = 1:nx + for j = 1:nx + Jij = full(J(spm_vec(x(1:2,i)),spm_vec(x(1:2,j)))); + A{i,j} = u{i}*Jij*v{j}; + end + z{i} = sum(n(1:(i - 1))) + (1:n(i)); +end +J = spm_cat(A); + + +% Markovian partition +%========================================================================== +function [x,u,y] = spm_Markov_blanket(J,z,m,mj) +% FORMAT [x,u,y] = spm_Markov_blanket(J,z,m,mj) +% Markovian partition +% J - Jacobian +% z - {1 x N} partition of states (indices) +% m - number of internal states [default: 3] +% +% x - {3 x n} particular partition of state indices +% x{1,j} - active states of j-th partition +% x{2,j} - sensory states of j-th partition +% x{3,j} - internal states of j-th partition +% +% u - location of partitions in scaling or embedding space +% +% y - {3 x n} particular partition of partition indices +% y{1,j} - active states of j-th partition +% y{2,j} - sensory states of j-th partition +% y{3,j} - internal states of j-th partition +%__________________________________________________________________________ + +% preliminaries +%-------------------------------------------------------------------------- +nz = length(z); % number of partitions +if nargin < 3 + m = 3; % maximum size of internal states +end +if nargin < 4 + mj = ones(nz,1); % eligible internal states +end +if isempty(mj) + mj = ones(nz,1); % eligible internal states +end + + +% Adjacency matrix (over z) +%-------------------------------------------------------------------------- +for i = 1:nz + for j = 1:nz + Lij = J(z{i},z{j}); + if any(any(Lij)) + L(i,j) = abs(norm(full(Lij)) > exp(-16)); + else + L(i,j) = 0; + end + end +end +L = double(L); + +% internal states (defined by graph Laplacian) +%-------------------------------------------------------------------------- +G = L + L'; +G = G - diag(diag(G)); +G = G - diag(sum(G)); +G = expm(G); + +% get principal dimensions of scaling space (X) +%-------------------------------------------------------------------------- +GRAPHICS = 1; +if GRAPHICS + [u,v] = eig(G,'nobalance'); + [v,j] = sort(real(diag(v)),'descend'); + u = u(:,j); + nj = min(32,size(u,2)); + v = v(1:nj); + for i = 1:nj + [p,h] = hist(real(u(:,i))); + dh = h(2) - h(1) + exp(-16); + p = p(:)/sum(p)/dh; + v(i) = log(v(i)) - p'*log(p + exp(-16))*dh; + end + [v,j] = sort(real(v),'descend'); + u = real(u(:,j)); +end + +% get Markov blanket and divide into sensory and active states +%-------------------------------------------------------------------------- +BL = L + L'; +B = BL + L'*L; +BL = BL - diag(diag(BL)); +B = B - diag(diag(B)); +nn = zeros(nz,1); + +% recursive partition +%-------------------------------------------------------------------------- +nm = spm_find_internal(z,J); +for i = 1:256 + + % internal states (defined by graph Laplacian) + %---------------------------------------------------------------------- + jj = ~(B*nn) & ~nn & mj; + if any(jj) + + % find densely coupled internal states (using the graph Laplacian) + %------------------------------------------------------------------ + j = find(jj & any(L(logical(B*nn),:))'); + if isempty(j) + j = find(jj); + end + [g,ij] = min(nm(j)); + j = j(ij); + if m > 1 + k = find(BL(:,j) & jj); + [d,ij] = sort(nm(k)); + j = [j;k(ij)]; + try,j = j(1:m); end + end + + jj = sparse(j,1,1,size(L,1),1); % internal states + bb = B*jj & ~jj & ~nn; % Markov blanket + ee = ~bb & ~jj & ~nn; % external states + b = find(bb); + e = find(ee); + s = b(find( any(L(b,e),2))); + a = b(find(~any(L(b,e),2))); + + % indices of individual states in the i-th particle + %------------------------------------------------------------------ + x{1,i} = spm_cat(z(a)); + x{2,i} = spm_cat(z(s)); + x{3,i} = spm_cat(z(j)); + + % states accounted for (nn) + %------------------------------------------------------------------ + nn = nn | bb | jj; + + else + + % no internal states - find active states (not influenced by e) + %------------------------------------------------------------------ + jj = ~any(L(~nn,nn),2); + if any(jj) + + % sensory states connected with active states + %-------------------------------------------------------------- + a = find(~nn); + a = a(find(jj,1)); + aa = sparse(a,1,1,size(L,1),1); + ss = (L*aa | L'*aa) & ~aa & ~nn; + a = find(aa); + s = find(ss); + j = []; + + % indices of individual states in the i-th particle + %-------------------------------------------------------------- + x{1,i} = spm_cat(z(a)); + x{2,i} = spm_cat(z(s)); + x{3,i} = []; + + % states accounted for (nn) + %-------------------------------------------------------------- + nn = nn | aa | ss; + + elseif any(~nn) + + % sensory states connected with sensory states + %-------------------------------------------------------------- + s = find(~nn); + ss = sparse(s(1),1,1,nz,1); + ss = ss | B*ss & ~nn; + s = find(ss); + a = []; + j = []; + + % indices of individual states in the i-th particle + %-------------------------------------------------------------- + x{1,i} = []; + x{2,i} = spm_cat(z(s)); + x{3,i} = []; + + % states accounted for (nn) + %-------------------------------------------------------------- + nn = nn | ss; + end + end + + % indices of partitions (i.e., n-states) in the i-th particle + %---------------------------------------------------------------------- + y{1,i} = a; + y{2,i} = s; + y{3,i} = j; + + % plot + %---------------------------------------------------------------------- + if all(nn) + if GRAPHICS,clf + + % colours for different particles + %-------------------------------------------------------------- + nx = size(x,2); + [bol,col,msz] = spm_MB_col(nx); + + % plot partitions in embedding space (which particle) + %-------------------------------------------------------------- + subplot(3,2,3) + for k = 1:nx + plot(u(y{1,k},1),u(y{1,k},2),'.','color',bol{k},'MarkerSize',msz), hold on + plot(u(y{2,k},1),u(y{2,k},2),'.','color',bol{k},'MarkerSize',msz), hold on + plot(u(y{3,k},1),u(y{3,k},2),'.','color',col{k},'MarkerSize',msz), hold on + end + axis square + title(sprintf('Particles [%i n-states]',nz),'Fontsize',16) + + + % plot particles in embedding space (which sort of state) + %-------------------------------------------------------------- + subplot(3,2,4) + for k = 1:nx + plot(u(y{1,k},1),u(y{1,k},2),'.r','MarkerSize',msz), hold on + plot(u(y{2,k},1),u(y{2,k},2),'.m','MarkerSize',msz), hold on + plot(u(y{3,k},1),u(y{3,k},2),'.b','MarkerSize',msz), hold on + end + axis square + title(sprintf('Markov partition [%i particles]',nx),'Fontsize',16) + + + % plot particles in three embedding dimensions + %-------------------------------------------------------------- + subplot(3,2,2) + for k = 1:nx + plot3(u(y{1,k},1),u(y{1,k},2),u(y{1,k},3),'.r','MarkerSize',msz), hold on + plot3(u(y{2,k},1),u(y{2,k},2),u(y{2,k},3),'.m','MarkerSize',msz), hold on + plot3(u(y{3,k},1),u(y{3,k},2),u(y{3,k},3),'.b','MarkerSize',msz), hold on + end + axis square + title('Embedding space','Fontsize',16) + rotate3d(gca,'on') + + + % Jacobian (ordered by partition and type) + %-------------------------------------------------------------- + j = spm_vec(x'); + k = spm_vec(x ); + subplot(3,2,5),imagesc(-log(abs(J(k,k)) + exp(-4))),axis square + subplot(3,2,6),imagesc(-log(abs(J(j,j)) + exp(-4))),axis square + + + % Colors + %-------------------------------------------------------------- + nj = spm_length(x); + msz = fix(16 + 128/nj); + j = 1:nj; + k = spm_unvec(j,x')'; + j = spm_unvec(j,x); + subplot(3,2,5),hold on + for q = 1:nx + plot(j{1,q},ones(size(x{1,q})),'.','color',bol{q}, 'MarkerSize',msz) + plot(j{2,q},ones(size(x{2,q})),'.','color',bol{q}, 'MarkerSize',msz) + plot(j{3,q},ones(size(x{3,q})),'.','color',col{q}, 'MarkerSize',msz) + plot(j{1,q},zeros(size(x{1,q})) + nj,'.','color','r','MarkerSize',msz) + plot(j{2,q},zeros(size(x{2,q})) + nj,'.','color','m','MarkerSize',msz) + plot(j{3,q},zeros(size(x{3,q})) + nj,'.','color','b','MarkerSize',msz) + end + title('Jacobian (by partition)','Fontsize',16) + + subplot(3,2,6),hold on + for q = 1:nx + plot(k{1,q},ones(size(x{1,q})),'.','color',bol{q}, 'MarkerSize',msz) + plot(k{2,q},ones(size(x{2,q})),'.','color',bol{q}, 'MarkerSize',msz) + plot(k{3,q},ones(size(x{3,q})),'.','color',col{q}, 'MarkerSize',msz) + plot(k{1,q},zeros(size(x{1,q})) + nj,'.','color','r','MarkerSize',msz) + plot(k{2,q},zeros(size(x{2,q})) + nj,'.','color','m','MarkerSize',msz) + plot(k{3,q},zeros(size(x{3,q})) + nj,'.','color','b','MarkerSize',msz) + end + title('Jacobian (by type)','Fontsize',16) + + end + break + end + +end + + +return + + +function [bol,col,msz] = spm_MB_col(n) +% FORMAT [bol,col,msz] = spm_MB_col(n) +% returns colours and market size for number of partitions +% n - number of partitions +%-------------------------------------------------------------------------- +rng(1); +msz = fix(16 + 64/n); +for k = 1:n + bol{k} = spm_softmax(log(rand(3,1))*2); + col{k} = bol{k}*(1 - 1/2) + ones(3,1)/2; +end diff --git a/toolbox/DEM/FEP_Manifold.m b/toolbox/DEM/FEP_Manifold.m index 7be65b11..a765712b 100644 --- a/toolbox/DEM/FEP_Manifold.m +++ b/toolbox/DEM/FEP_Manifold.m @@ -30,7 +30,7 @@ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: FEP_Manifold.m 6655 2015-12-23 20:21:27Z karl $ +% $Id: FEP_Manifold.m 7163 2017-09-04 09:12:50Z karl $ % default settings (GRAPHICS sets movies) @@ -89,7 +89,7 @@ % internal states (defined by principle eigenvector of Markov blanket) %-------------------------------------------------------------------------- -B = double((L + L' + L*L')); +B = double((L + L' + L'*L)); B = B - diag(diag(B)); v = spm_svd(B*B',1); [v,j] = sort(abs(v(:,1)),'descend'); diff --git a/toolbox/DEM/FEP_fluctuations.m b/toolbox/DEM/FEP_fluctuations.m new file mode 100644 index 00000000..5fbe07fb --- /dev/null +++ b/toolbox/DEM/FEP_fluctuations.m @@ -0,0 +1,406 @@ +function FEP_fluctuations +% This demonstration uses an ensemble of particles with intrinsic (Lorentz +% attractor) dynamics and (Newtonian) short-range coupling. The focus of +% this routine is to unpack the Bayesian perspective. We first simulate +% dynamics to nonequilibrium steady-state, identify the Markov blanket and +% then examine the encoding of external states by internal states; in terms +% of their expected values. +% +% The crucial aspect of this implicit inference (and the basis of the free +% energy principle) is the existence of a conditional synchronisation +% manifold, when conditioning internal and external states on the Markov +% blanket. This provides the basis for a mapping between internal and +% external states that can be interpreted in terms of a probabilistic +% representation or inference. +% +% This Bayesian perspective is illustrated in terms of a mapping between +% the canonical modes of internal and external states (as approximated +% with a polynomial expansion). The canonical modes her are evaluated +% using an estimate of the conditional expectations based upon the +% Euclidean proximity of Markov blanket states. The ensuing posterior over +% external states is than illustrated, in relation to the actual external +% states. We also simulate event related potentials by identifying +% several points in time when the Markov blankets revisit the same +% neighbourhood. Finally, to illustrate the underlying dynamics, the +% Jacobians or coupling among internal and external states are +% presented; using different orders of coupling (i.e., degrees of +% separation) +% +%__________________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% Karl Friston +% $Id: FEP_fluctuations.m 7163 2017-09-04 09:12:50Z karl $ + + +% default settings (GRAPHICS sets movies) +%-------------------------------------------------------------------------- +rng('default') +GRAPHICS = 1; + +% Demo of synchronization manifold using coupled Lorenz attractors +%========================================================================== +N = 128; % number of (Lorenz) oscillators +T = 2048; % number of time bins +dt = 1/32; % time interval + +% parameters +%-------------------------------------------------------------------------- +P.k = 1 - exp(-rand(1,N)*4); % variations in temporal scale +P.d = 1/8; % amplitude of random fluctuations + +% states +%-------------------------------------------------------------------------- +x.p = randn(2,N)*4; % microstates (position) +x.v = zeros(2,N); % microstates (velocity) +x.q = randn(3,N)/32; % microstates (states) +u = zeros(1,T); % exogenous fluctuations + + +% generate an dynamics from initial conditions +%========================================================================== +spm_figure('GetWin','Markov blanket');clf +if GRAPHICS + subplot(2,2,1) +else + subplot(2,1,1) +end +[Q,X,V,A,x] = spm_soup(x,u,P,T,dt,1); + +% States +%-------------------------------------------------------------------------- +% Q - history of microstates (states) +% X - history of microstates (position) +% V - history of microstates (velocity) + +for i = 1:size(X,3) + S(:,:,i) = [Q(:,:,i);X(:,:,i);V(:,:,i)]; +end + +% Markov blanket - parents, children, and parents of children +%========================================================================== + +% Adjacency matrix +%-------------------------------------------------------------------------- +t = (T - 256):T; % final time indices +L = sparse(double(any(A(:,:,t),3)))'; + +% internal states (defined by principle eigenvector of Markov blanket) +%-------------------------------------------------------------------------- +B = double((L + L' + L'*L)); +B = B - diag(diag(B)); +v = spm_svd(B*B',1); +[v,j] = sort(abs(v(:,1)),'descend'); + +% get Markov blanket and divide into sensory and active states +%-------------------------------------------------------------------------- +m = j(1:8); % internal cluster +mm = sparse(m,1,1,N,1); % internal states +bb = B*mm & (1 - mm); % Markov blanket +ee = 1 - bb - mm; % external states +b = find(bb); +e = find(ee); +m = find(mm); +s = b(find( any(L(b,e),2))); +a = b(find(~any(L(b,e),2))); + +% adjacency matrix - with partition underneath (LL) +%-------------------------------------------------------------------------- +k = [e; s; a; m]; +LL = L; +LL(e,e) = LL(e,e) + 1/8; +LL(s,s) = LL(s,s) + 1/8; +LL(a,a) = LL(a,a) + 1/8; +LL(m,m) = LL(m,m) + 1/8; +LL = LL(k,k); + +% plot dynamics for the initial and subsequent time periods +%-------------------------------------------------------------------------- +subplot(4,1,3) +r = 1:512; +plot(r,squeeze(Q(1,e,r)),':c'), hold on +plot(r,squeeze(Q(1,m,r)),' b'), hold off +axis([r(1) r(end) -32 32]) +xlabel('Time','FontSize',12) +title('Electrochemical dynamics','FontSize',16) + +subplot(4,1,4) +r = 1:T; +plot(r,squeeze(V(1,e,r)),':c'), hold on +plot(r,squeeze(V(1,m,r)),' b'), hold off +axis([r(1) r(end) -32 32]) +xlabel('Time','FontSize',12) +title('Newtonian dymanics','FontSize',16) + + +% Markov blanket - self-assembly +%========================================================================== +subplot(2,2,1) +imagesc(1 - LL) +axis square +xlabel('Element','FontSize',12) +xlabel('Element','FontSize',12) +title('Adjacency matrix','FontSize',16) + + +% follow self-assembly +%-------------------------------------------------------------------------- +clear M +for i = (T - 512):T + + % plot positions + %---------------------------------------------------------------------- + subplot(2,2,2),set(gca,'color','w') + + px = ones(3,1)*X(1,:,i) + Q([1 2 3],:,i)/16; + py = ones(3,1)*X(2,:,i) + Q([2 3 1],:,i)/16; + plot(px,py,'.b','MarkerSize',8), hold on + px = X(1,e,i); py = X(2,e,i); + plot(px,py,'.c','MarkerSize',24) + px = X(1,m,i); py = X(2,m,i); + plot(px,py,'.b','MarkerSize',24) + px = X(1,s,i); py = X(2,s,i); + plot(px,py,'.m','MarkerSize',24) + px = X(1,a,i); py = X(2,a,i); + plot(px,py,'.r','MarkerSize',24) + + xlabel('Position','FontSize',12) + ylabel('Position','FontSize',12) + title('Markov Blanket','FontSize',16) + axis([-1 1 -1 1]*8) + axis square, hold off, drawnow + + % save + %---------------------------------------------------------------------- + if i > (T - 128) && GRAPHICS + M(i - T + 128) = getframe(gca); + end + +end + +% set ButtonDownFcn +%-------------------------------------------------------------------------- +if GRAPHICS + h = findobj(gca); + set(h(1),'Userdata',{M,16}) + set(h(1),'ButtonDownFcn','spm_DEM_ButtonDownFcn') + xlabel('Click for Movie','Color','r') +end + + +% illustrate the Bayesian perspective (predictability of external states) +%========================================================================== +spm_figure('GetWin','Bayesian perspective');clf + +% establish a statistical dependency between internal (dynamic) states (XQ) +%-------------------------------------------------------------------------- +T = 512; % length of timeseries +t = size(X,3) - T - 2; +for i = 1:T + Xe(i,:) = spm_vec(V(:,e,i + t)); % external states + Xb(i,:) = spm_vec(S(:,[a;s],i + t)); % Markov blanket + Xm(i,:) = spm_vec(Q(:,m,i + t)); % internal states +end +xe = zeros(size(Xe)); +xm = zeros(size(Xm)); +iC = inv(cov(Xb)); + +% probabilistic proximity in the space of the Markov blanket +%-------------------------------------------------------------------------- +for i = 1:T + for j = 1:T + r = Xb(i,:) - Xb(j,:); + w(i,j) = exp(-(r*iC*r')/128); + end +end + +% convert into proper probability distribution +%-------------------------------------------------------------------------- +w = diag(sum(w,2))\w; + +% mean +%-------------------------------------------------------------------------- +for i = 1:T + for j = 1:T + xe(i,:) = xe(i,:) + w(i,j)*Xe(j,:); + xm(i,:) = xm(i,:) + w(i,j)*Xm(j,:); + end +end + +% covariance (not used) +%-------------------------------------------------------------------------- +% ce = zeros(size(Xe,1),size(Xe,2),size(Xe,2)); +% for i = 1:T +% for j = 1:T +% ce(i,:,:) = squeeze(ce(i,:,:)) + w(i,j)*(Xe(i,:) - xe(i,:))'*(Xe(j,:) - xe(j,:)); +% end +% end + +% normalise and identify canonical eigenvariates +%-------------------------------------------------------------------------- +xe = spm_detrend(xe); +xm = spm_detrend(xm); +CVA = spm_cva(xe,xm); + +% show results - canonical vectors over elements (mode M) +%-------------------------------------------------------------------------- +subplot(3,2,1) + +M = 1; +Ve = CVA.V(:,M); +Ve = spm_unvec(Ve,V(:,e,1)); +ve = sum(Ve.^2); +ve = ve/max(ve); +for k = 1:length(Ve) + c = [0 1 1]*ve(k) + [1 1 1]*(1 - ve(k)); + plot(X(1,e(k),end),X(2,e(k),end),'.','MarkerSize',32,'Color',c), hold on +end + +% overplot mode of motion +%-------------------------------------------------------------------------- +quiver(X(1,e,end),X(2,e,end),Ve(1,:),Ve(2,:)) + +Vm = CVA.W(:,M); +Vm = spm_unvec(Vm,Q(:,m,1)); +vm = sum(Vm.^2); +vm = vm/max(vm); +for k = 1:length(Vm) + c = [0 0 1]*vm(k) + [1 1 1]*(1 - vm(k)); + plot(X(1,m(k),end),X(2,m(k),end),'.','MarkerSize',32,'Color',c), hold on +end +xlabel('Position', 'FontSize',12) +ylabel('Position','FontSize',12) +title('Canonical mode','FontSize',16) + +% conditional synchronisation manifold (polynomial approximation) +%========================================================================== + +% polynomial approximation +%-------------------------------------------------------------------------- +xX = xm*CVA.W(:,M); +XX = [xX.^0 xX.^1 xX.^2 xX.^3 xX.^4 xX.^5]; +bE = pinv(XX)*Xe*CVA.V(:,M); +qE = XX*bE; + +% conditional expectation and variance +%-------------------------------------------------------------------------- +% for i = 1:T +% qC(i) = CVA.V(:,1)'*squeeze(ce(i,:,:))*CVA.V(:,1); +% end +qC = ones(size(qE)); +qC = abs(var(Xe*CVA.V(:,1) - qE)*qC/mean(qC)); + +% show results - conditional synchronisation manifold +%-------------------------------------------------------------------------- +subplot(3,2,2) +plot(CVA.w(:,1),Xe*CVA.V(:,1),'.c' ), hold on +plot(CVA.w(:,1),qE,'.b' ), hold off +xlabel('Internal mode', 'FontSize',12) +ylabel('External mode','FontSize',12) +title('Synchronisation manifold','FontSize',16), spm_axis tight + +% show results - conditional distributions as a function of time +%-------------------------------------------------------------------------- +subplot(3,1,2) +plot(Xe*CVA.V(:,1),'c' ), hold on +spm_plot_ci(qE',qC(:)'), hold off +xlabel('Time', 'FontSize',12) +ylabel('External states','FontSize',12) +title('Inferred and real motion','FontSize',16), spm_axis tight + + +% event related potentials +%========================================================================== + +% identify points of interest using the external canonical variate +%-------------------------------------------------------------------------- +u = CVA.v(:,1); +ue = []; +for i = 1:8 + [d,j] = max(u(33:end - 65)); + j = j + 32; + % j = fix(rand*T); % random times + k = (j - 32):(j + 64); % perstimulus time (around j) + u((j - 8):(j + 8)) = -Inf; % eliminate from next max(u(:,1)) + ue(:,i) = Xe(k,:)*CVA.V(:,1); + um(:,i) = Xm(k,:)*CVA.W(:,1); + us(i) = j; + +end +j = any(ue); +us = us(j); +ue = spm_detrend(ue(:,j)); +um = spm_detrend(um(:,j)); + +% plot points of interest on conditional density +%-------------------------------------------------------------------------- +subplot(3,1,2) +uy = get(gca,'Ylim'); hold on +for i = 1:length(us),plot([1 1]*us(i),uy,':'), end, hold off + +% show time locked (internal and external) fluctuations and their mean +%-------------------------------------------------------------------------- +subplot(3,2,5) +pst = (-32:64)*8; +plot(pst,ue,'c:',pst,um,'b:'), hold on +plot(pst,mean(ue,2),'c',pst,mean(um,2),'b'), hold on +plot([0 0],get(gca,'YLim'),'--'), hold off, axis square +xlabel('Time (milliseconds)', 'FontSize',12) +ylabel('Electrochemical response','FontSize',12) +title('Simulated ERP','FontSize',16) + +% canonical correlations +%-------------------------------------------------------------------------- +subplot(3,2,6) +bar(CVA.r,1/2,'c') +xlabel('Mode', 'FontSize',12) +ylabel('Correlation','FontSize',12) +title('Canonical correlations','FontSize',16), axis square + + + +% Jacobian's and generalised synchronisation +%========================================================================== +spm_figure('GetWin','Jacobians');clf + +% get Markov blanket indices the Jacobian +%-------------------------------------------------------------------------- +xi = spm_zeros(x); xi.v(:,e) = 1; iXe = find(spm_vec(xi)); +xi = spm_zeros(x); xi.q(:,m) = 1; iXm = find(spm_vec(xi)); + +% show results - Jacobians (of increasing order: 1 to n) +%-------------------------------------------------------------------------- +[d,j] = max(CVA.v(:,1)); +j = j + (-8:8); +J = spm_soup(Q(:,:,j),X(:,:,j),V(:,:,j),P); +J = mean(J,3); +j = [iXe;iXm]; +% q = 8; +% U = blkdiag(CVA.V(:,1:q),CVA.W(:,1:q)); % eigenmodes (not used) + +n = 4; +for i = 1:n + + % all states + %---------------------------------------------------------------------- + JJ = J^i; + subplot(n,2,(i - 1)*2 + 1) + spy(abs(JJ) > 1e-2,'k') + title(sprintf('%i-order coupling',i),'FontSize',16) + xlabel('All states','FontSize',12) + ylabel('All states','FontSize',12) + + % Internal and external states + %---------------------------------------------------------------------- + JJ = JJ(j,j); % JJ = pinv(U)*JJ(j,j)*U; + subplot(n,2,(i - 1)*2 + 2) + spy(abs(JJ) > 1e-2,'k') + title(sprintf('%i-order coupling',i),'FontSize',16) + xlabel('External and internal','FontSize',12) + ylabel('External and internal','FontSize',12) + +end + + +return + diff --git a/toolbox/DEM/FEP_physics.m b/toolbox/DEM/FEP_physics.m new file mode 100644 index 00000000..5ff94607 --- /dev/null +++ b/toolbox/DEM/FEP_physics.m @@ -0,0 +1,792 @@ +function FEP_physics +% This demonstration uses an ensemble of particles with intrinsic (Lorenz +% attractor) dynamics and (Newtonian) short-range coupling. the setup is +% used to solve for dynamics among an ensemble of particles; from which a +% Markov blanket emerges (which forms a particle at the next hierarchical +% scale. These ensemble dynamics are then used to illustrate different +% perspectives; namely, those afforded by quantum, statistical and +% classical mechanics. A detailed description of each of these three +% treatments precedes each of the sections in the script. these +% descriptions are in the form of a figure legend, where each section is +% summarised with a figure. +%__________________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% Karl Friston +% $Id: FEP_physics.m 7161 2017-08-26 19:29:24Z karl $ + + +% default settings (GRAPHICS sets movies) +%-------------------------------------------------------------------------- +rng('default') + +% Demo of synchronization manifold using coupled Lorenz attractors +%========================================================================== +N = 128; % number of (Lorenz) oscillators +T = 2048; % number of time bins +dt = 1/32; % time interval + +% parameters +%-------------------------------------------------------------------------- +P.k = 1 - exp(-rand(1,N)*4); % variations in temporal scale +P.a = rand(1,N) > 2/3; % no out influences +P.e = exp(0); % energy parameter (well depth) +P.d = 1/8; % amplitude of random fluctuations + +% states +%-------------------------------------------------------------------------- +x.p = randn(2,N)*4; % microstates (position) +x.v = zeros(2,N); % microstates (velocity) +x.q = randn(3,N)/32; % microstates (states) +u = zeros(1,T); % exogenous fluctuations + + +% generate an dynamics from initial conditions +%========================================================================== +spm_figure('GetWin','Markov blanket');clf +subplot(2,2,1) + +% States +%-------------------------------------------------------------------------- +% Q - history of microstates (states) +% X - history of microstates (position) +% V - history of microstates (velocity) +%-------------------------------------------------------------------------- +[Q,X,V,A] = spm_Manifold_solve(x,u,P,T,dt,1); + + + +% Markov blanket - parents, children, and parents of children +%========================================================================== + +% Adjacency matrix +%-------------------------------------------------------------------------- +t = (T - 256):T; % final time indices +L = sparse(double(any(A(:,:,t),3)))'; + +% internal states (defined by principle eigenvector of Markov blanket) +%-------------------------------------------------------------------------- +B = double((L + L' + L*L')); +B = B - diag(diag(B)); +v = spm_svd(B*B',1); +[v,j] = sort(abs(v(:,1)),'descend'); + +% get Markov blanket and divide into sensory and active states +%-------------------------------------------------------------------------- +mm = j(1:8); % internal cluster +jj = sparse(mm,1,1,N,1); % internal states +bb = B*jj & (1 - jj); % Markov blanket +ee = 1 - bb - jj; % external states +b = find(bb); +e = find(ee); +m = find(jj); +s = b(find( any(L(b,e),2))); +a = b(find(~any(L(b,e),2))); + +% adjacency matrix - with partition underneath (LL) +%-------------------------------------------------------------------------- +k = [e; s; a; m]; +LL = L; +LL(e,e) = LL(e,e) + 1/8; +LL(s,s) = LL(s,s) + 1/8; +LL(a,a) = LL(a,a) + 1/8; +LL(m,m) = LL(m,m) + 1/8; +LL = LL(k,k); + +% plot dynamics for the initial and subsequent time periods +%-------------------------------------------------------------------------- +subplot(4,1,3) +r = 1:512; +plot(r,squeeze(Q(1,e,r)),':c'), hold on +plot(r,squeeze(Q(1,m,r)),' b'), hold off +axis([r(1) r(end) -32 32]) +xlabel('Time','FontSize',12) +title('Electrochemical dynamics','FontSize',16) + +subplot(4,1,4) +r = 1:T; +plot(r,squeeze(V(1,e,r)),':c'), hold on +plot(r,squeeze(V(1,m,r)),' b'), hold off +axis([r(1) r(end) -32 32]) +xlabel('Time','FontSize',12) +title('Newtonian dymanics','FontSize',16) + + +% Markov blanket - self-assembly +%========================================================================== +subplot(2,2,2) +imagesc(1 - LL) +axis square +xlabel('Element','FontSize',12) +xlabel('Element','FontSize',12) +title('Adjacency matrix','FontSize',16) + + +% follow self-assembly +%-------------------------------------------------------------------------- +GRAPHICS = 0; +clear M +for i = (T - 128):T + + % plot positions + %---------------------------------------------------------------------- + subplot(2,2,2),set(gca,'color','w') + + px = ones(3,1)*X(1,:,i) + Q([1 2 3],:,i)/16; + py = ones(3,1)*X(2,:,i) + Q([2 3 1],:,i)/16; + plot(px,py,'.b','MarkerSize',8), hold on + px = X(1,e,i); py = X(2,e,i); + plot(px,py,'.c','MarkerSize',24) + px = X(1,m,i); py = X(2,m,i); + plot(px,py,'.b','MarkerSize',24) + px = X(1,s,i); py = X(2,s,i); + plot(px,py,'.m','MarkerSize',24) + px = X(1,a,i); py = X(2,a,i); + plot(px,py,'.r','MarkerSize',24) + + xlabel('Position','FontSize',12) + ylabel('Position','FontSize',12) + title('Markov Blanket','FontSize',16) + axis([-1 1 -1 1]*8) + axis square, hold off, drawnow + + % save + %---------------------------------------------------------------------- + if i > (T - 128) && GRAPHICS + M(i - T + 128) = getframe(gca); + end + +end + +% set ButtonDownFcn +%-------------------------------------------------------------------------- +if GRAPHICS + h = findobj(gca); + set(h(1),'Userdata',{M,16}) + set(h(1),'ButtonDownFcn','spm_DEM_ButtonDownFcn') + xlabel('Click for Movie','Color','r') +end + + +%% illustrate the quantum perspective (quantum mechanics) +%========================================================================== +% This section illustrates the quantum treatment of a single state – a +% microstate from the second external particle of the synthetic soup. The +% aim of this example is to show how one can characterise the dynamics of +% the state in terms of the Schrödinger potential and ensuing kinetic +% energy. Furthermore, this example illustrates how one can eschew the +% solution of the Schrödinger equation using the NESS lemma. Here, we will +% consider a single (micro) state in isolation by assuming its flow is a +% (linear) mixture of the marginal or expected flow under all other states +% and some fast random fluctuations. Although we know a lot about how these +% fluctuations are generated, we will treat them as stochastic and +% sufficiently fast that the only interesting behaviour can be captured by +% the Schrödinger potential. The timeseries is shown in the upper panel in +% terms of the state (solid line – arbitrarily assigned units of metres) +% and flow (dotted line). The sample distribution of states over time was +% evaluated in terms of the NESS potential using a six order polynomial fit +% to the negative logarithm of the sample density over 64 bins. The +% resulting estimate and its derivatives are shown in the left middle +% panel. From these, Equation (5.4) specifies the Schrödinger potential +% (left lower panel). One can then solve the Schrödinger equation to +% evaluate the wave function over position in state-space (middle panel) +% and its Fourier transform, over momentum (lower middle panel). The +% corresponding ensemble densities over position and momentum are shown in +% the right panels, superimposed upon the corresponding sample densities. +% Finally, the density over momentum specifies the kinetic energy via +% Equation (5.9). Here, the kinetic (and potential) energy was 2.29 ^ +% 10-33. To quantify this energy (and the Schrödinger potential) one needs +% the amplitude of the random fluctuations – or, equivalently, the reduced +% mass. This can be simply computed from the residuals of the flow having +% removed its expectation or marginal flow. The reduced mass of this +% quantum system was 5.52 ^ 10-38. This concludes a description of how the +% Schrödinger equation can be applied to characterise nonequilibrium +% steady-state dynamics. However, this is not how the results in this +% figure were generated: they were derived directly from the NESS potential +% without solving the Schrödinger equation. In other words, the ensemble +% density is specified directly by the NESS potential, which means that the +% wave function (and its Fourier transform) can be specified directly from +% the ensemble density. Here, we somewhat arbitrarily split the ensemble +% density into a symmetric Gaussian component and an asymmetric (positive) +% residual. We then simply assigned the (square root of the) two components +% to the real and imaginary parts of the wave function. This complementary +% derivation of the wave function illustrates the point made in the main +% text; namely, that one can either generate the wave function directly +% from ensemble density or one can start from the Schrödinger potential and +% solve the Schrödinger equation. +%-------------------------------------------------------------------------- +spm_figure('GetWin','quantum mechanics');clf + + +% extract timeseries and evaluate sample NESS density +%-------------------------------------------------------------------------- +t = (1:T)*dt; +q = squeeze(Q(1,s(2),:)); +q = spm_detrend(q); +b = max(abs(q)); +b = linspace(-b,b,64); +[n,b] = hist(q,b(:)); +db = b(2) - b(1); +n = n(:)/sum(n)/db; + +% approximate NESS potential (with a polynomial) +%-------------------------------------------------------------------------- +Vx = -log(n + eps); +PP = [b.^0 b.^1 b.^2 b.^3 b.^4 b.^5 b.^6]; +W = diag(spm_softmax(-Vx)); +B = (pinv(W*PP)*W*Vx); +Vx = @(B,b)[b.^0 b.^1 b.^2 b.^3 b.^4 b.^5 b.^6]*B; +dV = @(B,b)[b.^0 2*b.^1 3*b.^2 4*b.^3 5*b.^4 6*b.^5]*B(2:end); +ddV = @(B,b)[2*b.^0 6*b.^1 12*b.^2 20*b.^3 30*b.^4]*B(3:end); +p = exp(-Vx(B,b)); +p = p(:)/sum(p)/db; + +% wave function in terms of symmetric and antisymmetric parts +%-------------------------------------------------------------------------- +% ps = (p + flipud(p))/2; +% pa = (p - flipud(p))/2; +% psi = sqrt(ps - ps/2) + sqrt(-1)*sqrt(ps/2 + pa); +ps = exp(-b.^2/(2*(b(1)/4)^2)); +ps = ps*p(32); +pa = p - ps; +psi = sqrt(ps) + sqrt(-1)*sqrt(pa).*sign(b); + +% evaluate the flow due to the potential gradients SI UNITS +%-------------------------------------------------------------------------- +h = 6.62607004*1e-34/(2*pi); % m*m*kg/s +dqdt = gradient(q,dt); % m/s +dVdb = dV(B,q)/db; % /m + +% use the residuals to estimate the amplitude of effective fluctuations +%-------------------------------------------------------------------------- +gam = var(dqdt - dVdb*pinv(dVdb)*dqdt)/2; % m*m/s +m = h/(2*gam); % kg + +% combine to evaluate Schrödinger potential and kinetic energy +%-------------------------------------------------------------------------- +VS = h^2/(4*m)*(dV(B,b).^2/(db^2)/2 - ddV(B,b)/(db^2)); + % kg.m.m/s/s (Joule) +f = -h/(2*m)*dV(B,b)/db; % m/s +KE = (m/2)*p'*f.^2; % kg*m*m/s/s (Joule) +str = sprintf('Fluctuations (Kinetic energy : %-.2e Joules; %-.2e Kg)',KE,m); + +% trajectory +%-------------------------------------------------------------------------- +subplot(3,1,1) +plot(t,q,t,dqdt,':') +xlabel('Time (secs)', 'FontSize',12) +ylabel('State and flow (m ans m/s)','FontSize',12) +title(str,'FontSize',16), spm_axis tight + + +% position functions +%-------------------------------------------------------------------------- +subplot(3,3,4) +plot(b,Vx(B,b),b,dV(B,b)/db,'-.',b,ddV(B,b)/db/db,':') +xlabel('State space (m)', 'FontSize',12) +ylabel('Nats (a.u, /m and /m/m)','FontSize',12) +title('NESS potential','FontSize',16), spm_axis tight + +subplot(3,3,5) +plot(b,real(psi),b,imag(psi),':') +xlabel('State space (m)', 'FontSize',12) +ylabel('Amplitude (m/m)','FontSize',12) +title('Wave function','FontSize',16), spm_axis tight + +subplot(3,3,6) +plot(b,n,':',b,psi.*conj(psi)) +xlabel('State space (m)', 'FontSize',12) +ylabel('Probability density (a.u)','FontSize',12) +title('Ensemble density','FontSize',16), spm_axis tight + + +% equivalent formulations for momentum (h*k) +%-------------------------------------------------------------------------- +PSI = fft(psi)/sqrt(h)/2; +k = h*b/db/b(end); % kg*m/s +[nk,k] = hist(m*dqdt,k); +dk = k(2) - k(1); +nk = nk(:)/sum(nk)/dk; + +% momentum functions +%-------------------------------------------------------------------------- +subplot(3,3,7) +plot(b,VS) +xlabel('State space (m)', 'FontSize',12) +ylabel('Potential (kg.m.m/s/s (Joules)','FontSize',12) +title('Schrödinger potential','FontSize',16), spm_axis tight + +subplot(3,3,8) +plot(k,real(fftshift(PSI)),k,imag(fftshift(PSI)),':') +xlabel('Momentum (kg.m/s)', 'FontSize',12) +ylabel('Amplitude (a.u)','FontSize',12) +title('Wave function','FontSize',16), spm_axis tight + +subplot(3,3,9) +plot(k,nk,':',k,fftshift(PSI.*conj(PSI))) +xlabel('Momentum (kg.m/s)', 'FontSize',12) +ylabel('Probability density (a.u)','FontSize',12) +title('Ensemble density','FontSize',16), spm_axis tight + + + +%% illustrate the thermodynamic perspective (stochastic mechanics) +%========================================================================== +spm_figure('GetWin','stochastic mechanics'); clf +%-------------------------------------------------------------------------- +% This figure below illustrates the characterisation of the synthetic soup +% (or active matter) in terms of classical (stochastic) thermodynamics. The +% analysis is fairly simple and proceeds as follows: first, any partition +% of states (e.g., internal states) can be treated as an ensemble. In other +% words, the behaviour of any one element can be treated as if it was +% responding to the same thermodynamic potential as all remaining elements. +% One can then evaluate the thermodynamic potential that best explains the +% flow of states. Given this expected or predicted flow one can then +% evaluate the variance or amplitude of random fluctuations and, equipped +% with a mobility coefficient (here, we used a mobility of 0.2), one can +% then evaluate the temperature at any point in time. Note that this is +% possible because we are associating the distribution over the states of +% the ensemble with the equivalent statistics and would have been observed +% over time. Given the temperature and thermodynamic potential, one can +% then evaluate the free energy using the KL divergence between the +% associated thermodynamic and ensemble densities. As the states approach +% their random dynamic attractor (i.e., nonequilibrium steady-state) these +% density functions converge and the ensemble density ceases to change. At +% this point, it becomes the NESS density. The implicit changes in the +% ensemble density over time can be characterised in terms of entropy +% production, which can be partitioned in a number of ways (see main text). +% In the example here, we have focused on the entropy dissipated by +% probability currents that, when multiplied by temperature, corresponds to +% heat dissipation. In this somewhat heuristic illustration, we have (for +% simplicity) focused on the position in one dimension of the internal +% states surrounded by the principal Markov blanket. This is the small +% virus like particle in Figure 4. To estimate the thermodynamic and +% ensemble potentials, we used a fourth order polynomial expansion of +% position (and appropriate least squares estimators). The thermodynamic +% potential is that which best predicts the stochastic flow of states; +% where the ensemble density best predicts the sample density. To obtain +% more efficient estimators, we also averaged over 256 time beans at 28 +% consecutive intervals during the evolution of the system. We started at +% the 32nd time then to illustrate the thermodynamic, correlates of +% self-organisation during which the principal Markov blanket was formed. +% For interest, we repeated the analysis for the internal states, the +% blanket states and external states. The upper row of images shows the +% evolution of temperature shown using a (hot) colour scale with a dot at +% the position of the particles (in two dimensions). The second panel shows +% the corresponding evolution of temperature in the three ensembles as a +% function of time. The interesting thing here is that the internal (blue) +% and blanket (red) states start off at about the same temperature. +% However, during the course of self organisation, the internal states +% slowly increase their temperature to become hotter than the external +% states (cyan). In this example, the temperature of the internal states +% ended up being about twice the temperature of the blanket states. The +% third panel shows the corresponding free energy for each of the +% ensembles. The most notable thing here is that free energy decreases with +% time as the thermodynamic and ensemble potentials approach each other. +% This is most marked for the external and blanket states that could be +% thought of as spending their free energy to organise the internal states. +% After about five seconds, there is relatively little free energy left +% within the system. This is reflected in the bottom panel that shows the +% corresponding heat dissipation, which is most marked for the external +% states, as might be guessed from the changes in the thermodynamic free +% energy. Although heat dissipation can fall to low levels – as +% nonequilibrium steady-state is approached – the temperature of our +% synthetic virus remains relatively high (here, the temperature reached +% about 300° Kelvin, which is roughly body temperature). This follows from +% the fact that random fluctuations are still in play – arising from +% intrinsic fluctuations of the internal states of each internal particle +% (at the underlying hierarchical level). These fluctuations disperse +% states over the thermodynamic potential, while flow down potential energy +% gradients reconstitutes the ensemble density. Effectively, this flow +% (times distance) produces heat that is endowed by the intrinsic +% fluctuations. At nonequilibrium steady-state these two processes are in +% balance and heat dissipation is eliminated; because probability currents +% are zero at all points in state space. The lower panel shows the +% corresponding entropy as a function of time. The external states increase +% their entropy initially and then entropy falls as the system finds its +% random dynamical attractor. Note that the entropy of states (that are +% destined to become densely coupled internal states) progressively falls; +% thereby, violating the second law. This is what we would expect in this +% far from equilibrium scenario. Clearly, this is an idealised description +% of stochastic dynamics under the ensemble assumption. In reality, the +% dynamics are much more complicated and our treatment here can be +% construed as a mean field approximation, where all the interactions +% within and between the three ensembles are summarised with a common +% thermodynamic potential and ensemble density. Despite this approximation, +% this sort of analysis provides an intuitive characterisation of +% stochastic dynamics in terms of constructs that underpin the first and +% second laws of thermodynamics. +%-------------------------------------------------------------------------- + +% get positions and velocities of all states +%-------------------------------------------------------------------------- +bi = find(logical(bb)); % blanket particles +ei = find(logical(ee)); % external particles +mi = find(logical(jj)); % internal particles + + +% evaluate surprise (NESS potential) with distribution over states and time +%-------------------------------------------------------------------------- +nt = 28; % number of evaluations +wt = 32; % interval between evaluations +lt = 256; % trajectory length +n0 = 32; % intial evaluation + +% Ion mobility Coefficient of Air: 0.0002 +%------------------------------------------------------------------------- +kB = 1.38064852e-2; % Boltzmann constant J/K = g.nm.nm/s/s/K +mu = .2; % diffusion constant s/g +mu = mu*kB; + +J0 = (linspace(-1,1,64).^32)'*8; + +% Stochastic dynamics of partitions +%-------------------------------------------------------------------------- +ii = {mi, bi, ei}; +col = {'b','r','c'}; +for j = 1:numel(ii) + + % Stochastic dynamics of trajectories + %---------------------------------------------------------------------- + for i = 1:nt + + % get trajectories (and stochastic flow) + %------------------------------------------------------------------ + t = (i - 1)*wt + (1:lt) + n0; + q = squeeze(X(2,ii{j},t)); + p = gradient(q,dt); + + % stochastic density + %------------------------------------------------------------------ + b = linspace(min(q(:)),max(q(:)),64); + [n,b] = hist(q(:),b(:)); + n = n + spm_hanning(64)'*sum(n)*exp(-8); + n = n(:)/sum(n); + db = b(2) - b(1); + + + % estimate potential and amplitude of fluctuations + %------------------------------------------------------------------ + In = -log(n); + Wj = diag(spm_softmax(-In)); + Wv = 1; + + Vx = @(b)[b.^0 b.^1 b.^2 b.^3 b.^4];% b.^5 b.^6 b.^7 b.^8]; + dVdx = @(b)[0*b b.^0 2*b.^1 3*b.^2 4*b.^3];% 5*b.^4 6*b.^5 7*b.^6 8*b.^7]; + XJ = Vx(b); + XV = -mu*dVdx(q(:)); + BJ = pinv(Wj*XJ)*Wj*In; % polynomial coefficients - surprise + BV = pinv(Wv*XV)*Wv*p(:); % polynomial coefficients - potential + + + % evaluate gamma (temperature) by predicting flow + %------------------------------------------------------------------ + G = var(p(:) - XV*BV)/2; % amplitude of fluctuations m.m/s + Ts = G/mu; % temperature K + + % BV = G*BJ/mu; % NESS solution + + % evaluate free energy and entropies + %------------------------------------------------------------------ + Jj = Vx(b)*BJ + J0; + Jv = Vx(b)*BV/Ts + J0; + Jj = -log(spm_softmax(-Jj)); % ensemble potential + Jv = -log(spm_softmax(-Jv)); % thermodynamic potential + Pj = spm_softmax(-Jj)/db; % ensemble density over b + Pv = spm_softmax(-Jv)/db; % potential density over b + f = -G*gradient(Jv,db); % predicted flow + Fs = f/mu; % thermodynamic force + + + % evaluate entropy and heat production + %------------------------------------------------------------------ + dJdx = gradient(Jj,db); % gradient of surpise + dPdx = -dJdx.*Pj; % gradient of ensemble density + jp = f.*Pj - G*dPdx; % probability current + + Fz(i) = Pj'*(log(Pj) - log(Pv))*db; % thermodynamic free energy + S(i) = Pj'*(-log(Pj))*db; + Sflow(i) = f'*dPdx*db; % entropy - flow + Sfluc(i) = G*dPdx'*(dPdx./Pj)*db; % entropy - fluctuations + Stota(i) = jp'*(jp./Pj)/G*db; % entropy - total + Sdiss(i) = jp'*Fs/Ts*db; % entropy - dissipative + Qt(i) = jp'*Fs*db; % heat dissipation + TS(i) = Ts; % temperature + + + % heat maps + %------------------------------------------------------------------ + Hm(j,i) = TS(i); + xi{j,i} = squeeze(X(2,ii{j},t(end))); + xj{j,i} = squeeze(X(1,ii{j},t(end))); + + end + + % plot results + %---------------------------------------------------------------------- + tt = (1:length(Fz))*wt*dt; + + subplot(5,1,2), hold on + plot(tt,TS,col{j}), ylabel('Kelvin') + title('Temperature','FontSize',16), spm_axis tight + + subplot(5,1,3), hold on + plot(tt,Fz,col{j}), ylabel('Joules') + title('Thermodynamic Free energy','FontSize',16), spm_axis tight + + subplot(5,1,4), hold on + plot(tt,Qt,col{j},tt,Sflow.*TS,':','Color',col{j}),ylabel('Joules/s') + title('Heat dissipation','FontSize',16), spm_axis tight + + subplot(5,1,5), hold on + plot(tt,S,'Color',col{j}) + xlabel('Time (seconds)'), ylabel('Joules/K') + title('Entropy','FontSize',16), spm_axis tight + +end + +% heat maps (temperature) +%-------------------------------------------------------------------------- +rgb = colormap(hot); +kk = fix(linspace(1,nt,4)); +hm = Hm; +% hm(:) = hm(:) - min(hm(:)) + 1; +hm(:) = ceil(64*hm/max(hm(:))); +for k = 1:4 + subplot(5,4,k) + i = kk(k); + for j = 1:size(Hm,1) + plot(xi{j,i},xj{j,i},'.','MarkerSize',8,'Color',rgb(hm(j,i),:)) + hold on, axis square + axis([-1 1 -1 1]*8) + end + set(gca,'Color','k') +end + +% plot results(densities and thermodynamic potentials). +%-------------------------------------------------------------------------- +% The next figure provides illustrative potentials and density functions +% from the analysis above. In brief, they reflect the characterisation of +% stochastic thermodynamics of the external states of the synthetic soup. +% These graphs illustrate the relationships between distributions and flows +% that underpin quantification in terms of classical (stochastic) +% thermodynamics. In brief, this involves estimating two functions of phase +% or state space. The first (shown in red) is the surprise or +% self-information that characterises the ensemble density. The second +% (shown in blue) is a homologous potential energy function, whose +% gradients predict the flow at each point in phase space. At +% nonequilibrium steady-state, these two functions are the same. In other +% words, the thermodynamic potential becomes self-information. This means +% that the distance or, more strictly speaking, divergence from +% steady-state can be quantified in terms of the KL divergence between the +% associated probability density functions (shown on the left). When these +% densities converge, the ensemble density stops changing and becomes NESS +% density. The middle panel shows estimates of the ensemble and +% thermodynamic potentials. The ensemble potential (i.e., surprise) was +% estimated using a polynomial approximation to the (log) sample +% distribution over an ensemble of states. The corresponding density +% functions are shown in the left panel, where the sample distribution is +% shown as a dotted line. The right panel shows the gradients of the +% thermodynamic potential (blue line) that predicts the flow sampled by the +% simulation (dots). +%-------------------------------------------------------------------------- +spm_figure('GetWin','stochastic graphs'); clf +subplot(4,3,1) +plot(b,n/db,'r:',b,Pj,'r',b,Pv,'b') +xlabel('State (nm)'), ylabel('(a.u)') +title('Ensemble density','FontSize',16), spm_axis tight + +subplot(4,3,2) +plot(b,Jj,'r',b,Jv,'b') +xlabel('State (nm)'), ylabel('Joules') +title('Potentials','FontSize',16), spm_axis tight + +j = 1:32:spm_length(q); +subplot(4,3,3) +plot(b,f,'b',q(j),p(j),'b.','MarkerSize',1) +xlabel('State (nm)'), ylabel('nm/s') +title('Flow','FontSize',16), spm_axis tight + + +%% illustrate the Lagrangian perspective (classical mechanics) +%========================================================================== +% (Classical Mechanics): this section illustrates a treatment of our +% primordial soup under a classical (Hamiltonian or Lagrangian) +% perspective. By taking ensemble averages over various quantities, one can +% suppress the influence of intrinsic (random) fluctuations, thereby +% revealing conservative, Hamiltonian dynamics mediated by solenoidal flow. +% Here, we focus on the average position of the particles of the principal +% Markov blanket and ask whether the associated motion conforms to +% classical predictions. The picture here is of a ball rolling around in a +% potential well where, crucially, the potential well changes with external +% states. In particular, we considered a second order polynomial +% approximation to the NESS potential of the blankets position (averaged +% over its constituent particles), conditioned on the position of all +% external particles. By formulating this dependency as a linear mixture of +% external positions, the gradients that produce the average motion of the +% Markov blanket can be expressed as a polynomial expansion that is +% quadratic in the blanket positions and linear in the external positions. +% The polynomial coefficients can then be estimated, using least squares, +% to best predict the average motion of the blanket; thereby specifying the +% (conditional) ensemble density and Hamiltonian dynamics. Heuristically, +% this corresponds to characterising the average behaviour of the Markov +% blanket as the motion of a marble (or ball) in a quadratic well (or bowl) +% that moves with the external states. The resulting behaviour can then be +% characterised in terms of the ball’s mass that corresponds to the +% precision (i.e., inverse variance) of motion. Upper left panel: this +% phase portrait summarises the behaviour we are trying to explain by +% plotting the position (state) against velocity (motion). In the absence +% of external perturbations, the trajectory should be a perfect circle. +% However, it appears that the external states are moving the potential +% energy well to produce more erratic, although entirely conservative, +% behaviour. Middle panel: this illustrates the potential well in terms of +% the corresponding (conditional) ensemble density shown over time, as a +% function of (a linear mixture of) external states. The shaded area +% corresponds to regions of high probability density and the white line +% shows the trajectory of the position of the Markov blanket. The black +% line is the corresponding motion of the Markov blanket. This is a +% nontrivial solution, in the sense that the external states are not simply +% moving the Markov blanket states – they are inducing Hamiltonian motion +% by moving the potential energy well. Upper right panel: the resulting +% predictions of the blanket motion account almost exactly for its +% (generalised) motion (blue dots). The red line is the corresponding +% prediction for a single particle of the Markov blanket – and illustrates +% that the states of motion only becomes the motion of states when +% intrinsic fluctuations are suppressed. In other words, each member of the +% blanket ensemble is moving somewhat erratically and actively; however, +% their collective motion can be expressed as a nearly deterministic and +% instantaneous function of their collective positions. This is nontrivial; +% in the sense that the motion being predicted is orthogonal to the +% positions (of blanket and external particles) upon which the predictions +% are based. Using the estimates of the NESS potential afforded by the +% emergence of conservative dynamics, one can now quantify the ensemble +% density for any given external state, over both the motion of state +% (left) and the state of motion (right). Lower left panel: this shows the +% marginal distribution over position, averaged over the trajectory shown. +% The marginal density (solid line) is based on the polynomial coefficients +% that best predicted motion, while the dotted line corresponds to the +% sample density. Lower right panel: this is the equivalent ensemble +% density over average motion. The precision of this density determines the +% effective mass of the Markov blanket. In this example, if we assume that +% motion is expressed in nanometres per millisecond (i.e., slow motion at a +% macromolecular scale). Then the effective mass, given Planck's constant, +% is 136 femtograms. This corresponds to an extremely heavy virus – or a +% rather lightweight bacterium. For example, a typical E. coli would have a +% mass of 630 fg. Had we assumed that the velocity was expressed in terms +% of metres per millisecond, the mass would have been in excess of 2 tonnes +% (assuming a classical Planck's constant of unity). +%-------------------------------------------------------------------------- +spm_figure('GetWin','classical mechanics');clf + +% recover the expected state and velocity of the Markov blanket +%-------------------------------------------------------------------------- +i = 512:T; +t = length(i); +b = find(bb); % blanket particles +e = find(ee); % external particles +q = mean(squeeze(X(2,b,i)))'; % mean position +p = mean(squeeze(V(2,b,i)))'; % mean velocity +q1 = squeeze(X(2,b(1),i)); % first position +p1 = squeeze(V(2,b(1),i)); % first velocity +qx = squeeze(X(1,e,i))'; % external states +qx = [qx squeeze(X(2,e,i))']; + + +% period of oscillations +%-------------------------------------------------------------------------- +[~,j]= max(abs(fft(p))); +sig = 2*t/j/2; +sig = 32; + +% find canonical loads of external states +%-------------------------------------------------------------------------- +q = spm_conv(spm_detrend(q),sig,0); +p = spm_conv(p,sig,0); +q1 = spm_conv(spm_detrend(q1),sig,0); +p1 = spm_conv(p1,sig,0); +w = spm_conv(spm_detrend(qx),sig,0); + +Qp = var(p); % inverse mass or dispersion flow + +% estimates (external) state-dependent NESS potential +%-------------------------------------------------------------------------- +clear XB +pw = @(w)[w.^0 w.^1]; +dVdB = @(q,w) [q^0*pw(w) 2*q^1]; +phiB = @(B,q,w)[q^1*pw(w) q^2]*B; +for i = 1:t + XB(i,:) = -Qp * dVdB( q(i),w(i,:)); + X1(i,:) = -Qp * dVdB(q1(i),w(i,:)); +end + +% coefficients of polynomial expansion of gradients - and plot +%-------------------------------------------------------------------------- +B = pinv(XB)*p; + +subplot(3,2,1) +plot(p,q) +xlabel('Average velocity (nm/ms)', 'FontSize',12) +ylabel('Average position (nm)','FontSize',12) +title('Phase portrait','FontSize',16) + +subplot(3,2,2) +p0 = [min(p),max(p)]*(1 + 1/8); +plot(p,XB*B,'b.',p0,p0,'b--',p1/32,X1*B/32,'r:') +xlabel('Hamiltonian prediction', 'FontSize',12) +ylabel('State of motion (nm/ms)','FontSize',12) +title('Conservative dynamics','FontSize',16), spm_axis tight + +% recover state dependent density +%-------------------------------------------------------------------------- +qq = linspace(min(q)*1.2,max(q)*1.2,64); +tt = 1:4:t; +for i = 1:length(tt) + for j = 1:64 + phi(i,j) = phiB(B,qq(j),w(tt(i),:)); + end +end + +pd = spm_softmax(-phi'); + +subplot(3,1,2) +imagesc(tt*dt,qq,(1 - pd)), hold on +plot(tt*dt,q(tt),'w',tt*dt,p(tt),'k'), hold off, axis xy +xlabel('Time (ms)', 'FontSize',12) +ylabel('Position','FontSize',12) +title('Conditional density','FontSize',16) + +% marginal density over time +%-------------------------------------------------------------------------- +subplot(3,2,5) +nq = hist(q,qq); +dq = qq(2) - qq(1); +nq = nq/sum(nq)/dq; +pq = mean(pd,2)/dq; + +plot(qq,pq,qq,nq,':') +xlabel('Position (nm)', 'FontSize',12) +ylabel('Probability density (a.u.)','FontSize',12) +title('Marginal density over state','FontSize',16), spm_axis tight + +subplot(3,2,6) +[np,pp] = hist(p,64); +dp = pp(2) - pp(1); +np = np/sum(np)/dp; +qp = exp(-pp.^2/2/Qp); +qp = qp/sum(qp)/dp; + +plot(pp,qp,pp,np,':') +xlabel('Motion (nm/ms)', 'FontSize',12) +ylabel('Probability density (a.u.)','FontSize',12) +title('Marginal density over motion','FontSize',16), spm_axis tight + + +% marginal density over time (in femtograms) +%-------------------------------------------------------------------------- +h = 6.62607004*1e-34/(2*pi); % m*m*kg/s +h = h *1e33; % nm * nm * fg/ms +mass = h/Qp; +text(0,20,sprintf('mass %-.0f fg',mass)) + +return + diff --git a/toolbox/DEM/FEP_self_entropy.m b/toolbox/DEM/FEP_self_entropy.m new file mode 100644 index 00000000..5a561ebc --- /dev/null +++ b/toolbox/DEM/FEP_self_entropy.m @@ -0,0 +1,485 @@ +function FEP_self_entropy +% This demonstration uses an ensemble of particles with intrinsic (Lorentz +% attractor) dynamics and (Newtonian) short-range coupling. The focus of +% this routine is to unpack the Bayesian perspective. We first simulate +% dynamics to nonequilibrium steady-state, identify the Markov blanket and +% then examine the encoding of external states by internal states; in terms +% of their expected values. +% +% The crucial aspect of this implicit inference (and the basis of the free +% energy principle) is the existence of a conditional synchronisation +% manifold, when conditioning internal and external states on the Markov +% blanket. This provides the basis for a mapping between internal and +% external states that can be interpreted in terms of a probabilistic +% representation or inference. +% +% This Bayesian perspective is illustrated in terms of a mapping between +% the canonical modes of internal and external states (as approximated +% with a polynomial expansion). The canonical modes her are evaluated +% using an estimate of the conditional expectations based upon the +% Euclidean proximity of Markov blanket states. The ensuing posterior over +% external states is than illustrated, in relation to the actual external +% states. We also simulate event related potentials by identifying +% several points in time when the Markov blankets revisit the same +% neighbourhood. Finally, to illustrate the underlying dynamics, the +% Jacobians or coupling among internal and external states are +% presented; using different orders of coupling (i.e., degrees of +% separation) +% +%__________________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% Karl Friston +% $Id: FEP_self_entropy.m 7179 2017-10-02 18:13:03Z karl $ + + +% default settings (GRAPHICS sets movies) +%-------------------------------------------------------------------------- +rng('default') +GRAPHICS = 1; + +% Demo of synchronization manifold using coupled Lorenz attractors +%========================================================================== +N = 128; % number of (Lorenz) oscillators +T = 1024; % number of time bins +dt = 1/32; % time interval + +% parameters +%-------------------------------------------------------------------------- +P.k = 1 - exp(-rand(1,N)*4); % variations in temporal scale +P.d = 1/8; % amplitude of random fluctuations + +% states +%-------------------------------------------------------------------------- +x.p = randn(2,N)*4; % microstates (position) +x.v = zeros(2,N); % microstates (velocity) +x.q = randn(3,N)/32; % microstates (states) +u = zeros(1,T); % exogenous fluctuations + + +% generate an dynamics from initial conditions +%========================================================================== +spm_figure('GetWin','Markov blanket');clf +if GRAPHICS + subplot(2,2,1) +else + subplot(2,1,1) +end +load +% [Q,X,V,A,x] = spm_soup(x,u,P,T,dt,1); + +% States +%-------------------------------------------------------------------------- +% Q - history of microstates (states) +% X - history of microstates (position) +% V - history of microstates (velocity) + +for i = 1:size(X,3) + S(:,:,i) = [Q(1:2,:,i);X(:,:,i);V(:,:,i)]; +end + +% self organisation in terms of self entropy +%========================================================================== + +% Sample image of blanket states for the i-th blanket +%-------------------------------------------------------------------------- +W = 256; +X0 = ones(W,1); +it = 0:256:1024; +for i = 1:size(S,2) + + % time window + %---------------------------------------------------------------------- + for tt = 1:4 + t = it(tt); + + % get blanket and external states + %------------------------------------------------------------------ + for j = 1:W + ni = 1:size(S,2); + ni(i) = []; + b(j,:) = spm_vec(S(:, i,t + j))'; + e(j,:) = spm_vec(S(:,ni,t + j))'; + end + b = squeeze(b); + + % canonical variate analysis for dimension reduction + %------------------------------------------------------------------ + CVA = spm_cva(b,e,X0); + w = CVA.w; + + % get distances (Euclidean) + %------------------------------------------------------------------ + D = 0; + for j = 1:size(CVA.w,2) + d = CVA.w(:,j)*ones(1,W); + D = D + (d' - d).^2; + end + + % get imaging blanket states + %------------------------------------------------------------------ + bb = b; + for j = 1:W + d = D(:,j); + d(abs((1:W) - j) < W/8) = Inf; + [d,ii] = min(d); + D(ii,:) = Inf; + bb(j,:) = spm_vec(S(:,i,t + ii))'; + end + + % evaluate covariances + %------------------------------------------------------------------ + Cbbe = cov([b bb w]); + Cbb = cov([b bb]); + Cb = cov([b]); + + % evaluate relative entropy is + %------------------------------------------------------------------ + Hbbe = spm_logdet(Cbbe)/2; + Hbb = spm_logdet(Cbb)/2; + Hb = spm_logdet(Cb)/2; + + HB(i,tt) = Hb; + IB(i,tt) = Hb + Hb - Hbb; + HBb(i,tt) = Hbb - Hb; + + % accumulate and plot + %------------------------------------------------------------------ + subplot(3,4,tt), imagesc(Cbb), axis square + + subplot(3,1,2), bar([mean(HB,1) mean(HBb,1) mean(IB,1)]) + drawnow + + + end + + +end + + +return + +% Adjacency matrix +%-------------------------------------------------------------------------- +t = (T - 256):T; % final time indices +L = sparse(double(any(A(:,:,t),3)))'; + +% internal states (defined by principle eigenvector of Markov blanket) +%-------------------------------------------------------------------------- +B = double((L + L' + L'*L)); +B = B - diag(diag(B)); +v = spm_svd(B*B',1); +[v,j] = sort(abs(v(:,1)),'descend'); + +% get Markov blanket and divide into sensory and active states +%-------------------------------------------------------------------------- +m = j(1:8); % internal cluster +mm = sparse(m,1,1,N,1); % internal states +bb = B*mm & (1 - mm); % Markov blanket +ee = 1 - bb - mm; % external states +b = find(bb); +e = find(ee); +m = find(mm); +s = b(find( any(L(b,e),2))); +a = b(find(~any(L(b,e),2))); + +% adjacency matrix - with partition underneath (LL) +%-------------------------------------------------------------------------- +k = [e; s; a; m]; +LL = L; +LL(e,e) = LL(e,e) + 1/8; +LL(s,s) = LL(s,s) + 1/8; +LL(a,a) = LL(a,a) + 1/8; +LL(m,m) = LL(m,m) + 1/8; +LL = LL(k,k); + +% plot dynamics for the initial and subsequent time periods +%-------------------------------------------------------------------------- +subplot(4,1,3) +r = 1:512; +plot(r,squeeze(Q(1,e,r)),':c'), hold on +plot(r,squeeze(Q(1,m,r)),' b'), hold off +axis([r(1) r(end) -32 32]) +xlabel('Time','FontSize',12) +title('Electrochemical dynamics','FontSize',16) + +subplot(4,1,4) +r = 1:T; +plot(r,squeeze(V(1,e,r)),':c'), hold on +plot(r,squeeze(V(1,m,r)),' b'), hold off +axis([r(1) r(end) -32 32]) +xlabel('Time','FontSize',12) +title('Newtonian dymanics','FontSize',16) + + +% Markov blanket - self-assembly +%========================================================================== +subplot(2,2,1) +imagesc(1 - LL) +axis square +xlabel('Element','FontSize',12) +xlabel('Element','FontSize',12) +title('Adjacency matrix','FontSize',16) + + +% follow self-assembly +%-------------------------------------------------------------------------- +clear M +for i = (T - 512):T + + % plot positions + %---------------------------------------------------------------------- + subplot(2,2,2),set(gca,'color','w') + + px = ones(3,1)*X(1,:,i) + Q([1 2 3],:,i)/16; + py = ones(3,1)*X(2,:,i) + Q([2 3 1],:,i)/16; + plot(px,py,'.b','MarkerSize',8), hold on + px = X(1,e,i); py = X(2,e,i); + plot(px,py,'.c','MarkerSize',24) + px = X(1,m,i); py = X(2,m,i); + plot(px,py,'.b','MarkerSize',24) + px = X(1,s,i); py = X(2,s,i); + plot(px,py,'.m','MarkerSize',24) + px = X(1,a,i); py = X(2,a,i); + plot(px,py,'.r','MarkerSize',24) + + xlabel('Position','FontSize',12) + ylabel('Position','FontSize',12) + title('Markov Blanket','FontSize',16) + axis([-1 1 -1 1]*8) + axis square, hold off, drawnow + + % save + %---------------------------------------------------------------------- + if i > (T - 128) && GRAPHICS + M(i - T + 128) = getframe(gca); + end + +end + +% set ButtonDownFcn +%-------------------------------------------------------------------------- +if GRAPHICS + h = findobj(gca); + set(h(1),'Userdata',{M,16}) + set(h(1),'ButtonDownFcn','spm_DEM_ButtonDownFcn') + xlabel('Click for Movie','Color','r') +end + + +% illustrate the Bayesian perspective (predictability of external states) +%========================================================================== +spm_figure('GetWin','Bayesian perspective');clf + +% establish a statistical dependency between internal (dynamic) states (XQ) +%-------------------------------------------------------------------------- +T = 512; % length of timeseries +t = size(X,3) - T - 2; +for i = 1:T + Xe(i,:) = spm_vec(V(:,e,i + t)); % external states + Xb(i,:) = spm_vec(S(:,[a;s],i + t)); % Markov blanket + Xm(i,:) = spm_vec(Q(:,m,i + t)); % internal states +end +xe = zeros(size(Xe)); +xm = zeros(size(Xm)); +iC = inv(cov(Xb)); + +% probabilistic proximity in the space of the Markov blanket +%-------------------------------------------------------------------------- +for i = 1:T + for j = 1:T + r = Xb(i,:) - Xb(j,:); + w(i,j) = exp(-(r*iC*r')/128); + end +end + +% convert into proper probability distribution +%-------------------------------------------------------------------------- +w = diag(sum(w,2))\w; + +% mean +%-------------------------------------------------------------------------- +for i = 1:T + for j = 1:T + xe(i,:) = xe(i,:) + w(i,j)*Xe(j,:); + xm(i,:) = xm(i,:) + w(i,j)*Xm(j,:); + end +end + +% covariance (not used) +%-------------------------------------------------------------------------- +% ce = zeros(size(Xe,1),size(Xe,2),size(Xe,2)); +% for i = 1:T +% for j = 1:T +% ce(i,:,:) = squeeze(ce(i,:,:)) + w(i,j)*(Xe(i,:) - xe(i,:))'*(Xe(j,:) - xe(j,:)); +% end +% end + +% normalise and identify canonical eigenvariates +%-------------------------------------------------------------------------- +xe = spm_detrend(xe); +xm = spm_detrend(xm); +CVA = spm_cva(xe,xm); + +% show results - canonical vectors over elements (mode M) +%-------------------------------------------------------------------------- +subplot(3,2,1) + +M = 1; +Ve = CVA.V(:,M); +Ve = spm_unvec(Ve,V(:,e,1)); +ve = sum(Ve.^2); +ve = ve/max(ve); +for k = 1:length(Ve) + c = [0 1 1]*ve(k) + [1 1 1]*(1 - ve(k)); + plot(X(1,e(k),end),X(2,e(k),end),'.','MarkerSize',32,'Color',c), hold on +end + +% overplot mode of motion +%-------------------------------------------------------------------------- +quiver(X(1,e,end),X(2,e,end),Ve(1,:),Ve(2,:)) + +Vm = CVA.W(:,M); +Vm = spm_unvec(Vm,Q(:,m,1)); +vm = sum(Vm.^2); +vm = vm/max(vm); +for k = 1:length(Vm) + c = [0 0 1]*vm(k) + [1 1 1]*(1 - vm(k)); + plot(X(1,m(k),end),X(2,m(k),end),'.','MarkerSize',32,'Color',c), hold on +end +xlabel('Position', 'FontSize',12) +ylabel('Position','FontSize',12) +title('Canonical mode','FontSize',16) + +% conditional synchronisation manifold (polynomial approximation) +%========================================================================== + +% polynomial approximation +%-------------------------------------------------------------------------- +xX = xm*CVA.W(:,M); +XX = [xX.^0 xX.^1 xX.^2 xX.^3 xX.^4 xX.^5]; +bE = pinv(XX)*Xe*CVA.V(:,M); +qE = XX*bE; + +% conditional expectation and variance +%-------------------------------------------------------------------------- +% for i = 1:T +% qC(i) = CVA.V(:,1)'*squeeze(ce(i,:,:))*CVA.V(:,1); +% end +qC = ones(size(qE)); +qC = abs(var(Xe*CVA.V(:,1) - qE)*qC/mean(qC)); + +% show results - conditional synchronisation manifold +%-------------------------------------------------------------------------- +subplot(3,2,2) +plot(CVA.w(:,1),Xe*CVA.V(:,1),'.c' ), hold on +plot(CVA.w(:,1),qE,'.b' ), hold off +xlabel('Internal mode', 'FontSize',12) +ylabel('External mode','FontSize',12) +title('Synchronisation manifold','FontSize',16), spm_axis tight + +% show results - conditional distributions as a function of time +%-------------------------------------------------------------------------- +subplot(3,1,2) +plot(Xe*CVA.V(:,1),'c' ), hold on +spm_plot_ci(qE',qC(:)'), hold off +xlabel('Time', 'FontSize',12) +ylabel('External states','FontSize',12) +title('Inferred and real motion','FontSize',16), spm_axis tight + + +% event related potentials +%========================================================================== + +% identify points of interest using the external canonical variate +%-------------------------------------------------------------------------- +u = CVA.v(:,1); +ue = []; +for i = 1:8 + [d,j] = max(u(33:end - 65)); + j = j + 32; + % j = fix(rand*T); % random times + k = (j - 32):(j + 64); % perstimulus time (around j) + u((j - 8):(j + 8)) = -Inf; % eliminate from next max(u(:,1)) + ue(:,i) = Xe(k,:)*CVA.V(:,1); + um(:,i) = Xm(k,:)*CVA.W(:,1); + us(i) = j; + +end +j = any(ue); +us = us(j); +ue = spm_detrend(ue(:,j)); +um = spm_detrend(um(:,j)); + +% plot points of interest on conditional density +%-------------------------------------------------------------------------- +subplot(3,1,2) +uy = get(gca,'Ylim'); hold on +for i = 1:length(us),plot([1 1]*us(i),uy,':'), end, hold off + +% show time locked (internal and external) fluctuations and their mean +%-------------------------------------------------------------------------- +subplot(3,2,5) +pst = (-32:64)*8; +plot(pst,ue,'c:',pst,um,'b:'), hold on +plot(pst,mean(ue,2),'c',pst,mean(um,2),'b'), hold on +plot([0 0],get(gca,'YLim'),'--'), hold off, axis square +xlabel('Time (milliseconds)', 'FontSize',12) +ylabel('Electrochemical response','FontSize',12) +title('Simulated ERP','FontSize',16) + +% canonical correlations +%-------------------------------------------------------------------------- +subplot(3,2,6) +bar(CVA.r,1/2,'c') +xlabel('Mode', 'FontSize',12) +ylabel('Correlation','FontSize',12) +title('Canonical correlations','FontSize',16), axis square + + + +% Jacobian's and generalised synchronisation +%========================================================================== +spm_figure('GetWin','Jacobians');clf + +% get Markov blanket indices the Jacobian +%-------------------------------------------------------------------------- +xi = spm_zeros(x); xi.v(:,e) = 1; iXe = find(spm_vec(xi)); +xi = spm_zeros(x); xi.q(:,m) = 1; iXm = find(spm_vec(xi)); + +% show results - Jacobians (of increasing order: 1 to n) +%-------------------------------------------------------------------------- +[d,j] = max(CVA.v(:,1)); +j = j + (-8:8); +J = spm_soup(Q(:,:,j),X(:,:,j),V(:,:,j),P); +J = mean(J,3); +j = [iXe;iXm]; +% q = 8; +% U = blkdiag(CVA.V(:,1:q),CVA.W(:,1:q)); % eigenmodes (not used) + +n = 4; +for i = 1:n + + % all states + %---------------------------------------------------------------------- + JJ = J^i; + subplot(n,2,(i - 1)*2 + 1) + spy(abs(JJ) > 1e-2,'k') + title(sprintf('%i-order coupling',i),'FontSize',16) + xlabel('All states','FontSize',12) + ylabel('All states','FontSize',12) + + % Internal and external states + %---------------------------------------------------------------------- + JJ = JJ(j,j); % JJ = pinv(U)*JJ(j,j)*U; + subplot(n,2,(i - 1)*2 + 2) + spy(abs(JJ) > 1e-2,'k') + title(sprintf('%i-order coupling',i),'FontSize',16) + xlabel('External and internal','FontSize',12) + ylabel('External and internal','FontSize',12) + +end + + +return + diff --git a/toolbox/DEM/MDP_search_graphics.mat b/toolbox/DEM/MDP_search_graphics.mat index 2dd408d77b168478dc09517b477b0c045bc3c47d..55b692809192cc23266c73b408a542234f3d7ec1 100644 GIT binary patch delta 470867 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%0D>4~vU&DXd6tnPh3V6s;??Pk@6`dpGMI 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 !nn5sbrEI7sqKczRPsM&2^&Q6 z<<0NNm!3ZIS_!?>eYq9A-HO)LoQ#~x8%?84S-E=39@e`PvJAt^56 z;{6x{kXZSYH)2)Vv%C;2m#{PVaR-fR&?9if@a9oSF#YdEZF0pdu!$++`U+P-;W@rc=cWn24*SZ+_{r0$dKo#eO{+?SBe|Q zPkzm2_a{P4P{dpr(%NS$Rb?%@>A~8)rZKx39fH_10ATTo6nL}yq|C_Of7Q_)=MYx8 z@IO&8cd)CyV)E+kS(N0Lg3VD$==((rsZ|ME4uN=*dBm8nc0p@TpNq&IzC&6b(2)!FXyoP zD?)&EWZH8G0)Ny`S{X$fgJFg#-u5vT>Yv|@7pz=Bvs`@(&a3dV_2d(mvq8t#tkZ@g zV%EB4O5V-a`|y*f#Tk(N6z$1DRL0zQR%b5m3%+!o8KBt6x8d$nq~d<3p+}xyske=y z-hzjDJ>g+ zMMdcjgohyypt7r@ZAF9k2cW(2!r)Vr)0`NT~d9)iQRR55%lN<_(Vx`4L}Sl^fx_2 zSH3Awbuq4=LZ*OfM7HeT$V-#~YteJmgnIw1Lw=SnLwj#tVwo(7p$d1f9N+1ACFK*} z^KuKpBs|<7l0SifLBke!TQp2fkm&M~bBByD4{{Y8$V4-m=YY?F@NeT&1s~#bqReP- zjL*D=jVToxqF=C^cpj*@ZTqJq2svObjn9iMkt5B1CwgSnXW4!Z<89?) zIS_r^{<2gfiG;R45=w!5L5X|fMXp=%eQ~SN(_xgBtkuGP=@J5L#!!-QPO9ItIPaHd zRJR22TYnly!;pW_=lRtwIS35umoiV#Y9NrGBf9^szy@Rnd8}D>9(J1$y7JKEiyvU_ z>&{ypSB;&*&l@>GPk%D{7(QF$ws@CFB>ugLVDRUwe#xnlEgzRktw9)DJCxOmo;tPRVnEDKwIlkZ&0{Zv?gykEZdKvh z^r^AiX~W`^&jUk#vjO(v^^K?O%_y|QfYuX<#Na`7$oU%O+{kd+y?404)}X*4$`W|y z;}iqh6S={}oHEY9s5ergqC4KccXQ5}ED{dgR_=W#pZauBX=B$<1oqekTNwrYtzJAG z)5SZ~dNkc2Dmlye*X{@HLhv7W;m6BTel?nE{&a7hDGssjC!n>?vu>RF+M4Fmq}yQ^ zkZD8JJ4-AtlF1+jo zIPt9~F>ZGK9HM2Mq07!yifqbYn6ybYRReMKem!VJo>aq@<`&R`EO02S8^la;No%|| zXQypTrC%ZN(3rD_+pTCwyG`@-IURFObKh9BlNgMmowg64XPjEWPf=W?3CG+=s!nIQ zLGgMt?u-SR;TP1EPGCFhzh%`KL{ANW3hHjE4c{@{U6izz@)E{>>T-lM`6Qwwq5f)^ zN7+m{`K5l^v6@_J8dheVP>C9TOTF-Fw9H-n9S*1-K@A*^m3>bky>Z01=QO^qDxYXT ztPmJVgZU2-PP@JaLn7qR=uCU-9%GO@4r;@}(Tp!hVa`C^x7|`L;>&E``>z6)|9-Ho|v{ zGEv$_
  • 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

    =CM76-Yg{4pzXC+QZbKPe8|iKRnC&PG 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 Qf!AMclaP2~wduxx1Elp{I{*Lx delta 468985 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%0AFxO!9Fw}BEeG8!n_whI&if*B+;|e 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�#Q;I2F18)}X@_G@-L=<#*IllRzAHD$e-|Ej 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

    @N-P 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
    5_f0n?NX2|8b2N|g9xItIK1J~9n> z4g-19eo@=<+Hon|l*+vZ9Z%>Xf&Iu_9!;MI78dPvV!uEf#mYDtX|s0-otO|(9Ecrs z8vJDilq3@^2|QN_c|tNLorIR;`AEzT3|qn(P*q!wAPPHw-)ZIq!O z*BT8)v;orLn*}t8MQj*|4W#g&h(-y%qwejZm8xlX4T3{`g--Y;$_{uUhpQnfa_@$Q zYcTuyLr_wuLQa+Ysv&HPIFoP)>@+@Pu?2b!#6APgCJ|7Zg`UFyt0)Msl*E$5`nFx) z#@sh4NwgjImQdKWGkWWRR4?nOp#0cdKBMt6SEK65-v@vdcJ`dqmW`4R{oLxfLk$bn z&k98jwybb}H$Oj$$p5=S^2jSOAriFmrAPu%mZ2Ov4R4jX_C8AW-+TUh)z_KHIiVXD zTZh<4=f_7rx_r{(3vD|y#K#`3Ul8On`##;hVNQ6Y)8Se{)GCr;9j0hCyQu;FZ_EBH3c-m*vExF!{mHw z)!en}s_}Y$F1=y56BEsZ*J5GwkF#gWj=F*A;Lj{7fg{?@5+KL%1fdnbLXRDJ4+$*g zW3v1&5#v0Q7ui~e9ye8{Uw4~^IU$WJ=Q^!1Rh?ye>u0cqOX^%~+?WdO~)@qI926VchQEUaAlQDgMMcgyfN zC_9#;Q3c`JOFOeZpz3gSV=c+gs-}GTWE9(2R3Eh2La4nQXZl0MW2WsS^0^8&0a=I~ z<1SUY(j-aZ2!!Kc1$-FDOXOgjjI^zko`Ox@s8a1&?}?o?4{v4viUqueFL+YU9HrY3 zzhG!q+|KYj-$V;r`^Z@*N|d!tXI|&HMCHFiFZeJd@)KE)K-A6#QW)Zra4a%QbV$@* zWpXLrn`sG4b<`ma_R)~hkPS~L4IW!RSWW|z3!y)x1FTxZ77=F>A6>q~$BgzPoi>ID zu`fpuT$OTNl&3WCN3i@w+<~@;>Ra9xu@h2?N%UvuanDN?Kngc@?)Y)&iiTSaphB|ulBk|9b5Btv^{wG8E9bSIMVcA*Mp*_VBE^DJ(-$6guu_Wp$-in^8%loUpuqBHI znQx}kGU{qkg^x}tEi=jr4x==Vgf6_BN!I*Rw&&yBn5o_BUyCb zVO%^oK-J-EA)xouY=VY@fh<2ZC?XO5s$D#&N$pG{N-kpbtE=-1GlureEcxoJj`byr zaw&88`N0>kX^@c1(-r$WZtsVxAF2+jy8V`M%Vz?gooiYCrpGejT5nD^*#A#DDN8vF zMxvqMfp7Zo3d*ixe~htxh*~MEqBtbyFy^nKF0mQd{~b8+qUrX2g;o7S#u%zxJT_3z zC0B}3T%bWem_Mt?v7d}V-aOBV+E>}rt|II1GC3g*>eNbt!dlt0ME3+Q50YI=1ChD% zIuELUhU_h#SgTLv=gYKtfC zmjQi-YSAv`>Q8k)BSqIg=1}I`+NsW@4~bqx_ix`sLcHxq^!E==3#k-2^qgP&`jj_& zyRbO0EfTAeUoV=o1ko742ioP1lYT{kz|Zhrx}t4X=Wdo!Y2V9U zCp!;cqjX;Fc)@Xrr1N%L>&&ALI;JK9;^mFYjm%Y%3h-31Ag^lKDE=P#v<*mjAO&Ne z{vv+*GKd;8%B*on4!G$%D5*_^G5igvYV$8K3!8p#NBXyTD9oe`SRm|;vv@2ea!2!S z*wE)6-u)>NxALX|h79B&{s$T-M9)|dE!R|*H#rsEn7YKbOAPsr2$vAfSpc^Z3$!fK z5eciew8ta!zN+&9adPQ4t<&1+Du04xGZ zcb`t0Xjb}KOAV4D@u-v{QNchPX^jP&h(m>Xm1>IxWJprmZ zKSzo%p%d{U8kC|;6AR3Fr8pC9{x>E~Q81~H;Jl#0T`4w6UN+4%4|FeobJ=V-4 zc4`+RfB1hhSyP~SOyY+?Ap_e)VS#T)tl3Fi8>{zeZSKPkTxG5{;0;|mf!N6^!(gEp z6}|)@8e-9)QA)x)5FyT++$@2$)tcbr=T4AzhZtNG*aZC;3C(|tArA$$-N?a|cSZ+$ zwS}=Sg%leMZ~0mV_6{yjF&Jr){o6 zgV*SDaTTl8@)C2SAx*;$u7;*=p0&aPU5!$F0!)T7TcJTQnKg&yQOsG3?O{S)!)YJx zy{J5}Evl`i(ZHGz;u!CB5H%RTuxrgoWEc6)a4O_C3h|`!tOCsv)@QzXxu2!QVm|II z7op_Y3jaGkIvSecwv)izw#sAdDD+$O#6NBR5L*>{^;$9H33{`{w}E&-;nwN8;H~jb zPanw6?#~jxE*xsyp?CF(>D5S#H_%ytO{m6^zL#Zla5Za-L!wm^*RHILN25Z_STk_A zT-?d?JL6<{(GEy54L)+NQ(>)SerfOdtfZ} zOh5j*@vKhKp5--|ARS^l7vOuK2C6UkoPsh%BcaEL>f%rX0_w0QY)I8Us54z5)jnDj zU4iBp2T|+aa&O=uYAFLp9t0rDL+@WzdnQ;E z4LtJON#=1AeeCkdF(lTLmE+>j=;O1nBE@5m+wuu%M@;9G$t9Xrh2!b&FF2pwafW}W zu0{Jkl_*kxoxCrkK#^BJk?^kr*5>ral#)f?qaq9Y=CMuW10Ntd7HN=M#LRmO?xFy< z7Gn!0n)7;9J0KJI(uduh=69@5K#} zExdDJ*7Z*g;w%M`8~+B%vll+~5@)|dE>T@S8XK-W&HEv_LgcN;SfmPz@M1+HUTF9W z$oQ2JSy_Um`UoPS*PMh#j!X?3?bu2ad7eG4Ev!FL;GaM1mn+Gahjs+!mny-GHYhh~ zRvV%!eo6>!`DS7m^pMk?{6AXIeZXFCAMnNtrah8~s|tUSxTc-wugzi44*ikF-}R;# zh~t5HUfKWG>J%;Hd$ zzSY2E9mhgy2WY7gD>fP*3vZ*Cr$*Vs-#gy6(xz6Ha=t$sh+{QdGB&SRPn`F(@my*W zPsTOszRUMVENC)2yufx2UYW~K?)Rn-yg{v1yU$R35p!iXuZz8~g(E`+3S`*I++<;4 z^8$Ds$`!FZ{WLjcEXxazG2ND3(bZ!fLTr(&wI~dF3%p_n=@gPCUAWWUY|!!@&jl#U zg)PmsZ*j_dAsF-=ka*l##RO*|h!G$tK_tNWm^1FqUzq&H{{#HR3jIY4x|d0E2&Z2l z*@VjLRuMN~yToI@N?a%22eQ{_)}ztD;wZc#_pIh=y9QQCTB*UD7m2){`QFrhKaK`j z*IC~cp+JAiwiZJ!k^Ax$L1nHV$VmB@o zY=b}=SNJ{q$oHr}(s_q~#jpAylA&ZK!5>_Fg{dHjBvwp#Im>t|Sr7fQRq8xo+U0>W zIrS54Iu}ExkNkh$h)&(7)>F$eY!SI_vfeuU=;NoRE17hjtP9TewAxup%aW8}|RlAZo*726UDTe@re| z882AqDNV@2`swva0tsP^&py}c1n<~3kN;iaACcbB7hWXEFiHvz6c?VU3vyNRBRsab zFnRKdD?UMNXuj7gozS#0QS{*g;@4i3hC1VA!C|qx?sq%#p$Ga!MBMm;dwt@#_Byct zLN_HL?Wlp?-A9e@7kcRjZ4Cd_A8}GMI0(&{+uh#P&tFMgX99VmFA#1Gre03J8W2Y} zz&dEn;JY9CzM+yIzr~~ZV=sjLth9pt3hGzCP5SHgiuKhL#{22p9b(sY=PNKN=&-EoOkXnp7w=p%BA|W?&qTh;7(DxdWXZ zV$O5woHEev@lm;RZ{FDCMK~Qq;d4*gm=1KBBwS?>udft2n?3_RYga|HQiw<$ePWAuyC@L-Qvf~0 z(%7?GA@>4|>_U^{5GdJH;v4QszMcpWx)jyp?WsNU^>|4aZPR2GiIyZs4rrP3 zK#4oOwf#g|hcaT5i0nSIjaX3iqcpd9{bYM;V5c{(>YC8buz&?8{raIGeiXO5bu%jO zu`n;JhmFj?iw1Q_X&!hvA{!>Y6E{xmSms2#dYzKhfxgD~P-c}W92c%2l$HrVbI{%$ zQufy_(oC8XS$bq=belIVg)-LXY`WJVA4Rl7NQrhUELqa5EK)c<6m!tD>CxpgK_O{V zM2g(RlG1%#hNxcs8dQ=;srXsQ);h-47#LK%4C~8+2Gt5Im7@x-68hkDQy$9pO+qt{$Q*sR>cG?v7mzDy4XtvKu)se><=wON$ zlb|KHf_veM9w+zAq;UpcaKD2k=U|+_^y zH^=m_BY}M?@bZ;en6(|wSaxnoLY#gs{&cnO8!KK2THe!%p?fkIK>BpU!@nQQ4iZ%d zdYTie;degpcoEk=s?J(jA7r$fVUBCksRrW2h7It)S9Wr|B7p0wm8}cAqaCD?TpjqS zQ1wy1li;^il^mz_a^`qpp-#DYtnVe}>jNbOY}6>V0hxDuf%B%jJRxZuTcB!}^M+w8 zrULowuTm??rv}sl*9^HAU`u`Ig#4Sh_X}MX)IXK?Y{aS8irG#zJ~YG?Cf%^pLb1pF z6fpo?+#OVQkG6h3 zua%W0b<@mLsI084%&eRtGqbY7@|JoXD2J?DX{M$q@Y>{@WL8!xq*hv)qzx(}IO7y( z4rnPjgJJ>#GQ*$W_kI7hSg;n0#qjVv=RIeiefG9ngOs?)`1&GUe2Lm=;YlHn==4+@ zxGZ>p*&i;$(2dbgrW4GS?eSWH8SI!t4BOAmYCs3LPpR%Dn2D>MVqh*5Izw?xx_3c` zUaZeqOW&@dwP5PwK0~@)W7eZj$o?RMY70S%4TfkIq?nIqZ8}~kkuDMaH39=-ylm1? zkU_$Wx|H%af-}Wunk`3vZv?6BoIo*I=plw=cGL=Xhw0Ijo-5vnwW5Zd^dM z95pS?=mA=F@%2>ejl`bh-0sMjbXkLETI3byI&@yqjC?3cJ=bwR8MkNdf+!ym4qc*Z z^eMFF7-=kdeFd4Otd=@`@%o8vEY7V>?3!xIX2i98>Nq(0Fd&;^J|wOUbhVR0l~~MZ zP9^a;?!Az*KW3^U%-wpn?kjxxIYcyYFKB&F^g{C4we421&QPoVisCky zF)8ZuzzeH`17Cm?X^Xg#^s{BgM0_3O5+vJl0OUeN6xI$o<{#z?;R#r%(3z|Q%M(YI zSrO?9sR5vj{ADLIVn32q&d+)O$~RqTz>MVw))jH6j^p%F4REjvU9a6?6cg_{hc!%e zPj`l6a>DwcySbw)X*P}>s;$bS$JjkLW6~7Yqz_ZeqaoT4KH+>D)1ul=(t=vy=P7~2 zQqEFD0~K$2Mbg8ujs-iyN7T;>Ava?lB_;vQRl4-vZdt-MmdO>&5>|_g4t+bu{GoLc zM22}4X&1i%y2Cn-i8Xt~3Ooql!F7lF=_z&S=j@6sIVR%G>QqIva-D?x zo@wrZraAXSE^bfYr(ZS`LnVuxrF4Ode2keS=}rv(1-Er^xb0hE#+pFSdN1l|=M%1= zcd+$FEUl%7X=lEx=}bbgVn}Pn3X#JndD6&%Y#|l7^)~zgwh8!*uf$+^Q8ew_Z;_ZO z4P5gQH!mEiTM{`+kk&0nP&b(5K++OZb`o!;T}e)FPV{)ohY#xi-awB&$M5lE1G@@d;$F^|^ELf! zXcN+8D7(&h&NTV1^M4#IIVo9L=~JRuA_wBX&&Y`8v zs=7qOmPBRU$A#yGU~X-^>$zOL)#7Skrl@EO<V0cu{X&(ma#}6N8@UJ7us)8l?AG+|!krSRu&XmF zNuehM72Dt@>8vt*)I6mq;&FJhUX-A?&|1qgk$Yehwq0-K_UmICk+NHSEDQE(_IKK6{z~PUk=wXWZH`ShP1+o4-nT#v~CwX3vJ&#8F)LptNXwo6Rk9!+%!`byshBTd*pFK2F9o>#CDPk5=Q4si2 zibCA}wY*}I5rw4jeYAvVBF1^9$+nO>YOb{)>vp60@0BsT&Br4##hwMm`f9cVHV>!8 zKXKt^N-S+F%>)!Vd6*80UtV|jth%*(m8MZsCb4b$FgNtcH;u*7VN`r;uI&UW5Nh?% z8{?1J@JV9)P|bwm6NboZ4t$&ChsZt z_UT>*j?}L(SeX8G!JQ4rAR~*cGcBnak2|5f=AU%0-1qQF8DadNvhZZ8o`283D3ZfpY5)P$5aSpN1i=VlnY_%>& z7(6uK+rK!0R^!KvW0tC5q`UL?VWk>Qk(L!5~Au9oM55P=ck! z9>WA3LGaW&mtjK$7J{Qe>n-z*r`R|0HQ88^g71Q+P{Oy5KSSCg7XAv%G?+Hq$=1{c zdT194;BEH=M3sd`suiegyhWp;&s19Am@NSfhdZNw)WAq?szO>ljI%60ncT~^Gh+8R zgFy1?Z=*i5YZ8`uqTi~$O2+)8FC34lXnQrL^$HXglZ-s4Cj%>gL`svQYJMQif~EqN z0)@JzRob?3k>)-jn#s;@js1C-qZtDLR&J9UrVF{12O5e~>S`3qU+?jMmQ$t$9kFtl z)D-#}mSSvgJevQI*I>z)6fEdD>eSse7*lbMji*Ih#+V|Lp;MYA%4CCjJpXceZM52h z@q{3gxt0TC*T++p+kiBE+Da)RDO#J^*pC8sw6O*IW8q(dV%9n)IbX&Blk4TXC3cwO z5ayqRSHJ!LUl)aurJa-bzo~Q5<0FUd#H&J2W0o!TU9QcZZwOb|mo*$un#!-sxpO7_ zPUHMs7j5oY!v=%l*B@pHS$&CjGaoz{RocCcp3aAkJX2E=!TX0F|9rm43gwMlI2~4A zxUqfAE!};H0LAT%==+6pIhLz` z#A}u{iQ@?eu0Lk1{-Uiw?`aQG^~Q<$k>cuYwRd*YI<>iT^g`xX<&BY|(hl!rWzyOzQYtTg_-h3D*{o)o`=(N!L+4uehRr`rGSC!*HtIotD<1_Pmaj%liqSUm6?7ZSr~gi%dR8#+ zGDwm6C(+aYmEDJC(h4=Nqd5RAl5r1IbH$whnfv4(q7Hti@%yXf(U6!2+ya2CC2K#x zytW<(L0gLXoN#Ajsl-TH~q)ABOSp|Zftyu+|${0uH`nrz2JBHv(apdzfV_6 zY&Gk7QTb=SOOyxviQOciuWrWnK^S~g5Y|~w^8_NzBeu)%QEkSvSkx9~GmERt9R=_b zSv=PH2)#%GJ-Fu>xt2DU3_W7!9Vwj|%naT}1-wol)q7p5b$@?El1|`?`gGpz{q!$S z&#DImLYHhjrfRV2izL&#B++xm94-@-j^3d>izuW|qMiamJB8<>kq8p6KjMlXRd5XA z*SIuFdbX5-n8z%;ftivn2xijx9@@kF-cZS3BjY(oRz3jf0Z^a)`=IfCgAks%X1!_ZB@#UxE z(C2{lnw&O&xopHK{iJWaG58j6CYY2*+4X!<-z|#9SJ}8XXgJA~@eCBAT}Z+*`Qp8; zdVEE#@@njLU2{xv8+H?h!a&@$KrE0`&n1GK)KQJo5B z`AX<uCypiQy*8X!$%W)ZmbU&vWtwH*ndzNAtHuU|_ z>lY@he+;KE?yg#j&W$0n$GM3{4#;DIlsTr+EgAuTG2nTXQCJN;8!J?US<&ag7xHt= zf9t-J{83o~lR7QehH5QG@1f#0k5-c2`DQ6etKb86Hi-4*8uwt4lll)1R>E)BcOjE^n)W$%#Km#Sh`JfHcYCO`YvXk8=X$ z-;7WGf2|5aJf{>9QeuCR{@Al(5SfhfXgUW6H@c#jyyr>HbAAshlI153zF6pF6)RO&m_u zL%Rd{?e|sla5@AXE7>`n~6YkJX34FcUUx z9=UCvvr5q#KAKW$I(rXQY{$`!I;OWL@<%3c8Nly$j6%D}0(zo>uvjml1XalCqZ_mzdjLBEjg$K-It&q%%w@;myU5#D1T)DrP2b($_Tuet%D zXRJ${$IqA^AHS*Kwm{9=Jk!sW(Jx4JCQV=-L5w^KdjdtuSr;@xdVs61;%rntViw2o z|6;Gvx{Zo;W*nB1M~5TO=)*W}CzH+jI{~||A$mCc7(f}bou4q>D9~-Ch96-2473wX z#%yQ~97w_o41F|?e?xBm7sYK@c6Ny-3LHAAG|-^mTy0mQb@np8U2z+8yvHoIY&NO0 zJd5(VjQEbXuwlYl*_c#i-6R_rcSQ|ZijP8juE#8ewZzKJ6kmmRZcdX&#azZ;2^B#l zY$zbb*^lW(1ZW9t8R>p*_f%)1bqb8 z?xbD4t zT8o1bIGxeyIJ}1Pk2b+^k%o#A2V@|`{*OEfjdo&cH`U^BZiTEbSTSaA$Ckko;iY1%`d0>Wc zHTkgy@A8o&*Pw5pRj17#Lr~jdW2$6Q;QyyHMdW#`rHWU~)RFE*pSU-9fbe+M(6Y^H zsjJ+(IdI-#X)?(5QhU_aT|erKD~!{&?s@_QI}Am|?Q5XTMXuO8X1FA|E_cIn@`N6RJ!LHy7Pbb&8p97zt4C`%8%5>Id)bO3O_6aSP z{brmr_uKT=$x4%l6wQaN7KxIj0Z)AlwYjuUJrd~~bsl#<;PLH~TewE<$iVDq7heFF z@X-;Tu>MXM%r+M(JjK)_@39G&pVYc1|Wq+Of23$E_8?d;1gi{Y?= z_AaXcI8E@bXtRIS(#eU$Fc?o8yj!Z(_xf@Td(@tl)mmGl4;?gf9iyt>-#_UrV}TOi z-tnYI%JWm@n!i;Nw1_@d$_~ve2GUk4P@8|vy!ef$zhn5Za-%7qcGlvW8?L99O-8TM zWRl+&9c5nlXNrr~5lc~?Q16&xb7B-8_rC}<;-rHHXte$`_6@4AYHE$U(<~$VB}A9F z@T3SLfn-kh=cf1YG}Wg2AD?n~ZLA`VE1sl4cFy9k&39X(2UKA)B+wyTPPsW`c58S7 z&q@QnFv6-VWhi_w^UotnYBbK0;)fOAEI>?oeNN*tID_!Z!R7uMU#{n?O|&%gd@^3}O~`%2#cA()`W* zo_<3c>&~Fa^JHKT?s+`jzNnFS(;vxB!!JDfhm&Hs? zKT67y=xQ(aJwfIKMVSZqWr1F$*P4w|;x(qgOrg4E|Js5Q(sbwwcT|btK7$n^P)_i?CY2kfv z%S68OW?m_kzdLp#_zW8}?G&Fw1nPzSz4UW*Sph}|lWdv3>>)sx^Ovep`>8oJ1%Ivl z9IrI8&z#nv;JBm56KU{~V#rQzsf-WJC z)_n!NoYv))M)h&Tp$I2lwwkQaq31WxgE_vdE%dm&f_@6{)NA^bA8i* zde96K+;xXmIOZy{#Gn$Pg|B39Hjo2r7*{POJ@Xm?R_3oCxst(l(e6Lq%0l8HNovl+k+IyqeJ7+N(@hpky^UDqoc6q6L%}Tw{_K5rySK1>k>+wZi#JLAp` zvjwPg2#RQ?=uK8+K%dC+YVwuZL5vy*Wk0s5N)$V3i>YT`!vh4=4(OmHh(sTzt6)Ny zdK=uq7zu~{Kws$4py2q&i{Az_FnDN6f*UDEE99ia!uX)5O9IAIw_csjdAjDqSI98cU1o#?F8Q{E7Mll zpR&=B%%|O-W3!NXFYgTA&)W5S0JlFP&guA^0rfTdo6{I6cJ73I0m~`-PeS9J8*ux# zY>)$u<2Z-zn2*cv6VC^(WZ$?|e>u(}`45;{3fvsZ-~WUW_ph);6|z`5VO;woYQI9^ z^W)29bmNxV-U{jf@bVV_ovf1w8@CTHwlGL!*yQl&vyO{?Ly^6$54H?h&Y=$ygrrAU zhswGgH*Ys)Gn_8-?BCtwK7Y_dn%`n-8ry~dzGZ!uJpJ?Q<^EzxRitO>^vhQ7pwtXk6tNIB`Q2Z$#~vh$=gwSBhqqbAr}FqC zY_on6qkPAn8K(+Da^0M7Hb3q>n*NkL+?yF zH9N?tC&)bQdKN2pM5ab6Pns=7#8?>w<6(nMS$IReGP?m}fS?}Z3Em8ukIhUoj^~}B zKA1avkmD6l0bkfZ2Yo6;4>NC{o@Pfc-YvdjY`v}TkA;VuB&6U_Vnt#Aw~C!5sqolW6+BU`h;U-eE$hdljY==g!St8F$M)&VQwDFMNZNc zXl$(c z2n+R5kI}H%&j*6|771=Hhh3)H1b$U$mz5c_y3pu<=Ui9UI>J5s(h{bltiB zfpQ5Pf1hXbTp%ZA{Xg&Kdw z#yb7C0AcY)@ZJB$It_nV=hSEySg=y~^Gh4mWM+jNyYDfKe^3sB*xZI-lB_rOpvkt~ zJTKf6dP9z#ggSW$RbR7I>>^K(C=^zZg9NMT?*YiD^`a|~g&x%%a78ydeun!oK3hvy zjU+VL>?;81=VXNjANQ zR@3*xrUy;~ zu{7YMw7ZQb$@A?g0%f^1U3habJa_!Act1=I&%YHoklRO>LPoBj19Bw}am5DVDw2n? zDU#!Yh9Og-F>%}b3=tdyHn4;PV(WbTA-sO`4RZ&)`+X&)B&ZeC7bdzqRb#0#RCctX zrDi}*H(AU3r^mz=F9Hv^Vvr>GOkanO9Ocn{iH z3#_o?dhkE4Kgc~A&fPTjzB~H^bXp;Dj0a%l=GvG82`Yq#PeSECkWl6N*wH63d5%er_mLgKytNz z{YtySm==1b5_?y>A!sh8#qCZDISDVs!PW~8h%2GHVj-BjnqczmFr+Rm;Y*=j5<(sQ#^ikl_xj+o|1ACRV<)s?|^IP0qnHLS;@Q&1fa4z%B8G4!YWcY1qdvy90 zswx)vxLB`F+Kar{^ElV&f_A2C;d$@{rq|?%Rv6J8dD6yMg|d;ekBTN7Y7kM!=e_e6 zuM62)Oe^Y~9HbZU#Msala}$Hh4s_C;E}|HR#=-0FO+GjLS!=i1Qd_y~>B#z{V|$x( zss3R#{fk;v=we#4XD6DA0yAoeD7*ao3 zmGiruE#l|nYR?5+5hsds@u^ZKKJ-w#OD3IU9b#=w6Gp(|0(CAB@~}o?4kbb4;UahV zXf@zk_Zb*Z#0DRf|8b&xmpp3wlinaDk5%(RB6?Z=80A_P3@qf9RO2TEGT{BjD$jX9 z85rQx?EI;@`T{8ecJ4;A^Dn+SSoYLUf$`qas{0CqCTva2avVo%>$n^76uJ1y5sT@u zcg}>tr-F*4WCd^;`g%8H=kA4~qB*213gJCTg0{hbv)W%o!aB^;x73`m8D&U&$%!3% zF(VY~(M-n5*lU73iQ`v5OiLU&$Cz9e+Y)!PfR&iv4oYOTe^*~t7c8nO41}F!JeHh6 zB4D9mT;Dr+h>P)>D)r~TC3zCXOtc6PhO|%I7N0uejyvD?tL#thR=4{)VRTb@WC?PV z6%6ya(S8bg$yQF8i9LlUV)nk?p~de08PV{pDjj!~?RL%*0b!lI?evtduqFj(iF{-> zy;1RDDzJrH*Q>6*;K_14VCEGIZitjpXQO+#X3P?U_df9hvr{+v{7Xh|Lkf|0kBeW%Ou<%TBR_Y&dr}x(ZmrEqSJAs{vU7D8fl3=8IrF#o^s#Tms%*86Ryk6Ifv7Tov75|r){oi0Re6iL{tP4`Zu~mNR2X}y$AaTDei}B0zDBuZ z-scomV(qIuz=X4%_BgK6rx*WzAF==*!3}&9KdeNRmJ;0~Z{rh+46tXH-nf$w=sDgL z-2ah#hENi2XbMg7BD@FQhtK9o*M?7DltMf)YvX3q?TaPdDZbOz3Z4qy+dFgY)(uHs&-EceHl^XL@zr1Kg-2RhGm+rS&9xzbL z6(`j7KeXC>_dzYEE1y;7Y^CphD)b3&nxkQjc)vrjx`y_qn=T+sDd);gvd9mNkUl-x zDMov>DDPwKww)WqdF9T$e=x6A(6KX&b+~iz@=2U`-y7oV#~>pk*%2Gwgm-%So_`E0 zeJ`|?q`%T)8ZLCu?o9^{zUY2JHL}W!U?e`e!{jbh7EQ64Uz`dzNA7+nlo5-Ekf*?2 zG1Ov@zsoyp(@!GL3$6!+H?o8-!rrHJsuHy8N+^T&zy#@UV};#4U5N%f7sy3>rk*t7 z_hy~K7-ZbP?qE;-O!iBQ&5~Vs6Se$rI;`OST%7c&p+-?Noq+X4oSXF$a8ft;vbsPm%)+b1tXg1jt zpyy8pA}zPd&=y=pqT+h8T5Y3|s@sd~d;d%u4QbI=t4X9L?Lh*r>KXgbWc>9`zSmLz z`Qfu1dx&p-c_@X@(cbf5AFJ-oRU)N};;CLucv;8QN~~N5!>{0rsJj+zVb~h{Tq5;L z9fi)GjnnukGiyiECSH_GuEgvI&rjQ`57*{PV!wwDV!q3W8z{zM0HSd_*7NwnBj+m! zX`XTmo*x%=b_{s}$FF-~HyCy2_!v9Hd_1N4rM1=MdUv~^J!;d1hef;Y>#jV*SQ#%_ z<{n4}E)Hvm0{Eji&1v6fJ=qV!WT$#)$lo!wk5eF4AI|R*s%#P50@AVD4{^h9SU zKCl%Y=?}q}cR}@pE-HCcxA*~jOdB6eZp{x+jcq; z`g&q=yCVpw*PUFaY;exxxc32~HRK)Gb{HUH#T5I~&spw==R zMwvv?9q6|s=9-E8m5NYApXE7A3+#bLfU{X~2|=PlIJHAnV^N)Q{)hgd`xp%EE;?96 zO^j)z!RAOb4Bt3*y9N6pyTY1X9C0wPdOWI$oN7CLS27kh>+ZxT&X4J52Xe#Ml27SICMIV&)dtL|DZ%npIZKwMl?Mtkq7A0%_hpBT3bEQ0vl#Pl%P z#VB;Ic#O3P;aw&}R_F`hl&pQG5V{jZh?AB;2TQ@1CSAl!Vjr{!iWJ#06Is6Fa10@P z;^T~%+|qM<0RQbwmGJn);QI%MurTQl<+&K#XhN$Z4~_oJk!)hukKp2SCO@3?~~ak_O>xEk$;HwUgVCp3nxosKmM0 z&MtCWp9=bW{No>D3eF2eE|+R%VJaJ>TYd;^d=t0@#)sa)#x5cKtq@5mI`mBK-=2*S zkncJllRTpQ!T^^AHM>iwf6pT{Jt>z!a=rMRb>>?T<0lZS;LVBJ7?aGT0Gy7%SRPa1|dUnYog^8gC`f!SC^tNLM?S!vudl31F z#hSOl1#Ot%k+mAjO8`{aPzMpTs31gB#k{}W`b`*660VotYy4U>ta}T#MANLEa(8dy z9$t9L8?%&VM;GGzN;p=;3^i4;7|%Nk4gtp3B|c$E^PG>Cgp8baxvEg^gF%Ff6><~? z9@q$NuM%s*Pm4qooWp`fM6gtIH)^3glcN->WmF+}l3z%ro~CZ*54X&Aub) zuSmPC7k33i|6zVKGi~K4APl7;Sq`>vnFjyz%kGH);(4uvs^<(H z<_PS0Gg9j)`uY8n`MaN=OeSXDWoCbkxS3KYI@aoya3I9~rZ4OAwntf^ZyuRCX1)uz zZS6HT@t&E_9O`2+3Uk3fUU(8hyIQ2o%rLG(abUXlx{3ZwLuSs*bY}0&=v@QPnX$|- zxg!)!D67l9V4!S%KmL0pcYi_aaoeAdOq#|39@Tbv?<~ksRN`?!{s94hQ+pt*q`=8B zKa~yc+;{>)Vij7iF$g{8JjB($FxEu(GCIP1VEg>|UNt;i`-Kj)jz@E=_f9Z~Jl=Jj zc^TzPNx7o-D<&|-;#zO30j%V=ZB`5P558_kv2|cx573jqD4*HC5o5Ngt5o)d1Takx zBnJcZu+zr^Kil@2ytm6+hg8Yt4WeUV`q$!1n}R0=M}XtR?Gx;OAr$xF4E%I20=VOw zN&F1ueWaubG7marpJSV6R2u>4^_Xdh@VRVytEL$~BE-v-WaVR@Fb o|FSmgYYz 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 E51td;%K!iX diff --git a/toolbox/DEM/spm_DEM_ButtonDownFcn.m b/toolbox/DEM/spm_DEM_ButtonDownFcn.m index b8ad8265..3e206650 100644 --- a/toolbox/DEM/spm_DEM_ButtonDownFcn.m +++ b/toolbox/DEM/spm_DEM_ButtonDownFcn.m @@ -8,7 +8,7 @@ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_DEM_ButtonDownFcn.m 6377 2015-03-13 20:16:44Z karl $ +% $Id: spm_DEM_ButtonDownFcn.m 7111 2017-06-16 09:01:09Z guillaume $ % default %-------------------------------------------------------------------------- @@ -24,9 +24,18 @@ else % save avi file %------------------------------------------------------------------ - [FILENAME, PATHNAME] = uiputfile('*.avi','movie file'); - NAME = fullfile(PATHNAME,FILENAME); - movie2avi(S{1},NAME,'compression','none','fps',15) + [filename, pathname] = uiputfile('*.avi','movie file'); + if isequal(filename,0) || isequal(pathname,0), return; end + fname = fullfile(pathname,filename); + if spm_check_version('matlab','7.10') > 0 + writerObj = VideoWriter(fname,'Uncompressed AVI'); + writerObj.FrameRate = 15; + open(writerObj); + writeVideo(writerObj,S{1}); + close(writerObj); + else + movie2avi(S{1},fname,'compression','none','fps',15); %#ok + end end else @@ -38,14 +47,16 @@ if strcmp(get(gcf,'SelectionType'),'normal') return else - % save wav file %------------------------------------------------------------------ [filename, pathname] = uiputfile('*.wav','wave file'); - if ~(isequal(filename,0) || isequal(pathname,0)) - name = fullfile(pathname,filename); - S{1} = S{1}/max(S{1}(:)); - wavwrite(S{1},S{2},16,name); + if isequal(filename,0) || isequal(pathname,0), return; end + fname = fullfile(pathname,filename); + S{1} = S{1}/max(S{1}(:)); + if spm_check_version('matlab','8.0') > 0 + audiowrite(fname,S{1},S{2},'BitsPerSample',16); + else + wavwrite(S{1},S{2},16,fname); %#ok end end end diff --git a/toolbox/DEM/spm_MDP_DEM.m b/toolbox/DEM/spm_MDP_DEM.m index 6f3fc1b2..00f9272c 100644 --- a/toolbox/DEM/spm_MDP_DEM.m +++ b/toolbox/DEM/spm_MDP_DEM.m @@ -28,10 +28,10 @@ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_MDP_DEM.m 6901 2016-10-08 13:21:41Z karl $ +% $Id: spm_MDP_DEM.m 6932 2016-11-16 12:11:01Z karl $ -% evaluate true and priors over causes given discrete states +% evaluate true values and priors over causes given discrete states %-------------------------------------------------------------------------- po = spm_cross(O); ind = num2cell(o); @@ -75,11 +75,11 @@ qC = DEM.qU.C{t}(ic,ic); pE = DEM.U(:,t); pC = DEM.pU.C{t}(ic,ic); - gt = t > 1; + gt = t > 4; for i = 1:size(po,1) for j = 1:size(po,2) for k = 1:size(po,3) - rE = demi.U{i,j,k}(:,end); + rE = demi.U{i,j,k}(:,t); F(i,j,k) = F(i,j,k) + gt*spm_log_evidence(qE,qC,pE,pC,rE,pC); end end diff --git a/toolbox/DEM/spm_MDP_L.m b/toolbox/DEM/spm_MDP_L.m new file mode 100644 index 00000000..4854fd39 --- /dev/null +++ b/toolbox/DEM/spm_MDP_L.m @@ -0,0 +1,42 @@ +function L = spm_MDP_L(P,M,U,Y) +% log-likelihood function +% FORMAT L = spm_mdp_L(P,M,U,Y) +% P - parameter structure +% M - generative model +% U - inputs (observations or stimuli) +% Y - observed responses (or choices) +% +% This auxiliary function evaluates the log likelihood of a sequence of +% choices within and between trials under and MDP model of choice behaviour +% parameterised by P.required fields of the model MR: +% +% M.G - a function that returns a particular MDP parameterisation; i.e., +% MDP = M.G(P); +%__________________________________________________________________________ + +% place parameters in MDP +%-------------------------------------------------------------------------- +if ~isstruct(P); P = spm_unvec(P,M.pE); end +mdp = M.G(P); + +% place MDP in trial structure +%-------------------------------------------------------------------------- +n = numel(U); +[MDP(1:n)] = deal(mdp); +[MDP(1:n).o] = U{:}; +[MDP(1:n).u] = Y{:}; + +% solve MDP and accumulate log-likelihood +%-------------------------------------------------------------------------- +MDP = spm_MDP_VB_X(MDP); +L = 0; +for i = 1:n; + for t = 1:size(Y{i},2) + sub = num2cell(Y{i}(:,t)); + L = L + log(MDP(i).P(sub{:},t)); + end +end + +% cheat scaling to mimic multiple trials +%-------------------------------------------------------------------------- +L = L*32; diff --git a/toolbox/DEM/spm_MDP_VB.m b/toolbox/DEM/spm_MDP_VB.m index 20735b68..30ef4d13 100644 --- a/toolbox/DEM/spm_MDP_VB.m +++ b/toolbox/DEM/spm_MDP_VB.m @@ -2,47 +2,47 @@ % active inference and learning using variational Bayes % FORMAT [MDP] = spm_MDP_VB(MDP,OPTIONS) % -% MDP.S(N,1) - true initial state -% MDP.V(T - 1,P) - P allowable policies (control sequences) +% MDP.S(N,1) - true initial state +% MDP.V(T - 1,P) - P allowable policies (control sequences) % -% MDP.A(O,N) - likelihood of O outcomes given N hidden states -% MDP.B{M}(N,N) - transition probabilities among hidden states (priors) -% MDP.C(N,1) - prior preferences (prior over future outcomes) -% MDP.D(N,1) - prior probabilities (prior over initial states) +% MDP.A(O,N) - likelihood of O outcomes given N hidden states +% MDP.B{M}(N,N) - transition probabilities among hidden states (priors) +% MDP.C(N,1) - prior preferences (prior over future outcomes) +% MDP.D(N,1) - prior probabilities (prior over initial states) % -% MDP.a(O,N) - concentration parameters for A -% MDP.b{M}(N,N) - concentration parameters for B -% MDP.c(N,N) - concentration parameters for habitual B -% MDP.d(N,1) - concentration parameters for D -% MDP.e(P,1) - concentration parameters for u +% MDP.a(O,N) - concentration parameters for A +% MDP.b{M}(N,N) - concentration parameters for B +% MDP.c(N,N) - concentration parameters for habitual B +% MDP.d(N,1) - concentration parameters for D +% MDP.e(P,1) - concentration parameters for u % % optional: -% MDP.s(1,T) - vector of true states -% MDP.o(1,T) - vector of observations -% MDP.u(1,T) - vector of actions -% MDP.w(1,T) - vector of precisions +% MDP.s(1,T) - vector of true states +% MDP.o(1,T) - vector of observations +% MDP.u(1,T) - vector of actions +% MDP.w(1,T) - vector of precisions % -% MDP.alpha - upper bound on precision (Gamma hyperprior - shape [1]) -% MDP.beta - precision over precision (Gamma hyperprior - rate [1]) +% MDP.alpha - upper bound on precision (Gamma hyperprior - shape [1]) +% MDP.beta - precision over precision (Gamma hyperprior - rate [1]) % -% OPTIONS.plot - switch to suppress graphics: (default: [0]) -% OPTIONS.scheme - {'Free Energy' | 'KL Control' | 'Expected Utility'}; -% OPTIONS.habit - switch to suppress habit learning: (default: [1]) +% OPTIONS.plot - switch to suppress graphics: (default: [0]) +% OPTIONS.scheme - {'Free Energy' | 'KL Control' | 'Expected Utility'}; +% OPTIONS.habit - switch to suppress habit learning: (default: [1]) % % % produces: % -% MDP.P(M,T) - probability of emitting action 1,...,M at time 1,...,T -% MDP.Q(N,T) - an array of conditional (posterior) expectations over -% N hidden states and time 1,...,T -% MDP.X - and Bayesian model averages over policies -% MDP.R - conditional expectations over policies +% MDP.P(M,T) - probability of emitting action 1,...,M at time 1,...,T +% MDP.Q(N,T) - an array of conditional (posterior) expectations over +% N hidden states and time 1,...,T +% MDP.X - and Bayesian model averages over policies +% MDP.R - conditional expectations over policies % -% MDP.un - simulated neuronal encoding of hidden states -% MDP.xn - simulated neuronal encoding of policies -% MDP.wn - simulated neuronal encoding of precision (tonic) -% MDP.dn - simulated dopamine responses (phasic) -% MDP.rt - simulated reaction times +% MDP.un - simulated neuronal encoding of hidden states +% MDP.xn - simulated neuronal encoding of policies +% MDP.wn - simulated neuronal encoding of precision (tonic) +% MDP.dn - simulated dopamine responses (phasic) +% MDP.rt - simulated reaction times % % This routine provides solutions of an active inference scheme % (minimisation of variational free energy) using a generative model based @@ -100,7 +100,7 @@ % Copyright (C) 2005 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_MDP_VB.m 6751 2016-03-23 15:39:32Z guillaume $ +% $Id: spm_MDP_VB.m 7120 2017-06-20 11:30:30Z spm $ % deal with a sequence of trials diff --git a/toolbox/DEM/spm_MDP_VB_ERP.m b/toolbox/DEM/spm_MDP_VB_ERP.m index 23df03e5..1e797a19 100644 --- a/toolbox/DEM/spm_MDP_VB_ERP.m +++ b/toolbox/DEM/spm_MDP_VB_ERP.m @@ -29,7 +29,7 @@ % Copyright (C) 2005 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_MDP_VB_ERP.m 6854 2016-08-06 10:04:19Z karl $ +% $Id: spm_MDP_VB_ERP.m 7003 2017-02-02 18:22:56Z karl $ % defaults: assume the first factor is of interest @@ -130,7 +130,7 @@ subplot(4,1,2), imagesc(t,1:(size(v,2)),1 - v') title('Unit responses (low-level)' ,'FontSize',16), ylabel('Unit') -subplot(4,1,3), plot(t,x',t,y') +subplot(4,1,3), plot(t,x',t,y',':') title('Local field potentials','FontSize',16) ylabel('Depolarisation'),spm_axis tight grid on, set(gca,'XTick',(1:(length(t)/Nb))*Nb*dt) diff --git a/toolbox/DEM/spm_MDP_VB_LFP.m b/toolbox/DEM/spm_MDP_VB_LFP.m index e966a49a..0dae1cbf 100644 --- a/toolbox/DEM/spm_MDP_VB_LFP.m +++ b/toolbox/DEM/spm_MDP_VB_LFP.m @@ -5,12 +5,12 @@ % u - selected unit rate of change of firing (simulated voltage) % v - selected unit responses {number of trials, number of units} % -% MDP - structure (see spm_MDP_VB +% MDP - structure (see spm_MDP_VB_X.m) %__________________________________________________________________________ % Copyright (C) 2005 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_MDP_VB_LFP.m 6657 2015-12-31 17:59:31Z karl $ +% $Id: spm_MDP_VB_LFP.m 6978 2017-01-03 10:42:09Z karl $ % defaults @@ -133,7 +133,7 @@ end title('Local field potentials','FontSize',16) xlabel('time (seconds)','FontSize',12) -ylabel('Response','FontSize',12) +ylabel('response','FontSize',12) if Nt == 1, axis square, end % firing rates @@ -146,7 +146,7 @@ grid on, set(gca,'XTick',(1:(Ne*Nt))*Nb*dt), axis(a) title('Firing rates','FontSize',16) xlabel('time (seconds)','FontSize',12) - ylabel('Response','FontSize',12) + ylabel('response','FontSize',12) axis square end @@ -156,5 +156,6 @@ bar(spm_vec(dn),1,'k'), title('Phasic dopamine responses','FontSize',16) xlabel('time (updates)','FontSize',12) ylabel('change in precision','FontSize',12), spm_axis tight +YLim = get(gca,'YLim'); YLim(1) = 0; set(gca,'YLim',YLim); if Nt == 1, axis square, end diff --git a/toolbox/DEM/spm_MDP_VB_X.m b/toolbox/DEM/spm_MDP_VB_X.m index b04566eb..ee6935c3 100644 --- a/toolbox/DEM/spm_MDP_VB_X.m +++ b/toolbox/DEM/spm_MDP_VB_X.m @@ -11,6 +11,7 @@ % MDP.B{F}(NF,NF,MF) - transitions among states under MF control states % MDP.C{G}(O,T) - prior preferences over O outsomes in modality G % MDP.D{F}(NF,1) - prior probabilities over initial states +% MDP.E(P,1) - prior probabilities over policies % % MDP.a{G} - concentration parameters for A % MDP.b{F} - concentration parameters for B @@ -23,7 +24,7 @@ % % MDP.alpha - precision – action selection [16] % MDP.beta - precision over precision (Gamma hyperprior - [1]) -% MDP.tau - time constant for gradient descent +% MDP.tau - time constant for gradient descent [4] % MDP.eta - learning rate for a and b parameters % % OPTIONS.plot - switch to suppress graphics: (default: [0]) @@ -95,7 +96,7 @@ % Copyright (C) 2005 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_MDP_VB_X.m 6902 2016-10-08 19:28:25Z karl $ +% $Id: spm_MDP_VB_X.m 7120 2017-06-20 11:30:30Z spm $ % deal with a sequence of trials @@ -193,13 +194,19 @@ %---------------------------------------------------------------------- if isfield(MDP,'a') A{g} = spm_norm(MDP.a{g}); + rA{g} = spm_back(MDP.a{g}); qA{g} = spm_psi(MDP.a{g} + 1/16); wA{g} = 1./spm_cum(MDP.a{g}) - 1./(MDP.a{g} + p0); wA{g} = wA{g}.*(MDP.a{g} > 0); else - A{g} = MDP.A{g}; + A{g} = spm_norm(MDP.A{g}); + rA{g} = spm_back(MDP.A{g}); end + % ensure true probabilities are normalised + %---------------------------------------------------------------------- + MDP.A{g} = spm_norm(MDP.A{g}); + end % transition probabilities (priors) @@ -238,6 +245,15 @@ end end +% priors over policies - concentration parameters +%-------------------------------------------------------------------------- +if isfield(MDP,'E') + E = spm_norm(MDP.E); +else + E = spm_norm(ones(Np,1)); +end +qE = spm_log(E); + % prior preferences (log probabilities) : C %-------------------------------------------------------------------------- @@ -442,11 +458,11 @@ %====================================================================== S = size(V,1) + 1; F = zeros(Np,1); - for k = p - dF = 1; - for i = 1:Ni - F(k) = 0; - for j = 1:S + for k = p % loop over plausible policies + dF = 1; % reset criterion for this policy + for i = 1:Ni % iterate belief updates + F(k) = 0; % reset free energy for this policy + for j = 1:S % loop over future time points % marginal likelihood over outcome factors %---------------------------------------------------------- @@ -577,8 +593,8 @@ % posterior and prior beliefs about policies %------------------------------------------------------------------ - qu = spm_softmax(gu(t)*Q(p) + F(p)); - pu = spm_softmax(gu(t)*Q(p)); + qu = spm_softmax(qE(p) + gu(t)*Q(p) + F(p)); + pu = spm_softmax(qE(p) + gu(t)*Q(p)); % precision (gu) with free energy gradients (v = -dF/dw) %------------------------------------------------------------------ @@ -815,6 +831,13 @@ end end +function A = spm_back(A) +% normalisation of a probability transition matrix (columns) +%-------------------------------------------------------------------------- +for i = 1:size(A,1) + A(i,:,:,:,:) = A(i,:,:,:,:)/sum(A(i,:)); +end + function A = spm_cum(A) % summation of a probability transition matrix (columns) %-------------------------------------------------------------------------- diff --git a/toolbox/DEM/spm_MDP_VB_game.m b/toolbox/DEM/spm_MDP_VB_game.m index ce6cc50f..bed9a31f 100644 --- a/toolbox/DEM/spm_MDP_VB_game.m +++ b/toolbox/DEM/spm_MDP_VB_game.m @@ -32,7 +32,7 @@ % Copyright (C) 2005 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_MDP_VB_game.m 6763 2016-04-04 09:24:18Z karl $ +% $Id: spm_MDP_VB_game.m 6978 2017-01-03 10:42:09Z karl $ % numbers of transitions, policies and states %-------------------------------------------------------------------------- @@ -189,6 +189,8 @@ end title('Precision (dopamine)') ylabel('Precision','FontSize',12), spm_axis tight +YLim = get(gca,'YLim'); YLim(1) = 0; set(gca,'YLim',YLim); + % learning - D %-------------------------------------------------------------------------- diff --git a/toolbox/DEM/spm_MDP_check.m b/toolbox/DEM/spm_MDP_check.m index 1b5a5596..e0f55063 100644 --- a/toolbox/DEM/spm_MDP_check.m +++ b/toolbox/DEM/spm_MDP_check.m @@ -30,7 +30,7 @@ % Copyright (C) 2005 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_MDP_check.m 6748 2016-03-14 10:04:41Z karl $ +% $Id: spm_MDP_check.m 6977 2016-12-24 17:48:44Z karl $ % deal with a sequence of trials @@ -175,18 +175,51 @@ end end -% check names is specified +% check factors and outcome modalities have proper labels +%-------------------------------------------------------------------------- +for i = 1:Nf + try + MDP.label.factor{i}; + catch + MDP.label.factor{i} = sprintf('factor %i',i); + end + for j = 1:Ns(i) + try + MDP.label.name{i}{j}; + catch + MDP.label.name{i}{j} = sprintf('state %i(%i)',j,i); + end + end +end +for i = 1:Ng + try + MDP.label.modality(i); + catch + MDP.label.modality{i} = sprintf('modality %i',i); + end + for j = 1:No(i) + try + MDP.label.outcome{i}{j}; + catch + MDP.label.outcome{i}{j} = sprintf('outcome %i(%i)',j,i); + end + end +end + +% check names are specified properly %-------------------------------------------------------------------------- if isfield(MDP,'Aname') if numel(MDP.Aname) ~= Ng error('please specify an MDP.Aname for each modality') end +else + MDP.Aname = MDP.label.modality; end if isfield(MDP,'Bname') if numel(MDP.Bname) ~= Nf error('please specify an MDP.Bname for each factor') end +else + MDP.Bname = MDP.label.factor; end - - diff --git a/toolbox/DEM/spm_MDP_plot.m b/toolbox/DEM/spm_MDP_plot.m new file mode 100644 index 00000000..a48f8ace --- /dev/null +++ b/toolbox/DEM/spm_MDP_plot.m @@ -0,0 +1,281 @@ +function spm_MDP_plot(MDP) +% creates a movie of hierarchical expectations and outcomes +% FORMAT spm_MDP_plot(MDP)) +% +% MDP - nested MDP (and DEM) structures +% - (requires fields to specify the labels of states and outcomes) +%__________________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% Karl Friston +% $Id: spm_MDP_plot.m 6977 2016-12-24 17:48:44Z karl $ + +% Preliminaries +%-------------------------------------------------------------------------- +cla,axis([1 20 0 8]); axis image, hold on, box on +set(gca,'Fontsize',16,'XColor','r','TickLength',[0 0],'XTick',[],'YTick',[]) +title('Narrative construction','FontSize',16) + +% switch off basis functions for visual stimuli +%-------------------------------------------------------------------------- +try +global STIM +B = STIM.B; +STIM.B = 1; +end + +% hidden factors to display (one per level) +%-------------------------------------------------------------------------- +scale = 1 - 1/16; % background level for text +try k1 = MDP.label.k; catch, k1 = 1; end +try k2 = MDP.MDP.label.k; catch, k2 = 1; end + +% cycle over highest level +%-------------------------------------------------------------------------- +T1 = size(MDP.xn{k1},4); +F1 = fix(1024/(T1*numel(MDP.label.name{k1}{1}))); +F1 = min(max(F1,8),32); +for t1 = 1:T1 + + % draw stuff + %---------------------------------------------------------------------- + p = 1 - squeeze(MDP.xn{k1}(end,:,:,t1)); + p = p*scale; + str = MDP.label.name{k1}; + ns = size(p,1); + nt = size(p,2); + for i = 1:nt + for j = 1:ns + try + set(h1(i,j),'Color',[1 1 1]*p(j,i)); + catch + h1(i,j) = text(16*i/nt,j/ns + 6,str(j),... + 'HorizontalAlignment','center',... + 'Color',[1 1 1]*p(j,i),'FontSize',F1); + end + end + end + + + % next level down + %---------------------------------------------------------------------- + if isfield(MDP,'mdp') + T2 = size(MDP.mdp(t1).xn{k2},4); + F2 = fix(1024/(T2*numel(MDP.MDP.label.name{k1}{1}))); + F2 = min(max(F2,8),32); + for t2 = 1:T2 + + % draw stuff + %-------------------------------------------------------------- + p = 1 - squeeze(MDP.mdp(t1).xn{k2}(end,:,:,t2)); + p = p*scale; + str = MDP.MDP.label.name{k2}; + ns = size(p,1); + nt = size(p,2); + for i = 1:nt + for j = 1:ns + try + set(h2(i,j),'Color',[1 1 1]*p(j,i)); + catch + h2(i,j) = text(16*i/nt,j/ns + 4,str(j),... + 'HorizontalAlignment','center',... + 'Color',[1 1 1]*p(j,i),'FontSize',F2); + end + end + end + + % check for extra time points + %-------------------------------------------------------------- + try + delete(h2((nt + 1):end,:)) + end + + % next level down + %-------------------------------------------------------------- + if isfield(MDP.mdp(t1),'dem') + + % accumulated expectations from Bayesian filtering + %---------------------------------------------------------- + o = MDP.mdp(t1).dem(t2).X; + no = numel(o); + T = size(o{1},2); + + else + + % observed outcomes + %---------------------------------------------------------- + o = MDP.mdp(t1).o; + no = size(o,1); + T = 16; + end + + % outcome modalities + %-------------------------------------------------------------- + set(gca,'XTickLabel',MDP.MDP.label.modality) + set(gca,'XTick',16*(1:no)/no) + + F3 = fix(1024/(no*numel(MDP.MDP.label.outcome{1}{1}))); + F3 = min(max(F3,8),32); + for t3 = 1:T + + % draw stuff + %---------------------------------------------------------- + for i = 1:no + + if iscell(o) + + % probabilistic outcomes (expectations) + %-------------------------------------------------- + x = 16*i/no; + p = spm_softmax(log(o{i}(:,t3))/4); + str = MDP.MDP.label.outcome{i}; + [p,j] = sort(p,'descend'); + col = [1 1 1] - [0 1 1]*(p(1) - 1/numel(p)); + try + set(h3(i),'String',str(j(1)),... + 'Color',col); + catch + h3(i) = text(x,3,str(j(1)),... + 'HorizontalAlignment','center',... + 'Color',col,'FontSize',F3); + end + + % observations in image format + %-------------------------------------------------- + x = [-1 1] + x; + y = [-1 1] + 1; + try + px = MDP.mdp(t1).dem(t2).pU.x{1}(:,t3); + pv = MDP.mdp(t1).dem(t2).pU.v{2}(:,t3); + px = spm_unvec(px,MDP.MDP.DEM.G(1).x); + pv = spm_unvec(pv,MDP.MDP.DEM.G(2).v); + Y = MDP.MDP.DEM.label{i}(px,pv); + try + delete(h4(i)) + end + h4(i) = image(x,y,flipud(Y)*64); + + end + + else + + % deterministic outcomes + %-------------------------------------------------- + str = MDP.MDP.label.outcome{i}{o(i,t2)}; + try + set(h3(i),'String',str); + catch + h3(i) = text(16*i/no,2,str,'Color','r',... + 'HorizontalAlignment','center','FontSize',F3); + end + end + end + + % plot timelines + %---------------------------------------------------------- + x = [1 1]*(t3 + (t2 - 1)*T + (t1 - 1)*T*MDP.MDP.T); + x = 1 + 16*x/(MDP.MDP.T*MDP.T*T); + y = [7.2 8]; + try + set(l1,'XData',x); + catch + l1 = line(x,y,'Color','r','LineWidth',8); + end + + x = [1 1]*(t3 + (t2 - 1)*T); + x = 1 + 16*x/(T*T2); + y = [5.2 6]; + try + set(l2,'XData',x); + catch + l2 = line(x,y,'Color','r','LineWidth',8); + end + + x = [1 1]*t3; + x = 1 + 16*x/T; + y = [3.2 4]; + try + set(l3,'XData',x); + catch + l3 = line(x,y,'Color','r','LineWidth',8); + end + + % and save graphics + %---------------------------------------------------------- + try + M(end + 1) = getframe(gca); + catch + M = getframe(gca); + end + + end + end + + else + + % observed outcomes + %------------------------------------------------------------------ + o = MDP.o; + no = size(o,1); + T = 16; + F3 = fix(1024/(no*numel(MDP.label.outcome{1}{1}))); + F3 = min(max(F3,8),48); + + % outcome modalities + %------------------------------------------------------------------ + set(gca,'XTickLabel',MDP.label.modality) + set(gca,'XTick',16*(1:no)/no) + + for t3 = 1:T + + % draw stuff + %-------------------------------------------------------------- + for i = 1:no + str = MDP.label.outcome{i}{o(i,t1)}; + try + set(h3(i,j),'String',str); + catch + h3(i,j) = text(16*i/no,2,str,'Color','r',... + 'HorizontalAlignment','center','FontSize',F3); + end + end + + % plot timelines + %-------------------------------------------------------------- + x = [1 1]*(t3 + (t1 - 1)*T); + x = 1 + 16*x/(T*T1); + y = [7.2 8]; + try + set(l2,'XData',x); + catch + l2 = line(x,y,'Color','r','LineWidth',8); + end + + x = [1 1]*t3; + x = 1 + 16*x/T; + y = [5.2 6]; + try + set(l3,'XData',x); + catch + l3 = line(x,y,'Color','r','LineWidth',8); + end + + % and save graphics + %-------------------------------------------------------------- + try + M(end + 1) = getframe(gca); + catch + M = getframe(gca); + end + + end + end +end + + +% save movie +%-------------------------------------------------------------------------- +try, STIM.B = B; end +set(gca,'Userdata',{M,16}) +set(gca,'ButtonDownFcn','spm_DEM_ButtonDownFcn') + diff --git a/toolbox/DEM/spm_Manifold_solve.m b/toolbox/DEM/spm_Manifold_solve.m index c6a91fe6..46bc2eec 100644 --- a/toolbox/DEM/spm_Manifold_solve.m +++ b/toolbox/DEM/spm_Manifold_solve.m @@ -2,10 +2,67 @@ %========================================================================== function [Q,X,V,A,x] = spm_Manifold_solve(x,u,P,T,dt,PLOT) % FORMAT [Q,X,V,A,x] = spm_Manifold_solve(x,u,P,T,dt,PLOT) -% PLOT = 0 - no grphics +% FORMAT [J] = spm_Manifold_solve(Q,X,V,P) +% +% x - hidden states (3 x N) +% u - exogenous input +% P - parameter structure +% +% P.d - s.d. of random fluctuations +% +% PLOT = 0 - no graphics % PLOT = 1 - quick graphics % PLOT = 2 - quick graphics with trajectory % PLOT = 3 - pretty graphics +% +% returns: +% +% Q - history of microstates (states) +% X - history of microstates (position) +% V - history of microstates (velocity) +% A - adjacency matrix +% x - state structure +% +% This auxiliary routine integrates a system – or returns the Jacobian for +% specified states. It deals with the special case of within and between +% particle coupling. +%__________________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% Karl Friston +% $Id: spm_Manifold_solve.m 7166 2017-09-08 19:07:09Z karl $ + +% equations of motion +%-------------------------------------------------------------------------- +fx = @spm_lorenz_n; + +% compute Jacobian for pre-evaluated states +%========================================================================== +if isnumeric(x) + + % rearrange inputs + %---------------------------------------------------------------------- + Q = x; + X = u; + V = P; + P = T; + clear x + x.p = X(:,:,1); + x.v = V(:,:,1); + x.q = Q(:,:,1); + J = zeros(spm_length(x),spm_length(x),size(Q,3)); + + % evaluate Jacobian is for the states provided – and return + %---------------------------------------------------------------------- + for i = 1:size(Q,3) + x.p = X(:,:,i); + x.v = V(:,:,i); + x.q = Q(:,:,i); + J(:,:,i) = spm_diff(fx,x,0,P,1); + end + Q = J; + return +end % defaults @@ -13,6 +70,8 @@ try, T; catch, T = 512; end try, dt; catch, dt = 1/64; end try, PLOT; catch, PLOT = 0; end +try, P.d; catch, P.d = 1; end + % set up %-------------------------------------------------------------------------- @@ -21,12 +80,11 @@ N = size(x.p,2); % number of microsystems Q = zeros(3,N,T); % history of microstates (states) X = zeros(2,N,T); % history of microstates (position) -V = zeros(2,N,T); % history of microstates (dusty) +V = zeros(2,N,T); % history of microstates (velocity) A = zeros(N,N,T); % adjacency matrix % Integrate %-------------------------------------------------------------------------- -fx = @spm_lorenz_n; dn = 16; dt = dt/dn; for i = 1:T @@ -35,17 +93,24 @@ %---------------------------------------------------------------------- xn = spm_vec(x); for j = 1:dn - [f a] = fx(spm_unvec(xn,x),u,P); + + % flow + %------------------------------------------------------------------ + [f,a] = fx(spm_unvec(xn,x),u,P); + + % plus random fluctuations + %------------------------------------------------------------------ + f = f + randn(size(f)).*P.d; xn = xn + f*dt; end - x = spm_unvec(xn,x); + x = spm_unvec(xn,x); % adjacency matrix and states %---------------------------------------------------------------------- A(:,:,i) = a; - Q(:,:,i) = x.q; X(:,:,i) = x.p; V(:,:,i) = x.v; + Q(:,:,i) = x.q; % graphics %---------------------------------------------------------------------- @@ -117,12 +182,9 @@ return - - - + % Equations of motion %========================================================================== - function [f,A] = spm_lorenz_n(x,u,P) % Equations of motion for coupled Lorenz attractors % FORMAT [f,A] = spm_lorenz_n(x,u,P) @@ -148,13 +210,13 @@ % orders and flow %-------------------------------------------------------------------------- -[n N] = size(x.p); +[n,N] = size(x.p); f = x; % get distances (Euclidean) %-------------------------------------------------------------------------- D = 0; -X = cell(n); +X = cell(n,1); for i = 1:n d = ones(N,1)*x.p(i,:); X{i} = (d' - d); @@ -167,7 +229,7 @@ A = A - diag(diag(A)); % remove self conections A(P.a,:) = 0; % preclude outward edges A(:,P.b) = 0; % preclude inward edges -[i j] = find(A); +[i,j] = find(A); k = find(A); C = sparse(i,j,1./sqrt(D(k)),N,N); @@ -182,20 +244,21 @@ % State-dependent coupling %-------------------------------------------------------------------------- -xq = x.q(:,:)*A/8; -xp = x.q(1,:)*A; +xq = x.q(:,:)*A/8; +xp = x.q(1,:)*A; % Lorentz dynamics (Prandtl number = 10) %-------------------------------------------------------------------------- q = x.q + xq; - + f.q(1,:) = 10*(q(2,:) - q(1,:)); f.q(2,:) = (32 + xp).*q(1,:) - q(2,:) - q(1,:).*q(3,:); f.q(3,:) = q(2,:).*q(1,:) - 8/3*q(3,:); +% Implement particle specific time constants +%-------------------------------------------------------------------------- f.q = ones(3,1)*P.k.*f.q; - % Newtonian notion %========================================================================== @@ -210,12 +273,9 @@ % Newtonian motion %-------------------------------------------------------------------------- f.p = x.v; -f.v = F*32 - x.v*8 - x.p; +f.v = (F*32 - x.v*8 - x.p); % vectorised flow %-------------------------------------------------------------------------- -f = [f.p(:); f.v(:); f.q(:)]; +f = spm_vec(f); -% plus random fluctuations -%-------------------------------------------------------------------------- -f = f + randn(size(f)); diff --git a/toolbox/DEM/spm_find_internal.m b/toolbox/DEM/spm_find_internal.m new file mode 100644 index 00000000..3e90e80e --- /dev/null +++ b/toolbox/DEM/spm_find_internal.m @@ -0,0 +1,19 @@ +function nj = spm_find_internal(z,J) +% FORMAT nj = spm_find_internal(z,J) +% finds indices of internal states (that do not contribute to slow modes) +%__________________________________________________________________________ +[u,s] = eig(full(J),'nobalance'); +[s,j] = sort(real(diag(s)),'descend'); +u = u(:,j); +v = pinv(u); +nu = sum(s > (max(s) - 4)); +u = u(:,1:nu); +v = v(1:nu,:); +s = real(s(1:nu)); +nz = numel(z); +for i = 1:nz + dJdj = spm_zeros(J); + dJdj(: ,z{i}) = 1; + dJdj(z{i},z{i}) = 0; + nj(i) = exp(s')*diag(abs(v*dJdj*u)); +end diff --git a/toolbox/DEM/spm_soup.m b/toolbox/DEM/spm_soup.m new file mode 100644 index 00000000..6bf204f3 --- /dev/null +++ b/toolbox/DEM/spm_soup.m @@ -0,0 +1,264 @@ +% Integration scheme and graphics +%========================================================================== +function [Q,X,V,A,x] = spm_soup(x,u,P,T,dt,PLOT) +% FORMAT [Q,X,V,A,x] = spm_soup(x,u,P,T,dt,PLOT) +% FORMAT [J] = spm_soup(Q,X,V,P) +% +% x - hidden states (3 x N) +% u - exogenous input +% P - parameter structure +% +% PLOT = 0 - no graphics +% PLOT = 1 - quick graphics +% PLOT = 2 - quick graphics with trajectory +% PLOT = 3 - pretty graphics +% +% returns: +% +% Q - history of microstates (states) +% X - history of microstates (position) +% V - history of microstates (velocity) +% A - adjacency matrix +% x - state structure +% +% This auxiliary routine integrates a system – or returns the Jacobian for +% specified states. It deals with the special case of within and between +% particle coupling. +%__________________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% Karl Friston +% $Id: spm_soup.m 7163 2017-09-04 09:12:50Z karl $ + +% equations of motion +%-------------------------------------------------------------------------- +fx = @spm_lorenz_n; + +% compute Jacobian for pre-evaluated states +%========================================================================== +if isnumeric(x) + + % rearrange inputs + %---------------------------------------------------------------------- + Q = x; + X = u; + V = P; + P = T; + clear x + x.p = X(:,:,1); + x.v = V(:,:,1); + x.q = Q(:,:,1); + J = zeros(spm_length(x),spm_length(x),size(Q,3)); + + % evaluate Jacobian is for the states provided – and return + %---------------------------------------------------------------------- + for i = 1:size(Q,3) + x.p = X(:,:,i); + x.v = V(:,:,i); + x.q = Q(:,:,i); + J(:,:,i) = spm_diff(fx,x,0,P,1); + end + Q = J; + return +end + + +% defaults +%-------------------------------------------------------------------------- +try, T; catch, T = 512; end +try, dt; catch, dt = 1/64; end +try, PLOT; catch, PLOT = 0; end +try, P.d; catch, P.d = 1; end + + +% set up +%-------------------------------------------------------------------------- +if PLOT, cla, end +d = 8; % diameter for graphics markers +N = size(x.p,2); % number of microsystems +Q = zeros(3,N,T); % history of microstates (states) +X = zeros(2,N,T); % history of microstates (position) +V = zeros(2,N,T); % history of microstates (velocity) +A = zeros(N,N,T); % adjacency matrix + +% Integrate +%-------------------------------------------------------------------------- +dn = 16; +dt = dt/dn; +for i = 1:T + + % update + %---------------------------------------------------------------------- + xn = spm_vec(x); + for j = 1:dn + + % flow + %------------------------------------------------------------------ + [f,a] = fx(spm_unvec(xn,x),u,P); + + % plus random fluctuations + %------------------------------------------------------------------ + f = f + randn(size(f)).*P.d; + xn = xn + f*dt; + end + x = spm_unvec(xn,x); + + % adjacency matrix and states + %---------------------------------------------------------------------- + A(:,:,i) = a; + X(:,:,i) = x.p; + V(:,:,i) = x.v; + Q(:,:,i) = x.q; + + % graphics + %---------------------------------------------------------------------- + C = mean(x.q,2); + if PLOT == 3 + for j = 1:N + + % colour + %-------------------------------------------------------------- + c = x.q(:,j) - C; + c = spm_softmax(c/std(c)); + + % plot positions + %-------------------------------------------------------------- + set(gca,'color','k') + + px = x.p(1,j) + x.q([1 2 3],j)/32; + py = x.p(2,j) + x.q([2 3 1],j)/32; + plot(px,py,'.c','MarkerSize',24,'color',c), hold on + + end + xlabel('Position','FontSize',12) + title('Dynamics','FontSize',16) + axis([-1 1 -1 1]*d) + axis square + hold off + + % save image + %------------------------------------------------------------------ + if i < 128 + M(i) = getframe(gca); + end + + elseif PLOT > 0 + + % plot positions + %------------------------------------------------------------------ + set(gca,'color','w') + + px = ones(3,1)*x.p(1,:) + x.q([1 2 3],:)/32; + py = ones(3,1)*x.p(2,:) + x.q([2 3 1],:)/32; + plot(px,py,'.b','MarkerSize',8), hold on + px = x.p(1,:); + py = x.p(2,:); + plot(px,py,'.c','MarkerSize',24) + axis([-1 1 -1 1]*d) + + % plot trajectories + %------------------------------------------------------------------ + if PLOT == 1, hold off, end + xlabel('Position','FontSize',12) + title('Dynamics','FontSize',16) + axis square + + end + drawnow + +end + +% set ButtonDownFcn +%-------------------------------------------------------------------------- +if PLOT == 3 + h = findobj(gca); + set(h(1),'Userdata',{M,16}) + set(h(1),'ButtonDownFcn','spm_DEM_ButtonDownFcn') + xlabel('Click for Movie','Color','r') +end + + +return + + +% Equations of motion +%========================================================================== +function [f,A] = spm_lorenz_n(x,u,P) +% Equations of motion for coupled Lorenz attractors +% FORMAT [f,A] = spm_lorenz_n(x,u,P) +% x - hidden states (3 x N) +% u - exogenous input +% P - parameters +% P.k - variations in temporal scale +% +% f - flow +% A - weighted adjacency matrix +%__________________________________________________________________________ + + +% orders and flow +%-------------------------------------------------------------------------- +[n,N] = size(x.p); +f = x; + +% get distances (Euclidean) +%-------------------------------------------------------------------------- +D = 0; +X = cell(n); +for i = 1:n + d = ones(N,1)*x.p(i,:); + X{i} = (d' - d); + D = D + X{i}.^2; +end + +% enforce short-range coupling (and constraints) +%-------------------------------------------------------------------------- +A = D < 1; % coupling in range +A = A - diag(diag(A)); % remove self conections +[i,j] = find(A); +k = find(A); +C = sparse(i,j,1./sqrt(D(k)),N,N); + +% get electrochemical distances (Dynamic) +%-------------------------------------------------------------------------- +d = ones(N,1)*x.q(1,:); +D = abs(d' - d); +Q = sparse(i,j,8*exp(-D(k)*2) - 4,N,N); + +% Lorentz dynamics +%========================================================================== + +% local electrochemical average +%-------------------------------------------------------------------------- +xq = x.q(1,:)*A; + +% Lorentz dynamics (Prandtl number = 10) +%-------------------------------------------------------------------------- +f.q(1,:) = 10*(x.q(2,:) - x.q(1,:)) + xq/8; +f.q(2,:) = 32.*x.q(1,:) - x.q(2,:) - x.q(1,:).*x.q(3,:); +f.q(3,:) = x.q(2,:).*x.q(1,:) - 8/3*x.q(3,:); + +% Implement particle specific time constants +%-------------------------------------------------------------------------- +f.q = f.q*diag(P.k); + +% Newtonian notion +%========================================================================== + +% strong (repulsive - C) and weak (electrochemical - Q) forces +%-------------------------------------------------------------------------- +CQ = full((C.^2).*(Q - C)); +F = zeros(n,N); +for i = 1:n + F(i,:) = sum(X{i}.*CQ); +end + +% Newtonian motion +%-------------------------------------------------------------------------- +f.p = x.v*diag(1 + x.q(3,:)/64); +f.v = (F*32 - x.v*8 - x.p); + +% vectorised flow +%-------------------------------------------------------------------------- +f = spm_vec(f); + diff --git a/toolbox/FieldMap/FIL/pm_defaults_Prisma.m b/toolbox/FieldMap/FIL/pm_defaults_Prisma.m new file mode 100644 index 00000000..39697a95 --- /dev/null +++ b/toolbox/FieldMap/FIL/pm_defaults_Prisma.m @@ -0,0 +1,65 @@ +% SPM5 UPDATE 23/11/07 +% Sets the default values for the FieldMap toolbox +% +% FORMAT pm_defaults_Prisma +%_______________________________________________________________________ +% +% This file is intended for use with the Siemens fieldmap sequence +% on the Prisma scanner at the FIL and the most standard EPI sequences +% with PE blips = -1: nc_epi2d_v2f; +% +% Check phase over-sampling factor for TOTAL_EPI_READOUT_TIME +%_______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% Chloe Hutton and Jesper Andersson + +global pm_def + +% Defaults for creating field map. (See pm_make_fieldmap.m and +% FieldMap.man for more info.) +%======================================================================= +pm_def.INPUT_DATA_FORMAT = 'PM'; % 'RI' = load two real and + % imaginary image pairs + % 'PM' = load one or two + % phase and magnitude image + % pairs. +pm_def.SHORT_ECHO_TIME = 10.0; % Short echo time in ms +pm_def.LONG_ECHO_TIME = 12.46; % Long echo time in ms +pm_def.MASKBRAIN = 1; % Do brain masking (1 or 0, + % 0 for EPI fieldmaps) + +% Defaults for unwrapping options. (See pm_make_fieldmap.m and +% FieldMap.man for more info.) +%======================================================================= +pm_def.UNWRAPPING_METHOD = 'Mark3D'; % Unwrapping options are: + % 'Huttonish', 'Mark3D' or 'Mark2D' +pm_def.FWHM = 10; % FWHM of Gaussian filter used to + % implement weighted smoothing of + % unwrapped maps. +pm_def.PAD = 0; % Size of padding kernel if required. +pm_def.WS = 1; % Weighted or normal smoothing. + +% Flags for brain extraction +%======================================================================= +pm_def.MFLAGS.TEMPLATE = fullfile(spm('Dir'),'toolbox','FieldMap','T1.nii'); +pm_def.MFLAGS.FWHM = 5; % In mm +pm_def.MFLAGS.NERODE = 2; % In voxels +pm_def.MFLAGS.NDILATE = 4; % In voxels +pm_def.MFLAGS.THRESH = 0.5; +pm_def.MFLAGS.REG = 0.02; % A larger value helps segmentation to converge +pm_def.MFLAGS.GRAPHICS = 0; % A larger value helps segmentation to converge + +% Defaults for converting field map to voxel displacement map. +%======================================================================= +pm_def.EPI_BASED_FIELDMAPS = 0; % EPI=1, other=0. +pm_def.K_SPACE_TRAVERSAL_BLIP_DIR = -1; % Meaning blip gradients are negative => PE direction (of prewinder is positive) +pm_def.TOTAL_EPI_READOUT_TIME = 36.0; % EPI RO time (0.5*64*(1 + Over Sampling Factor/100)) = 72 with OS = 12% + +% Defaults for Unwarping. +%======================================================================= +pm_def.DO_JACOBIAN_MODULATION = 0; % Do jacobian modulation to adjust + % for compression or stretching + % No = 0, Yes = 1 + + diff --git a/toolbox/FieldMap/FIL/pm_defaults_Trio_al_128.m b/toolbox/FieldMap/FIL/pm_defaults_Trio_al_128.m index acf9f28a..ae951b11 100644 --- a/toolbox/FieldMap/FIL/pm_defaults_Trio_al_128.m +++ b/toolbox/FieldMap/FIL/pm_defaults_Trio_al_128.m @@ -1,7 +1,6 @@ -% SPM5 UPDATE 23/11/07 -% Sets the default values for the FieldMap toolbox +% Set the default values for the FieldMap toolbox % -% FORMAT pm_defaults_Trio_eFoV +% FORMAT pm_defaults_Trio_al_128 %_______________________________________________________________________ % % This file is intended for use with the Siemens fieldmap sequence @@ -12,7 +11,7 @@ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Chloe Hutton and Jesper Andersson -% $Id: pm_defaults_Trio_al_128.m 5265 2013-02-20 13:01:37Z guillaume $ +% $Id: pm_defaults_Trio_al_128.m 7211 2017-11-13 10:38:15Z guillaume $ global pm_def @@ -42,7 +41,7 @@ % Flags for brain extraction %======================================================================= -pm_def.MFLAGS.TEMPLATE = fullfile(spm('Dir'),'templates','T1.nii'); +pm_def.MFLAGS.TEMPLATE = fullfile(spm('Dir'),'toolbox','FieldMap','T1.nii'); pm_def.MFLAGS.FWHM = 5; % In mm pm_def.MFLAGS.NERODE = 2; % In voxels pm_def.MFLAGS.NDILATE = 4; % In voxels diff --git a/toolbox/FieldMap/FIL/pm_defaults_Trio_al_64.m b/toolbox/FieldMap/FIL/pm_defaults_Trio_al_64.m index b6e67906..cefcc923 100644 --- a/toolbox/FieldMap/FIL/pm_defaults_Trio_al_64.m +++ b/toolbox/FieldMap/FIL/pm_defaults_Trio_al_64.m @@ -1,7 +1,6 @@ -% SPM5 UPDATE 23/11/07 -% Sets the default values for the FieldMap toolbox +% Set the default values for the FieldMap toolbox % -% FORMAT pm_defaults_Trio_eFoV +% FORMAT pm_defaults_Trio_al_64 %_______________________________________________________________________ % % This file is intended for use with the Siemens fieldmap sequence @@ -12,7 +11,7 @@ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Chloe Hutton and Jesper Andersson -% $Id: pm_defaults_Trio_al_64.m 5265 2013-02-20 13:01:37Z guillaume $ +% $Id: pm_defaults_Trio_al_64.m 7211 2017-11-13 10:38:15Z guillaume $ global pm_def @@ -42,7 +41,7 @@ % Flags for brain extraction %======================================================================= -pm_def.MFLAGS.TEMPLATE = fullfile(spm('Dir'),'templates','T1.nii'); +pm_def.MFLAGS.TEMPLATE = fullfile(spm('Dir'),'toolbox','FieldMap','T1.nii'); pm_def.MFLAGS.FWHM = 5; % In mm pm_def.MFLAGS.NERODE = 2; % In voxels pm_def.MFLAGS.NDILATE = 4; % In voxels diff --git a/toolbox/FieldMap/FIL/pm_defaults_Trio_al_96.m b/toolbox/FieldMap/FIL/pm_defaults_Trio_al_96.m index 53e1ba74..eab5eec8 100644 --- a/toolbox/FieldMap/FIL/pm_defaults_Trio_al_96.m +++ b/toolbox/FieldMap/FIL/pm_defaults_Trio_al_96.m @@ -1,7 +1,6 @@ -% SPM5 UPDATE 23/11/07 -% Sets the default values for the FieldMap toolbox +% Set the default values for the FieldMap toolbox % -% FORMAT pm_defaults_Trio_eFoV +% FORMAT pm_defaults_Trio_al_96 %_______________________________________________________________________ % % This file is intended for use with the Siemens fieldmap sequence @@ -12,7 +11,7 @@ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Chloe Hutton and Jesper Andersson -% $Id: pm_defaults_Trio_al_96.m 5265 2013-02-20 13:01:37Z guillaume $ +% $Id: pm_defaults_Trio_al_96.m 7211 2017-11-13 10:38:15Z guillaume $ global pm_def @@ -42,7 +41,7 @@ % Flags for brain extraction %======================================================================= -pm_def.MFLAGS.TEMPLATE = fullfile(spm('Dir'),'templates','T1.nii'); +pm_def.MFLAGS.TEMPLATE = fullfile(spm('Dir'),'toolbox','FieldMap','T1.nii'); pm_def.MFLAGS.FWHM = 5; % In mm pm_def.MFLAGS.NERODE = 2; % In voxels pm_def.MFLAGS.NDILATE = 4; % In voxels diff --git a/toolbox/FieldMap/FieldMap.m b/toolbox/FieldMap/FieldMap.m index 687f3d84..db7126e3 100644 --- a/toolbox/FieldMap/FieldMap.m +++ b/toolbox/FieldMap/FieldMap.m @@ -103,10 +103,10 @@ % % Wellcome Trust and IBIM Consortium %__________________________________________________________________________ -% Copyright (C) 2006-2014 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2006-2016 Wellcome Trust Centre for Neuroimaging % Jesper Andersson and Chloe Hutton -% $Id: FieldMap.m 6416 2015-04-21 15:34:10Z guillaume $ +% $Id: FieldMap.m 6994 2017-01-26 16:19:14Z guillaume $ persistent PF FS WS PM % GUI related constants @@ -142,14 +142,9 @@ case 'welcome' % Unless specified, set visibility to on - if nargin==2 - if ~strcmp(varargin{2},'off') && ~strcmp(varargin{2},'Off') - visibility = 'On'; - else - visibility = 'Off'; - end - else - visibility = 'On'; + visibility = 'On'; + if nargin==2 && strcmpi(varargin{2},'off') + visibility = 'Off'; end DGW = 0; @@ -161,7 +156,7 @@ % there is no-one else out there. % if ~isempty(PM) - figure(PM); + if strcmpi(visibility,'on'), figure(PM); end set(PM,'Visible',visibility); return end @@ -198,39 +193,39 @@ uicontrol(PM,'Style','Text','String','Create field map in Hz',... 'Position',[100 480 300 020].*WS,... 'ForegroundColor','k','BackgroundColor',col,... - 'FontName',PF.times,'FontAngle','Italic') + 'FontName',PF.times,'FontAngle','Italic'); uicontrol(PM,'Style','Text','String','Short TE',... 'Position',[25 452 60 20].*WS,... 'ForegroundColor','k','BackgroundColor',col,... - 'FontName',PF.times) + 'FontName',PF.times); uicontrol(PM,'Style','Text','String','ms',... 'Position',[78 430 30 20].*WS,... 'ForegroundColor','k','BackgroundColor',col,... - 'FontName',PF.times) + 'FontName',PF.times); uicontrol(PM,'Style','Text','String','Long TE',... 'Position',[25 392 60 20].*WS,... 'ForegroundColor','k','BackgroundColor',col,... - 'FontName',PF.times) + 'FontName',PF.times); uicontrol(PM,'Style','Text','String','ms',... 'Position',[78 370 30 20].*WS,... 'ForegroundColor','k','BackgroundColor',col,... - 'FontName',PF.times) + 'FontName',PF.times); uicontrol(PM,'Style','Text','String',{'Mask brain:'},... 'Position',[30 310 80 35].*WS,... 'ForegroundColor','k','BackgroundColor',col,... - 'FontName',PF.times) + 'FontName',PF.times); uicontrol(PM,'Style','Text','String',{'Precalculated','field map:'},... 'Position',[30 275 80 35].*WS,... 'ForegroundColor','k','BackgroundColor',col,... - 'FontName',PF.times) + 'FontName',PF.times); uicontrol(PM,'Style','Text','String',{'Field map value:'},... 'Position',[240 280 100 20].*WS,... 'ForegroundColor','k','BackgroundColor',col,... - 'FontName',PF.times) + 'FontName',PF.times); uicontrol(PM,'Style','Text','String',{'Hz'},... 'Position',[403 280 20 20].*WS,... 'ForegroundColor','k','BackgroundColor',col,... - 'FontName',PF.times) + 'FontName',PF.times); %-Objects with Callbacks @@ -302,32 +297,32 @@ 'String','Create voxel displacement map (VDM) and unwarp EPI',... 'Position',[70 235 350 020].*WS,... 'ForegroundColor','k','BackgroundColor',col,... - 'FontName',PF.times,'FontAngle','Italic') + 'FontName',PF.times,'FontAngle','Italic'); uicontrol(PM,'Style','Text',... 'String','EPI-based field map',... 'Position',[50 200 200 020].*WS,... 'ForegroundColor','k','BackgroundColor',col,... - 'FontName',PF.times) + 'FontName',PF.times); uicontrol(PM,'Style','Text',... 'String','Polarity of phase-encode blips',... 'Position',[50 170 200 020].*WS,... 'ForegroundColor','k','BackgroundColor',col,... - 'FontName',PF.times) + 'FontName',PF.times); uicontrol(PM,'Style','Text',... 'String','Apply Jacobian modulation',... 'Position',[50 140 200 020].*WS,... 'ForegroundColor','k','BackgroundColor',col,... - 'FontName',PF.times) + 'FontName',PF.times); uicontrol(PM,'Style','Text',... 'String','Total EPI readout time',... 'Position',[50 110 200 020].*WS,... 'ForegroundColor','k','BackgroundColor',col,... - 'FontName',PF.times) + 'FontName',PF.times); uicontrol(PM,'Style','Text',... 'String','ms',... 'Position',[370 110 30 020].*WS,... 'ForegroundColor','k','BackgroundColor',col,... - 'FontName',PF.times) + 'FontName',PF.times); %-Objects with Callbacks @@ -448,7 +443,7 @@ 'ToolTipString','Site specific default files',... 'Position',[400 480 60 22].*WS); else - uicontrol(PM,'Style','PopUp',... + uicontrol(PM,'Style','popupmenu',... 'String',menu_items,... 'Enable','On',... 'ToolTipString','Site specific default files',... @@ -477,7 +472,7 @@ % Set input format if ~isempty(IP.uflags.iformat) - if strcmp(IP.uflags.iformat,'RI'); + if strcmp(IP.uflags.iformat,'RI') h = findobj(get(PM,'Children'),'Tag','IFormat','UserData',1); FieldMap('RadioOn',h); IP.uflags.iformat = 'RI'; diff --git a/toolbox/FieldMap/pm_create_connectogram_dtj.mexmaci64 b/toolbox/FieldMap/pm_create_connectogram_dtj.mexmaci64 index 26e7548e6f669df85930ee02fb926c58ff4d69e7..0491bfe971255ee1e5fbdc2d2a9c2fcb39471b07 100755 GIT binary patch literal 13484 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 literal 13464 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 Qj-hWQS9v)2&s&s#1LzkxKL7v# diff --git a/toolbox/FieldMap/pm_create_connectogram_dtj.mexw32 b/toolbox/FieldMap/pm_create_connectogram_dtj.mexw32 index 234898826f56cf730a37638dfa85a40ae3301ebb..b809bb90dd9d1ff66116f59aa0ee0307018e3ab9 100755 GIT binary patch delta 32 lcmZqhXz-Zuf#sj{v&e~Ge3&-$Z+2o_Bn9SgejzQv0Ra0=4r2fS delta 32 lcmZqhXz-ZufyMuTV93NTK1?gmY<6N?Bn9SgejzQv0RZBL4AB4p diff --git a/toolbox/FieldMap/pm_create_connectogram_dtj.mexw64 b/toolbox/FieldMap/pm_create_connectogram_dtj.mexw64 index d9c102778f25aaa9c40a0907b75c8edd42cbddfc..7ef3439eb23008363fd79dd1c207e02e99a31162 100755 GIT binary patch delta 32 lcmZn&Xb70_fu-d6)5wWme3*`X-|WQrNfylCY$1Pw0{{-q56S=l delta 32 lcmZn&Xb70_fkkzahH#;$Yk_GcOTgac_007!{40r$l diff --git a/toolbox/FieldMap/pm_diff.m b/toolbox/FieldMap/pm_diff.m index 0aaf93c4..30395d54 100644 --- a/toolbox/FieldMap/pm_diff.m +++ b/toolbox/FieldMap/pm_diff.m @@ -9,7 +9,7 @@ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Chloe Hutton -% $Id: pm_diff.m 6656 2015-12-24 16:49:52Z guillaume $ +% $Id: pm_diff.m 7120 2017-06-20 11:30:30Z spm $ if ischar(V) V = spm_vol(V); @@ -26,7 +26,7 @@ [X,dX,dY,dZ] = spm_sample_vol(V,x,y,z,hold); switch dir - case 1 + case 1 D = reshape(dX,dim(1),dim(2),dim(3)); case 2 D = reshape(dY,dim(1),dim(2),dim(3)); diff --git a/toolbox/FieldMap/pm_estimate_ramp.mexmaci64 b/toolbox/FieldMap/pm_estimate_ramp.mexmaci64 index 568dbf306d5b1e4c74405b391eaee2c5b752c339..7ba9a469ace7e7364ccc61eeb6653698ce74631a 100755 GIT binary patch literal 13484 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 QtZwZp#)$otA0dS7Kg<9v=l}o! diff --git a/toolbox/FieldMap/pm_estimate_ramp.mexw32 b/toolbox/FieldMap/pm_estimate_ramp.mexw32 index 7cb6363eae7d2a27928d8307792d24b474c82a57..4d936996400cbec722366d5d578d4a8bb84a5e24 100755 GIT binary patch delta 32 lcmZp0XmFVDfrU-xS>(hoK1_dWH#;#VNr3sAS4c*%0RY(i3|asH delta 32 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 diff --git a/toolbox/FieldMap/pm_ff_unwrap.mexw32 b/toolbox/FieldMap/pm_ff_unwrap.mexw32 index e7adeb7238b6d039107a0ace55b0af05534ff5ae..a1b6af8f31fcbcad73180811b89cf0c65ce225e4 100755 GIT binary patch delta 32 mcmZn&X$YC{f`wn^S>(hwK1{WXH(N1!DY5VY`I|eGE7$Hd`@zDS`Q$JCrNf0Nc0>R{#J2 diff --git a/toolbox/FieldMap/pm_ff_unwrap.mexw64 b/toolbox/FieldMap/pm_ff_unwrap.mexw64 index 21e481a9e727e7df92e77149d0a434552f1b0a93..323e14d620dbb48ba1458a37e469228538bae075 100755 GIT binary patch delta 33 mcmZojX-JvyfTisD)5wWWe3)%h88#a;25Nu>Hg{-NZ~y@RvJN2t delta 33 mcmZojX-JvyfJI}sV93NLKFmKD7&jX;25Nu>Hg{-NZ~y??pbOFf diff --git a/toolbox/FieldMap/pm_invert_phasemap_dtj.mexmaci64 b/toolbox/FieldMap/pm_invert_phasemap_dtj.mexmaci64 index dea596ffd2134fa2d4c2092d62e3f791077cb86d..b7611681c704725a42ea0116a896e18cb06659f5 100755 GIT binary patch literal 13684 zcmeHOeRLGn6`x7?h!UKHkBSOqwNgP46N4=gty#(H8=XaLuyR^(T*xljnry;;gn&e& z`Os-Pr`!JF;nbef*gsn8X%DgW^h7=CCQuUKC_%JFf}kiGj6#ebB%n-x_sz^^cayYM zPkZV)`%Y%=z3<(3-+lMpd*AGv$^J7Ro|`NPVx}MnS-5g=#U=_uBOsNFaMff8f~u}^ ztzN~el5dV=Qm|;q6d*<*NJUk{-kPw9n{=`~$N6U4v}q+O#buNmo>=Y9z49A1GD*0beDj zlh>nWuGw>?C4lHu8CDYqs_HFMeL+u!*Q`y|ugj8`XLTZ)d~Uo#ezz2JQPpDSDrW+h z!@|i?sW|xEbX=h1ZzR{2t*U`?HMF^6U1hmi6%LLo&lX4W?7k2qkbhi2h*eZ|L*>Y- zj@B>7VKP!IQ6V~2UVJRHt7^IDU+Fgs{i#%$Kp;9%9?dt`Y9l~)W4KgRkyqU2Dwgd4 z$fH&idvJ>mQ;?#N9GE*^E)#@0&Vn1wB@1wAyj2j2Knds%mu?0m?k~mfP3$mQehs9E!qt&b zkfhVKe&NE!`PLxBPxhp_nEE`2@K5G1*&GUcD;D3BsMmMFPxIUkI}==B(QTlqEW}0i zMALlJC2fJU1=1GysusADX~&&+Ie+B5)48gIX|++-d`k|~TrI3ICN(U>R>YcJQKk8w ztXuU7$7vKaZe#jQLx8dT81AiYw6Or`_DPi!pTz^7PnthJ3bg1hk@sbL#3CJoD)0o>aa-EYWROp$iD+GL|k*4lx(TV?S8 z)3g6>>g4WnKEu@@wKoBC>st)xvsC4Lp6=4zI^vWIcW%1LCrg2oK51Q_Pg?VVPulw7 zZF=@B$a={arKXS3G=Qd0(Dd1$v^w7>Ek0SDEgL&oeR~!pRKG6QpUsdS`h_V_dbkM) z_3XEVo*?dX#A`wUs1Jq1SEdSqZwT65aR zq`+(F1cR_^Bd(G$`eU_YU=65lt427WRU{ z%c%#Lwsr52Z0u9CqpZ=gjUu^@%EoTFaJSU-);Yt#sw>)_7sz1YCDPm?TDe?Ie`Z6j zAVf0m%VEa;$in`MeD-=Vqmzun3OlP`=|AR+lG*#0jjX4okE|=_8#Gxa4*O8z>rE5d z3rpp$8Xh9qr?BANx9Zu2oVmF+hGp5G-#ap%*2%=9FF-#bd=Yhiof-Q`!MCw1Lcya< z-#SZV`t2esY~OUFTYK9r?Rdj2o`rBFv$hSMGqgfqa>mwQ(Rwjb4-?OlutQvvm!L^I zx>p~QjSg9iDVgprci}Oq>9=3NLd~x2Olv0&4X!DA+fdWWG7%IA1<>7WnY%@5Dgf_K zoNJtGop(FcwL9(c#*4RYJl@*k@iuFPp8W>R(yhHHpME1ADm-#pDA0nE8E9Jod7vF2 z1c6470?h-MZ;-VU?2Qm_b2s)%4f*k*YO-ifihhrwXhSeYCo{S*moAfXwa~oyu-$HL zh(}a{Ja?mE#+#y-7))Cm=vARFZ>;t6KNBBvm+KR02%P|&Rnkf+Ex6Up-+ zB8CxZ1TvC7p(DY+SpBg0EX|KcJJQb{MMT--uM_MpE0aG`k+*qroX&wa1TH`>DI}WvQVK z9;YBnP;!CAV~Sp8@I=9rK~nxv3J)Uw6JnF^zgR)?&OPv?ZovJ3$On8s2J6`SG2$Qo z@;U@k{L^-9#{a>Q_#b0CPDm#s+p)eJLBErH`6#Z}6>S*cCGuc#9}Iat?YO5YX<a^ey13kob*cZ;%K%Litewd4;NsFUf}W78Ir z^TCBYAH2u+f1F|@<%1KO?xHy;SX@eAxY`wsq@E)cAQ7328;-VauDOT|H~Ua>e31T> zA*S;T(W?}msQ!Q}Oj(i=0dj?_ORkS$6NU5B+6+le?;;;i6q!#60LUeXB5ZAS=<53tv3-xC*!m}G+j$||ahBMf_`!xE+tlw}6Cf!#Hy#A~hrpBdIQH~0^`NqE0fDN(m z<%Ab;JTi;$n@v2M@WmF6zKf`D9%!mRhb>;#cFFahPYC9qaRoI_M`M0(|CIb*{A>?@ zho1k4HwIqTJfVka#c#A?gOLjlN8Urvj7^u`s&75sYM&%LLx-bmK?l>Xok)}DrZJiy z$m-hx1d3k4iAOmRxtJ4=nZ#61JY*6y&q3b2Omk1(yH@AyZC z(XSBCV%)ykq?S4!^(4?|uCKKEHp!?jvE|R6?olO?G1+2 zsxnW=Tj8lvOT#~%UsbWlU+S+|AdGIm&T);yAE=6i9iHHZNQE~Lb_Bf}BmSVbbWHAi zM`a|O$Q~NuA7kk2ppv5^5(+!kc^v`B5Bk?HLJv>*B8M+hUheP&N*$$@k#*%>;oo(? z#!(q`6gV&uZy@Ba40y`N?m|=jT4N>&2(9;&dxBqLB!9pW^aM6|9r=!{90hpOBM8Nnub|=Yh1ygJG5aH z{*eK7H7PdpdHm&6UnioW!dnsY;+)MB4ts-v{O_T`EF#IlC)F7@M*{1^IHwX8`TXTx z`&7+S<;MXXonHy~0;i<_hdwRzop8&Hfk^|CTeAix*Ws;;Ae=dpO>hw|oZ`ldeJn`F zNL1*^h!?8(Hd^ifv!G)aqNDi6g9?p7bRE9qqEdp3=+>E>6zDwm0*usZo!4vzEup=I zJ~&5d!bP;hI_G&DG|0Gae@&rxr_ennZR;)2fh_vt&nhMnr)Q?nb5iJeDfCS#^ld5h z>J-|WLT^l=?@ytBX43Kb;*$#g%{iHu{(k`9TJi6)$-H!IhmRfk*&LY{$9?>Jc)W5K zzJ&{=h`zc1sxlnHSjW67om=LQ-*nCRO$B2%3F_ixFBizQ<8DpFIG&x9YIxWr)tJd= zbO@2ekq8_=>!4+HzA-D^(2*Kf*l_IZVlpAGn2428K#b%PPFPul<97bwgq1l)zNY7{Cd`Tdb#S47+kI#=H-Yen7Wb)qENnQ2bM zBiW?iA3oXE(9!A-N1_eoi|xDNF40<*LPR^V6u6|mRg&lTAL(chXAE38-g>F;X4#%- z^4W3;`ofV=OZ!pTV4=P)sqY`8QAB6!gUfRg#*2aan}e;L!4PT|>bv9PqWODL%BJU) zEb?Ep{X|Q9qrauSsbdL!o63Y_jZ{E%&V0-(7B_x>u-V@f3bX}nI(L5irM@mXUZS(d z`+JH~pRJPC-Bz^q`>VV)-mDsXy}2cC0Zr?T^xC@p{>GE7jT!mn^x5iY{o1k_smz_< z-;OmWmR@Hhw8%cUw8z#*boN}*dMnDPgM4e?SLyReef3g?=xlv7-r_8M5)^z8~#47wASDJ%=w*v|AVfU9e=**tqo5e4&4qOH>pzK zg$tz}6R1)=ph=Mjb4Gl!mC7eUQ)t)kQj~twW4@Jr$dm|oD1)tBhfEl>T$Li^~RF_*?>|vL}y4|Sp#aE$XLR7rT);~gik%g}(;eDEF{+TYU=Pa)2LI~OQ z#;9(L>&8VN8+=(~gTGW`?>bm-En4dp!>muojoS0htjg|up7l3SZ*1_^618ViH}_k_ z9@fmY+tm2!A=PxQ(M{*LYHnXQ>t*h`8P@+01e#cB($_OJ%iJ5dwxx2PaUX*_xWGa~P*qF~c7HImY0t7-4;%v@FZV z2cX7lhiC-cP8x=8Tt?w6Q5|zIUo)Krx>+>B`eQf{B4fx1)?Wt-oz{8h;DIJqHoGi$-RMQsI<(lZOVs`ZwW>9&RZOr)r|7fi98t2rDsn~xw)a#PO zO~CZT^s~@amGL+C-qSD~>1Sue+`zmoWT;UyI;Wamizd{X)LC^BzMvt;R--khl6BL3 z=te>}Mlif__;mH{IH~4C#pOqsg92DuG#Wi~>NJSa@9}9T1B4kc9`kx)4J0dFYAiwH z8a`DJc}+JptGay3*E1O{p58e>ewf0$J4fB=cT8y(b?hvGv!Bx)317uU)m-aFPYyL+ z1?!Ef7v`epAjPfyIy{(bZRA7Q);f|Hx{N%(7@jU_Dzp86Dxg`Dkwawe zj2cUEb0e>7rslvLg!ijf^@L_Ur^ZoibC$5)qF-WC;BsFUs>oTcsyNC5&c;B)f z@E-CW_CDzKPog_HzvxaX3w?*JuOw?}q}gM{039&X0oP^5NPejpK8^`mU_cxlrB7kH zbR(%7Q;QcwI!-1UGpaG0Q%MVbGF|_xDnAF^%c^|_l~{zapE{scy>4QD1*SiP8hgAM zya9#)auR@?3GYE0SO|ACqJ4vt|d! z2bzNstRU4aDq#KnsKyLaI8{v`QWGK;pF@YLsbV2ahPILbk3=5ulY2~ODeG_Lg0+d+ zosb-vBeCPf6sSTfe6DFgz}=UjO2mg=G0FP+K*BI?DC^$^EwG$cm5$(??+NBZllK}i zG{?KNM6gT`jUWhShzD%&nHwFfe>)Ti5X2DN8(MG#PO3pz+tgwjRGNj75~O!PXLYhJbas`NjMwgD_5X5ZXp{ShC2)4gsSs%tS5$M z?6K1{U3}7}T^yz~10lH&KD`*aQN+Rs1vg2J&H*Q0#;inkBWi#ZG`|{pLWBYqR3oVx z7ts|3&no0e#e3Ng%czKIiA6l?`4( zc^N+5235iu*0UZ$?6F&L)r_~xr=|;=22Pb}#-v(tDe_T-H3f?b%V_A1Io)wt2u5DY z;ET`P@9d7BGiJ3RdR)*019lJqPtoFoEfw&F zZV>QdWr~RuPmV-1OM&J&z(sMHNIyVBUgjB?K7mTnbB?5dyuap^^hnF86lz}=YL`H@Z=EDG$SbhE=H_EIjfm+D3|YO#9(I0xP0@v9oOL#+ECMd^SqexDnoXWa)7 zj(pGL<&V(n@+&+(^olXo_i0iQzgLe3lfL+A9?W=J557k6*Z(zCs^)!sZ#0IbN8vE8 zJCfLj>^6%$tp9t|U>?o@7Fdi%!Xyj^*tUHw>#v70!Zz9?0^3Y{uSU9P2bZ>)I3f;u3)WrK)Fib2AJ zB&PHxt^f!{lMJ|XT=Z3(&wxYp`{KzWuJFK+9xvcate$`?ey`6|vEvIWdi*dS&Hn4@ zdBaVEpJ-El7MkbLi}jRp*t;E9-IxUIx%tWz`cIXq#@l+uxyVQPbP+7i&>$CTiChxx zvF!u?O@#L9z(38vDCKyEr9aPcB2wg zy0B+~f1O-%(SA^<9TRGoz`tJ95dPVpAM^XU|D*lfSMg58Z*M=h1-)VEa{&4s+RuF! zFJtBRbK-*p_H)nLa7I%p_HDS!-PN_u;~7o@{(tS~G~*ZEgWg)rxPYyjaaE1IQQ9+w z4c=3Dlq)EQWSO9nb$=O;!q|HSks{UHaR6J5)DSj2)_G3TZYT9k&>D7XsVlhYPDIvl zVuTZ{+kq02C#mJbcFQM-8Jk<78E0AFDs-S?SJ-nMZnW6@I82H@b>d_9n`>XyjaPD> z?-n+q1!x7~5gf40t%$yX&Rm*#*p)iWJLJ8)QdOK_-G@lGxr5tDuPdqXZK><2v?f^h z9isBMA z)ARzEZoH!#uce+Og|Vv+%_wBuk8_i+7O?K!g1v%uGk$lrH0x0fOTUPIQwLF1ex+%E zJCaTd)wuIAPJe#-hC%e*G}N-pa4H;hLRhK565P;J&ge z8V(!{-s5TMZ1e2!bhhC&%;UjO#NXK*2nX8&o&LtiUzB#XZER_5X}g1D7B{)av)R+q z-WiQ}0->YPwqSe26AB)SwuFL>%d{`|bVMWB0^y9r68+x;yF6{taKzIP^t7XgP|J~x zkO;JH^fX0VTRnmHMo(i$w4pVqD8EjAv!^5E+2X-)g6-j!j`l#S@WhgGH0lrB^9R)v zJ`!jR&~oAF*Z14f?g<6jj|M&Eo{xLBAT)NojKEVO3|}bx1b6g>!t*E*1g`X7zGhj? zdr^(bpMsgbfC(RHJ}fvd66YDtc}Q?B5a(N*0|rSE-lf07IXF-zjzOFr&beD~&JZWe zIRqDIV-hF8Ie#TMbikh8%Q=MBXmgS{J2+=la5{){7w7y)aDv3Sg>zDZ^8j%Qi32*5 zfC0*_$W(feDS435dOp#6n3Nrx1dHy0Id~Uw1>VmjNu(PU2fdShv2G=2(3mMXPW`Fk z=yE&UMTM>b)NBWj`m1{trXV#tsTGow#ERX$1^fld)vKKJhUDYUFRXCVtE92Q&#y8m z2=T#2IfUE~xT5s@vhp+nNYe|nB>TA2Nljz)dL|O-`5R>S&xD?9i}lbDVTT(9w}W0| zHCJ-;$Q)2eq~{If2_O}v|BXF&!v*{1gq{NGol?dx(jGZ38V4U08IrL_aVPxN8N7ch zOHz@YJ}2KRe?peukmdcdJS@u&S${wj?}5Ar@*eo@cwo&Rc<6XUSyxHFlNLWRZ@}-u@gwv7$J_(TG0zQ^ z{$*MBM)sj`pz!gkeG zyUIrmD{X2IQR+MuZEFaI_BJgR-)A@37b1x|n>=uYAMSxw&skb{S4UfCYp{!2HA_~N zII9GwQ*xy7)Tm3c4s-@W;UG9NIcW6vMca==aB8XGb>D$~RO3O$@yn`GS#FXgKlcK^ zQqrm{Nr>9l$+BLS&9dy2WtS}J)aEt_*akDXW z0Zm^XKz_bG>CUD%E};Kt0ljkpy>|iqzyi8?0UhDAB2VGO@67R@2mc*9ogA)4E=I;{ zZ;Bgv4e|}hcwJVJF0RCFCH+4AH<9z;m-ubX{)T9KV`~t9-#|Y`S8_uQe-dH;uY>rv z0)G>ho4>WAN@wtWrGm?-CyI?-F4pXUXSA|MGE rm_BHv$~|_ubbO0Oh-`5qV;V#znmHlknBUtG%n2F0x$fnEm!bR*dOS3q diff --git a/toolbox/FieldMap/pm_invert_phasemap_dtj.mexw32 b/toolbox/FieldMap/pm_invert_phasemap_dtj.mexw32 index 52198c29eb3ed7a488c740b4c18409314fa4260b..4302a8db3accd614d68a3e4cb527ec9927792892 100755 GIT binary patch delta 33 mcmZpOX^5Hdg5{g^v&e~We3)l)F>bbI>{I~@Y(AlC!2tmJat*}* delta 33 mcmZpOX^5Hdg2nHEV93NbKFkZ<88%xpcB+5{HlI+n-~a&P@C;7? diff --git a/toolbox/FieldMap/pm_invert_phasemap_dtj.mexw64 b/toolbox/FieldMap/pm_invert_phasemap_dtj.mexw64 index 68c9e028b5017980e419d1ebebbefa2e4a96d3e4..1e122bbdadc29037985b4c0f38b30ffd6e99c5d5 100755 GIT binary patch delta 32 lcmZq3XvmoGfTig9)5wWWe3)h*-E748NdwH^tf6&-695X?4}bsw delta 32 lcmZq3XvmoGfJJ$?V93NLK1`vBn~fMhX@L2gHMDMU0sz*63@!iw diff --git a/toolbox/FieldMap/pm_merge_regions.mexmaci64 b/toolbox/FieldMap/pm_merge_regions.mexmaci64 index 0e5705ee59583e6d480700c7ec2c287a8a5f9587..5ddd7fa3d5bba03cda14c3f2ab57d91324954663 100755 GIT binary patch literal 17916 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 OME6;`i@C~=3;zqzkcfZ) literal 17912 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 diff --git a/toolbox/FieldMap/pm_merge_regions.mexw32 b/toolbox/FieldMap/pm_merge_regions.mexw32 index ecac2f9e31a3ff8d01ddfe77a6e1e7bc6a64f68b..11dd94b8b2ea3ea181bf50219e983cbae3857dfd 100755 GIT binary patch delta 32 kcmZoDXegNQgXNd>v&e~me3*i4H+wN!>4N#2JM=0z0rnaV(f|Me delta 32 kcmZoDXegNQgT?QFV93NjK1_jCo4pvVbiw@19eNd<0Nx)AOaK4? diff --git a/toolbox/FieldMap/pm_merge_regions.mexw64 b/toolbox/FieldMap/pm_merge_regions.mexw64 index ffc435b29e5757c3557b6ffb802320e95331c8ff..72ef99f99e5a982a0175e77405e71f8dd120e43c 100755 GIT binary patch delta 35 ocmZqZU~K4MobZ69`1#YwiBEi(v-%k}8#6Lmf(15PSe@Vm01fO8j{pDw delta 35 ocmZqZU~K4MobZ4}Ww&6+#3w$?%G!*ZjTsp&!2+8ttWIzO0N0fZJpcdz diff --git a/toolbox/FieldMap/pm_pad.mexmaci64 b/toolbox/FieldMap/pm_pad.mexmaci64 index c852f182072a62f87fd02c8fb62bf664417c0597..0a7b7cce1c098cf26b832402e2d6c69b0820932d 100755 GIT binary patch literal 13308 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 literal 13256 zcmeHOe{2-T72dNCIKq!TSCEp1z$PLsDaOH21)CJ`0hjD1XK(^eoP@BP?X`X4?tI+s z5knhddcK6!_8K>>i>0bjl%Uo`ZL!o6LE2P@4Yi3>0!WpT($b_P>RE;exoJd6;QGDU zIs4A8Tl!D`>5iCr^S*iS&6_uG4r_MzooknGOcMl0u^NQJDxdDs+SMwrTnRaMv8bk2Z`w|8caHC9fFD8xIhuGKn)_Iy@VW4lB3 ztwA-W$Lq@{+AErGN#Dnnhv>jSx>U%N2yEpuj&k zrnYFoh!(}jczg2~SmGzRR*oMvGGV>(@H2sMqZ$Y|wf+lx?{j-wxdGw};x}s8>Zq#L zqBceSAuY!j?r+sX3r|}_AU=P+GX!BfA7X^^qyn)~)eW94p1cu>_uZV1<7vCeZqBx< zHtr5Ka#@hc?B&b}(wOd;)>uzf!^jaURU&$Hf;~6%spRYtpTC!sAJa*I7gY`V|D8Qa zvIJ!=Pkg>TS}$TZS}1NLtExU_?Y zF#jdxp&u}A<=$YRKGar*gb36_jFp?# z(+U-DTF(wy|H1*lCt~q6({JiXgLb>nj0F_SXp_#+Jv|` z9dz0Y^)~O0=~}34U4fz%9=o+8U`N1?fE@ul0(J!K2-p#@BVb3sj({BjI|Ba~5%6sG zrSAC3a5n4NoV|M?ZY{)xLiX+j=ybAD>oXmS@i*DHp%~|Urs9&1f4o*UK2lOuS-En+ zXS^#O=#!6U)=nQ0-#9nDPf2;QN@c%zAT7R;p5Es(&alBg+4Q)NWl`kppib+4TD?w3u}`yFB;&ZKLPlCJ&%EOwH@a3w4-pG@ajblKbn>$Z>^ zrUQmxk`V7v80^ISo$~$e*vqWLr#Iu6=-Kwn3pb$CaHdIoJT0f3zh^EP$?asRIBBgp zNp_pWGGR|Lo{&wpXxS9xWLh?oZ5R_fUc`NqY<5vNWb;v4eK%Pe@E&9a2fP$Z1fwfL z5{b8nAX?6Rwdzi9`DLFOb^DAf^4W}h&vC>hJ$ze}xUhq?1tojZSNSti6+7MrU!D9^ zABI27rdhkc{5)3P?lYh5X6nd~4RbN4cMvk)Jq3hXf;%av9yK*;0$Cp}klDvSi8W?L@Czd&-Jw^I4$Xn~iyv84V#>bfz z&_pySN91n4TO*>|**CIIe8PEW)_ZV7tn>Dah$Y^hpMSp(5H;vy1KGXtLZgmMrLY zS;>;JWQvd)lrtqm1I%|TMYG;^<5Qlko~J$AJnE@_>OlO81OOyGtemJn#@wr zjC@%xly&24u5XNqkNd-_aiT3RQSpnEhGoHXq_{lI^Ht8Kv5)bqL%*Tpl3INN;~4|Z&{ib7 z=a?B&2A07KmjU6YA(a3jo6mOjDxhrkb2G7zb@ ziKAUP0N3%%cqfTHhX(&U&T|TAzr@=4tX;rbiM4mJb`fj8%-Y3h<1v4;wn};`5-NQr z_h3FM*5E2>g%k)!;=1IIHpfF+SdU3jZD%|X)fx-s zmP@U1JzsDVxkyL~#bdfuuSsDTj0PG?A?Xj6N=@-#Q1XWxrN-8HeULxq8ucSj4^u^@ z6-yff@Fx~%4f}(6{?g+9n;CNJgngQOOufawOOs-F-X`Tu6wr5D%g*;}GQC(}k2Wf2 zMfc`C8|PQP`lO!8iPe`VHFXhxQw^g>e^b$UN8Y=JUivhfZP|xm4Bh}Z^gASQXA3>- z1VYbAhknHn%0VD+6LN?lU$c;2LJly59uYz22ZSUU0)UWj5)xy`F$;N}5I;kHY$2V5 zY+}gwEo2uVs|i6zphvevB~&UBDt`S&3q6OT>X6W&P#?cJcoyS?t|fV8j!+btD>&#m z^4Yp6WRB|Svn|J-M+HZl+u@!$%|(-zVvOeP{5!lr`34D7p+852+3x3yoL@v|7X5Tl zVIcv1pUbZx2dIq66EbV6(+!fC_U);uDc^CvSp0Qx9jKYB);y0)s)s`>kcQJWY5*O< zomR8Y;kh8E1m%}*{#^NaPIXS}Ij!Mz4X39${WYhrbDD3{?%NTtBVb3sj({BjI|6nD z>a_&0XqW!+X$50DbdZLaBCI4cWu42UXS<8@zVMuJKdeaPU#C(YDjDI zMx)iS<}G-IAK2m&U~TJh&!%e|ty?!wH0s~2u3WK<#+R}22Q_^|?oKV18>+|+L9bqm zZfcq+Qk4^_iIOpyu}W-xYbX-b+6b!Q&<5*f4@ezHxHlxUokN=={%A}CVigCi=7D&) zLB~~};4T(=@kX+BCxn}ssf*Dkx{OnHF9g1d^D?J3oYrx=om09kT0mDkyvzli4L=@unoKj`QCZf_zn;UuB9wa5a>P;JS430 zy>UD}Tge}%$4&YC>2dt|ar|G$@t=(2VT}IeuC>_v;dJ3d?|jpH;xka`-DvvGWHzdZ zic&?D-mLylvJ&2u54EWE@o-~M!{-(Bvba!~y7-7A_uYl{HG$fM?N)=WtvlioL2cG_ z%I`LTZmR`}KGTq_&op8}L2eYL{p1Ock%_5pfs-V;HHh>^XDqQ9!&92|bIHsYp2mes LWuKNHYJ%`jA|<+c diff --git a/toolbox/FieldMap/pm_pad.mexw32 b/toolbox/FieldMap/pm_pad.mexw32 index 44ac4ddebbe6675cd661e318566d812b0921722e..11d5da1b9c1eddbc2018f2baad1a0b580b1af0c0 100755 GIT binary patch delta 32 lcmZqhY4DlwfrUxtS>(hoK1^r)H#;#F$$|NscgTCN0RYxl3?~2p delta 32 lcmZqhY4DlwfhFL8V93NTK1}<2HajsE$$|NscgTCN0RY~l42J*! diff --git a/toolbox/FieldMap/pm_pad.mexw64 b/toolbox/FieldMap/pm_pad.mexw64 index e617c2588ab42e0f979884b2e3e8ecf30ea09732..da6d5e69eae8c4e2a4ed7ac988696a6cb54d32a7 100755 GIT binary patch delta 32 lcmZqhY4Dlwfu-d6)5wWme3*1YHajsck_PiPzmSpO1OWE;4l)1$ delta 32 lcmZqhY4Dlwfkkz|1c4Bh|$ diff --git a/toolbox/FieldMap/pm_restore_ramp.mexmaci64 b/toolbox/FieldMap/pm_restore_ramp.mexmaci64 index c49a2f61be5bc828ff0ce3a382f82046289ea8ca..bad638411a2547e0c3cb9bc5939d03a5327d002c 100755 GIT binary patch literal 9332 zcmeHNdvH`&89$rw*wWCuAl9fYEHu<0Ax(-80y1VLt9RR7#1cw60@qD)H`!r#v)l*W zP)0K(>GXCtMK{b&eM(e1z5_M3 zYNN0Kc1>B+Tt&P<1NPdevA`)kszvZ(PJXAnbvuEYq!Qd|iDBeR{&B@doDGu4_aD z;G+3XN9LTObm@i`P4ozPX}o7dyiqYp2RmVk#!5m(F%u6*6WvNQ5$WT&cs=$?w&x}h z0Jt=UP;sItYOfN}!g1A>mX2>s#A^~xz}Ry$HSD`JG#5o_^R@d5tepKe1I0E%Tqm}o zBw~u*AMfmoDM>?{F`g3+2f*<~R_qT^T0rve>6>2F^6_~@Ae<#M;L>=a6kM+;vG9A1 zuU5qC<<^V=7skVUg$cJn-DG+cB^cOvzrQWuoLMhdPa6wth)st$h38`#V*^caAv?^) zP1M<|1X(L#4>@dFYRj=VYU#-mUP!e4E^;OPt;BDl2aOa!>StPN+ zhlwE1_d+M`9$I<8`=Y9%J+7v5z{KC>oA0<^x~kcUr5K3>&@o z#G;+?RAYBPQCssL*sFyO<@PBGl}iY!*pizlNUa@%)NbqS$_Oziz1U z#?KUv>u&PFJRhSvV_jAVoFR<1k{;-RG2cq7RG_c|TV(5^Z>#S?-xgo{X4x{wx&8AF~kA?q*x<_pr2 zHZmJNCk_3Q>?wBrZzgH<#p%=gq1|QiPUG zNDuvWLh7hLW*&uxPTNF$>Bmo zmJ*jBx(v~k!WiU#k^DP7_BC*LA~1N= z9cZ~G?Ylgg&wtUk&9~jR!>4RNnkin-!OOC2{g#&Xkk6Ww)3Y1t&zGELvgIEeyisl3 zF?`0Xkw?})PoKWIG5Q!J{&n!ji1!Unx(sNqL-JE-)9Z5IB07{c>cBtBd9xP$ew(iW zZ#ewO`W$?B6Ndagq5e0!K>&~F1JM(d;rw)ABOQ=HlLBxkGOO71SsoA zIFL9nKg7Wz8_eh6ChggwET7UVNc=Cphsl48m|)9Qp7Ed1oEI9|+I}#12*5fT8op*U z21i!iPD2V=e-EbB!;wrNJ*!S$S8ce1);qZ$lVM=+m|I5m^QX->$mU=my|>PtGoZ4L z)2=)$d6=}q|8!t*vdZ+xC;eGcG2anN%PuXH)2$wwV)i+FSR>;)+8AFR4dh>xNBqw` z2h&UMFWB#Lnlim84`$u6^(xjxeRbZ$2RIUPDATQ1o;nH#o^ zp-h_@8d~m~Fc>kPraA?!iJhj{-e?;qp+Ws@DtdHE`>|odFjB_X4=B;EsUX1McVGEO0*n_YH7|!2JZ= zli)_d?FaV~xP9QTR&S@k<-sM0BU;p&HqgBNMIr_nnj^pZyp6{l`e{=S_o!>V$+&kt zb&96yMxUlC^aVUwpNu!e!}`t!0DT23QLpu`_C^y))9{A19y6{c4Be}#yUeJjc9+{W zd;3hI(D*%UX)tk9H@uyyH$j25XjcPShhq)ih#8A{!-;Nhcc0lAQ_Is7xZdmS)4Z!! zbw_DvdbBSQj+L8ZdjCr<3}re-Z+N%r)#;~;w;*ZM=to|vYcw7+Nb#;pBsd<}ItFfLq{CC(3TSVz2j^X$3$B5$jD!wdI15bOHzROmzMfSH?SB5^k zsJZ^oF&p7XZa3GS2be46ad~Ryx-+DiNiNLG$W@W^hM=>=kD%KGtrc{cpbdh4LeN%0 z?-R6L&>e#I3R;%9BB)fLQh`bZDix?ypi+TK1u7M&RG?CUN(Cwvs8pa*f&Y627A&pZ zj-ZQL6}$ouckNWVdUq;4W?1WHU)bfzw9-qlZvL`e>7@6?^m2S4N4HqKxiV~5?SfV% zp4ve7Jchc_zV-2GTDV{N^nROG30c8P;?alHP?hB{k*Ow27iPYBHgS9 ^;t8~WzhW-_)30>TpE z>@Bu_vA_f39;bycsi$J!UxIg(;E0W#yv(q%GaiPUV**q7yCwLCCHQA0c&r4!Qi5@J zT^N6&1miljP=BiprsjwD+PHd0Iq1zWe;8J~;K_Jut5973Bw(riPF(k3`@Ej4Kq2VY_*d-Uv>+G$L2vp(Bv`;>d- zb}yVmWJ1rba=KnINKqq&KSKW@P(*?niMB}ek~q{(p*TTEKp&I<)fp&MMx}Ys9KUaN z*1ks!t%SrsH`2^E-|u_Ox8Kg}?ak~jZoG4=k}+EuW6XiN2=!VyV-<#SF7=^7;NwR+zH2WQ0Pz-RzpJogK+#RaGAhbcg(^ zZbZ9li{l$#U}`JEh+exXq4 zPZs{JilB(k^@o(_6HP4yeX%Hn676y+}({IW0DtNMa{q1*Ul zl4;p#IRKw`KP+5ORn-R6zKA!VnLuHDUBcgSp-+77_2Tw)2@xkW?=~Yhs@mvkcjZWC zZh*iFc$#nI*Yd5Zy@USVS^K&CS#D_lTDG%RvprP}V$PXUFKk4L;&Tc|mOtWi?JlLkpX-mVSKNB8L3yJ&uc{t*%R^0#ZfniTT+FQX$pqgaZYuc^ zQ;{ov3hgq~xOyvx1BUjtOmA`G-UI6;Q%E)tH?5*A7GZLw$w$F| z9CYocVQ*uMmS-y}6dX$0`e9N|XzrF>G|j7nqW=BL3Q^7d*GHS9G8 zHu!zrfmjVDgs&TFynJXoE#L4%+j)(=0gLSHl=(`wA*x3xKB~IW+p}(6&HcHCMRq(} zwmiH3o*q@Nsm(Pj%8T6=!g%?1ZG*a@1!}hE8Jg+&zqhV7Pip1f>)EWUEnB^NK4a1< zmaT3(X}B4as;Tyh5+8CfPpZ!; z4Q~L_S0k+&=GO*+lS#vi36%D}(^NYltvW&yK|IL{Ph#AYxZ;*hrxodRCFrDLn^aPE zTc1m+@n2+0YUxF?I8-4GzW}O?Othp{+&8UA_fAMhzXH$ABk5_kbZ=TZO5sdP&gx@W zcFiMK&|UdWbf=}xG136=#S7C?$2rilX_wSNO;wq6^gZ&Myiy({e?u&=_axG; z_*)c!XMTDnfT`nL%HtbX68YnsLkyVqeE#g^Gsv|ElO}OfiT@SJQWDYQ(y$wklK71> zW1*6&UyYxI%n1P5S2(|&_#}9Da$DvF(BZV1RLsfJrh z{F?0`IrfplcA>D-r0&GanKs@Xawv(WQ|{DGq9-%005MRNJ2~XYY~qYG{2XQ#9JP|8 z>(oy+om7&WGYiPW17kc~orJIF2&vyZ@<(^#qH#~{Yu5d8CmY{@js17rXo!ryLq^#P z?gw6v{@(KZBVe#}CoA3Yf6YT=XWYqM6yfvI@NfB)+vS9F*Gu$H2{<3t4bPq?s4I@2UF&{ZFAb?E(rar^bZ5dU7-{)rA zGCKr+3jEa5XtLE0+c7n(+j;v4Z|S!^Tm2|+J9)d0w_UvL=4~%;`*=Hm)-3OS&ZKX> z6xF@`+Jka9AlIW&Bbsi6BASX9z3|#_V12-=?_W=hevfHUp!1+yC;Nios3ChJ{n3CH zG;}$l9fSa-@0Y#7Ub#0E z?e=SP#Ft}#pB#$Fb)W6^Ax_;F3VQvF6~#wa{1HYhvd4H7)2y2T??Fx0@!~A!4D2%o zXW~W5eF3jwCY|4kxg6-eL*g=ve`Gbipfy=3@~nxB5#r^@w@l=FgzV-Bn5R{U&mdkaZk+%tSf~S&)=d}2r3hRBBLVcnL_WCRIiKwFx1C`5${%ZwnAv8E6|zGZ1g|#a!0xC zvcryX7+XpWitW(D%ocOnoC_-*6!%tOG;YKDhyR@ka)$D7WCJG{#4Mjf<7bYsGviF`UQPd(8BRbd?^E^43siZ%0MXtr3{oZP|83l z1EmabRb+=602<(mqIwv&`nY(c=j6>!x9B_`Z1M(dWYCsG0ga;Y8 zwM&SLHAN!LdVf0(^nq=x0v6kWO*cbpF}L7ck%)It-Bh=c5;;dWW5ekI;T8y9p0X3RifIz|m5s{KoOh9d6 zZ$#ICP_fZ>DOHkTVBmJOk$o^ilnx(EezcghFf`wb=S>(hwK1}-Eo2?jENw9DM`I}!zN^k%G&$$cT delta 32 lcmZp0X>ghFf+hHXV93NbK1|{#Hd`^Sk^u8JzmSyR007pA3?~2p diff --git a/toolbox/FieldMap/pm_restore_ramp.mexw64 b/toolbox/FieldMap/pm_restore_ramp.mexw64 index 3a764d9f9d2c82eee5b7cbdf54735f2bbf26a831..8164d518ea0d5eac9172255a97e6b67ea54cbd6e 100755 GIT binary patch delta 32 lcmZqhXz-ZufTi^L)5wWWe3*`}-)zKqNfON8%pv`Q0{{ZJ4;=si delta 32 lcmZqhXz-ZufJJ?`V93NLK1|Ktn~fMRNrL&CIi!DZ007RV3(o)m diff --git a/toolbox/FieldMap/tbx_cfg_fieldmap.m b/toolbox/FieldMap/tbx_cfg_fieldmap.m index e0121485..b200691f 100644 --- a/toolbox/FieldMap/tbx_cfg_fieldmap.m +++ b/toolbox/FieldMap/tbx_cfg_fieldmap.m @@ -1,12 +1,12 @@ function fieldmap = tbx_cfg_fieldmap % MATLABBATCH Configuration file for toolbox 'FieldMap' %__________________________________________________________________________ -% Copyright (C) 2008-2015 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2008-2017 Wellcome Trust Centre for Neuroimaging -% $Id: tbx_cfg_fieldmap.m 6501 2015-07-17 14:32:09Z spm $ +% $Id: tbx_cfg_fieldmap.m 7086 2017-06-01 11:50:28Z guillaume $ -addpath(fullfile(spm('dir'),'toolbox','FieldMap')); +if ~isdeployed, addpath(fullfile(spm('dir'),'toolbox','FieldMap')); end %========================================================================== % Default values that are common to all fieldmap jobs @@ -134,17 +134,16 @@ %-------------------------------------------------------------------------- % ws Weighted smoothing %-------------------------------------------------------------------------- -ws = cfg_menu; -ws.tag = 'ws'; -ws.name = 'Weighted smoothing'; -ws.help = {'Select normal or weighted smoothing.'}; +ws = cfg_menu; +ws.tag = 'ws'; +ws.name = 'Weighted smoothing'; +ws.help = {'Select normal or weighted smoothing.'}; ws.labels = { 'Weighted Smoothing' 'No weighted smoothing' }'; -ws.values{1} = 1; -ws.values{2} = 0; -ws.def = @(val)pm_get_defaults('WS', val{:}); +ws.values = {1 0}; +ws.def = @(val)pm_get_defaults('WS', val{:}); %-------------------------------------------------------------------------- % uflags uflags diff --git a/toolbox/Longitudinal/tbx_cfg_longitudinal.m b/toolbox/Longitudinal/tbx_cfg_longitudinal.m index db31c1fb..c472d095 100644 --- a/toolbox/Longitudinal/tbx_cfg_longitudinal.m +++ b/toolbox/Longitudinal/tbx_cfg_longitudinal.m @@ -4,7 +4,7 @@ % Copyright (C) 2012 Wellcome Trust Centre for Neuroimaging % John Ashburner -% $Id: tbx_cfg_longitudinal.m 6798 2016-05-20 11:53:33Z john $ +% $Id: tbx_cfg_longitudinal.m 7155 2017-08-17 10:55:05Z john $ if ~isdeployed, addpath(fullfile(spm('Dir'),'toolbox','Longitudinal')); @@ -158,7 +158,7 @@ long2.tag = 'pairwise'; long2.name = 'Pairwise Longitudinal Registration'; long2.val = {vols1 vols2 tdif noise wparam bparam write_avg write_jacd write_divd write_defs}; -long2.help = {'Longitudinal registration of pairs of anatomical MRI scans. It is based on pairwise inverse-consistent alignment between the first and second scan of each subject, and incorporates a bias field correction. Prior to running the registration, the scans should already be in very rough alignment, although because the model incorporates a rigid-body transform, this need not be extremely precise. Note that there are a bunch of hyper-parameters to be specified. If you are unsure what values to take, then the defaults should be a reasonable guess of what works. Note that changes to these hyper-parameters will impact the results obtained.',... +long2.help = {'Longitudinal registration of pairs of anatomical MRI scans. It is based on pairwise inverse-consistent alignment between the first and second scan of each subject, and incorporates a bias field correction /* \cite{ashburner2013symmetric} */. Prior to running the registration, the scans should already be in very rough alignment, although because the model incorporates a rigid-body transform, this need not be extremely precise. Note that there are a bunch of hyper-parameters to be specified. If you are unsure what values to take, then the defaults should be a reasonable guess of what works. Note that changes to these hyper-parameters will impact the results obtained.',... '',... 'The alignment assumes that all scans have similar resolutions and dimensions, and were collected on the same (or very similar) MR scanner using the same pulse sequence. If these assumption are not correct, then the approach will not work as well.'}; long2.prog = @spm_pairwise; @@ -169,12 +169,12 @@ long.tag = 'series'; long.name = 'Serial Longitudinal Registration'; long.val = {vols tim noise wparam bparam write_avg write_jac write_div write_defs}; -long.help = {'Longitudinal registration of series of anatomical MRI scans for a single subject. It is based on groupwise alignment among each of the subject''s scans, and incorporates a bias field correction. Prior to running the registration, the scans should already be in very rough alignment, although because the model incorporates a rigid-body transform, this need not be extremely precise. Note that there are a bunch of hyper-parameters to be specified. If you are unsure what values to take, then the defaults should be a reasonable guess of what works. Note that changes to these hyper-parameters will impact the results obtained.',... +long.help = {'Longitudinal registration of series of anatomical MRI scans for a single subject. It is based on groupwise alignment among each of the subject''s scans, and incorporates a bias field correction /* \cite{ashburner2013symmetric} */. Prior to running the registration, the scans should already be in very rough alignment, although because the model incorporates a rigid-body transform, this need not be extremely precise. Note that there are a bunch of hyper-parameters to be specified. If you are unsure what values to take, then the defaults should be a reasonable guess of what works. Note that changes to these hyper-parameters will impact the results obtained.',... '',... 'The alignment assumes that all scans have similar resolutions and dimensions, and were collected on the same (or very similar) MR scanner using the same pulse sequence. If these assumption are not correct, then the approach will not work as well. There are a number of settings (noise estimate, regularisation etc). Default settings often work well, but it can be very helpful to try some different values, as these can have a large effect on the results.'}; long.prog = @spm_series_align; -cfg = cfg_repeat; +cfg = cfg_choice; cfg.tag = 'longit'; cfg.name = 'Longitudinal Registration'; cfg.values = {long2,long}; diff --git a/toolbox/MEEGtools/eb_read_lvm.m b/toolbox/MEEGtools/eb_read_lvm.m new file mode 100644 index 00000000..738ab571 --- /dev/null +++ b/toolbox/MEEGtools/eb_read_lvm.m @@ -0,0 +1,9 @@ +function [time, B] = eb_read_lvm(filename) +if num2str(filename(end-3:end)) == '.lvm' +else + filename = [filename,'.lvm']; +end +data = dlmread(filename, '\t',23,0); +% data = dlmread(filename, '\t',7,0); +time = data(:,1); +B = data(:,2:end); \ No newline at end of file diff --git a/toolbox/MEEGtools/spm_eeg_cont_power.m b/toolbox/MEEGtools/spm_eeg_cont_power.m index 24137f29..7946083a 100644 --- a/toolbox/MEEGtools/spm_eeg_cont_power.m +++ b/toolbox/MEEGtools/spm_eeg_cont_power.m @@ -15,9 +15,9 @@ % Copyright (C) 2011 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_eeg_cont_power.m 5640 2013-09-18 12:02:29Z vladimir $ +% $Id: spm_eeg_cont_power.m 7006 2017-02-06 11:09:06Z vladimir $ -SVNrev = '$Rev: 5640 $'; +SVNrev = '$Rev: 7006 $'; %-Startup %-------------------------------------------------------------------------- @@ -44,7 +44,7 @@ %-------------------------------------------------------------------------- % generate new meeg object with new filenames -Dnew = clone(D, ['h' fnamedat(D)], [D.nchannels D.nsamples D.ntrials]); +Dnew = clone(D, ['h' spm_str_manip(fnamedat(D),'t')], [D.nchannels D.nsamples D.ntrials]); % determine channels to process chanind = D.indchantype('MEEG'); diff --git a/toolbox/MEEGtools/spm_eeg_erp_correction.m b/toolbox/MEEGtools/spm_eeg_erp_correction.m index 7826c7a9..b574e2b5 100644 --- a/toolbox/MEEGtools/spm_eeg_erp_correction.m +++ b/toolbox/MEEGtools/spm_eeg_erp_correction.m @@ -16,9 +16,9 @@ % Copyright (C) 2010 Wellcome Trust Centre for Neuroimaging % Melanie Boly -% $Id: spm_eeg_erp_correction.m 5640 2013-09-18 12:02:29Z vladimir $ +% $Id: spm_eeg_erp_correction.m 6907 2016-10-21 09:41:59Z vladimir $ -SVNrev = '$Rev: 5640 $'; +SVNrev = '$Rev: 6907 $'; %-Startup %-------------------------------------------------------------------------- @@ -74,7 +74,7 @@ R = R*diag(spm_hanning(Ns))*R; end -Dnew = clone(D, ['C' D.fnamedat]); +Dnew = clone(D, ['C' fname(D)]); spm_progress_bar('Init', D.ntrials, 'Trials filtered'); drawnow; diff --git a/toolbox/MEEGtools/spm_eeg_fix_ctf_headloc.m b/toolbox/MEEGtools/spm_eeg_fix_ctf_headloc.m index dafa7990..dcab0bb2 100644 --- a/toolbox/MEEGtools/spm_eeg_fix_ctf_headloc.m +++ b/toolbox/MEEGtools/spm_eeg_fix_ctf_headloc.m @@ -26,7 +26,7 @@ % Copyright (C) 2008 Institute of Neurology, UCL % Vladimir Litvak, Robert Oostenveld -% $Id: spm_eeg_fix_ctf_headloc.m 6663 2016-01-08 16:45:32Z vladimir $ +% $Id: spm_eeg_fix_ctf_headloc.m 6942 2016-11-21 13:17:44Z guillaume $ [Finter,Fgraph,CmdLine] = spm('FnUIsetup','Fix CTF head locations',0); @@ -248,8 +248,6 @@ % % You should have received a copy of the GNU General Public License % along with FieldTrip. If not, see . -% -% $Id: spm_eeg_fix_ctf_headloc.m 6663 2016-01-08 16:45:32Z vladimir $ % My preferred ordering in the grad structure is: % 1st 151 coils are bottom coils of MEG channels diff --git a/toolbox/MEEGtools/spm_eeg_interpolate_artefact.m b/toolbox/MEEGtools/spm_eeg_interpolate_artefact.m index 64eb1e6a..a6409f10 100644 --- a/toolbox/MEEGtools/spm_eeg_interpolate_artefact.m +++ b/toolbox/MEEGtools/spm_eeg_interpolate_artefact.m @@ -15,9 +15,9 @@ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Stefan Kiebel -% $Id: spm_eeg_interpolate_artefact.m 5640 2013-09-18 12:02:29Z vladimir $ +% $Id: spm_eeg_interpolate_artefact.m 6965 2016-12-08 13:47:06Z vladimir $ -SVNrev = '$Rev: 5640 $'; +SVNrev = '$Rev: 6965 $'; %-Startup %-------------------------------------------------------------------------- @@ -74,7 +74,7 @@ S1 = []; S1.D = D; -S1.newname = ['i' D.fname]; +S1.outfile = ['i' D.fname]; S1.updatehistory = 0; D = spm_eeg_copy(S1); diff --git a/toolbox/MEEGtools/spm_eeg_plot_interactive.m b/toolbox/MEEGtools/spm_eeg_plot_interactive.m index adfa4c34..389635c3 100644 --- a/toolbox/MEEGtools/spm_eeg_plot_interactive.m +++ b/toolbox/MEEGtools/spm_eeg_plot_interactive.m @@ -8,7 +8,7 @@ % Copyright (C) 2008-2014 Wellcome Trust Centre for Neuroimaging % Vladimir Litvak -% $Id: spm_eeg_plot_interactive.m 6027 2014-05-30 11:33:34Z guillaume $ +% $Id: spm_eeg_plot_interactive.m 7096 2017-06-07 10:42:58Z vladimir $ D = spm_eeg_load; @@ -38,9 +38,11 @@ case 'MEG' cfg.grad = D.sensors('MEG'); data.grad = cfg.grad; + case 'MEGCOMB' + cfg.layout = 'CTF275.lay'; end -cfg.channel = data.label(D.indchantype(modality)); +cfg.channel = data.label(D.indchantype(modality, 'GOOD')); %-Display %-------------------------------------------------------------------------- @@ -52,6 +54,8 @@ elseif isfield(data, 'avg') ft_multiplotER(cfg, data); elseif isfield(data, 'powspctrm') - data.powspctrm = data.powspctrm(ind, :, :, :); + if strncmpi('rpt', data.dimord, 3) + data.powspctrm = data.powspctrm(ind, :, :, :); + end ft_multiplotTFR(cfg, data); end diff --git a/toolbox/MEEGtools/spm_eeg_tms_correct.m b/toolbox/MEEGtools/spm_eeg_tms_correct.m index d5e90d70..2ac2b8a4 100644 --- a/toolbox/MEEGtools/spm_eeg_tms_correct.m +++ b/toolbox/MEEGtools/spm_eeg_tms_correct.m @@ -23,9 +23,9 @@ % Neuroimage. 2007; 37(1):56-70. % % Vladimir Litvak -% $Id: spm_eeg_tms_correct.m 5674 2013-10-09 10:00:26Z vladimir $ +% $Id: spm_eeg_tms_correct.m 6965 2016-12-08 13:47:06Z vladimir $ -SVNrev = '$Rev: 5674 $'; +SVNrev = '$Rev: 6965 $'; %-Startup %-------------------------------------------------------------------------- @@ -93,8 +93,7 @@ S = []; S.D = tD; S.method = 'SVD'; - S.timewin = [-0.002 - 0.02]; + S.timewin = [-2 20]; S.svdthresh = 30; tD = spm_eeg_spatial_confounds(S); @@ -102,7 +101,7 @@ S = []; S.D = tD; - S.newname = [f '_trial' num2str(i) '.mat']; + S.outfile = [f '_trial' num2str(i) '.mat']; tD = spm_eeg_copy(S); delete(S.D); diff --git a/toolbox/MEEGtools/spm_opm_convert.m b/toolbox/MEEGtools/spm_opm_convert.m new file mode 100644 index 00000000..b02fe6ed --- /dev/null +++ b/toolbox/MEEGtools/spm_opm_convert.m @@ -0,0 +1,65 @@ +function Dout = spm_opm_convert(array,fnamedat,fs,scale) +% Convert array into SPM MEEG object +% FORMAT Dout = spm_opm_convert(array,fnamedat,fs,scale) +% +% array - numeric Array of 2,3,4 dimensions(channels,time,trials) +% fnamedat - string specifing output path of object(include extension .dat) +% fs - sampling frequency +% scale - scale factor to convert to fT [default: 1] +%__________________________________________________________________________ +% Copyright (C) 2017 Tim Tierney + +% Tim Tierney +% $Id: spm_opm_convert.m 7184 2017-10-10 10:12:38Z guillaume $ + +% determine output filename +[a, b] = fileparts(fnamedat); +outMat = fullfile(a,[b,'.mat']); + +% if scale is not supplied set a default of 1 +if nargin < 4 + scale = 1; +end + +array = array.*scale; + +% find number of dimensions and decide what to do based on result +dim = size(array); +L = length(dim); + +if L > 4 + % throw error for having unsupported number of dimensions + error('Array should not have more than 4 dimensions.'); +elseif L == 4 + % create MEG object with appropriate size + Dout = meeg(dim(1),dim(2),dim(3),dim(4)); + + % make it a blank object + Dout= blank(Dout,fnamedat); + + % set the smaple rate + Dout = Dout.fsample(fs); + + % fill in data with supplied array + Dout(1:dim(1),1:dim(2),1:dim(3),1:dim(4)) = array; +elseif L == 3 + % same with less dimensions + Dout = meeg(dim(1),dim(2),dim(3)); + Dout= blank(Dout,fnamedat); + Dout = Dout.fsample(fs); + Dout(1:dim(1),1:dim(2),1:dim(3)) = array; + +elseif L == 2 + %same with less dimensions + Dout = meeg(dim(1),dim(2),1); + Dout= blank(Dout,fnamedat); + Dout = Dout.fsample(fs); + Dout(1:dim(1),1:dim(2),1) = array; +else + % throw exception if I really don't know what to do + error('Array must have between 2 and 4 dimensions.'); +end + +% set the filename and save +Dout = fname(Dout,outMat); +Dout.save; diff --git a/toolbox/MEEGtools/spm_opm_denoise.m b/toolbox/MEEGtools/spm_opm_denoise.m new file mode 100644 index 00000000..5fc56342 --- /dev/null +++ b/toolbox/MEEGtools/spm_opm_denoise.m @@ -0,0 +1,78 @@ +function Dout = spm_opm_denoise(D,refD,derivative,gs,update,prefix) +% Denoise OPM data with specified regressors, optionally with derivatives +% and global signal +% FORMAT Dout = spm_opm_denoise(D,refD,derivative,gs,update,prefix) +% +% D - MEEG object +% refD - array or MEEG object containing regresssors for denoising +% derivative - boolean indicating whether to use derivatives or not +% gs - boolean indicating whether to use Global Signal or not +% update - boolean indicating whether to create MEEG object +% prefix - string to prefix file path with if update is TRUE +%__________________________________________________________________________ +% Copyright (C) 2017 Tim Tierney + +% Tim Tierney +% $Id: spm_opm_denoise.m 7184 2017-10-10 10:12:38Z guillaume $ + + +% check to make sure dimensions match between reference and MEEG object +ndim = size(D); +ldim = size(refD); +if (~all(ndim(2:3)==ldim(2:3))) + error('Dimensions of D and refD should be equal.'); +end + + +% ref, sensors and residual objects +ref = refD; +sensors = D; +res = zeros(size(sensors)); + +% need to loop over Ntrials of size winSize +Ntrials = size(sensors,3); +winSize = size(sensors,2); + +% loop (inefficient due to continued memory reallocation but ...) +for i=1:Ntrials + % add a mean column to the reference regressors + intercept = ones(winSize,1); + reference = ref(:,:,i)'; + reference = [reference intercept]; + + % optionally add derivatives + if (derivative) + drefer=diff(reference); + drefer=[drefer(1,:); drefer]; + reference=[drefer reference]; + end + + % optionally add global signal + if (gs) + trial = D(:,:,i)'; + gsrefer = mean(trial,2); + reference=[gsrefer reference]; + end + % reference is column major so transpose sensors + beta = pinv(reference)*sensors(:,:,i)'; + res(:,:,i) = (sensors(:,:,i)'- reference*beta)'; +end + +% make sure output has the singleton dimension if matrix supplied +if ((length(size(res)))==2) + outsize = [size(res) 1]; +else + outsize = size(res); +end + + +if (update) + % name, clone and fill with residual data + inFile = fnamedat(D); + [a,b] = fileparts(inFile); + outfile = fullfile(a,[prefix b '.dat']); + Dout = clone(D,outfile,outsize); + Dout(:,:,:) = res; +else + Dout = res; +end diff --git a/toolbox/Neural_Models/DEMO_dcm_fmri_nnm.m b/toolbox/Neural_Models/DEMO_dcm_fmri_nnm.m index 5adb9850..285bc13e 100644 --- a/toolbox/Neural_Models/DEMO_dcm_fmri_nnm.m +++ b/toolbox/Neural_Models/DEMO_dcm_fmri_nnm.m @@ -32,9 +32,9 @@ % DCM.options.centre % mean-centre inputs % DCM.options.P % starting estimates for parameters % DCM.options.hidden % indices of hidden regions - -% $Id: DEMO_dcm_fmri_nnm.m 6857 2016-08-19 15:17:06Z karl $ - + +% $Id: DEMO_dcm_fmri_nnm.m 6931 2016-11-16 12:09:58Z karl $ + % tests of spatial models: 'ECD', 'LFP' or 'IMG' %========================================================================== try @@ -47,14 +47,14 @@ end end load DCM_attention - + DCM = rmfield(DCM,{'a','b','c','d','options'}); - + % spatial models %========================================================================== DCM.options.nmm = 'TFM'; % two regional populations (E and I) - - + + % priors on connectivity %-------------------------------------------------------------------------- DCM.a{1} = [0 0 0;1 0 0;0 1 0]; @@ -67,14 +67,12 @@ DCM.b{2}(:,:,3) = [0 0 0;0 1 0;0 0 0]; DCM.c = [1 0 0;0 1 0;0 0 1]; DCM.d = []; - -DCM.options.maxit = 32; -DCM.options.hE = 8; - + % Bayesian model inversion %========================================================================== +DCM.options.maxit = 32; DCM = spm_dcm_fmri_nmm(DCM); - + % get posterior densities %-------------------------------------------------------------------------- pE = DCM.M.pE; @@ -82,41 +80,41 @@ qE = DCM.Ep; qC = DCM.Cp; vC = spm_unvec(diag(qC),qE); - - + + % electrophysiological correlates %========================================================================== spm_figure('GetWin','Figure 1'); clf - + % induced electrophysiological responses %-------------------------------------------------------------------------- [y,lfp,csd,w] = spm_gen_fmri(DCM.Ep,DCM.M,DCM.U); - + T = (1:size(y,1)) *DCM.Y.dt; % time of fMRI data t = (1:size(lfp,2))*DCM.U.dt; % time of LFP data j = 4:64; % frequencies to report n = 2; % in the n-th region -ind = csd(:,:,n); % induced responses every TR - - +ind = csd(:,:,n); % induced responses every TR + + % posterior parameter estimates %-------------------------------------------------------------------------- subplot(3,1,1), plot(T,y), hold on, plot(T,DCM.y + DCM.R,':'), hold off title('Haemodynamic responses','fontsize',16), spm_axis tight xlabel('Time (seconds)'),ylabel('Normalised BOLD') - + subplot(3,1,2), plot(t,lfp') title('Local field potential responses','fontsize',16), spm_axis tight -xlabel('Time (seconds)'),ylabel('Normalised BOLD') - +xlabel('Time (seconds)'),ylabel('depolarisation') + subplot(3,1,3), imagesc(T,w(j),spm_detrend(log(ind(:,j)))') -title('induced (log-power) responses','fontsize',16) -xlabel('Time (seconds)'),ylabel('Normalised BOLD') - +title('Induced responses (log)','fontsize',16) +xlabel('Time (seconds)'),ylabel('Frequency (Hz)') + % principal spectral mode and haemodynamic response %-------------------------------------------------------------------------- spm_figure('GetWin','Figure 2'); clf - + col = {'b','g','r'}; for i = 1:size(csd,3) ind = spm_detrend(csd(:,:,i)); @@ -132,10 +130,10 @@ title('Haemodynamic correlates','fontsize',16), axis square xlabel('Eigenvariate'),ylabel('Normalised BOLD') end - + % Bayesian model comparison and reduction %========================================================================== - + % neurovascular coupling parameters %-------------------------------------------------------------------------- j = spm_fieldindices(qE,'J'); @@ -143,62 +141,50 @@ dcm.M.pC = DCM.M.pC.J; dcm.Ep = DCM.Ep.J; dcm.Cp = DCM.Cp(j,j); - + % posterior parameter estimates %-------------------------------------------------------------------------- spm_dcm_bmr_all(dcm) - + subplot(3,2,5), imagesc(spm_cov2corr(qC(j,j))), axis square title('Neurovascular coupling','fontsize',16), xlabel('pre-synaptic input'),ylabel('Contribution') - - + + % The effects of attention %========================================================================== spm_figure('GetWin','Figure 3'); clf - + % extrinsic verses intrinsic and superficial versus deep %-------------------------------------------------------------------------- i = spm_fieldindices(qE,'N'); j = spm_find_pC(vC.N,qE.N,'B'); j = i(j); - + % posterior parameter estimates %-------------------------------------------------------------------------- subplot(2,2,1), spm_plot_ci(qE,qC,[],j), axis square title('Attentional modulation','fontsize',16), xlabel('Connection'),ylabel('Effect size (log scaling)') - + % Bayesian model comparison %-------------------------------------------------------------------------- clear rE rC F - + rE = pE.N.B; rC{1} = pC.N.B; % full model rC{2} = pC.N.B; rC{2}{1}(:,:,3) = 0; % superficial rC{3} = pC.N.B; rC{3}{2}(:,:,3) = 0; % deep rC{4} = pC.N.B; rC{4}{1}(:,:,3) = 0; rC{4}{2}(:,:,3) = 0; % both - + for i = 1:numel(rC) F(i,1) = spm_log_evidence(qE.N.B,vC.N.B,rE,rC{1},rE,rC{i}); end p = spm_softmax(F); - + % show results %-------------------------------------------------------------------------- subplot(2,2,2), bar(p), axis square title('Model comparison','fontsize',16), xlabel('Model'),ylabel('Posterior probability') -set(gca,'XTickLabel',{'full','infra','supra','null'}) - - - - - - - - - - - - +set(gca,'XTickLabel',{'full','supra','infra','null'}) diff --git a/toolbox/Neural_Models/spm_dcm_prior_responses.m b/toolbox/Neural_Models/spm_dcm_prior_responses.m index a829f006..0e65867c 100644 --- a/toolbox/Neural_Models/spm_dcm_prior_responses.m +++ b/toolbox/Neural_Models/spm_dcm_prior_responses.m @@ -17,7 +17,7 @@ function spm_dcm_prior_responses(Ep) % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_dcm_prior_responses.m 5951 2014-04-12 11:38:44Z karl $ +% $Id: spm_dcm_prior_responses.m 6917 2016-11-02 14:25:08Z karl $ % Model specification @@ -123,7 +123,7 @@ function spm_dcm_prior_responses(Ep) %---------------------------------------------------------------------- pE.b = pE.b - 32; pE.c = pE.c - 32; - [csd Hz] = spm_csd_mtf(pE,M,[]); + [csd, Hz] = spm_csd_mtf(pE,M,[]); [ccf, lag] = spm_csd2ccf(csd,Hz); % plot diff --git a/toolbox/Neural_Models/spm_induced_optimise.m b/toolbox/Neural_Models/spm_induced_optimise.m index ccc27e09..202994de 100644 --- a/toolbox/Neural_Models/spm_induced_optimise.m +++ b/toolbox/Neural_Models/spm_induced_optimise.m @@ -13,13 +13,13 @@ function spm_induced_optimise(Ep,model) % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_induced_optimise.m 6856 2016-08-10 17:55:05Z karl $ +% $Id: spm_induced_optimise.m 6937 2016-11-20 12:30:40Z karl $ % Model specification %========================================================================== if nargin < 2 - model = 'TFM'; + model = 'CMC'; end % number of regions in coupled map lattice @@ -45,7 +45,6 @@ function spm_induced_optimise(Ep,model) % get priors %-------------------------------------------------------------------------- pE = spm_dcm_neural_priors({0 0 0},{},1,options.model); -P = fieldnames(pE); pE = spm_L_priors(M.dipfit,pE); pE = spm_ssr_priors(pE); @@ -57,7 +56,8 @@ function spm_induced_optimise(Ep,model) % pE.J(3) = 1; %++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -P = {'G','T','S'}; +P = fieldnames(pE); +P = {'G','T','S'}; %++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ % use input argument if specified @@ -120,7 +120,7 @@ function spm_induced_optimise(Ep,model) for q = 1:length(dQ) qE = pE; qE = setfield(qE,P{k},{i,j},dQ(q)); - [G w] = spm_csd_mtf(qE,M,[]); + [G,w] = spm_csd_mtf(qE,M,[]); GW(:,q) = G{1}; end diff --git a/toolbox/Neural_Models/spm_lfp_demo.m b/toolbox/Neural_Models/spm_lfp_demo.m index 4b8c8db3..dd0092af 100644 --- a/toolbox/Neural_Models/spm_lfp_demo.m +++ b/toolbox/Neural_Models/spm_lfp_demo.m @@ -16,7 +16,7 @@ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_lfp_demo.m 6856 2016-08-10 17:55:05Z karl $ +% $Id: spm_lfp_demo.m 6937 2016-11-20 12:30:40Z karl $ % Model specification diff --git a/toolbox/Neural_Models/spm_seizure_demo.m b/toolbox/Neural_Models/spm_seizure_demo.m index 822f7102..921f37c0 100644 --- a/toolbox/Neural_Models/spm_seizure_demo.m +++ b/toolbox/Neural_Models/spm_seizure_demo.m @@ -14,7 +14,7 @@ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_seizure_demo.m 6856 2016-08-10 17:55:05Z karl $ +% $Id: spm_seizure_demo.m 6937 2016-11-20 12:30:40Z karl $ % Model specification @@ -173,7 +173,7 @@ W = 128; TFR = spm_wft(LFP,w*W*U.dt,W); subplot(4,1,3) -imagesc(t,w,abs(TFR)); +imagesc(t,w,spm_en(abs(TFR))); title('time-frequency response','FontSize',16) axis xy xlabel('time (s)') @@ -189,7 +189,7 @@ % predicted time frequency response %-------------------------------------------------------------------------- subplot(4,1,4) -imagesc(t,w,abs(csd{1}')); +imagesc(t,w,spm_en(abs(csd{1}'))); title('Predicted response','FontSize',16) axis xy xlabel('time (s)') diff --git a/toolbox/Neural_Models/spm_sigmoid_demo.m b/toolbox/Neural_Models/spm_sigmoid_demo.m index 198dc4c1..0575993e 100644 --- a/toolbox/Neural_Models/spm_sigmoid_demo.m +++ b/toolbox/Neural_Models/spm_sigmoid_demo.m @@ -29,7 +29,7 @@ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_sigmoid_demo.m 5922 2014-03-18 20:10:17Z karl $ +% $Id: spm_sigmoid_demo.m 6931 2016-11-16 12:09:58Z karl $ % relating R amd the variance %========================================================================== @@ -108,7 +108,7 @@ % compute kernels (over 128ms) %---------------------------------------------------------------------- - N = 128; + N = 64; dt = 1/1000; t = (1:N)*dt*1000; [K0,K1,K2] = spm_kernels(M0,M1,L1,L2,N,dt); diff --git a/toolbox/OldNorm/spm_brainwarp.mexmaci64 b/toolbox/OldNorm/spm_brainwarp.mexmaci64 index bad4008fcebfe6f325ecf775080f3becb076da1f..aa543a5ff9e6fcf9155c6a64b5369c547e02aac1 100755 GIT binary patch literal 198472 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 bAx2!ABspxV2}1PDAZkjGlqqo3t84!UkV8EZ literal 211936 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%0Dk=?`__gf#5Y*HBjB;rGuBX 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 diff --git a/toolbox/OldNorm/spm_brainwarp.mexw32 b/toolbox/OldNorm/spm_brainwarp.mexw32 index 099acb5e889c2e8ec2fa8ed9d51fbdb0f38c9b96..8b04bb0b619a51ce6d5c890ff0de711abe8fca30 100755 GIT binary patch delta 12301 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 Cbl7SD diff --git a/toolbox/OldNorm/spm_brainwarp.mexw64 b/toolbox/OldNorm/spm_brainwarp.mexw64 index f525e142d4d8123c0e8db572d4e7da7f7e377cbe..f6e8b70310e251da6e7c2a7cc428a71fc4382f1a 100755 GIT binary patch delta 44 xcmZozz}c{XbHWD}`DaffCw}o^?*GNq?9ABi%*eRinUP7+94xUt!-8psH~^Sz5U>CM delta 44 xcmZozz}c{XbHWD}4d&0G6TkQ{@77^%c4lmMW@Oy%%*do@4wl%SVZk&*8~|lg4sQSe diff --git a/toolbox/OldNorm/spm_cfg_normalise.m b/toolbox/OldNorm/spm_cfg_normalise.m index 1ceff4ec..2205afff 100644 --- a/toolbox/OldNorm/spm_cfg_normalise.m +++ b/toolbox/OldNorm/spm_cfg_normalise.m @@ -3,7 +3,7 @@ %__________________________________________________________________________ % Copyright (C) 2005-2012 Wellcome Trust Centre for Neuroimaging -% $Id: spm_cfg_normalise.m 4904 2012-09-06 15:08:56Z guillaume $ +% $Id: spm_cfg_normalise.m 7155 2017-08-17 10:55:05Z john $ if ~isdeployed, addpath(fullfile(spm('dir'),'toolbox','OldNorm')); end @@ -414,7 +414,7 @@ normalise.tag = 'oldnorm'; normalise.name = 'Old Normalise'; normalise.help = { - 'This very ancient module spatially (stereotactically) normalises MRI, PET or SPECT images into a standard space defined by some ideal model or template image[s]. The template images supplied with SPM conform to the space defined by the ICBM, NIH P-20 project, and approximate that of the the space described in the atlas of Talairach and Tournoux (1988). The transformation can also be applied to any other image that has been coregistered with these scans. A few researchers may wish to continue using this strategy, but (when good quality anatomical MRI scans are available) the DARTEL approach is now generally recommended instead.' + 'This very ancient module /* \cite{ashburner97b,ashburner99a} */ spatially (stereotactically) normalises MRI, PET or SPECT images into a standard space defined by some ideal model or template image[s]. The template images supplied with SPM conform to the space defined by the ICBM, NIH P-20 project, and approximate that of the the space described in the atlas of Talairach and Tournoux (1988). The transformation can also be applied to any other image that has been coregistered with these scans. A few researchers may wish to continue using this strategy, but (when good quality anatomical MRI scans are available) the DARTEL approach is now generally recommended instead.' '' 'Generally, the algorithms work by minimising the sum of squares difference between the image which is to be normalised, and a linear combination of one or more template images. For the least squares registration to produce an unbiased estimate of the spatial transformation, the image contrast in the templates (or linear combination of templates) should be similar to that of the image from which the spatial normalisation is derived. The registration simply searches for an optimum solution. If the starting estimates are not good, then the optimum it finds may not find the global optimum.' '' diff --git a/toolbox/OldSeg/spm_cfg_preproc.m b/toolbox/OldSeg/spm_cfg_preproc.m index 4a48750d..7110c819 100644 --- a/toolbox/OldSeg/spm_cfg_preproc.m +++ b/toolbox/OldSeg/spm_cfg_preproc.m @@ -3,7 +3,7 @@ %______________________________________________________________________ % Copyright (C) 2005-2016 Wellcome Trust Centre for Neuroimaging -% $Id: spm_cfg_preproc.m 6894 2016-09-30 16:48:46Z spm $ +% $Id: spm_cfg_preproc.m 6942 2016-11-21 13:17:44Z guillaume $ if ~isdeployed, addpath(fullfile(spm('dir'),'toolbox','OldSeg')); end @@ -275,9 +275,9 @@ msk = cfg_files; msk.tag = 'msk'; msk.name = 'Masking image'; -msk.val{1} = {''}; +msk.val = {{''}}; msk.help = {'The segmentation can be masked by an image that conforms to the same space as the images to be segmented. If an image is selected, then it must match the image(s) voxel-for voxel, and have the same voxel-to-world mapping. Regions containing a value of zero in this image do not contribute when estimating the various parameters. '}; -msk.filter = 'image'; +msk.filter = 'image'; msk.ufilter = '.*'; msk.num = [0 1]; % --------------------------------------------------------------------- diff --git a/toolbox/SRender/spm_sextract.m b/toolbox/SRender/spm_sextract.m index 782357cf..36ff2ef0 100644 --- a/toolbox/SRender/spm_sextract.m +++ b/toolbox/SRender/spm_sextract.m @@ -1,29 +1,27 @@ function out = spm_sextract(job) % Surface extraction -%_______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2008-2016 Wellcome Trust Centre for Neuroimaging % John Ashburner -% $Id: spm_sextract.m 4703 2012-03-29 20:30:30Z john $ +% $Id: spm_sextract.m 6960 2016-12-05 17:05:09Z guillaume $ + images = job.images; -Vi = spm_vol(strvcat(images)); -n = numel(Vi); %-#images -if n==0, error('no input images specified'), end -[pth,nam,ext] = fileparts(images{1}); +Vi = spm_vol(char(images)); out.Surface = {}; -for k=1:numel(job.surface), +for k=1:numel(job.surface) expression = job.surface(k).expression; thresh = job.surface(k).thresh; - + y = zeros(Vi(1).dim(1:3),'single'); spm_progress_bar('Init',Vi(1).dim(3),expression,'planes completed'); - for p = 1:Vi(1).dim(3), + for p = 1:Vi(1).dim(3) B = spm_matrix([0 0 -p 0 0 0 1 1 1]); - im = cell(1,n); - for i=1:n, + im = cell(1,numel(Vi)); + for i=1:numel(im) M = inv(B*inv(Vi(1).mat)*Vi(i).mat); im{i} = spm_slice_vol(Vi(i),M,Vi(1).dim(1:2),[0,NaN]); end @@ -35,31 +33,27 @@ spm_progress_bar('Set',p); end spm_smooth(y,y,[1.5,1.5,1.5]); - + [faces,vertices] = isosurface(y,thresh); - - if isempty(vertices) - error('No surface.'); - else - % Swap around x and y because isosurface does for some - % wierd and wonderful reason. - Mat = Vi(1).mat(1:3,:)*[0 1 0 0;1 0 0 0;0 0 1 0; 0 0 0 1]; - vertices = (Mat*[vertices' ; ones(1,size(vertices,1))])'; - %matname = fullfile(pth,sprintf('surf_%s_%.3d.mat',nam,k)); - %save(matname,'-V6','faces','vertices','expression','thresh','images'); - matname = fullfile(pth,sprintf('surf_%s_%.3d.gii',nam,k)); - save(gifti(struct('faces',faces,'vertices',vertices)),matname); - out.SurfaceFile{k} = matname; - spm_progress_bar('Clear'); - end + + if isempty(vertices), error('No surface.'); end + + % Swap around x and y because isosurface does for some + % wierd and wonderful reason. + Mat = Vi(1).mat(1:3,:)*[0 1 0 0;1 0 0 0;0 0 1 0; 0 0 0 1]; + vertices = (Mat*[vertices' ; ones(1,size(vertices,1))])'; + giiname = spm_file(images{1},... + 'prefix','surf_',... + 'suffix',sprintf('_%.3d',k),... + 'ext','gii', 'number',''); + save(gifti(struct('faces',faces,'vertices',vertices)),giiname); + out.SurfaceFile{k} = giiname; + spm_progress_bar('Clear'); end -return -%_______________________________________________________________________ -%_______________________________________________________________________ + +%========================================================================== function y = efun(im,f) -for i=1:numel(im), +for i=1:numel(im) eval(['i' num2str(i) '= im{i};']); end y = eval(f); -return - diff --git a/toolbox/SRender/spm_srender.m b/toolbox/SRender/spm_srender.m index 6841fefa..c68ff41b 100644 --- a/toolbox/SRender/spm_srender.m +++ b/toolbox/SRender/spm_srender.m @@ -1,12 +1,12 @@ function spm_srender(job) % A function for rendering surfaces % FORMAT spm_srender(job) -% job - a job structure (see spm_config_srender.m) -%_______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +% job - a job structure (see tbx_cfg_render.m) +%__________________________________________________________________________ +% Copyright (C) 2008-2016 Wellcome Trust Centre for Neuroimaging % John Ashburner -% $Id: spm_srender.m 5812 2013-12-20 17:52:07Z john $ +% $Id: spm_srender.m 6960 2016-12-05 17:05:09Z guillaume $ fg = spm_figure('GetWin','Graphics'); @@ -19,15 +19,14 @@ function spm_srender(job) set(fg,'CurrentAxes',ax); cameramenu drawnow -catch end -for i=1:numel(job.Object), +for i=1:numel(job.Object) obj = job.Object(i); - for j=1:numel(obj.SurfaceFile), + for j=1:numel(obj.SurfaceFile) FVo = struct(gifti(obj.SurfaceFile{j})); FV = struct('faces',FVo.faces,'vertices',FVo.vertices); - p = patch(FV, 'Parent',ax,... + p = patch(FV, 'Parent',ax,... 'FaceColor', [obj.Color.Red,obj.Color.Green, obj.Color.Blue],... 'FaceVertexCData', [],... 'EdgeColor', 'none',... @@ -41,7 +40,7 @@ function spm_srender(job) 'EdgeLighting','phong'); end end -for i=1:numel(job.Light), +for i=1:numel(job.Light) obj = job.Light(i); l = light('Parent',ax,... 'Position',obj.Position,... @@ -52,4 +51,3 @@ function spm_srender(job) set(fg,'CurrentAxes',ax); axis image equal off; drawnow; - diff --git a/toolbox/SRender/tbx_cfg_render.m b/toolbox/SRender/tbx_cfg_render.m index 764e69cd..c7fd3b4f 100644 --- a/toolbox/SRender/tbx_cfg_render.m +++ b/toolbox/SRender/tbx_cfg_render.m @@ -1,45 +1,52 @@ function render = tbx_cfg_render % Configuration file for toolbox 'Rendering' -%_______________________________________________________________________ -% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging +%__________________________________________________________________________ +% Copyright (C) 2008-2016 Wellcome Trust Centre for Neuroimaging % John Ashburner -% $Id: tbx_cfg_render.m 5010 2012-10-19 11:47:42Z john $ +% $Id: tbx_cfg_render.m 6960 2016-12-05 17:05:09Z guillaume $ -% --------------------------------------------------------------------- +if ~isdeployed, addpath(fullfile(spm('dir'),'toolbox','SRender')); end + +%-------------------------------------------------------------------------- % images Input Images -% --------------------------------------------------------------------- +%-------------------------------------------------------------------------- images = cfg_files; images.tag = 'images'; images.name = 'Input Images'; -images.help = {'These are the images that are used by the calculator. They are referred to as i1, i2, i3, etc in the order that they are specified.'}; +images.help = { + 'These are the images that are used by the calculator.' + 'They are referred to as i1, i2, i3, etc in the order that they are specified.' + }'; images.filter = 'image'; images.ufilter = '.*'; images.num = [1 Inf]; -% --------------------------------------------------------------------- + +%-------------------------------------------------------------------------- % expression Expression -% --------------------------------------------------------------------- +%-------------------------------------------------------------------------- expression = cfg_entry; expression.tag = 'expression'; expression.name = 'Expression'; expression.help = { - 'Example expressions (f):' - ' * Mean of six images (select six images)' - ' f = ''(i1+i2+i3+i4+i5+i6)/6''' - ' * Make a binary mask image at threshold of 100' - ' f = ''i1>100''' - ' * Make a mask from one image and apply to another' - ' f = ''i2.*(i1>100)''' - ' - here the first image is used to make the mask, which is applied to the second image' - ' * Sum of n images' - ' f = ''i1 + i2 + i3 + i4 + i5 + ...''' - }'; + 'Example expressions (f):' + ' * Mean of six images (select six images)' + ' f = ''(i1+i2+i3+i4+i5+i6)/6''' + ' * Make a binary mask image at threshold of 100' + ' f = ''i1>100''' + ' * Make a mask from one image and apply to another' + ' f = ''i2.*(i1>100)''' + ' - here the first image is used to make the mask, which is applied to the second image' + ' * Sum of n images' + ' f = ''i1 + i2 + i3 + i4 + i5 + ...''' + }'; expression.strtype = 's'; expression.num = [2 Inf]; expression.val = {'i1'}; -% --------------------------------------------------------------------- + +%-------------------------------------------------------------------------- % thresh Surface isovalue(s) -% --------------------------------------------------------------------- +%-------------------------------------------------------------------------- thresh = cfg_entry; thresh.tag = 'thresh'; thresh.name = 'Surface isovalue(s)'; @@ -47,285 +54,188 @@ thresh.strtype = 'e'; thresh.num = [1 1]; thresh.val = {0.5}; -% --------------------------------------------------------------------- + +%-------------------------------------------------------------------------- % surface Surface -% --------------------------------------------------------------------- -surface = cfg_branch; -surface.tag = 'surface'; -surface.name = 'Surface'; -surface.val = {expression thresh }; -surface.help = {'An expression and threshold for each of the surfaces to be generated.'}; -% --------------------------------------------------------------------- +%-------------------------------------------------------------------------- +surface = cfg_branch; +surface.tag = 'surface'; +surface.name = 'Surface'; +surface.val = {expression thresh }; +surface.help = {'An expression and threshold for each of the surfaces to be generated.'}; + +%-------------------------------------------------------------------------- % Surfaces Surfaces -% --------------------------------------------------------------------- -Surfaces = cfg_repeat; -Surfaces.tag = 'Surfaces'; -Surfaces.name = 'Surfaces'; -Surfaces.help = {'Multiple surfaces can be created from the same image data.'}; -Surfaces.values = {surface }; -Surfaces.num = [0 Inf]; -% --------------------------------------------------------------------- +%-------------------------------------------------------------------------- +Surfaces = cfg_repeat; +Surfaces.tag = 'Surfaces'; +Surfaces.name = 'Surfaces'; +Surfaces.help = {'Multiple surfaces can be created from the same image data.'}; +Surfaces.values = {surface }; +Surfaces.num = [0 Inf]; + +%-------------------------------------------------------------------------- % SExtract Surface Extraction -% --------------------------------------------------------------------- -SExtract = cfg_exbranch; -SExtract.tag = 'SExtract'; -SExtract.name = 'Surface Extraction'; -SExtract.val = {images Surfaces }; -SExtract.help = {'User-specified algebraic manipulations are performed on a set of images, with the result being used to generate a surface file. The user is prompted to supply images to work on and a number of expressions to evaluate, along with some thresholds. The expression should be a standard matlab expression, within which the images should be referred to as i1, i2, i3,... etc. An isosurface file is created from the results at the user-specified threshold.'}; -SExtract.prog = @spm_local_sextract; -%SExtract.vfiles = @filessurf; +%-------------------------------------------------------------------------- +SExtract = cfg_exbranch; +SExtract.tag = 'SExtract'; +SExtract.name = 'Surface Extraction'; +SExtract.val = {images Surfaces }; +SExtract.help = {'User-specified algebraic manipulations are performed on a set of images, with the result being used to generate a surface file. The user is prompted to supply images to work on and a number of expressions to evaluate, along with some thresholds. The expression should be a standard matlab expression, within which the images should be referred to as i1, i2, i3,... etc. An isosurface file is created from the results at the user-specified threshold.'}; +SExtract.prog = @spm_sextract; SExtract.vout = @vout_sextract; -% --------------------------------------------------------------------- +%-------------------------------------------------------------------------- % SurfaceFile Surface File -% --------------------------------------------------------------------- +%-------------------------------------------------------------------------- SurfaceFile = cfg_files; SurfaceFile.tag = 'SurfaceFile'; SurfaceFile.name = 'Surface File'; -SurfaceFile.help = {'Filename of the surf_*.gii file containing the rendering information. This can be generated via the surface extraction routine in SPM. Normally, a surface is extracted from grey and white matter tissue class images, but it is also possible to threshold e.g. an spmT image so that activations can be displayed.'}; -SurfaceFile.filter = 'mesh'; +SurfaceFile.help = { + 'Filename of the surf_*.gii file containing the rendering information.' + 'This can be generated via the surface extraction routine in SPM.' + 'Normally, a surface is extracted from grey and white matter tissue class images, but it is also possible to threshold e.g. an spmT image so that activations can be displayed.' + }; +SurfaceFile.filter = 'mesh'; SurfaceFile.ufilter = '.*'; SurfaceFile.num = [1 1]; -% --------------------------------------------------------------------- + +%-------------------------------------------------------------------------- % Red Red -% --------------------------------------------------------------------- -Red = cfg_menu; -Red.tag = 'Red'; -Red.name = 'Red'; -Red.help = {'The intensity of the red colouring (0 to 1).'}; -Red.labels = { - '0.0' - '0.2' - '0.4' - '0.6' - '0.8' - '1.0' - }'; -Red.values = { - 0 - 0.2 - 0.4 - 0.6 - 0.8 - 1 - }'; +%-------------------------------------------------------------------------- +Red = cfg_menu; +Red.tag = 'Red'; +Red.name = 'Red'; +Red.help = {'The intensity of the red colouring (0 to 1).'}; +Red.labels = {'0.0' '0.2' '0.4' '0.6' '0.8' '1.0'}; +Red.values = {0 0.2 0.4 0.6 0.8 1}; Red.val = {1}; -% --------------------------------------------------------------------- + +%-------------------------------------------------------------------------- % Green Green -% --------------------------------------------------------------------- -Green = cfg_menu; -Green.tag = 'Green'; -Green.name = 'Green'; -Green.help = {'The intensity of the green colouring (0 to 1).'}; -Green.labels = { - '0.0' - '0.2' - '0.4' - '0.6' - '0.8' - '1.0' - }'; -Green.values = { - 0 - 0.2 - 0.4 - 0.6 - 0.8 - 1 - }'; -Green.val = {1}; -% --------------------------------------------------------------------- +%-------------------------------------------------------------------------- +Green = cfg_menu; +Green.tag = 'Green'; +Green.name = 'Green'; +Green.help = {'The intensity of the green colouring (0 to 1).'}; +Green.labels = {'0.0' '0.2' '0.4' '0.6' '0.8' '1.0'}'; +Green.values = {0 0.2 0.4 0.6 0.8 1}; +Green.val = {1}; + +%-------------------------------------------------------------------------- % Blue Blue -% --------------------------------------------------------------------- -Blue = cfg_menu; -Blue.tag = 'Blue'; -Blue.name = 'Blue'; -Blue.help = {'The intensity of the blue colouring (0 to 1).'}; -Blue.labels = { - '0.0' - '0.2' - '0.4' - '0.6' - '0.8' - '1.0' - }'; -Blue.values = { - 0 - 0.2 - 0.4 - 0.6 - 0.8 - 1 - }'; -Blue.val = {1}; -% --------------------------------------------------------------------- +%-------------------------------------------------------------------------- +Blue = cfg_menu; +Blue.tag = 'Blue'; +Blue.name = 'Blue'; +Blue.help = {'The intensity of the blue colouring (0 to 1).'}; +Blue.labels = {'0.0' '0.2' '0.4' '0.6' '0.8' '1.0'}'; +Blue.values = {0 0.2 0.4 0.6 0.8 1}; +Blue.val = {1}; + +%-------------------------------------------------------------------------- % Color Color -% --------------------------------------------------------------------- -Color = cfg_branch; -Color.tag = 'Color'; -Color.name = 'Color'; -Color.val = {Red Green Blue }; -Color.help = {'Specify the colour using a mixture of red, green and blue. For example, white is specified by 1,1,1, black is by 0,0,0 and purple by 1,0,1.'}; -% --------------------------------------------------------------------- +%-------------------------------------------------------------------------- +Color = cfg_branch; +Color.tag = 'Color'; +Color.name = 'Color'; +Color.val = {Red Green Blue}; +Color.help = { + 'Specify the colour using a mixture of red, green and blue.' + 'For example, white is specified by 1,1,1, black is by 0,0,0 and purple by 1,0,1.' + }'; + +%-------------------------------------------------------------------------- % DiffuseStrength Diffuse Strength -% --------------------------------------------------------------------- -DiffuseStrength = cfg_menu; -DiffuseStrength.tag = 'DiffuseStrength'; -DiffuseStrength.name = 'Diffuse Strength'; -DiffuseStrength.help = {'The strength with which the object diffusely reflects light. Mat surfaces reflect light diffusely, whereas shiny surfaces reflect speculatively.'}; -DiffuseStrength.labels = { - '0.0' - '0.2' - '0.4' - '0.6' - '0.8' - '1.0' - }'; -DiffuseStrength.values = { - 0 - 0.2 - 0.4 - 0.6 - 0.8 - 1 - }'; +%-------------------------------------------------------------------------- +DiffuseStrength = cfg_menu; +DiffuseStrength.tag = 'DiffuseStrength'; +DiffuseStrength.name = 'Diffuse Strength'; +DiffuseStrength.help = {'The strength with which the object diffusely reflects light. Mat surfaces reflect light diffusely, whereas shiny surfaces reflect speculatively.'}; +DiffuseStrength.labels = {'0.0' '0.2' '0.4' '0.6' '0.8' '1.0'}'; +DiffuseStrength.values = {0 0.2 0.4 0.6 0.8 1}; DiffuseStrength.val = {0.8}; -% --------------------------------------------------------------------- + +%-------------------------------------------------------------------------- % AmbientStrength Ambient Strength -% --------------------------------------------------------------------- -AmbientStrength = cfg_menu; -AmbientStrength.tag = 'AmbientStrength'; -AmbientStrength.name = 'Ambient Strength'; -AmbientStrength.help = {'The strength with which the object reflects ambient (non-directional) lighting.'}; -AmbientStrength.labels = { - '0.0' - '0.2' - '0.4' - '0.6' - '0.8' - '1.0' - }'; -AmbientStrength.values = { - 0 - 0.2 - 0.4 - 0.6 - 0.8 - 1 - }'; +%-------------------------------------------------------------------------- +AmbientStrength = cfg_menu; +AmbientStrength.tag = 'AmbientStrength'; +AmbientStrength.name = 'Ambient Strength'; +AmbientStrength.help = {'The strength with which the object reflects ambient (non-directional) lighting.'}; +AmbientStrength.labels = {'0.0' '0.2' '0.4' '0.6' '0.8' '1.0'}'; +AmbientStrength.values = {0 0.2 0.4 0.6 0.8 1}; AmbientStrength.val = {0.2}; -% --------------------------------------------------------------------- + +%-------------------------------------------------------------------------- % SpecularStrength Specular Strength -% --------------------------------------------------------------------- -SpecularStrength = cfg_menu; -SpecularStrength.tag = 'SpecularStrength'; -SpecularStrength.name = 'Specular Strength'; -SpecularStrength.help = {'The strength with which the object specularly reflects light (i.e. how shiny it is). Mat surfaces reflect light diffusely, whereas shiny surfaces reflect speculatively.'}; -SpecularStrength.labels = { - '0.0' - '0.2' - '0.4' - '0.6' - '0.8' - '1.0' - }'; -SpecularStrength.values = { - 0 - 0.2 - 0.4 - 0.6 - 0.8 - 1 - }'; +%-------------------------------------------------------------------------- +SpecularStrength = cfg_menu; +SpecularStrength.tag = 'SpecularStrength'; +SpecularStrength.name = 'Specular Strength'; +SpecularStrength.help = {'The strength with which the object specularly reflects light (i.e. how shiny it is). Mat surfaces reflect light diffusely, whereas shiny surfaces reflect speculatively.'}; +SpecularStrength.labels = {'0.0' '0.2' '0.4' '0.6' '0.8' '1.0'}'; +SpecularStrength.values = {0 0.2 0.4 0.6 0.8 1}; SpecularStrength.val = {0.2}; -% --------------------------------------------------------------------- + +%-------------------------------------------------------------------------- % SpecularExponent Specular Exponent -% --------------------------------------------------------------------- -SpecularExponent = cfg_menu; -SpecularExponent.tag = 'SpecularExponent'; -SpecularExponent.name = 'Specular Exponent'; -SpecularExponent.help = {'A parameter describing the specular reflectance behaviour. It relates to the size of the high-lights.'}; -SpecularExponent.labels = { - '0.01' - '0.1' - '10' - '100' - }'; -SpecularExponent.values = { - 0.01 - 0.1 - 10 - 100 - }'; +%-------------------------------------------------------------------------- +SpecularExponent = cfg_menu; +SpecularExponent.tag = 'SpecularExponent'; +SpecularExponent.name = 'Specular Exponent'; +SpecularExponent.help = {'A parameter describing the specular reflectance behaviour. It relates to the size of the high-lights.'}; +SpecularExponent.labels = {'0.01' '0.1' '10' '100'}; +SpecularExponent.values = {0.01 0.1 10 100}; SpecularExponent.val = {10}; -% --------------------------------------------------------------------- + +%-------------------------------------------------------------------------- % SpecularColorReflectance Specular Color Reflectance -% --------------------------------------------------------------------- -SpecularColorReflectance = cfg_menu; -SpecularColorReflectance.tag = 'SpecularColorReflectance'; -SpecularColorReflectance.name = 'Specular Color Reflectance'; -SpecularColorReflectance.help = {'Another parameter describing the specular reflectance behaviour.'}; -SpecularColorReflectance.labels = { - '0.0' - '0.2' - '0.4' - '0.6' - '0.8' - '1.0' - }'; -SpecularColorReflectance.values = { - 0 - 0.2 - 0.4 - 0.6 - 0.8 - 1 - }'; +%-------------------------------------------------------------------------- +SpecularColorReflectance = cfg_menu; +SpecularColorReflectance.tag = 'SpecularColorReflectance'; +SpecularColorReflectance.name = 'Specular Color Reflectance'; +SpecularColorReflectance.help = {'Another parameter describing the specular reflectance behaviour.'}; +SpecularColorReflectance.labels = {'0.0' '0.2' '0.4' '0.6' '0.8' '1.0'}; +SpecularColorReflectance.values = {0 0.2 0.4 0.6 0.8 1}; SpecularColorReflectance.val = {0.8}; -% --------------------------------------------------------------------- + +%-------------------------------------------------------------------------- % FaceAlpha Face Alpha -% --------------------------------------------------------------------- -FaceAlpha = cfg_menu; -FaceAlpha.tag = 'FaceAlpha'; -FaceAlpha.name = 'Face Alpha'; -FaceAlpha.help = {'The opaqueness of the surface. A value of 1 means it is opaque, whereas a value of 0 means it is transparent.'}; -FaceAlpha.labels = { - '0.0' - '0.2' - '0.4' - '0.6' - '0.8' - '1.0' - }'; -FaceAlpha.values = { - 0 - 0.2 - 0.4 - 0.6 - 0.8 - 1 - }'; +%-------------------------------------------------------------------------- +FaceAlpha = cfg_menu; +FaceAlpha.tag = 'FaceAlpha'; +FaceAlpha.name = 'Face Alpha'; +FaceAlpha.help = { + 'The opaqueness of the surface.' + 'A value of 1 means it is opaque, whereas a value of 0 means it is transparent.' + }'; +FaceAlpha.labels = {'0.0' '0.2' '0.4' '0.6' '0.8' '1.0'}'; +FaceAlpha.values = {0 0.2 0.4 0.6 0.8 1}; FaceAlpha.val = {1}; -% --------------------------------------------------------------------- + +%-------------------------------------------------------------------------- % Object Object -% --------------------------------------------------------------------- -Object = cfg_branch; -Object.tag = 'Object'; -Object.name = 'Object'; -Object.val = {SurfaceFile Color DiffuseStrength AmbientStrength SpecularStrength SpecularExponent SpecularColorReflectance FaceAlpha }; -Object.help = {'Each object is a surface (from a surf_*.gii file), which may have a number of light-reflecting qualities, such as colour and shinyness.'}; -% --------------------------------------------------------------------- +%-------------------------------------------------------------------------- +Object = cfg_branch; +Object.tag = 'Object'; +Object.name = 'Object'; +Object.val = {SurfaceFile Color DiffuseStrength AmbientStrength SpecularStrength SpecularExponent SpecularColorReflectance FaceAlpha }; +Object.help = {'Each object is a surface (from a surf_*.gii file), which may have a number of light-reflecting qualities, such as colour and shinyness.'}; + +%-------------------------------------------------------------------------- % Objects Objects -% --------------------------------------------------------------------- -Objects = cfg_repeat; -Objects.tag = 'Objects'; -Objects.name = 'Objects'; -Objects.help = {'Several surface objects can be displayed together in different colours and with different reflective properties.'}; -Objects.values = {Object }; -Objects.num = [0 Inf]; -% --------------------------------------------------------------------- +%-------------------------------------------------------------------------- +Objects = cfg_repeat; +Objects.tag = 'Objects'; +Objects.name = 'Objects'; +Objects.help = {'Several surface objects can be displayed together in different colours and with different reflective properties.'}; +Objects.values = {Object }; +Objects.num = [0 Inf]; + +%-------------------------------------------------------------------------- % Position Position -% --------------------------------------------------------------------- +%-------------------------------------------------------------------------- Position = cfg_entry; Position.tag = 'Position'; Position.name = 'Position'; @@ -333,140 +243,53 @@ Position.strtype = 'e'; Position.num = [1 3]; Position.val = {[100 100 100]}; -% --------------------------------------------------------------------- -% Red Red -% --------------------------------------------------------------------- -Red = cfg_menu; -Red.tag = 'Red'; -Red.name = 'Red'; -Red.help = {'The intensity of the red colouring (0 to 1).'}; -Red.labels = { - '0.0' - '0.2' - '0.4' - '0.6' - '0.8' - '1.0' - }'; -Red.values = { - 0 - 0.2 - 0.4 - 0.6 - 0.8 - 1 - }'; -Red.val = {1}; -% --------------------------------------------------------------------- -% Green Green -% --------------------------------------------------------------------- -Green = cfg_menu; -Green.tag = 'Green'; -Green.name = 'Green'; -Green.help = {'The intensity of the green colouring (0 to 1).'}; -Green.labels = { - '0.0' - '0.2' - '0.4' - '0.6' - '0.8' - '1.0' - }'; -Green.values = { - 0 - 0.2 - 0.4 - 0.6 - 0.8 - 1 - }'; -Green.val = {1}; -% --------------------------------------------------------------------- -% Blue Blue -% --------------------------------------------------------------------- -Blue = cfg_menu; -Blue.tag = 'Blue'; -Blue.name = 'Blue'; -Blue.help = {'The intensity of the blue colouring (0 to 1).'}; -Blue.labels = { - '0.0' - '0.2' - '0.4' - '0.6' - '0.8' - '1.0' - }'; -Blue.values = { - 0 - 0.2 - 0.4 - 0.6 - 0.8 - 1 - }'; -Blue.val = {1}; -% --------------------------------------------------------------------- -% Color Color -% --------------------------------------------------------------------- -Color = cfg_branch; -Color.tag = 'Color'; -Color.name = 'Color'; -Color.val = {Red Green Blue }; -Color.help = {'Specify the colour using a mixture of red, green and blue. For example, white is specified by 1,1,1, black is by 0,0,0 and purple by 1,0,1.'}; -% --------------------------------------------------------------------- + +%-------------------------------------------------------------------------- % Light Light -% --------------------------------------------------------------------- -Light = cfg_branch; -Light.tag = 'Light'; -Light.name = 'Light'; -Light.val = {Position Color }; -Light.help = {'Specification of a light source in terms of position and colour.'}; -% --------------------------------------------------------------------- +%-------------------------------------------------------------------------- +Light = cfg_branch; +Light.tag = 'Light'; +Light.name = 'Light'; +Light.val = {Position Color}; +Light.help = {'Specification of a light source in terms of position and colour.'}; + +%-------------------------------------------------------------------------- % Lights Lights -% --------------------------------------------------------------------- -Lights = cfg_repeat; -Lights.tag = 'Lights'; -Lights.name = 'Lights'; -Lights.help = {'There should be at least one light specified so that the objects can be clearly seen.'}; -Lights.values = {Light }; -Lights.num = [0 Inf]; -% --------------------------------------------------------------------- +%-------------------------------------------------------------------------- +Lights = cfg_repeat; +Lights.tag = 'Lights'; +Lights.name = 'Lights'; +Lights.help = {'There should be at least one light specified so that the objects can be clearly seen.'}; +Lights.values = {Light}; +Lights.val = {Light}; +Lights.num = [0 Inf]; + +%-------------------------------------------------------------------------- % SRender Surface Rendering -% --------------------------------------------------------------------- -SRender = cfg_exbranch; -SRender.tag = 'SRender'; -SRender.name = 'Surface Rendering'; -SRender.val = {Objects Lights }; -SRender.help = {'This utility is for visualising surfaces. Surfaces first need to be extracted and saved in surf_*.gii files using the surface extraction routine.'}; -SRender.prog = @spm_local_srender; -% --------------------------------------------------------------------- -% render Rendering -% --------------------------------------------------------------------- -render = cfg_choice; -render.tag = 'render'; -render.name = 'Rendering'; -render.help = {'This is a toolbox that provides a limited range of surface rendering options. The idea is to first extract surfaces from image data, which are saved in rend_*.mat files. These can then be loaded and displayed as surfaces. Note that OpenGL rendering is used, which can be problematic on some computers. The tools are limited - and they do what they do.'}; -render.values = {SExtract SRender }; -%render.num = [0 Inf]; +%-------------------------------------------------------------------------- +SRender = cfg_exbranch; +SRender.tag = 'SRender'; +SRender.name = 'Surface Rendering'; +SRender.val = {Objects Lights}; +SRender.help = {'This utility is for visualising surfaces. Surfaces first need to be extracted and saved in surf_*.gii files using the surface extraction routine.'}; +SRender.prog = @spm_srender; -%====================================================================== -function spm_local_srender(job) -if ~isdeployed, addpath(fullfile(spm('dir'),'toolbox','SRender')); end -spm_srender(job); +%-------------------------------------------------------------------------- +% render Rendering +%-------------------------------------------------------------------------- +render = cfg_choice; +render.tag = 'render'; +render.name = 'Rendering'; +render.help = {'This is a toolbox that provides a limited range of surface rendering options. The idea is to first extract surfaces from image data, which are saved in rend_*.mat files. These can then be loaded and displayed as surfaces. Note that OpenGL rendering is used, which can be problematic on some computers. The tools are limited - and they do what they do.'}; +render.values = {SExtract SRender}; -%====================================================================== -function out=spm_local_sextract(job) -if ~isdeployed, addpath(fullfile(spm('dir'),'toolbox','SRender')); end -out=spm_sextract(job); -%====================================================================== +%========================================================================== function dep = vout_sextract(job) dep = cfg_dep; for k=1:numel(job.surface), dep(k) = cfg_dep; dep(k).sname = ['Surface File ' num2str(k)]; dep(k).src_output = substruct('.','SurfaceFile','()',{k}); -% dep(k).tgt_spec = cfg_findspec({{'filter','.*\.gii$'}}); dep(k).tgt_spec = cfg_findspec({{'filter','mesh'}}); end - diff --git a/toolbox/Shoot/spm_shoot_greens.m b/toolbox/Shoot/spm_shoot_greens.m index c9413b14..72a01d1f 100644 --- a/toolbox/Shoot/spm_shoot_greens.m +++ b/toolbox/Shoot/spm_shoot_greens.m @@ -9,17 +9,19 @@ % are necessary for dealing with each component individually % v - velocity field % -% FORMAT K = spm_shoot_greens('kernel',dm,prm) +% FORMAT [K,ld] = spm_shoot_greens('kernel',dm,prm) % dm - dimensions n1*n2*n3 % prm - Differential operator parameters (3 voxel sizes, 5 hyper-parameters) % K - Fourier transform representation of Green's function % - either size n1*n2*n3 or n1*n2*n3*3*3 +% ld(1) - Log determinant of operator +% ld(2) - Number of degrees of freedom % %________________________________________________________ % (c) Wellcome Trust Centre for NeuroImaging (2012) % John Ashburner -% $Id: spm_shoot_greens.m 6008 2014-05-22 12:08:01Z john $ +% $Id: spm_shoot_greens.m 7136 2017-07-18 10:51:48Z john $ spm_diffeo('boundary',0); @@ -30,8 +32,20 @@ F = spm_diffeo('kernel',d,prm); if size(F,4) == 1, % The differential operator is symmetric, so the Fourier transform should be real - F = 1./real(fftn(F)); - if prm(4)==0, F(1,1,1) = 0; end; + F = 1./real(fftn(F)); + sm = prod(size(F)); + if nargout >=2 + ld = log(F); + if prm(4)==0, ld(1,1,1) = 0; end + ld = -sum(ld(:)); + end + if prm(4)==0 + F(1,1,1) = 0; + sm = sm - 1; + end; + if nargout >=2 + ld = 3*ld + sm*sum(2*log(prm(1:3))); + end else for j=1:size(F,5), for i=1:size(F,4), @@ -39,16 +53,22 @@ F(:,:,:,i,j) = real(fftn(F(:,:,:,i,j))); end end + ld = 0; + sm = 0; for k=1:size(F,3), % Compare the following with inverting a 3x3 matrix... A = F(:,:,k,:,:); dt = A(:,:,:,1,1).*(A(:,:,:,2,2).*A(:,:,:,3,3) - A(:,:,:,2,3).*A(:,:,:,3,2)) +... A(:,:,:,1,2).*(A(:,:,:,2,3).*A(:,:,:,3,1) - A(:,:,:,2,1).*A(:,:,:,3,3)) +... A(:,:,:,1,3).*(A(:,:,:,2,1).*A(:,:,:,3,2) - A(:,:,:,2,2).*A(:,:,:,3,1)); - msk = find(dt==0); + msk = dt<=0; + if prm(4)==0 && k==1, msk(1,1,1) = true; end; dt = 1./dt; dt(msk) = 0; - if prm(4)==0 && k==1, dt(1,1,1) = 0; end; + if nargout>=2 + sm = sm + sum(sum(~msk)); + ld = ld - sum(log(dt(~msk))); + end F(:,:,k,1,1) = (A(:,:,:,2,2).*A(:,:,:,3,3) - A(:,:,:,2,3).*A(:,:,:,3,2)).*dt; F(:,:,k,2,1) = (A(:,:,:,2,3).*A(:,:,:,3,1) - A(:,:,:,2,1).*A(:,:,:,3,3)).*dt; F(:,:,k,3,1) = (A(:,:,:,2,1).*A(:,:,:,3,2) - A(:,:,:,2,2).*A(:,:,:,3,1)).*dt; @@ -63,6 +83,10 @@ end end varargout{1} = F; + if nargout>=2 + varargout{2} = [ld, sm]; + end + else % Convolve with the Green's function via Fourier methods m = varargin{1}; @@ -80,17 +104,12 @@ for i=1:3, m(:,:,:,i) = fftn(m(:,:,:,i)); end - for k=1:size(m,3), - a = m(:,:,k,:); - m(:,:,k,:) = 0; - for j=1:3, - for i=1:3, - m(:,:,k,j) = m(:,:,k,j) + F(:,:,k,j,i).*a(:,:,:,i); - end + for j=1:3, + a = single(0); + for i=1:3, + a = a + F(:,:,:,j,i).*m(:,:,:,i); end - end - for i=1:3, - v(:,:,:,i) = ifftn(m(:,:,:,i),'symmetric'); + v(:,:,:,j) = ifftn(a,'symmetric'); end end varargout{1} = v; diff --git a/toolbox/Shoot/tbx_cfg_shoot.m b/toolbox/Shoot/tbx_cfg_shoot.m index 5142b5e9..5057551d 100644 --- a/toolbox/Shoot/tbx_cfg_shoot.m +++ b/toolbox/Shoot/tbx_cfg_shoot.m @@ -1,7 +1,7 @@ function shoot = tbx_cfg_shoot % MATLABBATCH Configuration file for toolbox 'Shoot Tools' -% $Id: tbx_cfg_shoot.m 5485 2013-05-09 15:51:24Z john $ +% $Id: tbx_cfg_shoot.m 7155 2017-08-17 10:55:05Z john $ if ~isdeployed, addpath(fullfile(spm('dir'),'toolbox','Shoot')); end @@ -32,7 +32,7 @@ warp.tag = 'warp'; warp.name = 'Run Shooting (create Templates)'; warp.val = {images }; -warp.help = {'Run the geodesic shooting nonlinear image registration procedure. This involves iteratively matching all the selected images to a template generated from their own mean. A series of Template*.nii files are generated, which become increasingly crisp as the registration proceeds.'}; +warp.help = {'Run the geodesic shooting nonlinear image registration procedure /* \cite{ashburner2011diffeomorphic} */. This involves iteratively matching all the selected images to a template generated from their own mean /* \cite{john_averageshape} */. A series of Template*.nii files are generated, which become increasingly crisp as the registration proceeds.'}; warp.prog = @spm_shoot_template; warp.vout = @vout_shoot_template; % --------------------------------------------------------------------- @@ -72,7 +72,7 @@ warp1.name = 'Run Shoot (existing Templates)'; warp1.val = {images template }; warp1.check = @check_shoot_template; -warp1.help = {'Run the Shoot nonlinear image registration procedure to match individual images to pre-existing template data. Start out with smooth templates, and select crisp templates for the later iterations.'}; +warp1.help = {'Run the Shoot nonlinear image registration procedure /* \cite{ashburner2011diffeomorphic} */ to match individual images to pre-existing template data. Start out with smooth templates, and select crisp templates for the later iterations.'}; warp1.prog = @spm_shoot_warp; warp1.vout = @vout_shoot_warp; % --------------------------------------------------------------------- @@ -207,7 +207,7 @@ interp = cfg_menu; interp.tag = 'interp'; interp.name = 'Interpolation'; -interp.val{1} = double(1); +interp.val = {1}; interp.help = { 'The method by which the images are sampled when being written in a different space.' ' Nearest Neighbour: - Fastest, but not normally recommended.' @@ -433,7 +433,6 @@ fwhm = cfg_menu; fwhm.tag = 'fwhm'; fwhm.name = 'Smoothing'; -fwhm.val = {4}; fwhm.help = {'The scalar momenta can be smoothed with a Gaussian to reduce dimensionality. More smoothing is recommended if there are fewer training images or if more channels of data were used for driving the registration. From preliminary experimants, a value of about 10mm seems to work reasonably well.'}; fwhm.labels = { 'None' @@ -547,7 +546,7 @@ shoot.tag = 'shoot'; shoot.name = 'Shoot Tools'; shoot.help = { - 'This toolbox is based around the ``Diffeomorphic Registration using Geodesic Shooting and Gauss-Newton Optimisation'''' paper, which has been submitted to NeuroImage. The idea is to register images by estimating an initial velocity field, which can then be integrated to generate both forward and backward deformations. Currently, the software only works with images that have isotropic voxels, identical dimensions and which are in approximate alignment with each other. One of the reasons for this is that the approach assumes circulant boundary conditions, which makes modelling global rotations impossible. Because of these limitations, the registration should be based on images that have first been ``imported'''' via the New Segment toolbox.' + 'This toolbox is based around the ``Diffeomorphic Registration using Geodesic Shooting and Gauss-Newton Optimisation'''' paper /* \cite{ashburner2011diffeomorphic} */. The idea is to register images by estimating an initial velocity field, which can then be integrated to generate both forward and backward deformations. Currently, the software only works with images that have isotropic voxels, identical dimensions and which are in approximate alignment with each other. One of the reasons for this is that the approach assumes circulant boundary conditions, which makes modelling global rotations impossible. Because of these limitations, the registration should be based on images that have first been ``imported'''' via the New Segment toolbox.' 'The next step is the registration itself, which involves the simultaneous registration of e.g. GM with GM, WM with WM and 1-(GM+WM) with 1-(GM+WM) (when needed, the 1-(GM+WM) class is generated implicitly, so there is no need to include this class yourself). This procedure begins by creating a mean of all the images, which is used as an initial template. Deformations from this template to each of the individual images are computed, and the template is then re-generated by applying the inverses of the deformations to the images and averaging. This procedure is repeated a number of times.' '' 'This toolbox should be considered as only a beta (trial) version, and will include a number of (as yet unspecified) extensions in future updates. Please report any bugs or problems to the SPM mailing list.' diff --git a/toolbox/dcm_fnirs/spm_dcm_fnirs_estimate.m b/toolbox/dcm_fnirs/spm_dcm_fnirs_estimate.m index 298db8ab..79223438 100644 --- a/toolbox/dcm_fnirs/spm_dcm_fnirs_estimate.m +++ b/toolbox/dcm_fnirs/spm_dcm_fnirs_estimate.m @@ -53,15 +53,13 @@ % DCM.BIC % Bayesian Information criterion % % Note: This code -% (i) shows best results with spm_nlsi_GN.m (version 6481): -% Karl Friston $Id: spm_dcm_fnirs_estimate.m 6754 2016-03-25 06:44:58Z will $ -% (ii) is based on spm_dcm_estimate.m: -% Karl Friston $Id: spm_dcm_fnirs_estimate.m 6754 2016-03-25 06:44:58Z will $ +% (i) shows best results with spm_nlsi_GN.m (version 6481), +% (ii) is based on spm_dcm_estimate.m by Karl Friston. %__________________________________________________________________________ % Copyright (C) 2002-2015 Wellcome Trust Centre for Neuroimaging % Will Penny & Sungho Tak -% $Id: spm_dcm_fnirs_estimate.m 6754 2016-03-25 06:44:58Z will $ +% $Id: spm_dcm_fnirs_estimate.m 7060 2017-04-18 16:44:46Z will $ %-------------------------------------------------------------------------- %-Load DCM structure @@ -121,10 +119,10 @@ %-------------------------------------------------------------------------- % apply temporal filtering +addpath(fullfile(spm('Dir'), 'external', 'fieldtrip', 'preproc')); +forder = 5; ftype = 'but'; fdir = 'twopass'; + if strcmpi(Y.K.type, 'Butterworth IIR') - addpath(fullfile(spm('Dir'), 'external', 'fieldtrip', 'preproc')); - forder = 5; ftype = 'but'; fdir = 'twopass'; - nf = size(Y.K.cutoff, 1); for i = 1:ny for j = 1:nf @@ -145,8 +143,14 @@ % average time series over trials if strcmpi(Y.W.type, 'y') nc = size(Y.W.onsets, 2); - for i = 1:nc, wy{i,1} = spm_fnirs_wavg(y, round(Y.W.onsets{i}.*Y.P.fs)+1, round(Y.W.durations(i).*Y.P.fs)); end - y = cell2mat(wy); + for i = 1:nc, + wy{i,1} = spm_fnirs_wavg(y, round(Y.W.onsets{i}.*Y.P.fs)+1, round(Y.W.durations(i).*Y.P.fs)); + wy{i,1} = wy{i,1} - ones(size(wy{i,1},1),1) * wy{i,1}(1,:); + end + y = cell2mat(wy); + % remove very slow drift which may exist in averaged time series + hcutoff = 0.008; % default cutoff freq [Hz] + y = ft_preproc_highpassfilter(y', Y.P.fs, hcutoff, forder, ftype, fdir)'; end Y.P.ns = size(y, 1); nout = size(Y.P.wav, 2) * nch; diff --git a/toolbox/dcm_fnirs/spm_dcm_fnirs_priors.m b/toolbox/dcm_fnirs/spm_dcm_fnirs_priors.m index 883a1c8d..8241b0cf 100644 --- a/toolbox/dcm_fnirs/spm_dcm_fnirs_priors.m +++ b/toolbox/dcm_fnirs/spm_dcm_fnirs_priors.m @@ -29,9 +29,7 @@ % modelling for functional near-infrared spectroscopy. % Neuroimage 111: 338-349, 2015. % -% This script is based on spm_dcm_fmri_priors.m written by -% Karl Friston -% $Id: spm_dcm_fnirs_priors.m 6754 2016-03-25 06:44:58Z will $ +% This script is based on spm_dcm_fmri_priors.m written by Karl Friston. % % In this script, optics priors are added, prior covariance of A is changed, % prior for extended Balloon model (viscoelastic time constant) is added. @@ -39,7 +37,7 @@ % Copyright (C) 2015 Wellcome Trust Centre for Neuroimaging % Will Penny & Sungho Tak -% $Id: spm_dcm_fnirs_priors.m 6754 2016-03-25 06:44:58Z will $ +% $Id: spm_dcm_fnirs_priors.m 6942 2016-11-21 13:17:44Z guillaume $ % Unpack %-------------------------------------------------------------------------- diff --git a/toolbox/dcm_fnirs/spm_dcm_fnirs_specify.m b/toolbox/dcm_fnirs/spm_dcm_fnirs_specify.m index 20707536..a71f88a8 100644 --- a/toolbox/dcm_fnirs/spm_dcm_fnirs_specify.m +++ b/toolbox/dcm_fnirs/spm_dcm_fnirs_specify.m @@ -9,7 +9,7 @@ % Copyright (C) 2015-2016 Wellcome Trust Centre for Neuroimaging % Will Penny & Sungho Tak -% $Id: spm_dcm_fnirs_specify.m 6760 2016-03-29 15:57:32Z guillaume $ +% $Id: spm_dcm_fnirs_specify.m 7060 2017-04-18 16:44:46Z will $ %-------------------------------------------------------------------------- %-Interactive window @@ -85,13 +85,17 @@ %-Average time series over trials W.type = spm_input('average time series over trials?', '+1', 'y/n'); if strcmpi(W.type, 'y') + % read onset times from SPM.mat onsets = {}; names = {}; t0 = 0; for i = 1:n, nc = size(SPMn(i).Sess.U, 2); for j = 1:nc - onsets = [onsets t0+SPMn(i).Sess.U(j).ons]; - names = [names SPMn(i).Sess.U(j).name]; + str = ['include ' SPMn(i).Sess.U(j).name{1} '?']; + if spm_input(str, '+1', 'y/n', [1 0], 1) + onsets = [onsets t0+SPMn(i).Sess.U(j).ons]; + names = [names SPMn(i).Sess.U(j).name]; + end end t0 = t0 + P.ns(i)./P.fs; end @@ -104,9 +108,9 @@ fprintf('--------------------------------------------------------- \n'); fprintf('time window [begin end]\n'); fprintf('--------------------------------------------------------- \n'); - t0 = 0; + t0 = 0; wdur = min(diff(sort(cell2mat(W.onsets(:))))); for i = 1:nc, - W.durations(i) = spm_input(['for ' W.names{i} ':'], '+1', 'r', mean(diff(W.onsets{i})), 1); + W.durations(i) = spm_input(['for ' W.names{i} ':'], '+1', 'r', wdur, 1); fprintf('%-20s: %4.2f %4.2f [sec] \n', W.names{i}, t0, t0+W.durations(i)); t0 = t0 + W.durations(i); end @@ -136,14 +140,14 @@ % display channel positions load(P.fname.pos); spm_fnirs_viewer_sensor(R); -clear R; ans = spm_input('use all sensor measurements ?', '+1', 'y/n'); if strcmpi(ans, 'y') - P.rois = ones(1, P.nch); + P.rois = R.ch.label; elseif strcmpi(ans, 'n') P.rois = spm_input('sensors of interest:', '+1', 'n'); end +clear R; %-------------------------------------------------------------------------- %-Specify hemodynamic source positions diff --git a/toolbox/dcm_fnirs/spm_fx_fnirs.m b/toolbox/dcm_fnirs/spm_fx_fnirs.m index 6a4b5c9b..a993d123 100644 --- a/toolbox/dcm_fnirs/spm_fx_fnirs.m +++ b/toolbox/dcm_fnirs/spm_fx_fnirs.m @@ -37,13 +37,12 @@ % Neuroimage 49:3039-3046, 2010. % % This script is based on spm_fx_fmri.m written by -% Karl Friston & Klaas Enno Stephan -% $Id: spm_fx_fnirs.m 6826 2016-07-04 10:39:39Z will $ +% Karl Friston & Klaas Enno Stephan. %__________________________________________________________________________ % Copyright (C) 2015 Wellcome Trust Centre for Neuroimaging % Will Penny & Sungho Tak -% $Id: spm_fx_fnirs.m 6826 2016-07-04 10:39:39Z will $ +% $Id: spm_fx_fnirs.m 6942 2016-11-21 13:17:44Z guillaume $ % Neuronal motion %========================================================================== diff --git a/toolbox/dcm_meeg/spm_L_priors.m b/toolbox/dcm_meeg/spm_L_priors.m index 8e53486f..4a276340 100644 --- a/toolbox/dcm_meeg/spm_L_priors.m +++ b/toolbox/dcm_meeg/spm_L_priors.m @@ -31,7 +31,7 @@ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_L_priors.m 6856 2016-08-10 17:55:05Z karl $ +% $Id: spm_L_priors.m 6971 2016-12-14 18:49:19Z bernadette $ @@ -66,8 +66,8 @@ pE.Lpos = dipfit.Lpos; pC.Lpos = ones(3,n)*V; % positions pE.L = zeros(3,n); pC.L = ones(3,n)*64; % orientations - Sc = find(~cellfun(@isempty,dipfit.silent_source)); % silence sources for CSD - if(Sc); pC.L(:,Sc) = pC.L(:,Sc)*0; end + Sc = find(~cellfun(@isempty,dipfit.silent_source)); % silence sources for CSD + if(Sc); pC.L(:,Sc) = pC.L(:,Sc)*0; end case{'IMG'} %------------------------------------------------------------------ @@ -75,8 +75,8 @@ pE.Lpos = sparse(3,0); pC.Lpos = sparse(3,0); % positions pE.L = zeros(m,n); pC.L = ones(m,n)*64; % modes - Sc = find(~cellfun(@isempty,dipfit.silent_source)); % silence sources for CSD - if(Sc); pC.L(:,Sc) = pC.L(:,Sc)*0; end + Sc = find(~cellfun(@isempty,dipfit.silent_source)); % silence sources for CSD + if(Sc); pC.L(:,Sc) = pC.L(:,Sc)*0; end case{'LFP'} %------------------------------------------------------------------ @@ -105,7 +105,7 @@ case{'CMC','TFM'} %-------------------------------------------------------------- - pE.J{end + 1} = sparse(1,[3 7],[4 2],1,8); % 8 states + pE.J{end + 1} = sparse(1,3,1,1,8); % 8 states pC.J{end + 1} = sparse(1,[1 7],1/32,1,8); case{'LFP'} @@ -143,6 +143,17 @@ pE.J{end + 1} = []; % null pC.J{end + 1} = []; + case{'BGC'} + %-------------------------------------------------------------- + %assuming data are from STN + pE.J{end + 1} = sparse(1,5,1,1,10); % 10 states + pC.J{end + 1} = sparse(1,10); + + case{'MMC'} + %-------------------------------------------------------------- + pE.J{end + 1} = sparse(1,[1 3 7],[.2 .2 .6],1,8); % 8 states + pC.J{end + 1} = sparse(1,8); + case{'NULL'} %-------------------------------------------------------------- nx = size(pE.A,1)/m; @@ -162,7 +173,7 @@ pE.J{i}(model(i).J) = 1; end end - + % subsidiary (free) sources %---------------------------------------------------------------------- if isfield(model(i),'K') diff --git a/toolbox/dcm_meeg/spm_bgc_priors.m b/toolbox/dcm_meeg/spm_bgc_priors.m new file mode 100644 index 00000000..4edf02b0 --- /dev/null +++ b/toolbox/dcm_meeg/spm_bgc_priors.m @@ -0,0 +1,25 @@ +function [pE,pC] = spm_bgc_priors +% Prior moments for a basal ganglia circuit +% FORMAT [pE,pC] = spm_bgc_priors +% only contains priors for intrinsic parameters +% priors for extrinsic parameters are defined in spm_cmc_priors +%__________________________________________________________________________ +% Copyright (C) 2016 Wellcome Trust Centre for Neuroimaging + +% Bernadette van Wijk +% $Id: spm_bgc_priors.m 7185 2017-10-11 10:10:04Z spm $ + + +% synaptic parameters +%-------------------------------------------------------------------------- + +E.T = sparse(1,5); V.T = [1/4 1/4 1/4 1/4 1/4]; + +E.G=[ 0 0 0 0 0 0 0 0 0]; +V.G=[ 1/2 1/2 1/2 1/2 1/2 1/2 1/2 1/2 1/2]; + +E.S = 0; V.S = 1/16; % slope of sigmoid + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +pE = E; +pC = V; \ No newline at end of file diff --git a/toolbox/dcm_meeg/spm_dcm_csd.m b/toolbox/dcm_meeg/spm_dcm_csd.m index f2bf35e4..4e445517 100644 --- a/toolbox/dcm_meeg/spm_dcm_csd.m +++ b/toolbox/dcm_meeg/spm_dcm_csd.m @@ -41,7 +41,7 @@ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_dcm_csd.m 6481 2015-06-16 17:01:47Z karl $ +% $Id: spm_dcm_csd.m 7002 2017-02-02 18:22:04Z karl $ % check options @@ -168,10 +168,8 @@ %-------------------------------------------------------------------------- y = spm_fs_csd(DCM.xY.y,DCM.M); for i = 1:length(y) - n = size(y{i},1); - m = size(y{i},2)*size(y{i},3); - q = spm_Q(1/2,n,1); - Q{i,i} = kron(speye(m,m),q); + m = spm_length(y{i}); + Q{i,i} = speye(m,m); end DCM.xY.Q = spm_cat(Q); DCM.xY.X0 = sparse(size(Q,1),0); diff --git a/toolbox/dcm_meeg/spm_dcm_erp.m b/toolbox/dcm_meeg/spm_dcm_erp.m index 08b0381a..ac6796be 100644 --- a/toolbox/dcm_meeg/spm_dcm_erp.m +++ b/toolbox/dcm_meeg/spm_dcm_erp.m @@ -1,6 +1,6 @@ -function DCM = spm_dcm_erp(DCM) -% Estimate parameters of a DCM model (Newton's methods) -% FORMAT DCM = spm_dcm_erp(DCM) +function [DCM,dipfit] = spm_dcm_erp(DCM) +% Estimate parameters of a DCM model (Variational Lapalce) +% FORMAT [DCM,dipfit] = spm_dcm_erp(DCM) % % DCM % name: name string @@ -26,6 +26,10 @@ % options.CVA - use CVA for spatial modes [default = 0] % options.Nmax - maxiumum number of iterations [default = 64] % +% dipfit - Dipole structure (for electromagnetic forward model) +% See spm_dcm_erp_dipfit: this field is removed from DCM.M to save +% memory – and is offered as an output argument if needed +% % The scheme can be initialised with parameters for the neuronal model % and spatial (observer) model by specifying the fields DCM.P and DCM.Q, % respectively. If previous priors (DCM.M.pE and pC or DCM.M.gE and gC or @@ -36,7 +40,7 @@ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_dcm_erp.m 6725 2016-02-19 19:14:25Z karl $ +% $Id: spm_dcm_erp.m 7149 2017-08-08 13:14:36Z karl $ % check options (and clear persistent variables) %========================================================================== @@ -45,7 +49,6 @@ name = sprintf('DCM_%s',date); - % Filename and options %-------------------------------------------------------------------------- try, DCM.name; catch, DCM.name = name; end @@ -237,7 +240,7 @@ M.Nmax = Nmax; % re-intialise states -%------------------------------------------------------------------------- +%-------------------------------------------------------------------------- M.x = spm_dcm_neural_x(pE,M); @@ -410,6 +413,7 @@ % remove dipfit stucture to save memory %-------------------------------------------------------------------------- +dipfit = DCM.M.dipfit; DCM.M = rmfield(DCM.M,'dipfit'); % and save diff --git a/toolbox/dcm_meeg/spm_dcm_ind.m b/toolbox/dcm_meeg/spm_dcm_ind.m index 6259e90e..e7fd71de 100644 --- a/toolbox/dcm_meeg/spm_dcm_ind.m +++ b/toolbox/dcm_meeg/spm_dcm_ind.m @@ -35,7 +35,7 @@ % coupling; which correspond to within and between frequency coupling % respectively. % -% the number of notes can be optimised using Bayesian model selection. The +% The number of nodes can be optimised using Bayesian model selection. The % data are reduced to a fixed number of principal components that capture % the greatest variation inspection responses never peristimulus time. The % number of nodes specified by the user tries to reconstruct the response @@ -52,7 +52,7 @@ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_dcm_ind.m 5894 2014-02-26 14:27:01Z karl $ +% $Id: spm_dcm_ind.m 7143 2017-07-29 18:50:38Z karl $ % check options diff --git a/toolbox/dcm_meeg/spm_dcm_neural_priors.m b/toolbox/dcm_meeg/spm_dcm_neural_priors.m index fc678525..3023d578 100644 --- a/toolbox/dcm_meeg/spm_dcm_neural_priors.m +++ b/toolbox/dcm_meeg/spm_dcm_neural_priors.m @@ -34,10 +34,10 @@ % pC = 1; %__________________________________________________________________________ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging - + % Karl Friston -% $Id: spm_dcm_neural_priors.m 6727 2016-02-20 18:06:47Z karl $ - +% $Id: spm_dcm_neural_priors.m 6973 2016-12-15 12:34:20Z bernadette $ + % For generic schemes one can mix and match different types of sources; % furthermore, they can have different condition-specific modulation of % intrinsic connectivity parameters and different, source-specific- @@ -50,7 +50,7 @@ % model(i).K = [i j k ,...] % other states contributing to L %__________________________________________________________________________ - + % assemble priors for more than one sort of model %========================================================================== if isstruct(model) @@ -68,7 +68,6 @@ [pE,pC] = spm_cmc_priors(A,B,C); pE = rmfield(pE,int); pC = rmfield(pC,int); - % intrinsic parameters %---------------------------------------------------------------------- @@ -92,98 +91,145 @@ iC.B(model(i).B) = 1/16; end pE.int{i} = iE; - pC.int{i} = iC; + pC.int{i} = iC; + + if isfield(model(i),'Zf') && iscell(model(i).Zf) + + for k = 1:length(pC.B) + + if size(model(i).Zf,1)==1 + pE.Bf{1,k} = zeros(size(model(i).Zf{1,k})); + pC.Bf{1,k} = model(i).Zf{1,k} * 1/8; + elseif size(model(i).Zf,1)==2 + pE.Bf{1,k} = zeros(size(model(i).Zf{1,k})); + pC.Bf{1,k} = model(i).Zf{1,k} * 1/8; + pE.Bf{2,k} = zeros(size(model(i).Zf{1,k})); + pC.Bf{2,k} = model(i).Zf{2,k} * 1/8; + else disp('uncorrect specification Zf') + end + if size(model(i).Zb,1)==1 + pE.Bb{1,k} = zeros(size(model(i).Zb{1,k})); + pC.Bb{1,k} = model(i).Zb{1,k} * 1/8; + elseif size(model(i).Zb,1)==2 + pE.Bb{1,k} = zeros(size(model(i).Zb{1,k})); + pC.Bb{1,k} = model(i).Zb{1,k} * 1/8; + pE.Bb{2,k} = zeros(size(model(i).Zb{1,k})); + pC.Bb{2,k} = model(i).Zb{2,k} * 1/8; + else disp('uncorrect specification Zb') + end + pC.B{k} = 0*pC.B{k}; + end + end end return end - + + % get priors on neural model %-------------------------------------------------------------------------- switch lower(model) - + % linear David et al model (linear in states) %====================================================================== case{'erp','sep'} - + % prior moments on parameters %------------------------------------------------------------------ [pE,pC] = spm_erp_priors(A,B,C); - % linear David et al model (Canonical microcircuit) - %====================================================================== + % linear David et al model (Canonical microcircuit) + %====================================================================== case{'cmc'} - + % prior moments on parameters %------------------------------------------------------------------ [pE,pC] = spm_cmc_priors(A,B,C); - % linear David et al model (Canonical microcircuit with plasticity) - %====================================================================== + % linear David et al model (Canonical microcircuit with plasticity) + %====================================================================== case{'tfm'} - + % prior moments on parameters %------------------------------------------------------------------ [pE,pC] = spm_tfm_priors(A,B,C); - - % linear David et al model (linear in states) - with self-inhibition - %====================================================================== + + % linear David et al model (linear in states) - with self-inhibition + %====================================================================== case{'lfp'} - + % prior moments on parameters %------------------------------------------------------------------ [pE,pC] = spm_lfp_priors(A,B,C); - - - % Neural mass model (nonlinear in states) - %====================================================================== + + + % Neural mass model (nonlinear in states) + %====================================================================== case{'nmm','mfm'} - + % prior moments on parameters %------------------------------------------------------------------ [pE,pC] = spm_nmm_priors(A,B,C); - % Neural mass model (nonlinear in states) - %====================================================================== + % Neural mass model (nonlinear in states) + %====================================================================== case{'nmda'} - + % prior moments on parameters %------------------------------------------------------------------ [pE,pC] = spm_nmda_priors(A,B,C); - % Canonical neural mass model (nonlinear in states) - %====================================================================== + % Canonical neural mass model (nonlinear in states) + %====================================================================== case{'cmm'} - + % prior moments on parameters %------------------------------------------------------------------ [pE,pC] = spm_cmm_priors(A,B,C); - % Canonical neural mass model with NMDA channels(nonlinear in states) - %====================================================================== + % Canonical neural mass model with NMDA channels(nonlinear in states) + %====================================================================== case{'cmm_nmda'} - + % prior moments on parameters %------------------------------------------------------------------ [pE,pC] = spm_cmm_NMDA_priors(A,B,C); - % Neural field model (linear in states) - %====================================================================== + % Neural field model (linear in states) + %====================================================================== case{'nfm'} - + % prior moments on parameters %------------------------------------------------------------------ - [pE,pC] = spm_nfm_priors(A,B,C); + [pE,pC] = spm_nfm_priors(A,B,C); - % Null model - of Jacabian (linear in states) - %====================================================================== + % Neural field model (linear in states) + %====================================================================== + case{'bgc'} + + % prior moments on parameters + %------------------------------------------------------------------ + [pE,pC] = spm_bgc_priors; %no (A,B,C); + + + % Bhatt et al model (motor microcircuit) + %====================================================================== + case{'mmc'} + + % prior moments on parameters + %------------------------------------------------------------------ + [pE,pC] = spm_mmc_priors(A,B,C); + + + % Null model - of Jacabian (linear in states) + %====================================================================== case{'null'} - + % prior moments on parameters %------------------------------------------------------------------ [pE,pC] = spm_null_priors(A,B,C); diff --git a/toolbox/dcm_meeg/spm_dcm_tfm.m b/toolbox/dcm_meeg/spm_dcm_tfm.m index 075cdb39..7fc7e881 100644 --- a/toolbox/dcm_meeg/spm_dcm_tfm.m +++ b/toolbox/dcm_meeg/spm_dcm_tfm.m @@ -50,7 +50,7 @@ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_dcm_tfm.m 6234 2014-10-12 09:59:10Z karl $ +% $Id: spm_dcm_tfm.m 7149 2017-08-08 13:14:36Z karl $ % check options and preliminaries @@ -87,15 +87,15 @@ DCM.M.ds = 8; -% Get posterior from event-related responses +% Get posterior (and dipfit) from event-related responses %========================================================================== ERP = DCM; -[pth name] = fileparts(DCM.name); +[pth,name] = fileparts(DCM.name); ERP.name = fullfile(pth,[name '_erp']); ERP.M.ds = 0; -ERP.M.hE = 8; +ERP.M.hE = 6; ERP.M.hC = 1/128; -ERP = spm_dcm_erp(ERP); +[ERP,dipfit] = spm_dcm_erp(ERP); %-Feature selection using principal components (U) of lead-field %========================================================================== @@ -103,8 +103,8 @@ clear functions DCM.xY = ERP.xY; -DCM.M.dipfit = ERP.M.dipfit ; DCM.M.U = ERP.M.U; +DCM.M.dipfit = dipfit; DCM = spm_dcm_tfm_data(DCM); % Use posterior as the prior in a model of induced responses diff --git a/toolbox/dcm_meeg/spm_dcm_x_neural.m b/toolbox/dcm_meeg/spm_dcm_x_neural.m index 70743095..33ea4a81 100644 --- a/toolbox/dcm_meeg/spm_dcm_x_neural.m +++ b/toolbox/dcm_meeg/spm_dcm_x_neural.m @@ -12,7 +12,7 @@ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_dcm_x_neural.m 6855 2016-08-06 10:06:35Z karl $ +% $Id: spm_dcm_x_neural.m 6971 2016-12-14 18:49:19Z bernadette $ % paramteric state equation %-------------------------------------------------------------------------- @@ -160,7 +160,32 @@ x = spm_x_mfm(P); f = 'spm_fx_mfm'; - % Mean field model (nonlinear in states) - with covariance + + % Basal ganglia circuit (linear in states) - with covariance + %====================================================================== + case{'bgc'} + + % inital states and model + %------------------------------------------------------------------ + n = length(1); + m = 10; + x = sparse(n,m); + + f = 'spm_fx_bgc'; + + % Linear in states – motor microcircuit + %====================================================================== + case{'mmc'} + + % inital states + %------------------------------------------------------------------ + n = length(P.A{1}); % number of sources + m = 8; % number of states + x = sparse(n,m); + + f = 'spm_fx_mmc'; + + % Null model - of Jacabian (linear in states) %====================================================================== case{'null'} diff --git a/toolbox/dcm_meeg/spm_epileptor_demo.m b/toolbox/dcm_meeg/spm_epileptor_demo.m index dbfa3015..963644f3 100644 --- a/toolbox/dcm_meeg/spm_epileptor_demo.m +++ b/toolbox/dcm_meeg/spm_epileptor_demo.m @@ -14,7 +14,7 @@ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_epileptor_demo.m 6112 2014-07-21 09:39:53Z karl $ +% $Id: spm_epileptor_demo.m 6937 2016-11-20 12:30:40Z karl $ % Model specification @@ -26,7 +26,7 @@ Nc = 1; Ns = 1; options.spatial = 'LFP'; -options.model = 'CMC'; +options.model = 'TFM'; options.analysis = 'TFA'; M.dipfit.model = options.model; M.dipfit.type = options.spatial; @@ -108,8 +108,8 @@ p = linspace(-2,2,64); for i = 1:length(p) P = pE; - P.G(1) = p(i); - [G w] = spm_csd_mtf(P,M); + P.G(2) = p(i); + [G,w] = spm_csd_mtf(P,M); GW(:,i) = abs(G{1}); end @@ -143,7 +143,7 @@ % exogenous input %-------------------------------------------------------------------------- -U.u(:,1) = tanh((t - 1)*8)*3/2; +U.u(:,1) = tanh((t - 1)*8)*1; M.W = inv(diag(sparse(1,1,1,1,M.n) + exp(-32))); LFP = spm_int_sde(pE,M,U); @@ -168,7 +168,7 @@ W = 128; TFR = spm_wft(LFP,w*W*U.dt,W); subplot(4,1,3) -imagesc(t,w,abs(TFR)); +imagesc(t,w,spm_en(abs(TFR))) title('time-frequency response','FontSize',16) axis xy xlabel('time (s)') @@ -177,14 +177,14 @@ % now integrate a generative model to simulate a time frequency response %========================================================================== -M.f = M.h; -M = rmfield(M,'h'); -[csd,erp] = spm_csd_int(pE,M,U); +M.f = M.h; +M = rmfield(M,'h'); +csd = spm_csd_int(pE,M,U); % predicted time frequency response %-------------------------------------------------------------------------- subplot(4,1,4) -imagesc(t,w,spm_conv(abs(csd{1}'),4,4)); +imagesc(t,w,spm_en(abs(csd{1}'))); title('Predicted response','FontSize',16) axis xy xlabel('time (s)') diff --git a/toolbox/dcm_meeg/spm_erp_L.m b/toolbox/dcm_meeg/spm_erp_L.m index 3f1f0869..9b1fa8fd 100644 --- a/toolbox/dcm_meeg/spm_erp_L.m +++ b/toolbox/dcm_meeg/spm_erp_L.m @@ -25,11 +25,11 @@ % Copyright (C) 2005 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_erp_L.m 6720 2016-02-15 21:06:55Z karl $ +% $Id: spm_erp_L.m 7142 2017-07-26 20:38:45Z karl $ % Create a persient variable that rembers the last locations %-------------------------------------------------------------------------- -persistent LastLpos LastL +persistent LastLpos LastL % type of spatial model and modality diff --git a/toolbox/dcm_meeg/spm_fs_csd.m b/toolbox/dcm_meeg/spm_fs_csd.m index a8e92aa2..4b75ddae 100644 --- a/toolbox/dcm_meeg/spm_fs_csd.m +++ b/toolbox/dcm_meeg/spm_fs_csd.m @@ -11,14 +11,20 @@ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_fs_csd.m 6557 2015-09-20 12:44:30Z karl $ +% $Id: spm_fs_csd.m 7148 2017-08-04 15:27:29Z karl $ +% control the relative precision of (second-order) data features +%-------------------------------------------------------------------------- +beta = [1 1/8 2]; -% return (scaled) cross-spectra and covariance functions +% return (scaled) cross-spectra, covariance functions MAR coefficients %-------------------------------------------------------------------------- for i = 1:length(y); csd = y{i}; ccf = spm_csd2ccf(csd,M.Hz); - y{i} = [csd*8; ccf(1:8:end,:,:)]; - % y{i} = [log(csd); ccf(1:8:end,:,:)]; + mar = spm_ccf2mar(ccf,32); + for p = 1:mar.p + arc(p,:,:) = mar.lag(p).a; + end + y{i} = [csd*beta(1); ccf(1:8:end,:,:)*beta(2); arc*beta(3)]; end diff --git a/toolbox/dcm_meeg/spm_fx_bgc.m b/toolbox/dcm_meeg/spm_fx_bgc.m new file mode 100644 index 00000000..8e6b2302 --- /dev/null +++ b/toolbox/dcm_meeg/spm_fx_bgc.m @@ -0,0 +1,161 @@ +function [f,J,Q] = spm_fx_bgc(x,u,P,M) +% state equations for a neural mass model of the basal ganglia circuit +% models the circuit between striatum, gpe, stn, gpi, and thalamus as a +% single source (no extrinsic connections) +% +% order cells states +% 1 = striatum - ii x(1,1:2) +% 2 = gpe - ii x(1,3:4) +% 3 = stn - pyr x(1,5:6) +% 4 = gpi - ii x(1,7:8) +% 5 = thalamus - pyr x(1,9:10) +% +% G(1,1) = str -> str (-ve self) +% G(1,2) = str -> gpe (-ve ext) +% G(1,3) = gpe -> gpe (-ve self) +% G(1,4) = gpe -> stn (-ve ext) +% G(1,5) = stn -> gpe (+ve ext) +% G(1,6) = str -> gpi (-ve ext) +% G(1,7) = stn -> gpi (+ve ext) +% G(1,8) = gpi -> gpi (-ve self) +% G(1,9) = gpi -> tha (-ve ext) +%__________________________________________________________________________ +% Copyright (C) 2016 Wellcome Trust Centre for Neuroimaging + +% Bernadette van Wijk +% $Id: spm_fx_bgc.m 7185 2017-10-11 10:10:04Z spm $ + + +% check if intrinsic connections are free parameters +%-------------------------------------------------------------------------- +try, P.G; catch, P.G = 0; end + +% get dimensions and configure state variables +%-------------------------------------------------------------------------- +x = spm_unvec(x,M.x); % neuronal states +n = size(x,1); % number of sources + +% [default] fixed parameters +%-------------------------------------------------------------------------- +G = [2 2 2 2 2 2 2 2 2]*200; % synaptic connection strengths +T = [8 8 4 8 8]; % synaptic time constants [str,gpe,stn,gpi,tha]; +R = 2/3; % slope of sigmoid activation function +% NB for more pronounced state dependent transfer functions use R = 3/2; + +if isfield(M,'BGC_G'); G = M.BGC_G; end +if isfield(M,'BGC_T'); T = M.BGC_T; end + + +% [specified] fixed parameters +%-------------------------------------------------------------------------- +if isfield(M,'pF') + try, E = M.pF.E; end + try, G = M.pF.G; end + try, T = M.pF.T; end + try, R = M.pF.R; end +end + +% input connections +%-------------------------------------------------------------------------- +C = exp(P.C); + +% pre-synaptic inputs: s(V) +%-------------------------------------------------------------------------- +R = R.*exp(P.S); % gain of activation function +F = 1./(1 + exp(-R*x + 0)); % firing rate +S = F - 1/(1 + exp(0)); % deviation from baseline firing (0) + +% input +%========================================================================== +if isfield(M,'u') + + % endogenous input + %---------------------------------------------------------------------- + U = u(:)*128; + +else + % exogenous input + %---------------------------------------------------------------------- + U = C*u(:)*32; +end + + +% time constants and intrinsic connections +%========================================================================== +T = T/1000; +for i = 1:size(P.T,2) + T(:,i) = T(:,i).*exp(P.T(:,i)); +end + + +% intrinsic/extrinsic connections to be optimised +%-------------------------------------------------------------------------- +j = 1:9; +for i = 1:size(P.G,2) + G(:,j(i)) = G(:,j(i)).*exp(P.G(:,i)); +end + + +% Motion of states: f(x) +%-------------------------------------------------------------------------- + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% 1 - Str: ii + +% inhibitory interneurons: Hidden states - error +%-------------------------------------------------------------------------- +u = U; +u = - G(:,1)*S(:,1) + u; +f(:,2) = (u - 2*x(:,2) - x(:,1)./T(1,1))./T(1,1); + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% 2 - GPe: ii + +% inhibitory interneurons: Hidden states - error +%-------------------------------------------------------------------------- +u = 0; +u = - G(:,2)*S(:,1) + G(:,5)*S(:,5) - G(:,3)*S(:,3) + u; +f(:,4) = (u - 2*x(:,4) - x(:,3)./T(1,2))./T(1,2); + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% 3 - STN: pyr + +% pyramidal cells: Hidden causes - error +%-------------------------------------------------------------------------- +u = 0; +u = - G(:,4)*S(:,3) + u; +f(:,6) = (u - 2*x(:,6) - x(:,5)./T(1,3))./T(1,3); + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% 4 - GPi: ii + +% inhibitory interneurons: Hidden states - error +%-------------------------------------------------------------------------- +u = 0; +u = G(:,6)*S(:,5) - G(:,7)*S(:,1) - G(:,8)*S(:,7) + u; +f(:,8) = (u - 2*x(:,8) - x(:,7)./T(1,4))./T(1,4); + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% 5 - Thalamus: pyr + +% pyramidal cells: Hidden causes - error +%-------------------------------------------------------------------------- +u = 0; +u = - G(:,9)*S(:,7) + u; +f(:,10) = (u - 2*x(:,10) - x(:,9)./T(1,5))./T(1,5); + + + + +% Voltage +%========================================================================== +f(:,1) = x(:,2); +f(:,3) = x(:,4); +f(:,5) = x(:,6); +f(:,7) = x(:,8); +f(:,9) = x(:,10); +f = spm_vec(f); diff --git a/toolbox/dcm_meeg/spm_fx_cmc_tfm.m b/toolbox/dcm_meeg/spm_fx_cmc_tfm.m index 8a17731c..7d49c9ad 100644 --- a/toolbox/dcm_meeg/spm_fx_cmc_tfm.m +++ b/toolbox/dcm_meeg/spm_fx_cmc_tfm.m @@ -40,7 +40,7 @@ % Copyright (C) 2005 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_fx_cmc_tfm.m 6857 2016-08-19 15:17:06Z karl $ +% $Id: spm_fx_cmc_tfm.m 6922 2016-11-02 17:28:23Z karl $ % get dimensions and configure state variables @@ -52,7 +52,7 @@ % [default] fixed parameters %-------------------------------------------------------------------------- E = [2 1 1 1]*512; % extrinsic (forward and backward) -T = [256 128 16 32]; % synaptic rate constants +T = [16 8 1 2]*16; % synaptic rate constants R = 1; % gain of activation function B = 0; % baseline firing @@ -74,7 +74,9 @@ % pre-synaptic inputs: s(V) %-------------------------------------------------------------------------- -V = x(:,1:2:end); % Voltage +ig = 2*(1:4); % indices of conductance +iv = ig - 1; % indices of voltage +V = x(:,iv); % Voltage F = 1./(1 + exp(B - R*V)); % firing rate S = F - 1/(1 + exp(B)); % deviation @@ -105,22 +107,22 @@ % extrinsic connections %-------------------------------------------------------------------------- -% forward (i) 2 sp -> ss (+ve) -% forward (ii) 1 sp -> dp (+ve) -% backward (i) 2 dp -> sp (-ve) -% backward (ii) 1 dp -> ii (-ve) +% forward A{1} sp -> ss +% forward A{2} sp -> dp +% backward A{3} dp -> sp +% backward A{4} dp -> ii %-------------------------------------------------------------------------- -% Neuronal states (deviations from baseline firing) +% Neuronal states (deviations from baseline) %-------------------------------------------------------------------------- -% S(:,1) - voltage (spiny stellate cells) -% S(:,2) - conductance (spiny stellate cells) -% S(:,3) - voltage (superficial pyramidal cells) -% S(:,4) - conductance (superficial pyramidal cells) -% S(:,5) - current (inhibitory interneurons) -% S(:,6) - conductance (inhibitory interneurons) -% S(:,7) - voltage (deep pyramidal cells) -% S(:,8) - conductance (deep pyramidal cells) +% x(:,1) - voltage (spiny stellate cells) +% x(:,2) - conductance (spiny stellate cells)but +% x(:,3) - voltage (superficial pyramidal cells) +% x(:,4) - conductance (superficial pyramidal cells) +% x(:,5) - current (inhibitory interneurons) +% x(:,6) - conductance (inhibitory interneurons) +% x(:,7) - voltage (deep pyramidal cells) +% x(:,8) - conductance (deep pyramidal cells) %-------------------------------------------------------------------------- % ss sp ii dp % intrinsic connections %-------------------------------------------------------------------------- @@ -150,12 +152,9 @@ % Afferents %========================================================================== -u = zeros(n,4); % intrinsic – inhibitory -v = zeros(n,4); % intrinsic – excitatory -w = zeros(n,4); % extrinsic – excitatory -ig = 2*(1:4); % indices of conductance -iv = ig - 1; % indices of voltage - +u = zeros(n,4); % intrinsic – inhibitory +v = zeros(n,4); % intrinsic – excitatory +w = zeros(n,4); % extrinsic – excitatory % Granular layer (excitatory interneurons): spiny stellate: Hidden causes %-------------------------------------------------------------------------- @@ -181,7 +180,7 @@ w(:,4) = A{2}*S(:,2); -if nargin > 4; f = -u; J = v; Q = w; return, end +if nargin > 4; f = u; J = v; Q = w; return, end % Conductance and voltage %========================================================================== diff --git a/toolbox/dcm_meeg/spm_fx_gen.m b/toolbox/dcm_meeg/spm_fx_gen.m index 2efc9a66..2ecc52b1 100644 --- a/toolbox/dcm_meeg/spm_fx_gen.m +++ b/toolbox/dcm_meeg/spm_fx_gen.m @@ -40,7 +40,7 @@ % Copyright (C) 2005 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_fx_gen.m 6727 2016-02-20 18:06:47Z karl $ +% $Id: spm_fx_gen.m 6971 2016-12-14 18:49:19Z bernadette $ % model-specific parameters @@ -50,6 +50,8 @@ %-------------------------------------------------------------------------- fx{1} = @spm_fx_erp; % ERP model fx{2} = @spm_fx_cmc; % CMC model +fx{3} = @spm_fx_bgc; % basal ganglia circuit +fx{4} = @spm_fx_mmc; % motor micro circuit % indices of extrinsically coupled hidden states %-------------------------------------------------------------------------- @@ -59,17 +61,32 @@ efferent(2,:) = [3 3 7 7]; % sources of CMC connections afferent(2,:) = [2 8 4 6]; % targets of CMC connections +efferent(3,:) = [9 9 9 9]; % sources of BGC connections (thalamus) +afferent(3,:) = [2 6 2 6]; % targets of BGC connections (striatum & STN) + +efferent(4,:) = [3 3 7 7]; % sources of MMC connections +afferent(4,:) = [2 4 8 0]; % targets of MMC connections + + % scaling of afferent extrinsic connectivity (Hz) %-------------------------------------------------------------------------- -E(1,:) = [64 2 32 8]*1000; % ERP connections -E(2,:) = [64 4 64 8]*1000; % CMC connections +E(1,:) = [1 0 1 0]*200; % ERP connections +E(2,:) = [1 .3571 1 .625]*100000; % CMC connections (to ctx) with T = [2 2 16 28] gives [200 100 200 100] = regular DCM +E(3,:) = [1.8 1.2 1.8 1.2]*100000; % BGC connections (to bgc) with T_str=8 and T_stn=4 gives A = 144 and 48 +E(4,:) = [.9 .9 .11 0]*100000; % MMC connections (to mmc) with T_mp=3 and T_sp=2 gives A = 270 and 180; with T_dp=18 gives A=200 + +if isfield(M,'ERP_E'); E(1,:)= M.ERP_E; end +if isfield(M,'CMC_E'); E(2,:)= M.CMC_E; end +if isfield(M,'BGC_E'); E(3,:)= M.BGC_E; end +if isfield(M,'MMC_E'); E(4,:)= M.MMC_E; end % intrinsic delays log(ms) %-------------------------------------------------------------------------- D(1) = 2; % ERP connections D(2) = 1; % CMC connections - - +D(3) = 4; % BGC connections +D(4) = 1; % MMC connections + % get model specific operators %========================================================================== if isvector(x) @@ -81,10 +98,14 @@ n = numel(x); model = M.dipfit.model; for i = 1:n - if strcmp(model(i).source,'ERP') + if strcmp(model(i).source,'ERP') nmm(i) = 1; elseif strcmp(model(i).source,'CMC') nmm(i) = 2; + elseif strcmp(model(i).source,'BGC') + nmm(i) = 3; + elseif strcmp(model(i).source,'MMC') + nmm(i) = 4; end end @@ -121,7 +142,6 @@ end end - % assemble flow %========================================================================== N = M; @@ -223,9 +243,7 @@ for i = 1:n P.D(i,i) = P.D(i,i) + log(D(nmm(i))); end -Q = spm_dcm_delay(P,M,J,0); -return % N-th order Taylor approximation to delay %-------------------------------------------------------------------------- diff --git a/toolbox/dcm_meeg/spm_fx_mmc.m b/toolbox/dcm_meeg/spm_fx_mmc.m new file mode 100644 index 00000000..ac2b4e1c --- /dev/null +++ b/toolbox/dcm_meeg/spm_fx_mmc.m @@ -0,0 +1,249 @@ +function [f,J,Q] = spm_fx_mmc(x,u,P,M) +% state equations for a neural mass model of motor cortex +% Bhatt et al. 2016 Neuroimage +% +% FORMAT [f,J,D] = spm_fx_mmc(x,u,P,M) +% FORMAT [f,J] = spm_fx_mmc(x,u,P,M) +% FORMAT [f] = spm_fx_mmc(x,u,P,M) +% x - state vector +% x(:,1) - voltage (middle pyramidal cells) +% x(:,2) - conductance (middle pyramdidal cells) +% x(:,3) - voltage (superficial pyramidal cells) +% x(:,4) - conductance (superficial pyramidal cells) +% x(:,5) - current (inhibitory interneurons) +% x(:,6) - conductance (inhibitory interneurons) +% x(:,7) - voltage (deep pyramidal cells) +% x(:,8) - conductance (deep pyramidal cells) +% +% f - dx(t)/dt = f(x(t)) +% J - df(t)/dx(t) +% D - delay operator dx(t)/dt = f(x(t - d)) +% = D(d)*f(x(t)) +% +% Prior fixed parameter scaling [Defaults] +% +% E = (forward, backward, lateral) extrinsic rates +% G = intrinsic rates +% D = propagation delays (intrinsic, extrinsic) +% T = synaptic time constants +% S = slope of sigmoid activation function +% +%__________________________________________________________________________ +% Copyright (C) 2016 Wellcome Trust Centre for Neuroimaging + +% Bernadette van Wijk +% $Id: spm_fx_mmc.m 7185 2017-10-11 10:10:04Z spm $ + + +% get dimensions and configure state variables +%-------------------------------------------------------------------------- +x = spm_unvec(x,M.x); % neuronal states +n = size(x,1); % number of sources + + +% [default] fixed parameters +%-------------------------------------------------------------------------- +G = [2 4 2 2 2 2 2 2 2 2 4 2 2 2]*200; % intrinsic connections +T = [3 2 12 18]; % synaptic time constants [mp sp ii dp] + +if isfield(M,'MMC_G'); G = M.MMC_G; end +if isfield(M,'MMC_T'); T = M.MMC_T; end + + +% [specified] fixed parameters +%-------------------------------------------------------------------------- +if isfield(M,'pF') + try, E = M.pF.E; end + try, G = M.pF.G; end + try, T = M.pF.T; end + try, R = M.pF.R; end +end + + +% Extrinsic connections +%-------------------------------------------------------------------------- +% mp = middle pyramidal +% sp = superficial pyramidal +% dp = deep pyramidal +% ii = inhibitory interneurons +%-------------------------------------------------------------------------- +if n > 1 + E = [1 1/2 1 1/2]*200; % extrinsic (forward and backward) + A{1} = exp(P.A{1})*E(1); % forward connections (sp -> mp) + A{2} = exp(P.A{2})*E(2); % forward connections (sp -> sp) + A{3} = exp(P.A{3})*E(3); % backward connections (dp -> dp) + +else + A = {0,0,0,0}; +end + +% detect and reduce the strength of reciprocal (lateral) connections +%-------------------------------------------------------------------------- +for i = 1:length(A) + L = (A{i} > exp(-8)) & (A{i}' > exp(-8)); + A{i} = A{i}./(1 + 4*L); +end + +% input connections +%-------------------------------------------------------------------------- +C = exp(P.C); + +% pre-synaptic inputs: s(V) +%-------------------------------------------------------------------------- +R = 2/3; % slope of sigmoid activation function +B = 0; % bias or background (sigmoid) +R = R.*exp(P.S); % gain of activation function +F = 1./(1 + exp(-R*x + B)); % firing rate +S = F - 1/(1 + exp(B)); % deviation from baseline firing + +% input +%========================================================================== +if isfield(M,'u') + + % endogenous input + %---------------------------------------------------------------------- + U = u(:)*1536; + +else + % exogenous input + %---------------------------------------------------------------------- + U = C*u(:)*32; + +end + + +% time constants and intrinsic connections +%========================================================================== +T = ones(n,1)*T/1000; +G = ones(n,1)*G; + +% extrinsic connections +%-------------------------------------------------------------------------- +% forward (i) 2 sp -> mp (+ve) +% forward (ii) 1 sp -> dp (+ve) +% backward (i) 2 dp -> sp (-ve) +% backward (ii) 1 dp -> ii (-ve) +%-------------------------------------------------------------------------- +% free parameters on time constants and intrinsic connections +%-------------------------------------------------------------------------- +% G(:,1) mp -> mp (-ve self) 4 +% G(:,2) mp -> sp (+ve rec ) 4 +% G(:,3) ii -> mp (-ve rec ) 4 +% G(:,4) ii -> ii (-ve self) 4 +% G(:,5) mp -> ii (+ve rec ) 4 +% G(:,6) dp -> ii (+ve rec ) 2 +% G(:,7) sp -> sp (-ve self) 4 +% G(:,8) sp -> mp (+ve rec ) 4 +% G(:,9) ii -> dp (-ve rec ) 2 +% G(:,10) dp -> dp (-ve self) 1 +% G(:,11) sp -> dp (+ve rec) 2 +% G(:,12) ii -> sp (-ve rec) 4 +% G(:,13) sp -> ii (+ve rec) 4 +% G(:,14) dp -> sp (+ve rec) 2 +%-------------------------------------------------------------------------- +% Neuronal states (deviations from baseline firing) +%-------------------------------------------------------------------------- +% S(:,1) - voltage (middle pyramidal cells) +% S(:,2) - conductance (middle pyramidal cells) +% S(:,3) - voltage (superficial pyramidal cells) +% S(:,4) - conductance (superficial pyramidal cells) +% S(:,5) - current (inhibitory interneurons) +% S(:,6) - conductance (inhibitory interneurons) +% S(:,7) - voltage (deep pyramidal cells) +% S(:,8) - conductance (deep pyramidal cells) +%-------------------------------------------------------------------------- +j = [1 2 3 4]; +for i = 1:size(P.T,2) + T(:,j(i)) = T(:,j(i)).*exp(P.T(:,i)); +end + +j = 1:14; +for i = 1:size(P.G,2) + G(:,j(i)) = G(:,j(i)).*exp(P.G(:,i)); +end + +% Modulatory effects of dp depolarisation on intrinsic connection j(1) +%-------------------------------------------------------------------------- +if isfield(P,'M') + G(:,j(1)) = G(:,j(1)).*exp(-P.M*32*S(:,7)); +end + + +% Motion of states: f(x) +%-------------------------------------------------------------------------- + +% Conductance +%========================================================================== + +% Middle layer (middle pyramidal cells): Hidden causes +%-------------------------------------------------------------------------- +u = A{1}*S(:,3)+ U; +u = - G(:,1).*S(:,1) - G(:,3).*S(:,5) + G(:,8).*S(:,3) + u; +f(:,2) = (u - 2*x(:,2) - x(:,1)./T(:,1))./T(:,1); + +% Supra-granular layer (superficial pyramidal cells): Hidden causes - error +%-------------------------------------------------------------------------- +u = A{2}*S(:,3);% + U; +u = - G(:,7).*S(:,3) + G(:,2).*S(:,1) - G(:,12).*S(:,5) + G(:,14).*S(:,7) + u; +f(:,4) = (u - 2*x(:,4) - x(:,3)./T(:,2))./T(:,2); + +% Supra-granular layer (inhibitory interneurons): Hidden states - error +%-------------------------------------------------------------------------- +u = 0; %- A{4}*S(:,7); +u = - G(:,4).*S(:,5) + G(:,5).*S(:,1) + G(:,6).*S(:,7) + G(:,13).*S(:,3) + u; +f(:,6) = (u - 2*x(:,6) - x(:,5)./T(:,3))./T(:,3); + +% Infra-granular layer (deep pyramidal cells): Hidden states +%-------------------------------------------------------------------------- +u = A{3}*S(:,7);% + U; +u = - G(:,10).*S(:,7) - G(:,9).*S(:,5) + G(:,11).*S(:,3) + u; +f(:,8) = (u - 2*x(:,8) - x(:,7)./T(:,4))./T(:,4); + +% Voltage +%========================================================================== +f(:,1) = x(:,2); +f(:,3) = x(:,4); +f(:,5) = x(:,6); +f(:,7) = x(:,8); +f = spm_vec(f); + + + +if nargout < 2; return, end + +% Jacobian +%========================================================================== +if isfield(M,'x'), x = spm_vec(M.x); else, x = sparse(M.n,1); end +if isfield(M,'u'), u = spm_vec(M.u); else, u = sparse(M.m,1); end +J = spm_diff(M.f,x,u,P,M,1); + + +if nargout < 3; return, end + + +% delays +%========================================================================== +% Delay differential equations can be integrated efficiently (but +% approximately) by absorbing the delay operator into the Jacobian +% +% dx(t)/dt = f(x(t - d)) +% = Q(d)f(x(t)) +% +% J(d) = Q(d)df/dx +%-------------------------------------------------------------------------- +% Implement: dx(t)/dt = f(x(t - d)) = inv(1 + D.*dfdx)*f(x(t)) +% = Q*f = Q*J*x(t) +%-------------------------------------------------------------------------- +Q = spm_dcm_delay(P,M,J); + + +return + +% notes and alpha function (kernels) +%========================================================================== +% x = t*exp(k*t) +% x' = exp(k*t) + k*t*exp(k*t) +% = exp(k*t) + k*x +% x'' = 2*k*exp(k*t) + k^2*t*exp(k*t) +% = 2*k*(x' - k*x) + k^2*x +% = 2*k*x' - k^2*x diff --git a/toolbox/dcm_meeg/spm_int_U.m b/toolbox/dcm_meeg/spm_int_U.m index 03a84be0..35ff236b 100644 --- a/toolbox/dcm_meeg/spm_int_U.m +++ b/toolbox/dcm_meeg/spm_int_U.m @@ -64,7 +64,7 @@ % Copyright (C) 2005 Wellcome Trust Centre for Neuroimaging % Karl Friston -% $Id: spm_int_U.m 6855 2016-08-06 10:06:35Z karl $ +% $Id: spm_int_U.m 7148 2017-08-04 15:27:29Z karl $ % convert U to U.u if necessary %-------------------------------------------------------------------------- @@ -108,7 +108,7 @@ % check for delay operator %-------------------------------------------------------------------------- try - [fx dfdx D] = f(x,u,P,M); + [fx,dfdx,D] = f(x,u,P,M); catch D = 1; end @@ -128,7 +128,7 @@ %---------------------------------------------------------------------- if i == 1 || du*du' > 1e-6 try - [fx dfdx] = feval(f,x,u,P,M); + [fx,dfdx] = feval(f,x,u,P,M); catch dfdx = spm_diff(f,x,u,P,M,1); end diff --git a/toolbox/dcm_meeg/spm_mmc_priors.m b/toolbox/dcm_meeg/spm_mmc_priors.m new file mode 100644 index 00000000..00c04c1b --- /dev/null +++ b/toolbox/dcm_meeg/spm_mmc_priors.m @@ -0,0 +1,137 @@ +function [E,V] = spm_mmc_priors(A,B,C) +% prior moments for a canonical motor cortex microcircuit model +% FORMAT [E,V] = spm_mmc_priors(A,B,C) +% +% A{3},B{m},C - binary constraints on extrinsic connections +% +% pE - prior expectation - f(x,u,P,M) +% +% synaptic parameters +%-------------------------------------------------------------------------- +% pE.T - syaptic time constants +% pE.S - activation function parameters +% pE.G - intrinsic connection strengths +% +% connectivity parameters +%-------------------------------------------------------------------------- +% pE.A - extrinsic +% pE.B - trial-dependent (driving) +% pE.N - trial-dependent (modulatory) +% pE.C - stimulus input +% pE.D - delays +% +% stimulus and noise parameters +%-------------------------------------------------------------------------- +% pE.R - onset and dispersion +% +% pC - prior (co)variances +% +% Because priors are specified under log normal assumptions, most +% parameters are simply scaling coefficients with a prior expectation +% and variance of one. After log transform this renders pE = 0 and +% pC = 1; The prior expectations of what they scale are specified in +% spm_fx_mmc +%__________________________________________________________________________ +% Copyright (C) 2016 Wellcome Trust Centre for Neuroimaging + +% Bernadette van Wijk +% $Id$ + + +% default: a single source model +%-------------------------------------------------------------------------- +if nargin < 3 + A = {0 0 0}; + B = {}; + C = 1; +end + +% disable log zero warning +%-------------------------------------------------------------------------- +warning('off','MATLAB:log:logOfZero'); +n = size(C,1); % number of sources +u = size(C,2); % number of inputs + +% parameters for neural-mass forward model +%========================================================================== + +% restructure adjacency matrices +%-------------------------------------------------------------------------- +D{1} = A{1}; % forward (i) +D{2} = A{1}; % forward (ii) +D{3} = A{2}; % backward (i) +D{4} = A{2}; % backward (ii) + +% modulatory extrinsic connectivity +%-------------------------------------------------------------------------- +E.M = 0*A{3}; +V.M = ~~A{3}/32; +A = D; + +% extrinsic connectivity +%-------------------------------------------------------------------------- +Q = sparse(n,n); +for i = 1:length(A) + A{i} = ~~A{i}; + E.A{i} = A{i}*32 - 32; + V.A{i} = A{i}/16; + Q = Q | A{i}; +end + +% allow intrinsic delays +%-------------------------------------------------------------------------- +Q = Q | speye(n,n); + +% driving connectivity - input-dependent scaling +%-------------------------------------------------------------------------- +for i = 1:length(B) + B{i} = ~~B{i}; + E.B{i} = 0*B{i}; + V.B{i} = (B{i} & Q & ~V.M)/8; +end + +% modulatory connectivity - input-dependent scaling +%-------------------------------------------------------------------------- +for i = 1:length(B) + E.N{i} = 0*B{i}; + V.N{i} = (B{i} & Q & V.M)/8; +end + +% exogenous connectivity - where inputs enter +%-------------------------------------------------------------------------- +C = ~~C; +E.C = C*32 - 32; +V.C = C/32; + +% synaptic parameters +%-------------------------------------------------------------------------- +m = 14; % number of free intrinsic connections +E.T = sparse(1,4); V.T = sparse(1,4) + 1/8; % time constants +E.G = sparse(n,m); V.G = sparse(n,m) + 1/4; % intrinsic connectivity +E.D = sparse(n,n); V.D = Q/64; % delay +E.S = 0; V.S = 1/32; % slope of sigmoid + +% set stimulus parameters: onset and dispersion +%-------------------------------------------------------------------------- +E.R = sparse(u,2); V.R = ones(u,1)*[1/16 1/16]; +warning('on','MATLAB:log:logOfZero'); + +return + + + +% demo for log-normal pdf +%========================================================================== +x = (1:64)/16; +for i = [2 16 32 128] + v = 1/i; + p = 1./x.*exp(-log(x).^2/(2*v))/sqrt(2*pi*v); + plot(x,p) + text(x(16),p(16),sprintf('variance = 1/%i',1/v)) + hold on +end +xlabel('scaling') +ylabel('density') +grid on +hold off +axis square

  • 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 HiZn`=EKdfC%qObL!XEa+n~jJWE&-u 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 z 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 z )|mf2@|tGQZE}uYEGlX}EqhZ%obC0b1A+ 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

    Z&u1OV=CegC4V|%~2+fo< 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�_4qjz_$O=0!f>7cd`+lha&& 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 delta 14341 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 diff --git a/spm_render_vol.mexw64 b/spm_render_vol.mexw64 index b2a6c8c9c24d415fbe0e48ed58d9e10d7e196825..f991b10dc659d4b1595b2cfde5ff404aa486bde2 100755 GIT binary patch delta 43 wcmZqp!P)SGbHWQ2rDsngC%*Av%9d=lVr;i!WZZ7W$h0dNEWZ6m3KNGo0GWLeBme*a delta 43 wcmZqp!P)SGbHWQ2ZRXFR6W{nSP4{lLVr;i!WZZ7W$h0dNEWZ6m3KNGo0D!#@;s5{u diff --git a/spm_resels_vol.mexmaci64 b/spm_resels_vol.mexmaci64 index bd5152cd4fb7f8613c71a54a1c0cf6a890d5a0e4..a26df15480ffd05842abf7743bc8b0ad724554af 100755 GIT binary patch literal 185956 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 delta 40 tcmZp8z}E19ZNdW1e-7), error('Can''t decompose matrix'); end +if any(abs(svd(A0)-1)>1e-7), error('Cannot decompose matrix.'); end t = A0(2,3); if t==0, t=eps; end a0 = pinv(A0([1 2],[2 3])')*[(A0(3,2)-(A0(2,2)-1)/t) (A0(3,3)-1)]'; diff --git a/spm_results_nidm.m b/spm_results_nidm.m index 4578c78a..9c46a7f8 100644 --- a/spm_results_nidm.m +++ b/spm_results_nidm.m @@ -20,10 +20,10 @@ % PROV-DM: The PROV Data Model: % http://www.w3.org/TR/prov-dm/ %__________________________________________________________________________ -% Copyright (C) 2013-2016 Wellcome Trust Centre for Neuroimaging +% Copyright (C) 2013-2017 Wellcome Trust Centre for Neuroimaging % Guillaume Flandin -% $Id: spm_results_nidm.m 6903 2016-10-12 11:36:41Z guillaume $ +% $Id: spm_results_nidm.m 7057 2017-04-13 16:45:49Z guillaume $ %-Get input parameters, interactively if needed @@ -62,7 +62,7 @@ %-------------------------------------------------------------------------- gz = '.gz'; %-Compressed NIfTI {'.gz', ''} NIDMversion = '1.3.0'; -SVNrev = '$Rev: 6903 $'; +SVNrev = '$Rev: 7057 $'; %-Reference space %-------------------------------------------------------------------------- @@ -352,6 +352,7 @@ %-Provenance %-------------------------------------------------------------------------- [V,R] = spm('Ver'); +V = V(4:end); idResults = getid('niiri:spm_results_id',isHumanReadable); pp.entity(idResults,{... @@ -366,7 +367,7 @@ 'prov:type',nidm_conv('nidm_spm_results_nidm',pp),... 'prov:type','prov:SoftwareAgent',... 'prov:label',{'spm_results_nidm','xsd:string'},... - nidm_conv('nidm_softwareVersion',pp),{[V(4:end) '.' char(regexp(SVNrev,'\$Rev: (\w.*?) \$','tokens','once'))],'xsd:string'},... + nidm_conv('nidm_softwareVersion',pp),{[V '.' char(regexp(SVNrev,'\$Rev: (\w.*?) \$','tokens','once'))],'xsd:string'},... }); idExport = getid('niiri:export_id',isHumanReadable); @@ -389,7 +390,7 @@ 'prov:type',nidm_conv('src_SPM',p),... 'prov:type','prov:SoftwareAgent',... 'prov:label',{'SPM','xsd:string'},... - nidm_conv('nidm_softwareVersion',p),{[V(4:end) '.' R],'xsd:string'},... + nidm_conv('nidm_softwareVersion',p),{[V '.' R],'xsd:string'},... }); %-Entity: Coordinate Space @@ -797,50 +798,44 @@ %-Entity: Height Threshold %-------------------------------------------------------------------------- thresh(1).type = nidm_conv('obo_statistic',p); -thresh(1).label = 'Height Threshold'; thresh(1).value = xSPM.u; % TabDat.ftr{1,2}(1) +thresh(1).label = sprintf('Height Threshold: %s=%f)',xSPM.STAT,thresh(1).value); thresh(2).type = nidm_conv('nidm_PValueUncorrected',p); -thresh(2).label = 'Height Threshold'; thresh(2).value = TabDat.ftr{1,2}(2); +thresh(2).label = sprintf('Height Threshold: p<%f (unc.)',thresh(2).value); thresh(3).type = nidm_conv('obo_FWERadjustedpvalue',p); -thresh(3).label = 'Height Threshold'; thresh(3).value = TabDat.ftr{1,2}(3); +thresh(3).label = sprintf('Height Threshold: p<%f (FWE)',thresh(3).value); td = regexp(xSPM.thresDesc,'p\D?(?[\.\d]+) \((?\S+)\)','names'); if isempty(td) td = regexp(xSPM.thresDesc,'\w=(?[\.\d]+)','names'); if ~isempty(td) - thresh_order = 1:3; % Statistic - thresh_desc = sprintf(': %s=%f)',xSPM.STAT,xSPM.u); + thresh_order = 1:3; % Statistic else warning('Unkwnown threshold type.'); - thresh_order = 1:3; % unknown - thresh_desc = ''; + thresh_order = 1:3; % unknown end else switch td.thresDesc case 'FWE' - thresh_order = [3 1 2]; % FWE - thresh_desc = sprintf(': p<%f (FWE)',TabDat.ftr{1,2}(3)); + thresh_order = [3 1 2]; % FWE case 'unc.' - thresh_order = [2 1 3]; % uncorrected - thresh_desc = sprintf(': p<%f (unc.)',TabDat.ftr{1,2}(2)); + thresh_order = [2 1 3]; % uncorrected % Set uncorrected p-value threshold to the user-defined value % (to avoid possible floating point approximations) %thresh(2).value = str2double(td.u); + thresh(2).label = sprintf('Height Threshold: p<%s (unc.)',td.u); case 'FDR' thresh(3).type = nidm_conv('obo_qvalue',p); - thresh(3).label = 'Height Threshold'; thresh(3).value = str2double(td.u); - thresh_order = [3 1 2]; % FDR - thresh_desc = sprintf(': p<%s (FDR)',td.u); + thresh(3).label = sprintf(':Height Threshold: p<%s (FDR)',td.u); + thresh_order = [3 1 2]; % FDR otherwise warning('Unkwnown threshold type.'); thresh_order = 1:3; % unknown - thresh_desc = ''; end end thresh = thresh(thresh_order); -thresh(1).label = [thresh(1).label thresh_desc]; idHeightThresh = getid('niiri:height_threshold_id',isHumanReadable); idHeightThresh2 = getid('niiri:height_threshold_id_2',isHumanReadable); idHeightThresh3 = getid('niiri:height_threshold_id_3',isHumanReadable); @@ -1151,14 +1146,14 @@ %========================================================================== %serialize(pp,fullfile(outdir,'nidm.provn')); serialize(pp,fullfile(outdir,'nidm.ttl')); -try, serialize(pp,fullfile(outdir,'nidm.jsonld')); end -%serialize(pp,fullfile(outdir,'nidm.json')); +serialize(pp,fullfile(outdir,'nidm.jsonld')); +serialize(pp,fullfile(outdir,'nidm.json')); %serialize(pp,fullfile(outdir,'nidm.pdf')); i = 1; while true nidmfile = fullfile(SPM.swd,sprintf('spm_%04d.nidm.zip',i)); - if spm_existfile(nidmfile), i = i + 1; else break; end + if spm_existfile(nidmfile), i = i + 1; else, break; end end f = zip(nidmfile,'*',outdir); for i=1:numel(f) @@ -1200,7 +1195,7 @@ %u = ['file://' s strrep(spm_file(u,'cpath'),'\','/')]; e = ' '; for i=1:length(e) - u = strrep(u,e(i),['%' dec2hex(e(i))]); + u = strrep(u,e(i),['%' dec2hex(double(e(i)))]); end u = spm_file(u,'filename'); @@ -1209,32 +1204,38 @@ % function checksum = sha512sum(file) %========================================================================== function checksum = sha512sum(file) -md = java.security.MessageDigest.getInstance('SHA-512'); -file = spm_file(file,'cpath'); -fid = fopen(file,'rb'); -if fid == -1, error('Cannot open "%s".',file); end -md.update(fread(fid,Inf,'*uint8')); -fclose(fid); -checksum = typecast(md.digest,'uint8'); -checksum = lower(reshape(dec2hex(checksum)',1,[])); - +if strcmp(spm_check_version,'matlab') + md = java.security.MessageDigest.getInstance('SHA-512'); + file = spm_file(file,'cpath'); + fid = fopen(file,'rb'); + if fid == -1, error('Cannot open "%s".',file); end + md.update(fread(fid,Inf,'*uint8')); + fclose(fid); + checksum = typecast(md.digest,'uint8'); + checksum = lower(reshape(dec2hex(checksum)',1,[])); +else + checksum = hash('sha512', fileread(spm_file(file,'cpath'))); +end %========================================================================== % function checksum = md5sum(data) %========================================================================== function checksum = md5sum(data) if ~nargin - data = char(java.util.UUID.randomUUID); + data = char(javaMethod('randomUUID','java.util.UUID')); end -md = java.security.MessageDigest.getInstance('MD5'); -if ischar(data) - md.update(uint8(data)); +if strcmp(spm_check_version,'matlab') + md = java.security.MessageDigest.getInstance('MD5'); + if ischar(data) + md.update(uint8(data)); + else + md.update(typecast(data,'uint8')); + end + checksum = typecast(md.digest,'uint8'); + checksum = lower(reshape(dec2hex(checksum)',1,[])); else - md.update(typecast(data,'uint8')); + checksum = hash('md5', typecast(data,'char')); end -checksum = typecast(md.digest,'uint8'); -checksum = lower(reshape(dec2hex(checksum)',1,[])); - %========================================================================== % function img2nii(img,nii,xSPM) diff --git a/spm_results_ui.m b/spm_results_ui.m index 9a739368..0051bb36 100644 --- a/spm_results_ui.m +++ b/spm_results_ui.m @@ -124,7 +124,7 @@ % Copyright (C) 1996-2013 Wellcome Trust Centre for Neuroimaging % Karl Friston & Andrew Holmes -% $Id: spm_results_ui.m 6647 2015-12-14 19:12:54Z guillaume $ +% $Id: spm_results_ui.m 7204 2017-11-08 17:26:52Z guillaume $ %========================================================================== @@ -236,7 +236,7 @@ % warning statements from MATLAB. %__________________________________________________________________________ -SVNid = '$Rev: 6647 $'; +SVNid = '$Rev: 7204 $'; %-Condition arguments %-------------------------------------------------------------------------- @@ -1138,14 +1138,14 @@ h4 = uicontrol('Parent',hGraphUIButtsF,'Style','popupmenu',... 'ToolTipString','edit axis text annotations',... 'FontSize',FS(10),... - 'String','text|Title|Xlabel|Ylabel',... + 'String',{'text','Title','Xlabel','Ylabel'},... 'Callback','spm_results_ui(''PlotUiCB'')',... 'Interruptible','on','Enable','on',... 'Position',[230 005 070 020].*WS); h5 = uicontrol('Parent',hGraphUIButtsF,'Style','popupmenu',... 'ToolTipString','change various axes attributes',... 'FontSize',FS(10),... - 'String','attrib|LineWidth|XLim|YLim|handle',... + 'String',{'attrib','LineWidth','XLim','YLim','handle'},... 'Callback','spm_results_ui(''PlotUiCB'')',... 'Interruptible','off','Enable','on',... 'Position',[305 005 070 020].*WS); diff --git a/spm_sample_vol.mexmaci64 b/spm_sample_vol.mexmaci64 index b20bea257ffe9938200ba2ad58b7c45b41a0e5bb..3d790df53dc9bf49243632d58f4ec6888a95fead 100755 GIT binary patch literal 181764 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 z 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 QR2kVE8PTLJ=H{#a0K}eYiU0rr literal 203528 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 z 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 PJ?jgjiYHD%1%Cep1zy7J delta 13421 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 Om1e($76&XLeE%2Nc+P$R diff --git a/spm_sample_vol.mexw64 b/spm_sample_vol.mexw64 index 2e9750e09227257ea574998d343b3b7a63e1039f..0f501ea63ba8cee5635b3fdf8a93c7ef5ecf4497 100755 GIT binary patch delta 39 scmZo@;Am*znDBx{^4ZhKiEn(E+Vq;O7`Iz7GVXc?7Tf;gIU|Pz07|(Kk^lez delta 39 scmZo@;Am*znDBx{iTQKr#5X=nn-ZF>7`Iz7GVXc?7Tf;gIU|Pz05ic4Pyhe` diff --git a/spm_slice_vol.mexmaci64 b/spm_slice_vol.mexmaci64 index 5ae28af77d80e316d25ab192b2e30cb9511cd2a0..72735bdfd1bd56888b4a31bcf410e34dd20a7b19 100755 GIT binary patch literal 181764 zcmeEv3w%`7wRZv&No(*-YS6SLn%f(6ponlqB??M(MkhEUv=W`zM64;1wxSe?#(t(^ z(ol}$XxfU6ZPB#VUizS3Pdg2+R8R`UJ-YoBxG%;Z55LAc*% ze!s~%d#}Cs*=L`%*4}%a|5Dc6O!=bk$+>xOd4A{Nu8^7Y@=O~|$F-!AW5$dfH>P;v zcgK%4)3NPk-mhwJH^z@?Z}5{2Mdo-Up&jp=JM^Mt=-;PGCB|y-Uo- za2zw{zVEizzjUL$Ok>=bwztRoy)>r1?|paDccU5c<2U3-#&a-=Fl}!yT2q~k8FSBr zQ7LPAznK$NdqYNQ zy{&H~BupMi63TI`lW~+Z^YAwW>1s65Sl%sR2-0jV9lx5Nc1xIzhI;?5TS5d6_FUwd zmkc4FKbCzONBeU^R?OeN7rG_f5|g76U&n#hsT;R>_wa|W`2Dm?4lQ~0<1uT=Lrxa? z(w7qwzWn8cerB3^_)Ec${byZX-~1asal&^ejl2B5@82`Nbinr>!BJ5)4M~)IO%m6uL{CYarxIVC2mVT6V;ioM#s;vlD?mgkXCy&NNn_5)n+0rH z8goVts015xM(R}}+Sn7Su^o4zv7I2IRC?qeQc4<2k4#ln*t7J=ODe&}(j${pBHGw6 z)z~v^>^TroDml^*C*F!9j!7;_{)d^2Ry#*kdz#hmF{>r9obG8rC1+&kcbHfx=i7O% z&02^yyG@EVQa=pYpR-llA(;n>1g8?q8Q% z^r^RK|DZLI`%p4hcVv0>C6OoOYMwAImmc|{BzWoc$XK4MOD9emB3V8g`KBn@-m^

    (t4$4 VPI}>$#Ke~q+Qyb7e1$t^{|6FtL}vg1 delta 45441 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 BCNuy5 literal 194232 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 z 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 z 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 diff --git a/spm_diffeo.mexw32 b/spm_diffeo.mexw32 index afc21559909c77c599abb046c7afb76d903432aa..9550e0050b8539c0fb6a816b57c2edbf6a49f43a 100755 GIT binary patch delta 26248 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 ibFW481f`#DJ^RXlFRQ9R1 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 XGXT2}mztTH8g4e!rgD;iuMz$aFHP~} diff --git a/external/eeprobe/write_eep_cnt.mexa64 b/external/eeprobe/write_eep_cnt.mexa64 index d8f665d6543e2bc0d9cfd5616b24a06341850955..99aae218b2dfe2557addf91d013e8f2c363dbac4 100755 GIT binary patch literal 162573 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 Mu@Rfp&0*~S08J<>x&QzG literal 151846 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 WOO6k_KK^4%SQ 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. +% +% $Id$ + +% import .mgrid electrode positions +elec_xyz = ft_read_sens(mgridfile, 'senstype', 'eeg'); + +% convert xyz coordinates to ijk coordinates +mri = ft_read_mri(mrifile); +elec_ijk.elecpos(:, 1) = elec_xyz.elecpos(:, 1)/mri.hdr.xsize; +elec_ijk.elecpos(:, 2) = elec_xyz.elecpos(:, 2)/mri.hdr.ysize; +elec_ijk.elecpos(:, 3) = elec_xyz.elecpos(:, 3)/mri.hdr.zsize; + +% adjust for bioimage suite indexing first voxel at [0 0 0] instead of [1 1 1] +elec_ijk.elecpos = elec_ijk.elecpos+1; + +% convert ijk coordinates to mri head coordinates +elec = keepfields(mri, {'unit', 'coordsys'}); +elec.label = elec_xyz.label; +elec.elecpos = ft_warp_apply(mri.transform, elec_ijk.elecpos); + +% ensure that the elec description is up-to-date +elec = ft_datatype_sens(elec); diff --git a/external/fieldtrip/connectivity/ft_connectivity_corr.m b/external/fieldtrip/connectivity/ft_connectivity_corr.m index 03fb5258..2889421c 100644 --- a/external/fieldtrip/connectivity/ft_connectivity_corr.m +++ b/external/fieldtrip/connectivity/ft_connectivity_corr.m @@ -101,7 +101,7 @@ allchanindx = ft_getopt(varargin, 'allchanindx'); if isempty(dimord) - error('input parameters should contain a dimord'); + ft_error('input parameters should contain a dimord'); end siz = [size(input) 1]; @@ -120,7 +120,7 @@ A = zeros(newsiz); % FIXME this only works for data without time dimension - if numel(siz)==5 && siz(5)>1, error('this only works for data without time'); end + if numel(siz)==5 && siz(5)>1, ft_error('this only works for data without time'); end for j = 1:siz(1) %rpt loop AA = reshape(input(j, chan, chan, : ), [nchan nchan siz(4:end)]); AB = reshape(input(j, chan, pchan,: ), [nchan npchan siz(4:end)]); @@ -233,5 +233,5 @@ case '-logabs' c = -log(1 - abs(c).^2); otherwise - error('complex = ''%s'' not supported', str); + ft_error('complex = ''%s'' not supported', str); end diff --git a/external/fieldtrip/connectivity/ft_connectivity_csd2transfer.m b/external/fieldtrip/connectivity/ft_connectivity_csd2transfer.m index 0f26cd7a..82702c76 100644 --- a/external/fieldtrip/connectivity/ft_connectivity_csd2transfer.m +++ b/external/fieldtrip/connectivity/ft_connectivity_csd2transfer.m @@ -21,22 +21,29 @@ % a multiple pairwise factorization is done. % tol = scalar value (default: 1e-18) tolerance limit truncating % the iterations +% sfmethod = 'multivariate', or 'bivariate' +% stabilityfix = false, or true. zigzag-reduction by means of tapering of the +% intermediate time domain representation when computing the +% plusoperator % % The code for the Wilson-Burg algorithm has been very generously provided by -% Dr. Mukesh Dhamala, and Prof. Mingzhou Ding and his group. +% Dr. Mukesh Dhamala, and Prof. Mingzhou Ding and his group, and has been +% adjusted for efficiency. % % If you use this code for studying directed interactions, please cite from % the following references: -% -M.Dhamala, G.Rangarajan, M.Ding, Physical Review Letters 100, 018701 (2008) -% -M.Dhamala, G.rangarajan, M.Ding, Neuroimage 41, 354 (2008) +% -M.Dhamala, R.Rangarajan, M.Ding, Physical Review Letters 100, 018701 (2008) +% -M.Dhamala, R.Rangarajan, M.Ding, Neuroimage 41, 354 (2008) % Undocumented options: % % block % blockindx % svd +% conditional +% init % -% Copyright (C) 2009-2011, Jan-Mathijs Schoffelen +% Copyright (C) 2009-2017, Jan-Mathijs Schoffelen % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -56,19 +63,21 @@ % % $Id$ +sfmethod = ft_getopt(varargin, 'sfmethod', 'multivariate'); numiteration = ft_getopt(varargin, 'numiteration', 100); +fb = ft_getopt(varargin, 'feedback', 'none'); +checkconvergence = ft_getopt(varargin, 'checkconvergence', true); +init = ft_getopt(varargin, 'init', 'chol'); + channelcmb = ft_getopt(varargin, 'channelcmb', {}); +channeltriplet = ft_getopt(varargin, 'channeltriplet', {}); block = ft_getopt(varargin, 'block', []); tol = ft_getopt(varargin, 'tol', 1e-18); -fb = ft_getopt(varargin, 'feedback', 'textbar'); -sfmethod = ft_getopt(varargin, 'sfmethod', 'multivariate'); -dosvd = ft_getopt(varargin, 'svd', 'no'); -doconditional = ft_getopt(varargin, 'conditional', 0); -init = ft_getopt(varargin, 'init', 'chol'); -checkconvergence = ft_getopt(varargin, 'checkconvergence', true); -dosvd = istrue(dosvd); -doconditional = istrue(doconditional); +dosvd = istrue(ft_getopt(varargin, 'svd', 'no')); +doconditional = istrue(ft_getopt(varargin, 'conditional', 0)); +stabilityfix = istrue(ft_getopt(varargin, 'stabilityfix', false)); + doblock = isstruct(block) || doconditional; if doconditional && isempty(block) @@ -80,10 +89,11 @@ end end -% check whether input data is valid +% check whether input data is valid, it should contain crsspctrm with label +% (so no linearly indexed labelcmb) freq = ft_checkdata(freq, 'datatype', 'freq'); if ~isfield(freq, 'crsspctrm') || ~isfield(freq, 'label') - error('the input data does not contain cross-spectral density data in the supported format'); + ft_error('the input data does not contain cross-spectral density data in the supported format'); end hasrpt = ~isempty(strfind(freq.dimord, 'rpt')); @@ -93,33 +103,101 @@ nrpt = 1; end -if ~isempty(channelcmb) && ~(strcmp(channelcmb{1}, 'all') && strcmp(channelcmb{2}, 'all')) && ~strcmp(sfmethod, 'bivariate') +if ~isempty(channelcmb) && ~(strcmp(channelcmb{1}, 'all') && strcmp(channelcmb{2}, 'all')) && strcmp(sfmethod, 'bivariate') % enforce sfmethod to be bivariate sfmethod = 'bivariate'; end -% if bivariate is requested without channelcmb, do all versus all pairwise -if isempty(channelcmb) && strcmp(sfmethod, 'bivariate') - channelcmb = {'all' 'all'}; -end +if strcmp(sfmethod, 'bivariate') + % this method allows the {'all' 'all'} channelcmb + if isempty(channelcmb) + channelcmb = {'all' 'all'}; + end +elseif strcmp(sfmethod, 'trivariate') + % this method requires an explicit definition of the triplets (an {'all' + % 'all' 'all'} scenario might become computationally heavy quite rapidly + if isempty(channeltriplet) + ft_error('triplet wise factorization requires an explicit specification of the triplets'); + end + + % create an Ntriplet x 3 index matrix, to be used below + [~,i2] = match_str(channeltriplet(:,1),freq.label); + cmbindx(:,1) = i2; + [~,i2] = match_str(channeltriplet(:,2),freq.label); + cmbindx(:,2) = i2; + [~,i2] = match_str(channeltriplet(:,3),freq.label); + cmbindx(:,3) = i2; +elseif strcmp(sfmethod, 'bivariate_conditional') + % this method requires a non-empty channelcmb {Nx2} with a corresponding + % channelcnd{Nx1}. The elements in channelcnd can be cell-arrays + if isempty(channelcmb) || size(channelcmb,2) ~= 3 + error('a decomposition that aims at bivariate granger, conditioned on a third channel, requires a channelcmb consisting of 3 columns'); + end + + % this method requires a channeltriplet + channeltriplet = cell(0,3); + + % ensure channelcnd to be a cell array of cell arrays + for k = 1:size(channelcmb,1) + if ~iscell(channelcmb{k,3}) + channelcmb{k,3} = {channelcmb{k,3}}; + end + end + + for k = 1:size(channelcmb,1) + for m = 1:numel(channelcmb{k,3}) + channeltriplet(end+1,1:2) = channelcmb(k,1:2); + channeltriplet{end, 3} = channelcmb{k, 3}{m}; + end + end + + % remove double occurrences, unique does not work for cell arrays with + % the argument 'rows' + tmp = channeltriplet; + utmp = unique(tmp(:)); + ok = true(size(tmp,1),1); + tmpindx = zeros(size(tmp)); + for k = 1:size(tmpindx,1) + [~, tmpindx(k,:)] = match_str(tmp(k,:)', utmp); + tmptmpindx = tmpindx(k,:); + tmptmpindx = tmptmpindx([1 2 3;1 3 2;2 1 3;2 3 1;3 1 2;3 2 1]); + if ~isempty(intersect(tmpindx(1:(k-1),:), tmptmpindx, 'rows')) + ok(k) = false; + elseif tmpindx(k,1)==tmpindx(k,2) + ok(k) = false; + end + end + channeltriplet = channeltriplet(ok,:); +% +% tmp = cell(0,3); +% while ~isempty(channeltriplet) +% tmp = cat(1, tmp, channeltriplet(end,:)); +% channeltriplet(strcmp(channeltriplet(:,1),channeltriplet{end,1})&... +% strcmp(channeltriplet(:,2),channeltriplet{end,2})&... +% strcmp(channeltriplet(:,3),channeltriplet{end,3}),:) = []; +% end +% channeltriplet = tmp; +% +end -if ~isempty(channelcmb) +if ~isempty(channelcmb) && numel(freq.label)>1 && strncmp(sfmethod, 'bivariate', 9) if numel(channelcmb)==2 && strcmp(channelcmb{1},'all') && strcmp(channelcmb{2}, 'all') + % create an Npair x 2 indexing matrix, to be used below [cmbindx(:,1), cmbindx(:,2)] = find(tril(ones(numel(freq.label)),-1)); ok = true(size(cmbindx,1),1); end - channelcmb = ft_channelcombination(channelcmb, freq.label); + channelcmb = ft_channelcombination(channelcmb(:,1:2), freq.label); end if ~isempty(block) % sanity check 1 if ~isstruct(block) - error('block should be a struct-array'); + ft_error('block should be a struct-array'); end % sanity check 2 if strcmp(sfmethod, 'bivariate') - error('when block is specified, it is not OK to do bivariate decomposition'); + ft_error('when block is specified, it is not OK to do bivariate decomposition'); end end @@ -140,10 +218,14 @@ ix = 1:min(siz1,siz2); npair = sum(sum(list1(:,ix)~=list2(:,ix),2)~=0); fprintf('computing pairwise non-parametric spectral factorization on %d channel pairs\n', npair);%size(channelcmb,1) - numel(unique(channelcmb(:)))); +elseif strcmp(sfmethod, 'bivariate_conditional') + % no text elseif strcmp(sfmethod, 'multivariate') fprintf('computing multivariate non-parametric spectral factorization on %d channels\n', numel(freq.label)); +elseif strcmp(sfmethod, 'trivariate') + fprintf('computing tripletwise non-parametric spectral factorization\n'); else - error('unknown sfmethod %s', sfmethod); + ft_error('unknown sfmethod %s', sfmethod); end @@ -179,7 +261,7 @@ Stmp = nan; else [Htmp, Ztmp, Stmp] = sfactorization_wilson(tmp, freq.freq, ... - numiteration, tol, fb, init); + numiteration, tol, fb, init, checkconvergence, stabilityfix); end % undo SVD @@ -202,7 +284,7 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% if ntim>1, - error('blockwise factorization of tfrs is not yet possible'); + ft_error('blockwise factorization of tfrs is not yet possible'); end % create a blockindx array that assigns each channel to a block @@ -231,7 +313,7 @@ nfact = size(tmp1,1)+size(tmp2,1)+1; maxnfact = 500; if nfact>maxnfact - error('at present the number of factorizations for conditional granger is set to 500'); + ft_error('at present the number of factorizations for conditional granger is set to 500'); end factorizations = cell(nfact,1); @@ -273,7 +355,7 @@ end [Htmp, Ztmp, Stmp] = sfactorization_wilson(Stmp, freq.freq, ... - numiteration, tol, fb, init); + numiteration, tol, fb, init, checkconvergence, stabilityfix); % undo PCA if dopca @@ -330,16 +412,16 @@ for m = 1:ntim tmp = reshape(freq.crsspctrm(k,:,:,:,m), siz(2:end-1)); [Htmp, Ztmp, Stmp] = sfactorization_wilson(tmp, freq.freq, ... - numiteration, tol, fb, init); + numiteration, tol, fb, init, checkconvergence, stabilityfix); H(k,:,:,:,m) = Htmp; Z(k,:,:,m) = Ztmp; S(k,:,:,:,m) = Stmp; end end -elseif strcmp(sfmethod, 'multivariate') && nrpt>1 && doblock && ~doconditional, +elseif strcmp(sfmethod, 'multivariate') && nrpt>1 && doblock && ~doconditional % error - error('single trial estimates and blockwise factorisation is not yet implemented'); + ft_error('single trial estimates and blockwise factorisation is not yet implemented'); elseif strcmp(sfmethod, 'bivariate') %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -351,7 +433,7 @@ cmbindx = zeros(size(channelcmb)); ok = true(size(cmbindx,1), 1); for k = 1:size(cmbindx,1) - [tmp, cmbindx(k,:)] = match_str(channelcmb(k,:)', freq.label); + [~, cmbindx(k,:)] = match_str(channelcmb(k,:)', freq.label); if ~isempty(intersect(cmbindx(1:(k-1),:), cmbindx(k,:), 'rows')) ok(k) = false; elseif cmbindx(k,1)==cmbindx(k,2) @@ -368,7 +450,7 @@ if ntim>1, for kk = 1:ntim [Htmp, Ztmp, Stmp] = sfactorization_wilson2x2(freq.crsspctrm(:,:,:,kk), ... - freq.freq, numiteration, tol, cmbindx, fb, init, checkconvergence); + freq.freq, numiteration, tol, cmbindx, fb, init, checkconvergence, stabilityfix); if kk==1, H = Htmp; Z = Ztmp; @@ -395,7 +477,7 @@ for k = 1:numel(begchunk) fprintf('computing factorization of chunck %d/%d\n', k, numel(begchunk)); [Htmp, Ztmp, Stmp] = sfactorization_wilson2x2(freq.crsspctrm, freq.freq, ... - numiteration, tol, cmbindx(begchunk(k):endchunk(k),:), fb, init, checkconvergence); + numiteration, tol, cmbindx(begchunk(k):endchunk(k),:), fb, init, checkconvergence, stabilityfix); begix = (k-1)*nperchunk*4+1; endix = min(k*nperchunk*4, size(cmbindx,1)*4); @@ -406,55 +488,168 @@ end else [H, Z, S] = sfactorization_wilson2x2(freq.crsspctrm, freq.freq, ... - numiteration, tol, cmbindx, fb, init, checkconvergence); + numiteration, tol, cmbindx, fb, init, checkconvergence, stabilityfix); end end labelcmb = cell(size(cmbindx,1)*4, 2); for k = 1:size(cmbindx,1) - indx = (k-1)*4 + (1:4); - labelcmb{indx(1),1} = [channelcmb{k,1},'[',channelcmb{k,1},channelcmb{k,2},']']; - labelcmb{indx(1),2} = [channelcmb{k,1},'[',channelcmb{k,1},channelcmb{k,2},']']; - labelcmb{indx(2),1} = [channelcmb{k,2},'[',channelcmb{k,1},channelcmb{k,2},']']; - labelcmb{indx(2),2} = [channelcmb{k,1},'[',channelcmb{k,1},channelcmb{k,2},']']; - labelcmb{indx(3),1} = [channelcmb{k,1},'[',channelcmb{k,1},channelcmb{k,2},']']; - labelcmb{indx(3),2} = [channelcmb{k,2},'[',channelcmb{k,1},channelcmb{k,2},']']; - labelcmb{indx(4),1} = [channelcmb{k,2},'[',channelcmb{k,1},channelcmb{k,2},']']; - labelcmb{indx(4),2} = [channelcmb{k,2},'[',channelcmb{k,1},channelcmb{k,2},']']; + duplet = strcat(channelcmb{k,:}); + indx = (k-1)*4 + (1:4); + labelcmb{indx(1),1} = [channelcmb{k,1},'[',duplet,']']; + labelcmb{indx(1),2} = [channelcmb{k,1},'[',duplet,']']; + labelcmb{indx(2),1} = [channelcmb{k,2},'[',duplet,']']; + labelcmb{indx(2),2} = [channelcmb{k,1},'[',duplet,']']; + labelcmb{indx(3),1} = [channelcmb{k,1},'[',duplet,']']; + labelcmb{indx(3),2} = [channelcmb{k,2},'[',duplet,']']; + labelcmb{indx(4),1} = [channelcmb{k,2},'[',duplet,']']; + labelcmb{indx(4),2} = [channelcmb{k,2},'[',duplet,']']; + end + +elseif strcmp(sfmethod, 'bivariate_conditional') + % recursively call this function, and concatenate the output + + optarg = varargin; + sel = strcmp(optarg, 'bivariate_conditional'); + optarg{sel} = 'trivariate'; + sel = find(strcmp(optarg, 'channeltriplet')); + if ~isempty(sel) + optarg{sel+1} = channeltriplet; + else + optarg = cat(2, optarg, {'channeltriplet', channeltriplet}); + end + out3 = ft_connectivity_csd2transfer(freq, optarg{:}); + + % get the required duplets + optarg = varargin; + sel = strcmp(optarg, 'bivariate_conditional'); + optarg{sel} = 'bivariate'; + sel = find(strcmp(optarg, 'channelcmb')); + + % ensure all the necessary duplets, for bidirectionality, but exclude + % double occurrences + tmp = [optarg{sel+1}(:,[1 3]);optarg{sel+1}(:,[2 3])]; + utmp = unique(tmp(:)); + ok = true(size(tmp,1),1); + tmpindx = zeros(size(tmp)); + for k = 1:size(tmpindx,1) + [~, tmpindx(k,:)] = match_str(tmp(k,:)', utmp); + if ~isempty(intersect(tmpindx(1:(k-1),:), [tmpindx(k,:);tmpindx(k,[2 1])], 'rows')) + ok(k) = false; + elseif tmpindx(k,1)==tmpindx(k,2) + ok(k) = false; + end + end + optarg{sel+1} = tmp(ok,:); + + out2 = ft_connectivity_csd2transfer(freq, optarg{:}); + + H = cat(1, out3.transfer, out2.transfer); + Z = cat(1, out3.noisecov, out2.noisecov); + S = cat(1, out3.crsspctrm, out2.crsspctrm); + labelcmb = cat(1, out3.labelcmb, out2.labelcmb); + +elseif strcmp(sfmethod, 'trivariate') + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % tripletwise factorization resulting in linearly indexed transfer functions + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + %FIXME remove auto-combinations and double occurrences + + %do multiple 3x3 factorization efficiently + if ntim>1, + for kk = 1:ntim + [Htmp, Ztmp, Stmp] = sfactorization_wilson3x3(freq.crsspctrm(:,:,:,kk), ... + freq.freq, numiteration, tol, cmbindx, fb, init, checkconvergence, stabilityfix); + if kk==1, + H = Htmp; + Z = Ztmp; + S = Stmp; + H(:,:,2:ntim) = nan; + Z(:,:,2:ntim) = nan; + S(:,:,2:ntim) = nan; + else + H(:,:,kk) = Htmp; + Z(:,:,kk) = Ztmp; + S(:,:,kk) = Stmp; + end + end + else + % if the number of pairs becomes too big, it seems to slow down quite a + % bit. try to chunk + nperchunk = 2000; + if size(cmbindx,1)>nperchunk + begchunk = 1:nperchunk:size(cmbindx,1); + endchunk = [nperchunk:nperchunk:size(cmbindx,1) size(cmbindx,1)]; + H = zeros(9*size(cmbindx,1), numel(freq.freq)); + S = zeros(9*size(cmbindx,1), numel(freq.freq)); + Z = zeros(9*size(cmbindx,1), 1); + for k = 1:numel(begchunk) + fprintf('computing factorization of chunck %d/%d\n', k, numel(begchunk)); + [Htmp, Ztmp, Stmp] = sfactorization_wilson3x3(freq.crsspctrm, freq.freq, ... + numiteration, tol, cmbindx(begchunk(k):endchunk(k),:), fb, init, checkconvergence, stabilityfix); + + begix = (k-1)*nperchunk*9+1; + endix = min(k*nperchunk*9, size(cmbindx,1)*9); + H(begix:endix, :) = Htmp; + S(begix:endix, :) = Stmp; + Z(begix:endix, :) = Ztmp; + + end + else + [H, Z, S] = sfactorization_wilson3x3(freq.crsspctrm, freq.freq, ... + numiteration, tol, cmbindx, fb, init, checkconvergence, stabilityfix); + end end + labelcmb = cell(size(cmbindx,1)*9, 2); + for k = 1:size(cmbindx,1) + triplet = strcat(channeltriplet{k,:}); + indx = (k-1)*9 + (1:9); + + labelcmb{indx(1),1} = [channeltriplet{k,1},'[',triplet,']']; + labelcmb{indx(1),2} = [channeltriplet{k,1},'[',triplet,']']; + labelcmb{indx(2),1} = [channeltriplet{k,2},'[',triplet,']']; + labelcmb{indx(2),2} = [channeltriplet{k,1},'[',triplet,']']; + labelcmb{indx(3),1} = [channeltriplet{k,3},'[',triplet,']']; + labelcmb{indx(3),2} = [channeltriplet{k,1},'[',triplet,']']; + labelcmb{indx(4),1} = [channeltriplet{k,1},'[',triplet,']']; + labelcmb{indx(4),2} = [channeltriplet{k,2},'[',triplet,']']; + labelcmb{indx(5),1} = [channeltriplet{k,2},'[',triplet,']']; + labelcmb{indx(5),2} = [channeltriplet{k,2},'[',triplet,']']; + labelcmb{indx(6),1} = [channeltriplet{k,3},'[',triplet,']']; + labelcmb{indx(6),2} = [channeltriplet{k,2},'[',triplet,']']; + labelcmb{indx(7),1} = [channeltriplet{k,1},'[',triplet,']']; + labelcmb{indx(7),2} = [channeltriplet{k,3},'[',triplet,']']; + labelcmb{indx(8),1} = [channeltriplet{k,2},'[',triplet,']']; + labelcmb{indx(8),2} = [channeltriplet{k,3},'[',triplet,']']; + labelcmb{indx(9),1} = [channeltriplet{k,3},'[',triplet,']']; + labelcmb{indx(9),2} = [channeltriplet{k,3},'[',triplet,']']; + end elseif strcmp(sfmethod, 'bivariate') && nrpt>1, % error - error('single trial estimates and linear combination indexing is not implemented'); + ft_error('single trial estimates and linear combination indexing is not implemented'); end -% create output -output = []; +%%%%%%%%%%%%%%%%%%%%%%%%% +% create output structure +%%%%%%%%%%%%%%%%%%%%%%%%% +output = keepfields(freq, {'freq' 'time' 'cumtapcnt' 'cumsumcnt' 'block' 'blockindx'}); +output.crsspctrm = S; +output.transfer = H; +output.noisecov = Z; if strcmp(sfmethod, 'multivariate') output.dimord = freq.dimord; else - if strcmp(freq.dimord(1:9), 'chan_chan'), + if strncmp(freq.dimord, 'chan_chan', 9), freq.dimord = ['chancmb_',freq.dimord(strfind(freq.dimord,'freq'):end)]; end - output.dimord = freq.dimord; end -output.label = freq.label; -output.freq = freq.freq; -output.crsspctrm = S; -output.transfer = H; -output.noisecov = Z; -if isfield(freq, 'time'), output.time = freq.time; end -if isfield(freq, 'cumtapcnt'), output.cumtapcnt = freq.cumtapcnt; end -if isfield(freq, 'cumsumcnt'), output.cumsumcnt = freq.cumsumcnt; end if exist('labelcmb', 'var') && ~isempty(labelcmb) output.labelcmb = labelcmb; - %output = rmfield(output, 'label'); -end -if isfield(freq, 'blockindx') - output.blockindx = freq.blockindx; -end -if isfield(freq, 'block') - output.block = freq.block; +else + output.label = freq.label; end diff --git a/external/fieldtrip/connectivity/ft_connectivity_dtf.m b/external/fieldtrip/connectivity/ft_connectivity_dtf.m index c5b34b2b..05195ea8 100644 --- a/external/fieldtrip/connectivity/ft_connectivity_dtf.m +++ b/external/fieldtrip/connectivity/ft_connectivity_dtf.m @@ -12,7 +12,16 @@ % additional options need to be specified as key-value pairs and are: % 'hasjack' = 0 (default) is a boolean specifying whether the input % contains leave-one-outs, required for correct variance -% estimate +% estimate. +% 'feedback' = string, determining verbosity (default = 'none'), see FT_PROGRESS +% 'crsspctrm' = matrix containing the cross-spectral density. If this +% matrix is defined, the function +% returns the ddtf, which requires an estimation of partial +% coherence from this matrix. +% 'invfun' = 'inv' (default) or 'pinv', the function used to invert the +% crsspctrm matrix to obtain the partial coherence. Pinv is +% useful if the data are poorly-conditioned. +% % % Output arguments: % d = partial directed coherence matrix Nchan x Nchan x Nfreq (x Ntime). @@ -25,7 +34,7 @@ % is assumed to contain the leave-one-out estimates of H, thus a more % reliable estimate of the relevant quantities. -% Copyright (C) 2009-2013, Jan-Mathijs Schoffelen +% Copyright (C) 2009-2017, Jan-Mathijs Schoffelen % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -45,57 +54,70 @@ % % $Id$ -hasjack = ft_getopt(varargin, 'hasjack', 0); -powindx = ft_getopt(varargin, 'powindx'); -% FIXME build in feedback -% FIXME build in dDTF etc +hasjack = ft_getopt(varargin, 'hasjack', 0); +powindx = ft_getopt(varargin, 'powindx'); +feedback = ft_getopt(varargin, 'feedback', 'none'); +crsspctrm = ft_getopt(varargin, 'crsspctrm'); +invfun = ft_getopt(varargin, 'invfun', 'inv'); + +switch invfun + case {'inv' 'pinv'} + invfun = str2func(invfun); + otherwise + ft_error('unknown specification of inversion-function for the transfer matrix'); +end + +if ~isempty(powindx) + % this error message is rather uninformative, but is kept for now for + % backward compatibility reasons (i.e. it might exist when called from + % ft_connectivityanalysis + ft_error('linearly indexed data for dtf computation is at the moment not supported'); +end siz = [size(input) 1]; n = siz(1); -%ncmb = siz(2); outsum = zeros(siz(2:end)); outssq = zeros(siz(2:end)); -if isempty(powindx) - % data are represented as chan_chan_therest - for j = 1:n - tmph = reshape(input(j,:,:,:,:), siz(2:end)); +% check the crsspctrm, if it's present, compute the partial coherence +if ~isempty(crsspctrm) + assert(isequal(size(crsspctrm),size(input)), 'the input data should be of the same size as the crsspctrm'); + fprintf('computing dDTF in the presence of a crsspctrm\n'); + + % the crsspctrm allows for the partial coherence to be computed + pdim = prod(siz(4:end)); + tmpcrs = reshape(crsspctrm, [siz(1:3) pdim]); + ft_progress('init', feedback, 'computing partial coherence...'); + for k = 1:n + ft_progress(k/n, 'computing partial coherence for replicate %d from %d\n', k, n); + tmp = reshape(tmpcrs(k,:,:,:), [siz(2:3) pdim]); + for m = 1:pdim + tmp(:,:,m) = invfun(tmp(:,:,m)); + tmp(:,:,m) = abs(tmp(:,:,m))./sqrt(abs(diag(tmp(:,:,m))*diag(tmp(:,:,m))')); + end + tmpcrs(k,:,:,:) = tmp; + end + ft_progress('close'); + crsspctrm = reshape(tmpcrs, siz); +end + +% data should be represented as chan_chan_therest +for j = 1:n + tmph = reshape(input(j,:,:,:,:), siz(2:end)); + if isempty(crsspctrm) + % plain DTF den = sum(abs(tmph).^2,2); tmpdtf = abs(tmph)./sqrt(repmat(den, [1 siz(2) 1 1 1])); - outsum = outsum + tmpdtf; - outssq = outssq + tmpdtf.^2; - %tmp = outsum; tmp(2,1,:,:) = outsum(1,2,:,:); tmp(1,2,:,:) = outsum(2,1,:,:); outsum = tmp; - %tmp = outssq; tmp(2,1,:,:) = outssq(1,2,:,:); tmp(1,2,:,:) = outssq(2,1,:,:); outssq = tmp; - % FIXME swap the order of the cross-terms to achieve the convention such that - % labelcmb {'a' 'b'} represents: a->b + else + % dDTF + tmpc = reshape(crsspctrm(j,:,:,:,:), siz(2:end)); + + den = sum(sum(abs(tmph).^2,3),2); + tmpdtf = abs(tmph)./sqrt(repmat(den, [1 siz(2) siz(4) 1 1 1])); + tmpdtf = tmpdtf.*tmpc; end -else - error('linearly indexed data for dtf computation is at the moment not supported'); -%FIXME this needs to be thought through -> also, as a multivariate measure -%a pairwise decomposition does not make sense, should this be dealt with by -%ft_connectivityanalysis? - % % data are linearly indexed -% sortindx = [0 0 0 0]; -% for k = 1:ncmb -% iauto1 = find(sum(cfg.powindx==cfg.powindx(k,1),2)==2); -% iauto2 = find(sum(cfg.powindx==cfg.powindx(k,2),2)==2); -% icross1 = k; -% icross2 = find(sum(cfg.powindx==cfg.powindx(ones(ncmb,1)*k,[2 1]),2)==2); -% indx = [iauto1 icross2 icross1 iauto2]; -% -% if isempty(intersect(sortindx, sort(indx), 'rows')), -% sortindx = [sortindx; sort(indx)]; -% for j = 1:n -% tmph = reshape(input(j,indx,:,:), [2 2 siz(3:end)]); -% den = sum(abs(tmph).^2,2); -% tmpdtf = reshape(abs(tmph)./sqrt(repmat(den, [1 2 1 1])), [4 siz(3:end)]); -% outsum(indx,:) = outsum(indx,:) + tmpdtf([1 3 2 4],:); -% outssq(indx,:) = outssq(indx,:) + tmpdtf([1 3 2 4],:).^2; -% % FIXME swap the order of the cross-terms to achieve the convention such that -% % labelcmb {'a' 'b'} represents: a->b -% end -% end -% end + outsum = outsum + tmpdtf; + outssq = outssq + tmpdtf.^2; end dtf = outsum./n; diff --git a/external/fieldtrip/connectivity/ft_connectivity_granger.m b/external/fieldtrip/connectivity/ft_connectivity_granger.m index 59217063..4441fb53 100644 --- a/external/fieldtrip/connectivity/ft_connectivity_granger.m +++ b/external/fieldtrip/connectivity/ft_connectivity_granger.m @@ -44,7 +44,7 @@ % The code is loosely based on the code used in: % Brovelli, et. al., PNAS 101, 9849-9854 (2004). % -% Copyright (C) 2009-2013, Jan-Mathijs Schoffelen +% Copyright (C) 2009-2017, Jan-Mathijs Schoffelen % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -86,7 +86,7 @@ switch method case 'granger' - if issquare && isempty(powindx), + if issquare && isempty(powindx) %%%%%%%%%%%%%%%%%%%%%%%%%%%% % data are chan_chan_therest %%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -211,7 +211,7 @@ end end - elseif ~issquare && isstruct(powindx) + elseif ~issquare && isstruct(powindx) && isfield(powindx, 'n') %%%%%%%%%%%%%%%%%%%%%% %blockwise conditional %%%%%%%%%%%%%%%%%%%%%% @@ -232,6 +232,56 @@ outsum = outsum + tmp; outssq = outssq + tmp.^2; end + + elseif ~issquare && isstruct(powindx) + %%%%%%%%%%%%%%%%%%%%%% + %triplet conditional + %%%%%%%%%%%%%%%%%%%%%% + + % decode from the powindx struct which rows in the data correspond with + % the triplets, and which correspond with the duplets + ublockindx = unique(powindx.blockindx); + nperblock = zeros(size(ublockindx)); + for k = 1:numel(ublockindx) + nperblock(k,1) = sum(powindx.blockindx==ublockindx(k)); + end + if ~all(ismember(nperblock,[4 9])) + error('the data should be a mixture of trivariate and bivariate decompositions'); + end + indx_triplets = ismember(powindx.blockindx, ublockindx(nperblock==9)); ntriplets = sum(indx_triplets)./9; + indx_duplets = ismember(powindx.blockindx, ublockindx(nperblock==4)); nduplets = sum(indx_duplets)./4; + + % this assumes well-behaved powindx.cmbindx + cmbindx2 = reshape(powindx.cmbindx(indx_duplets, 1), 2, [])'; + cmbindx3 = reshape(powindx.cmbindx(indx_triplets,1), 3, [])'; + + cmbindx2 = cmbindx2(1:2:end,:); + cmbindx3 = cmbindx3(1:3:end,:); + + cmbindx = powindx.outindx; + + n = size(H,1); + siz = size(H); + + outsum = zeros(size(cmbindx,1), size(H,3)); + outssq = outsum; + + % call the low-level function + for k = 1:n + H3 = reshape(H(k,indx_triplets,:,:), [3 3 ntriplets siz(3:end)]); + Z3 = reshape(Z(k,indx_triplets), [3 3 ntriplets]); + + H2 = reshape(H(k,indx_duplets,:,:), [2 2 nduplets siz(3:end)]); + Z2 = reshape(Z(k,indx_duplets), [2 2 nduplets]); + + tmp = triplet_conditionalgranger(H3,Z3,cmbindx3,H2,Z2,cmbindx2,cmbindx); + + outsum = outsum + tmp; + outssq = outssq + tmp.^2; + end + + + end case 'instantaneous' @@ -295,12 +345,12 @@ % S = crosspectrum nchan x nchan x nfreq % powindx{1} is a list of indices for block1 % powindx{2} is a list of indices for block2 - error('instantaneous causality is not implemented for blockwise factorizations'); + ft_error('instantaneous causality is not implemented for blockwise factorizations'); elseif isstruct(powindx) %blockwise conditional - error('blockwise conditional instantaneous causality is not implemented'); + ft_error('blockwise conditional instantaneous causality is not implemented'); else - error('not implemented'); + ft_error('not implemented'); end case 'total' @@ -388,11 +438,25 @@ elseif issquare && isstruct(powindx) %blockwise conditional - error('blockwise conditional total interdependence is not implemented'); + ft_error('blockwise conditional total interdependence is not implemented'); + end + +case 'iis' + ft_warning('THIS IS EXPERIMENTAL CODE, USE AT YOUR OWN RISK!'); + % this is experimental + if ~issquare && isempty(powindx) + A = transfer2coeffs(shiftdim(H),(0:size(H,3)-1)); + ncmb = size(A,1)./4; + iis = coeffs2iis(reshape(A,[2 2 ncmb size(A,2)]),reshape(Z,[2 2 ncmb])); + iis = repmat(iis(:),[1 4])'; + outsum = iis(:); + outssq = nan(size(outsum)); + else + ft_error('iis can only be computed when the input contains sets of bivariate factorizations'); end otherwise - error('unsupported output requested'); + ft_error('unsupported output requested'); end granger = outsum./n; diff --git a/external/fieldtrip/connectivity/ft_connectivity_laggedcoherence.m b/external/fieldtrip/connectivity/ft_connectivity_laggedcoherence.m index 3d5781fb..4677aff1 100644 --- a/external/fieldtrip/connectivity/ft_connectivity_laggedcoherence.m +++ b/external/fieldtrip/connectivity/ft_connectivity_laggedcoherence.m @@ -127,9 +127,9 @@ % check if the input data is valid for this function freqout = ft_checkdata(freqout, 'datatype', {'freq'}, 'feedback', cfg.feedback,'dimord',{'rpttap_chan_freq_time','rpt_chan_freq_time'}); if ~isfield(freqout,'fourierspctrm') - error('ft_connectivity_laggedcoherence requires frequency data with a fourierspctrm.'); + ft_error('ft_connectivity_laggedcoherence requires frequency data with a fourierspctrm.'); elseif size(freqout.fourierspctrm,4)==1 - error('ft_connectivity_laggedcoherence requires frequency data with a time axis') + ft_error('ft_connectivity_laggedcoherence requires frequency data with a time axis') end % ensure that cfg.lag is present @@ -154,16 +154,16 @@ % some proper error handling if numel(freqout.label)==0 - error('no channels were selected'); + ft_error('no channels were selected'); end if ~(strcmp(cfg.output,'lcoh') || strcmp(cfg.output,'csd')) - error('cfg.output must be either ''lcoh'' or ''csd'''); + ft_error('cfg.output must be either ''lcoh'' or ''csd'''); end index = cellfun('isclass',cfg.trialsets,'char'); if sum(index)>0 index2 = cellfun(@(x) strcmp(x,'all'),cfg.trialsets(index),'UniformOutput',true); if any(index2==0) - error('each cell of cfg.trialsets must contain either a 1xN vector, or ''all'''); + ft_error('each cell of cfg.trialsets must contain either a 1xN vector, or ''all'''); end cfg.trialsets(index) = {1:size(freqout.fourierspctrm,1)}; end @@ -230,9 +230,9 @@ power(:,lagindx,2,trialindx) = power(:,lagindx,2,trialindx)+ abs(fcs2(chancmbind(:,2),tcounter)).^2; hasdata(trialindx,lagindx) = true; nsmplslaggedcps(lagindx,trialindx) = nsmplslaggedcps(lagindx,trialindx)+1; - end; - end; - end; + end + end + end % calculate lagged coherence if strcmp('lcoh',cfg.output) @@ -301,7 +301,7 @@ if sum(hasdata(trials,lagindx),1)==0 laggedcrsspctrm(trialset,:,lagindx) = NaN; end - end; + end end % make output structure lcoh = []; @@ -346,7 +346,7 @@ case 'yes' % method-specfic checks if cfg.nlags>1 - error('when calculating timeresolved lcoh, cfg.nlags must be set to 1'); + ft_error('when calculating timeresolved lcoh, cfg.nlags must be set to 1'); end % select pairs of timepoints with relative lag cfg.lag (identified with precision cfg.precision) @@ -376,8 +376,8 @@ power(:,tcounter,1,trialindx) = abs(fcs1(chancmbind(:,1),tcounter)).^2; power(:,tcounter,2,trialindx) = abs(fcs2(chancmbind(:,2),tcounter)).^2; hasdata(trialindx,tcounter) = true; - end; - end; + end + end % calculate lagged coherence if strcmp('lcoh',cfg.output) @@ -438,7 +438,7 @@ laggedcrsspctrm(trialset,:,toii)= sumlaggedcps(:,toii)/sumnsmpls; powspctrm1(trialset,:,toii) = sumpower(:,toii,1)/sumnsmpls; powspctrm2(trialset,:,toii) = sumpower(:,toii,2)/sumnsmpls; - end; + end end % make output structure lcoh = []; diff --git a/external/fieldtrip/connectivity/ft_connectivity_mutualinformation.m b/external/fieldtrip/connectivity/ft_connectivity_mutualinformation.m index 79260433..c7b5da56 100644 --- a/external/fieldtrip/connectivity/ft_connectivity_mutualinformation.m +++ b/external/fieldtrip/connectivity/ft_connectivity_mutualinformation.m @@ -66,7 +66,7 @@ end if numel(lags)>1 || lags~=0, - if numel(refindx)>1, error('with multiple lags, or with a lag~=0 only a single refindx is allowed'); end + if numel(refindx)>1, ft_error('with multiple lags, or with a lag~=0 only a single refindx is allowed'); end refdata = input(refindx,:); n = size(refdata,2); @@ -101,7 +101,7 @@ % check validity of refindx if length(refindx)~=numel(refindx) % could be channelcmb indexing - error('channelcmb indexing is not supported'); + ft_error('channelcmb indexing is not supported'); end diff --git a/external/fieldtrip/connectivity/ft_connectivity_pdc.m b/external/fieldtrip/connectivity/ft_connectivity_pdc.m index 06bbf278..dc78c9f1 100644 --- a/external/fieldtrip/connectivity/ft_connectivity_pdc.m +++ b/external/fieldtrip/connectivity/ft_connectivity_pdc.m @@ -14,6 +14,13 @@ % contains leave-one-outs, required for correct variance % estimate % 'feedback' = string, determining verbosity (default = 'none'), see FT_PROGRESS +% 'invfun' = 'inv' (default) or 'pinv', the function used to invert the +% transfer matrix to obtain the fourier transform of the +% MVAR coefficients. Use 'pinv' if the data are +% poorly-conditioned. +% 'noisecov' = matrix containing the covariance of the residuals of the +% MVAR model. If this matrix is defined, the function +% returns the generalized partial directed coherence. % % Output arguments: % p = partial directed coherence matrix Nchan x Nchan x Nfreq (x Ntime). @@ -25,8 +32,17 @@ % computed across observations. When nrpt>1 and hasjack is true the input % is assumed to contain the leave-one-out estimates of H, thus a more % reliable estimate of the relevant quantities. +% +% This function implements the metrices described in: +% - Baccala et al., Biological Cybernetics 2001, 84(6), 463-74. +% - Baccala et al., 15th Int.Conf.on DSP 2007, 163-66. +% +% The implemented algorithm has been tested against the implementation in +% the SIFT-toolbox. It yields numerically identical results to what is +% known in the SIFT-toolbox as 'nPDC' (for PDC) and 'GPDC' for generalized +% pdc. -% Copyright (C) 2009-2013, Jan-Mathijs Schoffelen +% Copyright (C) 2009-2017, Jan-Mathijs Schoffelen % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -48,15 +64,34 @@ hasjack = ft_getopt(varargin, 'hasjack', 0); feedback = ft_getopt(varargin, 'feedback', 'none'); +invfun = ft_getopt(varargin, 'invfun', 'inv'); +noisecov = ft_getopt(varargin, 'noisecov'); + +switch invfun + case {'inv' 'pinv'} + invfun = str2func(invfun); + otherwise + ft_error('unknown specification of inversion-function for the transfer matrix'); +end % crossterms are described by chan_chan_therest siz = [size(input) 1]; n = siz(1); +if ~isempty(noisecov) + ft_progress('init', feedback, 'computing generalized partial directed coherence...'); + scale = diag(sqrt(1./diag(noisecov))); % get the 1./sqrt(var) of the signals +else + ft_progress('init', feedback, 'computing partial directed coherence...'); + scale = eye(siz(2)); +end + +% pre-allocate some variables outsum = zeros(siz(2:end)); outssq = zeros(siz(2:end)); -% computing pdc is easiest on the inverse of the transfer function +% the mathematics for pdc is most straightforward using the inverse of the +% transfer function pdim = prod(siz(4:end)); tmpinput = reshape(input, [siz(1:3) pdim]); ft_progress('init', feedback, 'inverting the transfer function...'); @@ -64,20 +99,22 @@ ft_progress(k/n, 'inverting the transfer function for replicate %d from %d\n', k, n); tmp = reshape(tmpinput(k,:,:,:), [siz(2:3) pdim]); for m = 1:pdim - tmp(:,:,m) = inv(tmp(:,:,m)); + tmp(:,:,m) = scale*invfun(tmp(:,:,m)); end tmpinput(k,:,:,:) = tmp; end ft_progress('close'); input = reshape(tmpinput, siz); -ft_progress('init', feedback, 'computing metric...'); for j = 1:n ft_progress(j/n, 'computing metric for replicate %d from %d\n', j, n); invh = reshape(input(j,:,:,:,:), siz(2:end)); + + den = sum(abs(invh).^2,1); tmppdc = abs(invh)./sqrt(repmat(den, [siz(2) 1 1 1 1])); - %if ~isempty(cfg.submethod), tmppdc = baseline(tmppdc, cfg.submethod, baselineindx); end + + outsum = outsum + tmppdc; outssq = outssq + tmppdc.^2; end diff --git a/external/fieldtrip/connectivity/ft_connectivity_powcorr_ortho.m b/external/fieldtrip/connectivity/ft_connectivity_powcorr_ortho.m index e34dc545..c41718a3 100644 --- a/external/fieldtrip/connectivity/ft_connectivity_powcorr_ortho.m +++ b/external/fieldtrip/connectivity/ft_connectivity_powcorr_ortho.m @@ -50,11 +50,11 @@ n = size(mom,1); ntap = tapvec(1); if ~all(tapvec==ntap) - error('unequal number of tapers per observation is not yet supported'); + ft_error('unequal number of tapers per observation is not yet supported'); end % FIXME think about multiple tapers per trial %if ntap>1 -% error('more than one taper per observation is not yet supported'); +% ft_error('more than one taper per observation is not yet supported'); %end % create a sparse matrix tra, that can be used as a right multiplying @@ -82,7 +82,7 @@ c = zeros(n, numel(refindx));%;*2); N = ones(n,1); %warning off; -for k = 1:numel(refindx) +for k = 1:numel(refindx) indx = refindx(k); ref = mom(indx,:); crefnorm = conj(ref./abs(ref)); diff --git a/external/fieldtrip/connectivity/ft_connectivity_ppc.m b/external/fieldtrip/connectivity/ft_connectivity_ppc.m index ef82e28f..b778132b 100644 --- a/external/fieldtrip/connectivity/ft_connectivity_ppc.m +++ b/external/fieldtrip/connectivity/ft_connectivity_ppc.m @@ -76,7 +76,7 @@ c = reshape(c,siz(2:end)); % remove the first singular dimension else c = NaN(siz(2:end)); % for one observation, we should return NaNs - warning('ft_connectivity_ppc:nTrials', 'computation ppc requires >1 trial, returning NaNs') + ft_warning('ft_connectivity_ppc:nTrials', 'computation ppc requires >1 trial, returning NaNs') end [leave1outsum, leave1outssq] = deal(0); diff --git a/external/fieldtrip/connectivity/ft_connectivity_psi.m b/external/fieldtrip/connectivity/ft_connectivity_psi.m index ed632dc4..96765042 100644 --- a/external/fieldtrip/connectivity/ft_connectivity_psi.m +++ b/external/fieldtrip/connectivity/ft_connectivity_psi.m @@ -70,7 +70,7 @@ nbin = ft_getopt(varargin, 'nbin'); if isempty(dimord) - error('input parameters should contain a dimord'); + ft_error('input parameters should contain a dimord'); end if (length(strfind(dimord, 'chan'))~=2 || ~isempty(strfind(dimord, 'pos'))>0) && ~isempty(powindx), diff --git a/external/fieldtrip/connectivity/ft_connectivity_wpli.m b/external/fieldtrip/connectivity/ft_connectivity_wpli.m index 7a024d5e..7526546f 100644 --- a/external/fieldtrip/connectivity/ft_connectivity_wpli.m +++ b/external/fieldtrip/connectivity/ft_connectivity_wpli.m @@ -74,7 +74,7 @@ wpli = reshape(wpli,siz(2:end)); % remove the first singular dimension else wpli = NaN(siz(2:end)); % for one observation, we should return NaNs - warning('ft_connectivity_wpli:nTrials', 'computation wpli requires >1 trial, returning NaNs'); + ft_warning('ft_connectivity_wpli:nTrials', 'computation wpli requires >1 trial, returning NaNs'); end [leave1outsum, leave1outssq] = deal(zeros([1 siz(2:end)])); diff --git a/external/fieldtrip/connectivity/private/coeffs2iis.m b/external/fieldtrip/connectivity/private/coeffs2iis.m new file mode 100644 index 00000000..2902dbf2 --- /dev/null +++ b/external/fieldtrip/connectivity/private/coeffs2iis.m @@ -0,0 +1,63 @@ +function iis = coeffs2iis(A,C) + +% COEFFS2IIS computes the instantaneous interaction strength based on the +% MVAR-coefficients and a noise covariance matrix. The underlying +% assumption is that the MVAR-models have been fitted in a bivariate +% fashion. It uses the definition according to Vinck et al. Neuroimage 2015 +% (108). +% +% Input data: +% A = 2x2xncmbxorder, matrix with MVAR-coefficients +% C = 2x2xncmb , covariance matrices of the noise + +siz = [size(C) 1]; +ncmb = siz(3); + +P1 = repmat(eye(2), [1 1 ncmb]); +P2 = repmat(eye(2), [1 1 ncmb]); + +% deciphering some code from Martin Vinck, this swaps the indices in the +% denominator w.r.t. the other (i.e. my implementation from the paper) + +% projection matrices +P1(2,1,:) = -C(1,2,:)./C(1,1,:); +P2(1,2,:) = -C(2,1,:)./C(2,2,:); + +B12 = A; +B21 = A; +for k = 1:size(A,4) + B12(:,:,:,k) = mtimes2x2(P1,A(:,:,:,k)); + B21(:,:,:,k) = mtimes2x2(P2,A(:,:,:,k)); +end + +num = abs(P1(2,1,:)) + abs(P2(1,2,:)); + +m12 = zeros(size(num)); +m21 = zeros(size(num)); +for k = 1:size(B12,4) + m12 = max(m12, abs(B12(2,1,:,k))); %swapped indices w.r.t below + m21 = max(m21, abs(B21(1,2,:,k))); +end + +iis = shiftdim(num./(m12+m21)); + +% P1(2,1,:) = -C(1,2,:)./C(2,2,:); +% P2(1,2,:) = -C(2,1,:)./C(1,1,:); +% +% B12 = A; +% B21 = A; +% for k = 1:size(A,4) +% B12(:,:,:,k) = mtimes2x2(P1,A(:,:,:,k)); +% B21(:,:,:,k) = mtimes2x2(P2,A(:,:,:,k)); +% end +% +% num = abs(P1(2,1,:)) + abs(P2(1,2,:)); +% +% m12 = zeros(size(num)); +% m21 = zeros(size(num)); +% for k = 1:size(B12,4) +% m12 = max(m12, abs(B12(1,2,:,k))); +% m21 = max(m21, abs(B21(2,1,:,k))); +% end +% +% iis = shiftdim(num./(m12+m21)); diff --git a/external/fieldtrip/connectivity/private/ctranspose2x2.m b/external/fieldtrip/connectivity/private/ctranspose2x2.m new file mode 100644 index 00000000..2519e2fb --- /dev/null +++ b/external/fieldtrip/connectivity/private/ctranspose2x2.m @@ -0,0 +1,7 @@ +function out = ctranspose2x2(in) + +% compute ctranspose of multiple 2x2 matrices, input is 2x2xN + +out = conj(in); +out(1,2,:,:) = conj(in(2,1,:,:)); +out(2,1,:,:) = conj(in(1,2,:,:)); diff --git a/external/fieldtrip/connectivity/private/ctranspose3x3.m b/external/fieldtrip/connectivity/private/ctranspose3x3.m new file mode 100644 index 00000000..f9e837de --- /dev/null +++ b/external/fieldtrip/connectivity/private/ctranspose3x3.m @@ -0,0 +1,11 @@ +function out = ctranspose3x3(in) + +% compute ctranspose of multiple 3x3 matrices, input is 3x3xN + +out = conj(in); +out(1,2,:,:) = conj(in(2,1,:,:)); +out(2,1,:,:) = conj(in(1,2,:,:)); +out(1,3,:,:) = conj(in(3,1,:,:)); +out(3,1,:,:) = conj(in(1,3,:,:)); +out(2,3,:,:) = conj(in(3,2,:,:)); +out(3,2,:,:) = conj(in(2,3,:,:)); diff --git a/external/fieldtrip/connectivity/private/defaultId.m b/external/fieldtrip/connectivity/private/defaultId.m new file mode 100644 index 00000000..f4e1ee99 --- /dev/null +++ b/external/fieldtrip/connectivity/private/defaultId.m @@ -0,0 +1,57 @@ +function id = defaultId + +% DEFAULTID returns a string that can serve as warning or error identifier, +% for example 'FieldTip:ft_read_header:line345'. +% +% See also WARNING, ERROR, FT_NOTICE, FT_INFO, FT_DEBUG + +% Copyright (C) 2017, Robert Oostenveld +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +stack = dbstack('-completenames'); + +% remove the functions that pertain to the notification system itself +keep = true(size(stack)); +keep(strcmp({stack.name}, 'defaultId')) = false; % this function itself +keep(strcmp({stack.name}, 'ft_notification')) = false; % this one is doing the work underneath ft_error/ft_warning/ft_notice/etc. +keep(strcmp({stack.name}, 'ft_error')) = false; +keep(strcmp({stack.name}, 'ft_warning')) = false; +keep(strcmp({stack.name}, 'ft_notice')) = false; +keep(strcmp({stack.name}, 'ft_info')) = false; +keep(strcmp({stack.name}, 'ft_debug')) = false; +stack = stack(keep); + +% remove the non-FieldTrip functions from the path, these should not be part of the default message identifier +keep = true(size(stack)); +[v, p] = ft_version; +for i=1:numel(stack) + keep(i) = strncmp(p, stack(i).file, length(p)); +end +stack = stack(keep); + +if ~isempty(stack) + % it is called from within a function + stack = flipud(stack); + name = {stack.name}; + id = ['FieldTrip' sprintf(':%s', name{:}) ':line' num2str(stack(end).line)]; +else + % it is called from the command line + id = 'FieldTrip:commandline'; +end diff --git a/external/fieldtrip/connectivity/private/det2x2.m b/external/fieldtrip/connectivity/private/det2x2.m index 82f9bdc4..260d5d1e 100644 --- a/external/fieldtrip/connectivity/private/det2x2.m +++ b/external/fieldtrip/connectivity/private/det2x2.m @@ -36,6 +36,6 @@ elseif numel(siz)==2, d = det(x); else - error('not implemented'); + ft_error('not implemented'); % write for loop for the higher dimensions, using normal inv end diff --git a/external/fieldtrip/connectivity/private/det3x3.m b/external/fieldtrip/connectivity/private/det3x3.m new file mode 100644 index 00000000..115770f4 --- /dev/null +++ b/external/fieldtrip/connectivity/private/det3x3.m @@ -0,0 +1,37 @@ +function d = det3x3(x) + +% DET3X3 computes determinant of matrix x, using explicit analytic definition +% if size(x) = [3 3 K M] + +% Copyright (C) 2017, Donders Centre for Cognitive Neuroimaging, Nijmegen, NL +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +siz = size(x); +if all(siz(1:2)==3), + d = x(1,1,:,:).*x(2,2,:,:).*x(3,3,:,:) - ... + x(1,1,:,:).*x(2,3,:,:).*x(3,2,:,:) - ... + x(1,2,:,:).*x(2,1,:,:).*x(3,3,:,:) + ... + x(1,2,:,:).*x(2,3,:,:).*x(3,1,:,:) + ... + x(1,3,:,:).*x(2,1,:,:).*x(3,2,:,:) - ... + x(1,3,:,:).*x(2,2,:,:).*x(3,1,:,:); +else + ft_error('not implemented'); + % write for loop for the higher dimensions, using normal inv +end diff --git a/external/fieldtrip/connectivity/private/fixname.m b/external/fieldtrip/connectivity/private/fixname.m index 96a345ec..76fd5951 100644 --- a/external/fieldtrip/connectivity/private/fixname.m +++ b/external/fieldtrip/connectivity/private/fixname.m @@ -1,19 +1,20 @@ -function str = fixname(str) +function str = fixname(str, version) % FIXNAME changes all inappropriate characters in a sting into '_' -% such that it can be used as a filename or as a structure field name. If -% the string begins with a numeric digit, an 'x' is prepended. +% so that it can be used as a filename or as a field name in a structure. +% If the string begins with a digit, an 'x' is prepended. % % Use as % str = fixname(str) % % MATLAB 2014a introduces the matlab.lang.makeValidName and -% matlab.lang.makeUniqueStrings functions for constructing unique MATLAB identifiers, -% but this particular implementation also works with older MATLAB versions. +% matlab.lang.makeUniqueStrings functions for constructing unique +% identifiers, but this particular implementation also works with +% older MATLAB versions. % % See also DEBLANK -% Copyright (C) 2012-2016, Robert Oostenveld +% Copyright (C) 2012-2017, Robert Oostenveld % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -33,19 +34,48 @@ % % $Id$ -str = lower(str); -str(regexp(str,'\W')) = '_'; - -while(str(1) == '_'), str = str(2:end); end; % remove all underscore at the begin of the string -while(str(end) == '_'), str = str(1:end-1); end; % remove all underscore at the end of the string - -if int8(str(1))<58 && int8(str(1))>47 - % the string begins with a digit, prepend an 'x' - str = ['x' str]; +if nargin<2 + version = 'default'; end -% truncate the string if it's too long: MATLAB maximizes the string length to 63 characters (and throws a warning when truncating) -if numel(str)>63 - str = str(1:63); - ft_warning(sprintf('%s exceeds MATLAB''s maximum name length of 63 characters and has been truncated to %s', str, str(1:63))); +switch version + case 'default' + if isempty(str) + str='x'; + end + str = lower(str); + str(regexp(str,'\W')) = '_'; + while(str(1) == '_'), str = str(2:end); end % remove all underscore at the begin of the string + while(str(end) == '_'), str = str(1:end-1); end % remove all underscore at the end of the string + if int8(str(1))<58 && int8(str(1))>47 + % the string begins with a digit, prepend an 'x' + str = ['x' str]; + end + % truncate the string if it's too long: MATLAB maximizes the string length to 63 characters (and throws a warning when truncating) + if numel(str)>63 + str = str(1:63); + warning('%s exceeds MATLAB''s maximum name length of 63 characters and has been truncated to %s', str, str(1:63)); + end + + case '2014a' + str = matlab.lang.makeValidName(str); + + case 'X_base64encode_X' + % this uses some code from Mathworks file exchange + ft_hastoolbox('fileexchange', 1); + % the following is an encoding that can be reverted + str = strtrim(base64encode(str)); + str(str=='=') = '_'; % replace the '=' sign with '_' + str = ['X' str 'X']; % start and end with an 'X' + + case 'X_base64decode_X' + % this uses some code from Mathworks file exchange + ft_hastoolbox('fileexchange', 1); + % revert the encoding + str = str(2:end-1); % it starts and ends with 'X' + str(str=='_') = '='; % the '=' sign has been replaced with '_' + str = char(base64decode(str)); + + otherwise + error('unsupported version "%s"', version); end diff --git a/external/fieldtrip/connectivity/private/ft_getopt.m b/external/fieldtrip/connectivity/private/ft_getopt.m index 21ed892a..0d433115 100644 --- a/external/fieldtrip/connectivity/private/ft_getopt.m +++ b/external/fieldtrip/connectivity/private/ft_getopt.m @@ -8,19 +8,19 @@ % where the input values are % s = structure or cell-array % key = string -% default = any valid MATLAB data type +% default = any valid MATLAB data type (optional, default = []) % emptymeaningful = boolean value (optional, default = 0) % -% If the key is present as field in the structure, or as key-value -% pair in the cell-array, the corresponding value will be returned. +% If the key is present as field in the structure, or as key-value pair in the +% cell-array, the corresponding value will be returned. % -% If the key is not present, ft_getopt will return an empty array. +% If the key is not present, ft_getopt will return the default, or an empty array +% when no default was specified. % -% If the key is present but has an empty value, then the emptymeaningful -% flag specifies whether the empty value or the default value should -% be returned. If emptymeaningful==true, then an empty array will be -% returned. If emptymeaningful==false, then the specified default will -% be returned. +% If the key is present but has an empty value, then the emptymeaningful flag +% specifies whether the empty value or the default value should be returned. +% If emptymeaningful==true, then the empty array will be returned. +% If emptymeaningful==false, then the specified default will be returned. % % See also FT_SETOPT, FT_CHECKOPT @@ -60,27 +60,27 @@ else val = opt.(key); end - + elseif isa(opt, 'cell') % get the key-value from the cell-array if mod(length(opt),2) error('optional input arguments should come in key-value pairs, i.e. there should be an even number'); end - + % the 1st, 3rd, etc. contain the keys, the 2nd, 4th, etc. contain the values keys = opt(1:2:end); vals = opt(2:2:end); - + % the following may be faster than cellfun(@ischar, keys) valid = false(size(keys)); for i=1:numel(keys) valid(i) = ischar(keys{i}); end - + if ~all(valid) error('optional input arguments should come in key-value pairs, the optional input argument %d is invalid (should be a string)', i); end - + hit = find(strcmpi(key, keys)); if isempty(hit) % the requested key was not found @@ -91,7 +91,7 @@ else error('multiple input arguments with the same name'); end - + elseif isempty(opt) % no options are specified, return default val = default; diff --git a/external/fieldtrip/connectivity/private/ft_getopt.mexmaci64 b/external/fieldtrip/connectivity/private/ft_getopt.mexmaci64 index 1e499c9421e1062ba1178bd37b44ea26728740c3..48fecb34b3878cd01301ebf956190ce9f9db8af2 100755 GIT binary patch literal 9680 zcmeHNU2Ggz6~62II6tOd2d6cn&}peFm;BizC~4BB-r7!g!A>3Qv=Ly&v+G&!(Al5N z&ZO(eiL5v-ow`P*DWyVHu+#@C1P>r2A_3K+w3vrLO?Zhah$=*rvD`|9LO?BKIp3W- z-q|rmec%brmG3?0JLlYU&zyVbdiKt|{{A~R>lurzVT^5{8l@_&V{D2j%Ezd-)iEZ^ zgFVLvxu~{52Y(Tmd@^#w)(f31n`+6d8V3DIn_QhiW1#@Aby>Gv%O?C#mW!s9EG~5vnU$5nrlk8d`2t*a!Xn zN%;Gg2+G64yw*1fW!cI-q2)$oEtk%7Tst4*jc(6=;Q+WMJ|XvrEUOtgZ75mQl?3Bk z5dPXl2Vks`)e6>$Lsgc$V}miDmA5`tp;#yI>%}U|IbAM}Ws`YbE||uu{ycYBu>QC( zpUuAEWm#ALo4=@VG$;B1`~4xlTYdg;opGwN+?zQ3`JV2CcTY&d$O}y11>6Kw;K#rI z?qY1B9SX_4?=}!^0TxA)7`s3nuH4DkK9V6n(8sCcZA6FfW~@N^&BXUp^%vNpZuJWT z{Dn_3_UV8O@Z(f5&K*m?xNY{K{lk;j=I^`O*|eL6<9h?!NH^xDO}wvnsib1K-EckV zi?O}ZX%rMQvrE^K+0xFDF`};KL)feS4lC_T+Sw#chQB&Kt?d%YPzaxgyg**W;SPKvW-vp+F?E5-C2iF)l* zWzxX<18R@6drY1N*gQSDwbu__thAOWluGMK-j4J3G;b$(dxp1X zdHW=9pW^M)ynTkZn1xC!=C{)NEN?OGmDcBZ`vPyV&MK`~yOq}S)Y6R4eBy7kzG4HF z*0+exW*}U=R;g4nc;s6AJ-EH#E`#d>_bYIChF*LH+(~dh1~&`td*FTmZVp@--1FcT zz&!)*O>k$x{TW;dTpdl;Vh-F^a3kQ_z*`#Vn`Lv|v3YIA;#;BE5b7qm58C7~*9g~WgyrqvwNmVKq)RdOi)DcN3 zN{S?Y&1mVWVtc@gq-G1|SXNbX^t&f*={{$Qq~}Mql%h*{15v1kmXb~=x}~yIK9|-; z8R>NT<&{i5UfiSY-aBUOmQzn8gIIb1fmkWCEns->0hZEL#gGE>1N_R;no%@GwACx5 zi=sevx>WAcGSt&pQ9<@|Z$mI%iFP}A6o>FyvhhiAY7%sj#7H&y)J5>}v zrM1U@|L!4*dJYe>RKR1QHqaAxv-^}C8HO=E*#7p|I=EZ@?Griq1r{kqBhiNX4YQuSdM}Ca=hP2I8Rdx1ryzPNvW0S|mU;}MuQ)nLpFfar))Ue>QZ=0~2q~rDQN_>{%I9O6 znRz7nRXVmqw>e?ZZ!H@@{BoqZlP1kbDMdAvEs)475sXZqbkrTPaw${G=h*hNMkj3Q zaZ5AQ5v8D=P>mwwbn-jbOb1I7c(*;*{3g98W$gW{4R~|CohrwWQQ>DyMBP&-->Y&6 z8cFMY$AQlWfG5P+72Y)y^!o94vwr+=K(7SwaTik;x10&!7X$eF0sKk;|2lyG5Ws&8 z;0TTE{*i*p<^aY)tzRz%@U{TPiND{zCxDN*csch&0gUe)@S+3X>};e;Z{_*707y5E z%5I^GIfzniqPm6ZN2%go$0Xn!5zaBm_)b840!{s#yu*x#5y;C@<-Xehi z`QCuWe^ad3tVpoRHbt764GOq+Ya)q%Q*vQ-J96=gjmQ;?Er@{Fd|VFOj?3{4hqLZh X!&z^W;lSHoI1u}a|88HgWi$3~)uY>q literal 9832 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 delta 33 mcmZp0X>eJ<$YTBPQ|M$CMjxgvZ#D-pCP{(?Ht&$~U! delta 32 lcmZqhXz-ZugT. +% +% $Id$ + +global ft_default + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% determine who is calling + +stack = dbstack('-completenames'); +% st(1) is this function +% st(2) is the calling function +switch stack(2).name + case 'ft_debug' + level = 'debug'; + case 'ft_info' + level = 'info'; + case 'ft_notice' + level = 'notice'; + case 'ft_warning' + level = 'warning'; + case 'ft_error' + level = 'error'; + otherwise + error('this function cannot be called from %s', stack(2).name); +end + +% remove this function itself and the ft_xxx calling function +stack = stack(3:end); + +% remove the non-FieldTrip functions from the path, these should not be part of the default message identifier +keep = true(size(stack)); +p = fileparts(which('ft_defaults')); +for i=1:numel(stack) + keep(i) = strncmp(p, stack(i).file, length(p)); +end +stack = stack(keep); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% handle the defaults + +if isfield(ft_default, 'notification') && isfield(ft_default.notification, level) + % this would be error, warning, notice, info, debug + s = ft_default.notification.(level); +else + s = []; +end + +% start with an empty state structure +if isempty(s) + s = struct('identifier', {}, 'state', {}, 'timestamp', {}); +end + +% set the default notification state +if ~ismember('all', {s.identifier}) + s = setstate(s, 'all', 'on'); +end + +% set the default backtrace state +defaultbacktrace = false; +if ~ismember('backtrace', {s.identifier}) + switch level + case {'debug' 'info' 'notice'} + s = setstate(s, 'backtrace', 'off'); + case 'warning' + defaultbacktrace = true; + t = warning('query', 'backtrace'); % get the default state + s = setstate(s, 'backtrace', t.state); + case 'error' + s = setstate(s, 'backtrace', 'on'); + end % switch +end + +% set the default verbose state +defaultverbose = false; +if ~ismember('verbose', {s.identifier}) + switch level + case 'warning' + defaultverbose = true; + t = warning('query', 'verbose');% get the default state + s = setstate(s, 'verbose', t.state); + otherwise + s = setstate(s, 'verbose', 'off'); + end +end + +% set the default timeout +if ~ismember('timeout', {s.identifier}) + s = setstate(s, 'timeout', 60); +end + +% set the last notification to empty +if ~ismember('last', {s.identifier}) + state.message = ''; + state.identifier = ''; + state.stack = struct('file', {}, 'name', {}, 'line', {}); + s = setstate(s, 'last', state); +end + +if strcmp(level, 'warning') + ws = warning; + % warnings should be on in general + warning on + % the backtrace is handled by this function + warning off backtrace + % the verbose message is handled by this function + warning off verbose +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% set the notification state according to the input + +if numel(varargin)>0 && (isstruct(varargin{1}) || isempty(varargin{1})) + ft_default.notification.(level) = varargin{1}; + return +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% act according to the first input argument + +if isempty(varargin) + varargin{1} = 'query'; +end + +switch varargin{1} + case 'on' + if numel(varargin)>1 + % switch a specific item on + msgId = varargin{2}; + s = setstate(s, msgId, 'on'); + if strcmp(msgId, 'backtrace') + defaultbacktrace = false; + end + if strcmp(msgId, 'verbose') + defaultverbose = false; + end + % return the message state of all + varargout{1} = getreturnstate(s, msgId); + else + % switch all on + s = setstate(s, 'all', 'on'); + % return the message state of all + varargout{1} = getreturnstate(s); + end + + case 'off' + if numel(varargin)>1 + % switch a specific item off + msgId = varargin{2}; + s = setstate(s, msgId, 'off'); + if strcmp(msgId, 'backtrace') + defaultbacktrace = false; + end + if strcmp(msgId, 'verbose') + defaultverbose = false; + end + % return the specific message state + varargout{1} = getreturnstate(s, msgId); + else + % switch all off + s = setstate(s, 'all', 'off'); + % return the message state of all + varargout{1} = getreturnstate(s); + end + + case 'once' + if numel(varargin)>1 + % switch a specific item to once + msgId = varargin{2}; + s = setstate(s, msgId, 'once'); + % return the specific message state + varargout{1} = getreturnstate(s, msgId); + else + % switch all to once + s = setstate(s, 'all', 'once'); + % return the message state of all + varargout{1} = getreturnstate(s); + end + + case 'timeout' + % set the timeout, this is used for 'once' + if ischar(varargin{2}) + s = setstate(s, 'timeout', str2double(varargin{2})); + else + s = setstate(s, 'timeout', varargin{2}); + end + + case {'last' '-last'} + % return the last notification + varargout{1} = getstate(s, 'last'); + + case {'clear' '-clear'} + % reset the notification system + s = []; + + case {'query' '-query'} + if numel(varargin)>1 + % select a specific item + msgId = varargin{2}; + if ~ismember(msgId, {s.identifier}) + error('Unknown setting or incorrect message identifier ''%s''.', msgId); + end + msgState = getstate(s, msgId); + if nargout + varargout{1} = getreturnstate(s, msgId); + elseif strcmp(msgId, 'verbose') + if istrue(msgState) + fprintf('%s output is verbose.\n', level); + else + fprintf('%s output is terse.\n', level); + end + elseif strcmp(msgId, 'backtrace') + if istrue(msgState) + fprintf('%s backtraces are enabled.\n', level); + else + fprintf('%s backtraces are disabled.\n', level); + end + else + fprintf('The state of %s ''%s'' is ''%s''\n', level, msgId, msgState); + end + else + % return all items + r = getreturnstate(s); + + if nargout + % return the state of all items + varargout{1} = r; + else + % show the state of all items that are different from the default + default = getstate(s, 'all'); + fprintf('The default %s state is ''%s''.', level, default); + r = r(~strcmp({r.state}, default)); + % don't show these + r(strcmp('verbose', {r.identifier})) = []; + r(strcmp('backtrace', {r.identifier})) = []; + if ~isempty(r) + fprintf(' Items not set to the default are\n\n'); + end + for i=1:numel(r) + fprintf(' %4s %s\n', r(i).state, r(i).identifier); + end + fprintf('\n'); + end + end + + otherwise + + if nargout + varargout{1} = getreturnstate(s); + end + + % first input might be msgId + if numel(varargin)>1 && ~isempty(regexp(varargin{1}, '^\w*:', 'once')) + msgId = varargin{1}; + varargin = varargin(2:end); % shift them all by one + else + msgId = defaultId; + end + + % get the state for this notification, it will default to the 'all' state + msgState = getstate(s, msgId); + + % errors are always to be printed + if strcmp(level, 'error') + msgState = 'on'; + end + + if strcmp(msgState, 'once') + timeout = getstate(s, 'timeout'); + since = elapsed(gettimestamp(s, msgId)); + if (since>timeout) + % the timeout has passed, update the timestamp and print the message + s = settimestamp(s, msgId, tic); + msgState = 'on'; + else + % the timeout has not yet passed, do not print the message + msgState = 'off'; + end + end + + % use an automatically generated default identifier + if isempty(msgId) + msgId = defaultId; + end + + % store the last notification + state.message = strtrim(sprintf(varargin{:})); % remove the trailing newline + state.identifier = msgId; + state.stack = stack; + s = setstate(s, 'last', state); + + if strcmp(msgState, 'on') + + if strcmp(level, 'error') + % update the global variable, we won't return here after the error + ft_default.notification.(level) = s; + % the remainder is fully handled by the ERROR function + if ~isempty(msgId) + error(msgId, varargin{:}); + else + error(varargin{:}); + end + + elseif strcmp(level, 'warning') + if ~isempty(msgId) + warning(msgId, varargin{:}); + else + warning(varargin{:}); + end + + else + % ensure there is a line end + if isempty(regexp(varargin{1}, '\\n$', 'once')) % note the double \\ + varargin{1} = [varargin{1} '\n']; + end + fprintf(varargin{:}); + + end % if level=error, warning or otherwise + + % decide whether the stack trace should be shown + if istrue(getstate(s, 'backtrace')) + for i=1:numel(stack) + % show the deepest and lowest-level function first + [p, f, x] = fileparts(stack(i).file); + if isequal(f, stack(i).name) + funname = stack(i).name; + else + funname = sprintf('%s>%s', f, stack(i).name); + end + filename = stack(i).file; + if isempty(fileparts(filename)) + % it requires the full path + filename = fullfile(pwd, filename); + end + if ft_platform_supports('html') + fprintf(' In %s at line %d\n', filename, stack(i).line, funname, stack(i).line); + else + fprintf(' In ''%s'' at line %d\n', filename, stack(i).line); + end + end + fprintf('\n'); + end + + % decide whether a verboe message should be shown + if istrue(getstate(s, 'verbose')) + if ~isempty(msgId) + fprintf('Type "ft_%s off %s" to suppress this message.\n', level, msgId) + else + fprintf('Type "ft_%s off" to suppress this message.\n', level) + end + end + + end % if msgState is on + +end % switch varargin{1} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% update the global variable +if defaultbacktrace && ~isempty(s) + % do not keep the default, it will be determined again on the next call + s = s(~strcmp({s.identifier}, 'backtrace')); +end +if defaultverbose && ~isempty(s) + % do not keep the default, it will be determined again on the next call + s = s(~strcmp({s.identifier}, 'verbose')); +end +ft_default.notification.(level) = s; + +if strcmp(level, 'warning') + % return to the original warning state + warning(ws); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTIONS +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +function r = getreturnstate(s, msgId) +if nargin<2 + r = s; + % don't return these + r(strcmp('timeout', {r.identifier})) = []; + r(strcmp('last', {r.identifier})) = []; + % don't return the timestamps + r = rmfield(r, 'timestamp'); +else + msgState = getstate(s, msgId); + r = struct('identifier', msgId, 'state', msgState); +end + +function state = getstate(s, msgId) +identifier = {s.identifier}; +sel = find(strcmp(identifier, msgId)); +if numel(sel)==1 + state = s(sel).state; + if isempty(state) + state = getstate(s, 'all'); + end +else + state = getstate(s, 'all'); +end + +function timestamp = gettimestamp(s, msgId) +identifier = {s.identifier}; +sel = find(strcmp(identifier, msgId)); +if numel(sel)==1 + timestamp = s(sel).timestamp; +else + timestamp = nan; +end + +function s = setstate(s, msgId, state) +if isempty(msgId), return; end % this happens from the command line +identifier = {s.identifier}; +sel = find(strcmp(identifier, msgId)); +if numel(sel)==1 + s(sel).state = state; +else + s(end+1).identifier = msgId; + s(end ).state = state; + s(end ).timestamp = nan; +end + +function s = settimestamp(s, msgId, timestamp) +if isempty(msgId), return; end % this happens from the command line +identifier = {s.identifier}; +sel = find(strcmp(identifier, msgId)); +if numel(sel)==1 + s(sel).timestamp = timestamp; +else + s(end+1).identifier = msgId; + s(end ).state = []; + s(end ).timestamp = timestamp; +end + +function t = elapsed(start) +if isempty(start) || isnan(start) + t = inf; +else + t = toc(start); +end diff --git a/external/fieldtrip/private/ft_platform_supports.m b/external/fieldtrip/connectivity/private/ft_platform_supports.m similarity index 56% rename from external/fieldtrip/private/ft_platform_supports.m rename to external/fieldtrip/connectivity/private/ft_platform_supports.m index 0770d385..c0676b62 100644 --- a/external/fieldtrip/private/ft_platform_supports.m +++ b/external/fieldtrip/connectivity/private/ft_platform_supports.m @@ -3,41 +3,43 @@ % FT_PLATFORM_SUPPORTS returns a boolean indicating whether the current platform % supports a specific capability % -% Usage: -% tf = ft_platform_supports(what) -% tf = ft_platform_supports('matlabversion', min_version, max_version) +% Use as +% status = ft_platform_supports(what) +% or +% status = ft_platform_supports('matlabversion', min_version, max_version) % -% The following values are allowed for the 'what' parameter: -% value means that the following is supported: +% The following values are allowed for the 'what' parameter, which means means that +% the specific feature explained on the right is supported: % % 'which-all' which(...,'all') -% 'exists-in-private-directory' exists(...) will look in the /private -% subdirectory to see if a file exists +% 'exists-in-private-directory' exists(...) will look in the /private subdirectory to see if a file exists % 'onCleanup' onCleanup(...) % 'alim' alim(...) % 'int32_logical_operations' bitand(a,b) with a, b of type int32 % 'graphics_objects' graphics sysem is object-oriented -% 'libmx_c_interface' libmx is supported through mex in the -% C-language (recent Matlab versions only -% support C++) -% 'stats' all statistical functions in -% FieldTrip's external/stats directory +% 'libmx_c_interface' libmx is supported through mex in the C-language (recent MATLAB versions only support C++) +% 'images' all image processing functions in FieldTrip's external/images directory +% 'signal' all signal processing functions in FieldTrip's external/signal directory +% 'stats' all statistical functions in FieldTrip's external/stats directory % 'program_invocation_name' program_invocation_name() (GNU Octave) -% 'singleCompThread' start Matlab with -singleCompThread -% 'nosplash' -nosplash -% 'nodisplay' -nodisplay -% 'nojvm' -nojvm +% 'singleCompThread' start MATLAB with -singleCompThread +% 'nosplash' start MATLAB with -nosplash +% 'nodisplay' start MATLAB with -nodisplay +% 'nojvm' start MATLAB with -nojvm % 'no-gui' start GNU Octave with --no-gui % 'RandStream.setGlobalStream' RandStream.setGlobalStream(...) % 'RandStream.setDefaultStream' RandStream.setDefaultStream(...) % 'rng' rng(...) % 'rand-state' rand('state') % 'urlread-timeout' urlread(..., 'Timeout', t) -% 'griddata-vector-input' griddata(...,...,...,a,b) with a and b -% vectors -% 'griddata-v4' griddata(...,...,...,...,...,'v4'), -% that is v4 interpolation support +% 'griddata-vector-input' griddata(...,...,...,a,b) with a and b vectors +% 'griddata-v4' griddata(...,...,...,...,...,'v4') with v4 interpolation support % 'uimenu' uimenu(...) +% 'weboptions' weboptions(...) +% 'parula' parula(...) +% 'html' html rendering in desktop +% +% See also FT_VERSION, VERSION, VER, VERLESSTHAN if ~ischar(what) error('first argument must be a string'); @@ -60,30 +62,42 @@ tf = is_matlab(); case 'int32_logical_operations' - % earlier version of Matlab don't support bitand (and similar) + % earlier version of MATLAB don't support bitand (and similar) % operations on int32 - tf = is_octave() || ~matlabversion(-inf, '2012a'); + tf = is_octave() || ~matlabversion(-Inf, '2012a'); case 'graphics_objects' - % introduced in Matlab 2014b, graphics is handled through objects; + % introduced in MATLAB 2014b, graphics is handled through objects; % previous versions use numeric handles tf = is_matlab() && matlabversion('2014b', Inf); case 'libmx_c_interface' % removed after 2013b - tf = matlabversion(-Inf, '2013b'); + tf = is_matlab() && matlabversion(-Inf, '2013b'); + + case 'images' + root_dir = fileparts(which('ft_defaults')); + external_stats_dir = fullfile(root_dir, 'external', 'images'); + + tf = has_all_functions_in_dir(external_stats_dir, {}); + + case 'signal' + root_dir = fileparts(which('ft_defaults')); + external_stats_dir = fullfile(root_dir, 'external', 'signal'); + + tf = has_all_functions_in_dir(external_stats_dir, {}); case 'stats' - root_dir=fileparts(which('ft_defaults')); - external_stats_dir=fullfile(root_dir,'external','stats'); + root_dir = fileparts(which('ft_defaults')); + external_stats_dir = fullfile(root_dir, 'external', 'stats'); - % these files are only used by other functions in the external/stats - % directory - exclude_mfiles={'common_size.m',... - 'iscomplex.m',... - 'lgamma.m'}; + % these files are only used by other functions in the external/stats directory + exclude_mfiles = { + 'common_size.m' + 'iscomplex.m' + }; - tf = has_all_functions_in_dir(external_stats_dir,exclude_mfiles); + tf = has_all_functions_in_dir(external_stats_dir, exclude_mfiles); case 'program_invocation_name' % Octave supports program_invocation_name, which returns the path @@ -91,10 +105,10 @@ tf = is_octave(); case 'singleCompThread' - tf = is_matlab() && matlabversion(7.8, inf); + tf = is_matlab() && matlabversion(7.8, Inf); - case {'nosplash','nodisplay','nojvm'} - % Only on Matlab + case {'nosplash', 'nodisplay', 'nojvm'} + % Only on MATLAB tf = is_matlab(); case 'no-gui' @@ -105,31 +119,46 @@ tf = is_matlab() && matlabversion('2008b', '2011b'); case 'RandStream.setGlobalStream' - tf = is_matlab() && matlabversion('2012a', inf); + tf = is_matlab() && matlabversion('2012a', Inf); case 'randomized_PRNG_on_startup' - tf = is_octave() || ~matlabversion(-Inf,'7.3'); + tf = is_octave() || ~matlabversion(-Inf, '7.3'); case 'rng' - % recent Matlab versions - tf = is_matlab() && matlabversion('7.12',Inf); + % recent MATLAB versions + tf = is_matlab() && matlabversion('7.12', Inf); case 'rand-state' % GNU Octave tf = is_octave(); case 'urlread-timeout' - tf = is_matlab() && matlabversion('2012b',Inf); + tf = is_matlab() && matlabversion('2012b', Inf); case 'griddata-vector-input' tf = is_matlab(); case 'griddata-v4' - tf = is_matlab() && matlabversion('2009a',Inf); + tf = is_matlab() && matlabversion('2009a', Inf); case 'uimenu' tf = is_matlab(); + case {'weboptions', 'webread', 'websave'} + tf = is_matlab() && matlabversion('2014b', Inf); + + case 'webwrite' + tf = is_matlab() && matlabversion('2015a', Inf); + + case 'boundary' + tf = is_matlab() && matlabversion('2014b', Inf); + + case 'parula' + tf = is_matlab() && matlabversion('2014b', Inf); + + case 'html' + tf = ~is_octave() && usejava('desktop') && desktop('-inuse'); + otherwise error('unsupported value for first argument: %s', what); @@ -148,7 +177,7 @@ % SUBFUNCTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function tf = is_octave() -persistent cached_tf; +persistent cached_tf if isempty(cached_tf) cached_tf = logical(exist('OCTAVE_VERSION', 'builtin')); @@ -161,21 +190,19 @@ % SUBFUNCTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function tf = has_all_functions_in_dir(in_dir, exclude_mfiles) -% returns true if all functions in in_dir are already provided by the -% platform -m_files=dir(fullfile(in_dir,'*.m')); -n=numel(m_files); +% returns true if all functions in in_dir are already provided by the platform +m_files = dir(fullfile(in_dir,'*.m')); +n = numel(m_files); -for k=1:n - m_filename=m_files(k).name; - if isempty(which(m_filename)) && ... - isempty(strmatch(m_filename,exclude_mfiles)) - tf=false; +for k = 1:n + m_filename = m_files(k).name; + if isempty(which(m_filename)) && isempty(strmatch(m_filename,exclude_mfiles)) + tf = false; return; end end -tf=true; +tf = true; end % function @@ -187,19 +214,19 @@ % MATLABVERSION checks if the current MATLAB version is within the interval % specified by min and max. % -% Use, e.g., as: -% if matlabversion(7.0, 7.9) -% % do something -% end +% Use as +% if matlabversion(7.0, 7.9) +% % do something +% end % % Both strings and numbers, as well as infinities, are supported, eg.: -% matlabversion(7.1, 7.9) % is version between 7.1 and 7.9? -% matlabversion(6, '7.10') % is version between 6 and 7.10? (note: '7.10', not 7.10) -% matlabversion(-Inf, 7.6) % is version <= 7.6? -% matlabversion('2009b') % exactly 2009b -% matlabversion('2008b', '2010a') % between two versions -% matlabversion('2008b', Inf) % from a version onwards -% etc. +% matlabversion(7.1, 7.9) % is version between 7.1 and 7.9? +% matlabversion(6, '7.10') % is version between 6 and 7.10? (note: '7.10', not 7.10) +% matlabversion(-Inf, 7.6) % is version <= 7.6? +% matlabversion('2009b') % exactly 2009b +% matlabversion('2008b', '2010a') % between two versions +% matlabversion('2008b', Inf) % from a version onwards +% etc. % % See also VERSION, VER, VERLESSTHAN @@ -209,22 +236,22 @@ % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. % -% FieldTrip is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. % -% FieldTrip is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. % -% You should have received a copy of the GNU General Public License -% along with FieldTrip. If not, see . +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . % % $Id$ -% this does not change over subsequent calls, making it persistent speeds it up +% the version does not change, making it persistent speeds up the subsequent calls persistent curVer if nargin<2 @@ -245,7 +272,9 @@ [maxY, maxAb] = parseMatlabRelease(max); inInterval = orderedComparison(minY, minAb, maxY, maxAb, year, ab); -else % perform comparison with respect to version number + +else + % perform comparison with respect to version number [major, minor] = parseMatlabVersion(curVer); [minMajor, minMinor] = parseMatlabVersion(min); [maxMajor, maxMinor] = parseMatlabVersion(max); @@ -255,6 +284,9 @@ end % function +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function [year, ab] = parseMatlabRelease(str) if (str == Inf) year = Inf; ab = Inf; @@ -266,6 +298,9 @@ end end % function +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function [major, minor] = parseMatlabVersion(ver) if (ver == Inf) major = Inf; minor = Inf; @@ -279,10 +314,13 @@ major = str2num(major); minor = str2num(strtok(rest, '.')); end -end % function +end % function -% checks if testA is in interval (lowerA,upperA); if at edges, checks if testB is in interval (lowerB,upperB). +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function inInterval = orderedComparison(lowerA, lowerB, upperA, upperB, testA, testB) +% checks if testA is in interval (lowerA,upperA); if at edges, checks if testB is in interval (lowerB,upperB). if (testA < lowerA || testA > upperA) inInterval = false; else @@ -295,5 +333,4 @@ inInterval = inInterval && (testB <= upperB); end end -end % function - +end % function diff --git a/external/fieldtrip/connectivity/private/ft_progress.m b/external/fieldtrip/connectivity/private/ft_progress.m index 559686aa..d7dce75e 100644 --- a/external/fieldtrip/connectivity/private/ft_progress.m +++ b/external/fieldtrip/connectivity/private/ft_progress.m @@ -27,6 +27,8 @@ function ft_progress(varargin) % pause(0.1); % end % ft_progress('close') +% +% See also WAITBAR % Copyright (C) 2004-2008, Robert Oostenveld % diff --git a/external/fieldtrip/connectivity/private/ft_warning.m b/external/fieldtrip/connectivity/private/ft_warning.m index 18b0ce00..58f3985e 100644 --- a/external/fieldtrip/connectivity/private/ft_warning.m +++ b/external/fieldtrip/connectivity/private/ft_warning.m @@ -1,39 +1,40 @@ -function [ws, warned] = ft_warning(varargin) +function varargout = ft_warning(varargin) -% FT_WARNING will throw a warning for every unique point in the -% stacktrace only, e.g. in a for-loop a warning is thrown only once. +% FT_WARNING prints a warning message on screen, depending on the verbosity +% settings of the calling high-level FieldTrip function. This function works +% similar to the standard WARNING function, but also features the "once" mode. % -% Use as one of the following -% ft_warning(string) -% ft_warning(id, string) -% Alternatively, you can use ft_warning using a timeout -% ft_warning(string, timeout) -% ft_warning(id, string, timeout) -% where timeout should be inf if you don't want to see the warning ever -% again. +% Use as +% ft_warning(...) +% with arguments similar to fprintf, or +% ft_warning(msgId, ...) +% with arguments similar to warning. % -% Use as ft_warning('-clear') to clear old warnings from the current -% stack +% You can switch of all warning messages using +% ft_warning off +% or for specific ones using +% ft_warning off msgId % -% It can be used instead of the MATLAB built-in function WARNING, thus as -% s = ft_warning(...) -% or as -% ft_warning(s) -% where s is a structure with fields 'identifier' and 'state', storing the -% state information. In other words, ft_warning accepts as an input the -% same structure it returns as an output. This returns or restores the -% states of warnings to their previous values. +% To switch them back on, you would use +% ft_warning on +% or for specific ones using +% ft_warning on msgId +% +% Warning messages are only printed once per timeout period using +% ft_warning timeout 60 +% ft_warning once +% or for specific ones using +% ft_warning once msgId % -% It can also be used as -% [s w] = ft_warning(...) -% where w is a boolean that indicates whether a warning as been thrown or not. +% You can see the most recent messages and identifier using +% ft_warning last % -% Please note that you can NOT use it like this -% ft_warning('the value is %d', 10) -% instead you should do -% ft_warning(sprintf('the value is %d', 10)) +% You can query the current on/off/once state for all messages using +% ft_warning query +% +% See also FT_ERROR, FT_WARNING, FT_NOTICE, FT_warning, FT_DEBUG, ERROR, WARNING -% Copyright (C) 2012-2016, Robert Oostenveld, J?rn M. Horschig +% Copyright (C) 2012-2017, Robert Oostenveld, J?rn M. Horschig % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -53,205 +54,12 @@ % % $Id$ -global ft_default -warned = false; -ws = []; - -stack = dbstack; -if any(strcmp({stack(2:end).file}, 'ft_warning.m')) - % don't call FT_WARNING recursively, see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=3068 - return; -end - -if nargin < 1 - error('You need to specify at least a warning message'); -end - -if isstruct(varargin{1}) - warning(varargin{1}); - return; -end - -if ~isfield(ft_default, 'warning') - ft_default.warning = []; -end -if ~isfield(ft_default.warning, 'stopwatch') - ft_default.warning.stopwatch = []; -end -if ~isfield(ft_default.warning, 'identifier') - ft_default.warning.identifier = []; -end -if ~isfield(ft_default.warning, 'ignore') - ft_default.warning.ignore = {}; -end - -% put the arguments we will pass to warning() in this cell array -warningArgs = {}; - -if nargin==3 - % calling syntax (id, msg, timeout) - - warningArgs = varargin(1:2); - msg = warningArgs{2}; - timeout = varargin{3}; - fname = [warningArgs{1} '_' warningArgs{2}]; - -elseif nargin==2 && isnumeric(varargin{2}) - % calling syntax (msg, timeout) - - warningArgs = varargin(1); - msg = warningArgs{1}; - timeout = varargin{2}; - fname = warningArgs{1}; - -elseif nargin==2 && isequal(varargin{1}, 'off') - - ft_default.warning.ignore = union(ft_default.warning.ignore, varargin{2}); - return - -elseif nargin==2 && isequal(varargin{1}, 'on') - - ft_default.warning.ignore = setdiff(ft_default.warning.ignore, varargin{2}); - return - -elseif nargin==2 && ~isnumeric(varargin{2}) - % calling syntax (id, msg) - - warningArgs = varargin(1:2); - msg = warningArgs{2}; - timeout = inf; - fname = [warningArgs{1} '_' warningArgs{2}]; - -elseif nargin==1 - % calling syntax (msg) - - warningArgs = varargin(1); - msg = warningArgs{1}; - timeout = inf; % default timeout in seconds - fname = [warningArgs{1}]; - -end - -if ismember(msg, ft_default.warning.ignore) - % do not show this warning - return; -end - -if isempty(timeout) - error('Timeout ill-specified'); -end - -if timeout ~= inf - fname = fixname(fname); % make a nice string that is allowed as fieldname in a structures - line = []; -else - % here, we create the fieldname functionA.functionB.functionC... - [tmpfname, ft_default.warning.identifier, line] = fieldnameFromStack(ft_default.warning.identifier); - if ~isempty(tmpfname), - fname = tmpfname; - clear tmpfname; - end -end - -if nargin==1 && ischar(varargin{1}) && strcmp('-clear', varargin{1}) - if strcmp(fname, '-clear') % reset all fields if called outside a function - ft_default.warning.identifier = []; - ft_default.warning.stopwatch = []; - else - if issubfield(ft_default.warning.identifier, fname) - ft_default.warning.identifier = rmsubfield(ft_default.warning.identifier, fname); - end - end - return; -end - -% and add the line number to make this unique for the last function -fname = horzcat(fname, line); - -if ~issubfield('ft_default.warning.stopwatch', fname) - ft_default.warning.stopwatch = setsubfield(ft_default.warning.stopwatch, fname, tic); -end - -now = toc(getsubfield(ft_default.warning.stopwatch, fname)); % measure time since first function call - -if ~issubfield(ft_default.warning.identifier, fname) || ... - (issubfield(ft_default.warning.identifier, fname) && now>getsubfield(ft_default.warning.identifier, [fname '.timeout'])) - - % create or reset field - ft_default.warning.identifier = setsubfield(ft_default.warning.identifier, fname, []); - - % warning never given before or timed out - ws = warning(warningArgs{:}); - ft_default.warning.identifier = setsubfield(ft_default.warning.identifier, [fname '.timeout'], now+timeout); - ft_default.warning.identifier = setsubfield(ft_default.warning.identifier, [fname '.ws'], msg); - warned = true; +if nargout + varargout{:} = ft_notification(varargin{:}); +elseif isequal(varargin, {'last'}) + % return an answer anyway + varargout{1} = ft_notification(varargin{:}); else - - % the warning has been issued before, but has not timed out yet - ws = getsubfield(ft_default.warning.identifier, [fname '.ws']); - -end - -end % function ft_warning - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% helper functions -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -function [fname, ft_previous_warnings, line] = fieldnameFromStack(ft_previous_warnings) -% stack(1) is this function, stack(2) is ft_warning -stack = dbstack('-completenames'); -if size(stack) < 3 - fname = []; - line = []; - return; -end -i0 = 3; -% ignore ft_preamble -while strfind(stack(i0).name, 'ft_preamble') - i0=i0+1; + ft_notification(varargin{:}); end -fname = horzcat(fixname(stack(end).name)); -if ~issubfield(ft_previous_warnings, fixname(stack(end).name)) - ft_previous_warnings.(fixname(stack(end).name)) = []; % iteratively build up structure fields -end - - -for i=numel(stack)-1:-1:(i0) - % skip postamble scripts - if strncmp(stack(i).name, 'ft_postamble', 12) - break; - end - - fname = horzcat(fname, '.', horzcat(fixname(stack(i).name))); % , stack(i).file - if ~issubfield(ft_previous_warnings, fname) % iteratively build up structure fields - setsubfield(ft_previous_warnings, fname, []); - end -end - -% line of last function call -line = ['.line', int2str(stack(i0).line)]; -end - -% function outcome = issubfield(strct, fname) -% substrindx = strfind(fname, '.'); -% if numel(substrindx) > 0 -% % separate the last fieldname from all former -% outcome = eval(['isfield(strct.' fname(1:substrindx(end)-1) ', ''' fname(substrindx(end)+1:end) ''')']); -% else -% % there is only one fieldname -% outcome = isfield(strct, fname); -% end -% end - -% function strct = rmsubfield(strct, fname) -% substrindx = strfind(fname, '.'); -% if numel(substrindx) > 0 -% % separate the last fieldname from all former -% strct = eval(['rmfield(strct.' fname(1:substrindx(end)-1) ', ''' fname(substrindx(end)+1:end) ''')']); -% else -% % there is only one fieldname -% strct = rmfield(strct, fname); -% end -% end diff --git a/external/fieldtrip/connectivity/private/inv2x2.m b/external/fieldtrip/connectivity/private/inv2x2.m index f15d80a1..388940d7 100644 --- a/external/fieldtrip/connectivity/private/inv2x2.m +++ b/external/fieldtrip/connectivity/private/inv2x2.m @@ -32,11 +32,11 @@ adjx = [ det2x2(x([2 3],[2 3],:,:)) -det2x2(x([1 3],[2 3],:,:)) det2x2(x([1 2],[2 3],:,:)); ... -det2x2(x([2 3],[1 3],:,:)) det2x2(x([1 3],[1 3],:,:)) -det2x2(x([1 2],[1 3],:,:)); ... det2x2(x([2 3],[1 2],:,:)) -det2x2(x([1 3],[1 2],:,:)) det2x2(x([1 2],[1 2],:,:))]; - denom = det2x2(x); + denom = det3x3(x); d = adjx./denom([1 1 1],[1 1 1],:,:); elseif numel(siz)==2, d = inv(x); else - error('cannot compute slicewise inverse'); + ft_error('cannot compute slicewise inverse'); % write for loop for the higher dimensions, using normal inv end diff --git a/external/fieldtrip/connectivity/private/inv3x3.m b/external/fieldtrip/connectivity/private/inv3x3.m new file mode 100644 index 00000000..c378966d --- /dev/null +++ b/external/fieldtrip/connectivity/private/inv3x3.m @@ -0,0 +1,36 @@ +function d = inv3x3(x) + +% INV3X3 computes inverse of matrix x, using explicit analytic definition +% if size(x) = [3 3 K M] + +% Copyright (C) 2012, Donders Centre for Cognitive Neuroimaging, Nijmegen, NL +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +siz = size(x); +if all(siz(1:2)==3), + adjx = [ det2x2(x([2 3],[2 3],:,:)) -det2x2(x([1 3],[2 3],:,:)) det2x2(x([1 2],[2 3],:,:)); ... + -det2x2(x([2 3],[1 3],:,:)) det2x2(x([1 3],[1 3],:,:)) -det2x2(x([1 2],[1 3],:,:)); ... + det2x2(x([2 3],[1 2],:,:)) -det2x2(x([1 3],[1 2],:,:)) det2x2(x([1 2],[1 2],:,:))]; + denom = det3x3(x); + d = adjx./denom([1 1 1],[1 1 1],:,:); +else + ft_error('cannot compute slicewise inverse'); + % write for loop for the higher dimensions, using normal inv +end diff --git a/external/fieldtrip/connectivity/private/istrue.m b/external/fieldtrip/connectivity/private/istrue.m new file mode 100644 index 00000000..742a0997 --- /dev/null +++ b/external/fieldtrip/connectivity/private/istrue.m @@ -0,0 +1,42 @@ +function y = istrue(x) + +% ISTRUE converts an input argument like "yes/no", "true/false" or "on/off" into a +% boolean. If the input is boolean, then it will remain like that. + +% Copyright (C) 2009-2012, Robert Oostenveld +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +true_list = {'yes' 'true' 'on' 'y' }; +false_list = {'no' 'false' 'off' 'n' 'none'}; + +if ischar(x) + % convert string to boolean value + if any(strcmpi(x, true_list)) + y = true; + elseif any(strcmpi(x, false_list)) + y = false; + else + error('cannot determine whether "%s" should be interpreted as true or false', x); + end +else + % convert numerical value to boolean + y = logical(x); +end + diff --git a/external/fieldtrip/connectivity/private/keyval.m b/external/fieldtrip/connectivity/private/keyval.m index b176ce8d..0043c72b 100644 --- a/external/fieldtrip/connectivity/private/keyval.m +++ b/external/fieldtrip/connectivity/private/keyval.m @@ -44,7 +44,7 @@ end if mod(length(varargin),2) - error('optional input arguments should come in key-value pairs, i.e. there should be an even number'); + ft_error('optional input arguments should come in key-value pairs, i.e. there should be an even number'); end % the 1st, 3rd, etc. contain the keys, the 2nd, 4th, etc. contain the values @@ -58,7 +58,7 @@ end if ~all(valid) - error('optional input arguments should come in key-value pairs, the optional input argument %d is invalid (should be a string)', i); + ft_error('optional input arguments should come in key-value pairs, the optional input argument %d is invalid (should be a string)', i); end hit = find(strcmpi(key, keys)); @@ -69,7 +69,7 @@ % the requested key was found val = vals{hit}; else - error('multiple input arguments with the same name'); + ft_error('multiple input arguments with the same name'); end if nargout>1 diff --git a/external/fieldtrip/connectivity/private/mtimes3x3.m b/external/fieldtrip/connectivity/private/mtimes3x3.m new file mode 100644 index 00000000..b6f9a420 --- /dev/null +++ b/external/fieldtrip/connectivity/private/mtimes3x3.m @@ -0,0 +1,36 @@ +function z = mtimes3x3(x, y) + +% MTIMES3X3 compute x*y where the dimensionatity is 3x3xN or 3x3xNxM + +% Copyright (C) 2017, Donders Centre for Cognitive Neuroimaging, Nijmegen, NL +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +z = complex(zeros(size(x))); +%xconj = conj(x); + +z(1,1,:,:) = x(1,1,:,:).*y(1,1,:,:) + x(1,2,:,:).*y(2,1,:,:) + x(1,3,:,:).*y(3,1,:,:); +z(1,2,:,:) = x(1,1,:,:).*y(1,2,:,:) + x(1,2,:,:).*y(2,2,:,:) + x(1,3,:,:).*y(3,2,:,:); +z(1,3,:,:) = x(1,1,:,:).*y(1,3,:,:) + x(1,2,:,:).*y(2,3,:,:) + x(1,3,:,:).*y(3,3,:,:); +z(2,1,:,:) = x(2,1,:,:).*y(1,1,:,:) + x(2,2,:,:).*y(2,1,:,:) + x(2,3,:,:).*y(3,1,:,:); +z(2,2,:,:) = x(2,1,:,:).*y(1,2,:,:) + x(2,2,:,:).*y(2,2,:,:) + x(2,3,:,:).*y(3,2,:,:); +z(2,3,:,:) = x(2,1,:,:).*y(1,3,:,:) + x(2,2,:,:).*y(2,3,:,:) + x(2,3,:,:).*y(3,3,:,:); +z(3,1,:,:) = x(3,1,:,:).*y(1,1,:,:) + x(3,2,:,:).*y(2,1,:,:) + x(3,3,:,:).*y(3,1,:,:); +z(3,2,:,:) = x(3,1,:,:).*y(1,2,:,:) + x(3,2,:,:).*y(2,2,:,:) + x(3,3,:,:).*y(3,2,:,:); +z(3,3,:,:) = x(3,1,:,:).*y(1,3,:,:) + x(3,2,:,:).*y(2,3,:,:) + x(3,3,:,:).*y(3,3,:,:); diff --git a/external/fieldtrip/connectivity/private/sandwich3x3.m b/external/fieldtrip/connectivity/private/sandwich3x3.m new file mode 100644 index 00000000..75ada72a --- /dev/null +++ b/external/fieldtrip/connectivity/private/sandwich3x3.m @@ -0,0 +1,95 @@ +function z = sandwich3x3(x, y) + +% SANDWICH3X3 compute x*y*x' provided y is Hermitian and dimensionality is 3x3xN + +% Copyright (C) 2017, Donders Centre for Cognitive Neuroimaging, Nijmegen, NL +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +% FIXME build in check for hermitianity +z = complex(zeros(size(x))); +xconj = conj(x); +xabs2 = abs(x).^2; + +z(1,1,:,:) = xabs2(1,1,:,:).*y(1,1,:,:) + ... + xabs2(1,2,:,:).*y(2,2,:,:) + ... + xabs2(1,3,:,:).*y(3,3,:,:) + ... + 2.*real( x(1,2,:,:).*y(2,1,:,:).*xconj(1,1,:,:) ) + ... + 2.*real( x(1,3,:,:).*y(3,1,:,:).*xconj(1,1,:,:) ) + ... + 2.*real( x(1,3,:,:).*y(3,2,:,:).*xconj(1,2,:,:) ); + + %(x(1,2,:,:).*y(2,1,:,:) + x(1,3,:,:).*y(3,1,:,:)).*xconj(1,1,:,:) + ... + %(x(1,1,:,:).*y(1,2,:,:) + x(1,3,:,:).*y(3,2,:,:)).*xconj(1,2,:,:) + ... + %(x(1,1,:,:).*y(1,3,:,:) + x(1,2,:,:).*y(2,3,:,:)).*xconj(1,3,:,:); + +z(2,1,:,:) = (x(2,1,:,:).*y(1,1,:,:) + x(2,2,:,:).*y(2,1,:,:) + x(2,3,:,:).*y(3,1,:,:)).*xconj(1,1,:,:) + ... + (x(2,1,:,:).*y(1,2,:,:) + x(2,2,:,:).*y(2,2,:,:) + x(2,3,:,:).*y(3,2,:,:)).*xconj(1,2,:,:) + ... + (x(2,1,:,:).*y(1,3,:,:) + x(2,2,:,:).*y(2,3,:,:) + x(2,3,:,:).*y(3,3,:,:)).*xconj(1,3,:,:); + +z(3,1,:,:) = (x(3,1,:,:).*y(1,1,:,:) + x(3,2,:,:).*y(2,1,:,:) + x(3,3,:,:).*y(3,1,:,:)).*xconj(1,1,:,:) + ... + (x(3,1,:,:).*y(1,2,:,:) + x(3,2,:,:).*y(2,2,:,:) + x(3,3,:,:).*y(3,2,:,:)).*xconj(1,2,:,:) + ... + (x(3,1,:,:).*y(1,3,:,:) + x(3,2,:,:).*y(2,3,:,:) + x(3,3,:,:).*y(3,3,:,:)).*xconj(1,3,:,:); + +z(1,2,:,:) = conj(z(2,1,:,:)); + +z(2,2,:,:) = xabs2(2,1,:,:).*y(1,1,:,:) + ... + xabs2(2,2,:,:).*y(2,2,:,:) + ... + xabs2(2,3,:,:).*y(3,3,:,:) + ... + 2.*real( x(2,2,:,:).*y(2,1,:,:).*xconj(2,1,:,:) ) + ... + 2.*real( x(2,3,:,:).*y(3,1,:,:).*xconj(2,1,:,:) ) + ... + 2.*real( x(2,3,:,:).*y(3,2,:,:).*xconj(2,2,:,:) ); + + %(x(2,2,:,:).*y(2,1,:,:) + x(2,3,:,:).*y(3,1,:,:)).*xconj(2,1,:,:) + ... + %(x(2,1,:,:).*y(1,2,:,:) + x(2,3,:,:).*y(3,2,:,:)).*xconj(2,2,:,:) + ... + %(x(2,1,:,:).*y(1,3,:,:) + x(2,2,:,:).*y(2,3,:,:)).*xconj(2,3,:,:); + +z(3,2,:,:) = (x(3,1,:,:).*y(1,1,:,:) + x(3,2,:,:).*y(2,1,:,:) + x(3,3,:,:).*y(3,1,:,:)).*xconj(2,1,:,:) + ... + (x(3,1,:,:).*y(1,2,:,:) + x(3,2,:,:).*y(2,2,:,:) + x(3,3,:,:).*y(3,2,:,:)).*xconj(2,2,:,:) + ... + (x(3,1,:,:).*y(1,3,:,:) + x(3,2,:,:).*y(2,3,:,:) + x(3,3,:,:).*y(3,3,:,:)).*xconj(2,3,:,:); + +z(1,3,:,:) = conj(z(3,1,:,:)); + +z(2,3,:,:) = conj(z(3,2,:,:)); + +z(3,3,:,:) = xabs2(3,1,:,:).*y(1,1,:,:) + ... + xabs2(3,2,:,:).*y(2,2,:,:) + ... + xabs2(3,3,:,:).*y(3,3,:,:) + ... + 2.*real( x(3,2,:,:).*y(2,1,:,:).*xconj(3,1,:,:) ) + ... + 2.*real( x(3,3,:,:).*y(3,1,:,:).*xconj(3,1,:,:) ) + ... + 2.*real( x(3,3,:,:).*y(3,2,:,:).*xconj(3,2,:,:) ); + + %(x(3,2,:,:).*y(2,1,:,:) + x(3,3,:,:).*y(3,1,:,:)).*xconj(3,1,:,:) + ... + %(x(3,1,:,:).*y(1,2,:,:) + x(3,3,:,:).*y(3,2,:,:)).*xconj(3,2,:,:) + ... + %(x(3,1,:,:).*y(1,3,:,:) + x(3,2,:,:).*y(2,3,:,:)).*xconj(3,3,:,:); +% +%b1 b2 b7 a1 a2' a4' b1' b3' b5' +%b3 b4 b8 a2 a3 a5' b2' b4' b6' +%b5 b6 b9 a4 a5 a6 b7' b8' b9' +% +%b1*a1+b2*a2+b7*a4 b1*a2'+b2*a3+b7*a5 b1*a4'+b2*a5'+b7*a6 b1' b3' b5' +%b3*a1+b4*a2+b8*a4 b3*a2'+b4*a3+b8*a5 b3*a4'+b4*a5'+b8*a6 b2' b4' b6' +%b5*a1+b6*a2+b9*a4 b5*a2'+b6*a3+b9*a5 b5*a4'+b6*a5'+b9*a6 b7' b8' b9' +% +% + +%b1*a1*b1'+b2*a2*b1'+b1*a2'*b2'+b2*a3*b2' b1*a1*b3'+b2*a2*b3'+b1*a2'*b4'+b2*a3*b4' +%b3*a1*b1'+b4*a2*b1'+b3*a2'*b2'+b4*a3*b2' b3*a1*b3'+b4*a2*b3'+b3*a2'*b4'+b4*a3*b4' +% +%a1*abs(b1)^2 + a2*(b1'*b2) + a2'*(b1*b2') + a3*abs(b2)^2 a1*b1*b3' + a2*b2*b3' + a2'*b1*b4' + a3*b2*b4' +%a1*b1'*b3 + a2*b1'*b4 + a2'*b2'*b3 + a3*b2'*b4 a1*abs(b3)^2 + a2*(b3'*b4) + a2'*(b3*b4') + a3*abs(b4)^2 diff --git a/external/fieldtrip/connectivity/private/sfactorization_wilson.m b/external/fieldtrip/connectivity/private/sfactorization_wilson.m index 24c63a4c..aee0dc3c 100644 --- a/external/fieldtrip/connectivity/private/sfactorization_wilson.m +++ b/external/fieldtrip/connectivity/private/sfactorization_wilson.m @@ -1,4 +1,4 @@ -function [H, Z, S, psi] = sfactorization_wilson(S,freq,Niterations,tol,fb,init,checkflag) +function [H, Z, S, psi] = sfactorization_wilson(S,freq,Niterations,tol,fb,init,checkflag,stabilityfix) % SFACTORIZATION_WILSON performs multivariate non-parametric spectral factorization on % cross-spectra, based on Wilson's algorithm. @@ -40,6 +40,7 @@ % % $Id$ +if nargin<8, stabilityfix = false; end if nargin<7, checkflag = true; end if nargin<6, init = 'chol'; end if nargin<5, fb = 'none'; end @@ -48,7 +49,7 @@ dfreq = round(diff(freq)*1e5)./1e5; % allow for some numeric issues if ~all(dfreq==dfreq(1)) - error('FieldTrip:connectivity:sfactorization_wilson', 'frequency axis is not evenly spaced'); + ft_error('FieldTrip:connectivity:sfactorization_wilson', 'frequency axis is not evenly spaced'); end if freq(1)~=0 @@ -118,7 +119,7 @@ case 'chol' [tmp, dum] = chol(gam0); if dum - warning('initialization with ''chol'' for iterations did not work well, using arbitrary starting condition'); + ft_warning('initialization with ''chol'' for iterations did not work well, using arbitrary starting condition'); tmp = randn(m,1000); %arbitrary initial condition tmp = (tmp*tmp')./1000; %tmp = triu(tmp); @@ -132,7 +133,7 @@ %tmp = triu(tmp); [tmp, dum] = chol(tmp); otherwise - error('initialization method should be eithe ''chol'' or ''rand'''); + ft_error('initialization method should be eithe ''chol'' or ''rand'''); end h = tmp; @@ -149,7 +150,7 @@ %invpsi = inv(psi(:,:,ind)); g(:,:,ind) = psi(:,:,ind)\Sarr(:,:,ind)/psi(:,:,ind)'+I;%Eq 3.1 end - gp = PlusOperator(g,m,N); %gp constitutes positive and half of zero lags + gp = PlusOperator(g,m,N,stabilityfix); %gp constitutes positive and half of zero lags psi_old = psi; for k = 1:N2 @@ -198,7 +199,7 @@ end %--------------------------------------------------------------------- -function gp = PlusOperator(g,nchan,nfreq) +function gp = PlusOperator(g,nchan,nfreq,stabilityfix) % This function is for [ ]+operation: % to take the positive lags & half of the zero lag and reconstitute @@ -214,6 +215,15 @@ gamp(1, :) = reshape(triu(reshape(beta0, [nchan nchan])),[1 nchan^2]); gamp(nfreq+1:end,:) = 0; +% smooth with a window, only for the long latency boundary: this is a +% stabilityfix proposed by Martin Vinck +if stabilityfix + w = tukeywin(nfreq*2, 0.5); + gamp(1:nfreq,:) = gamp(1:nfreq,:).*repmat(w(nfreq+1:end),[1 nchan^2]); +else + % nothing to be done here +end + % reconstituting gp = fft(gamp); gp = reshape(transpose(gp), [nchan nchan numel(gp)/(nchan^2)]); diff --git a/external/fieldtrip/connectivity/private/sfactorization_wilson2x2.m b/external/fieldtrip/connectivity/private/sfactorization_wilson2x2.m index 0e483b66..22062ce3 100644 --- a/external/fieldtrip/connectivity/private/sfactorization_wilson2x2.m +++ b/external/fieldtrip/connectivity/private/sfactorization_wilson2x2.m @@ -1,4 +1,4 @@ -function [H, Z, S, psi] = sfactorization_wilson2x2(S,freq,Niterations,tol,cmbindx,fb,init,checkflag) +function [H, Z, S, psi] = sfactorization_wilson2x2(S,freq,Niterations,tol,cmbindx,fb,init,checkflag,stabilityfix) % SFACTORIZATION_WILSON2X2 performs pairwise non-parametric spectral factorization on % cross-spectra, based on Wilson's algorithm. @@ -21,7 +21,7 @@ % Written by M. Dhamala & G. Rangarajan, UF, Aug 3-4, 2006. % Email addresses: mdhamala@bme.ufl.edu, rangaraj@math.iisc.ernet.in -% Copyright (C) 2009-2013, Jan-Mathijs Schoffelen +% Copyright (C) 2009-2017, Jan-Mathijs Schoffelen % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -41,18 +41,19 @@ % % $Id$ -if nargin<8, checkflag = true; end -if nargin<7, init = 'chol'; end -if nargin<6, fb = 'none'; end -if nargin<5, - error('FieldTrip:connectivity:sfactorization_wilson2x2', 'when requesting multiple pairwise spectral decomposition, ''cmbindx'' needs to be specified'); +if nargin<9 || isempty(stabilityfix), stabilityfix = false; end +if nargin<8 || isempty(checkflag), checkflag = true; end +if nargin<7 || isempty(init), init = 'chol'; end +if nargin<6 || isempty(fb), fb = 'none'; end +if nargin<5 || isempty(cmbindx) + ft_error('FieldTrip:connectivity:sfactorization_wilson2x2', 'when requesting multiple pairwise spectral decomposition, ''cmbindx'' needs to be specified'); end -if nargin<4, tol = 1e-8; end -if nargin<3, Niterations = 1000; end; +if nargin<4 || isempty(tol), tol = 1e-8; end +if nargin<3 || isempty(Niterations), Niterations = 1000; end; dfreq = round(diff(freq)*1e5)./1e5; % allow for some numeric issues if ~all(dfreq==dfreq(1)) - error('FieldTrip:connectivity:sfactorization_wilson2x2', 'frequency axis is not evenly spaced'); + ft_error('FieldTrip:connectivity:sfactorization_wilson2x2', 'frequency axis is not evenly spaced'); end if freq(1)~=0 @@ -91,34 +92,19 @@ % preallocate memory for the identity matrix I = repmat(eye(2),[1 1 m N2]); % Defining 2 x 2 identity matrix -% %Step 1: Forming 2-sided spectral densities for ifft routine in matlab -% Sarr = zeros(2,2,m,N2) + 1i.*zeros(2,2,m,N2); -% for c = 1:m -% Stmp = S(cmbindx(c,:),cmbindx(c,:),:); -% -% % the input cross-spectral density is assumed to be weighted with a -% % factor of 2 in all non-DC and Nyquist bins, therefore weight the -% % DC-bin with a factor of 2 to get a correct two-sided representation -% Sarr(:,:,c,1) = Stmp(:,:,1).*2; -% -% for f_ind = 2:N -% Sarr(:,:,c, f_ind) = Stmp(:,:,f_ind); -% Sarr(:,:,c,(N2+2)-f_ind) = Stmp(:,:,f_ind).'; -% end -% end -% Sarr2 = Sarr; - % preallocate memory for the 2-sided spectral density Sarr = zeros(2,2,N2,m) + 1i.*zeros(2,2,N2,m); + +% --- Step 1: Form 2-sided spectral densities for ifft routine in matlab for c = 1:m Sarr(:,:,1:N,c) = S(cmbindx(c,:),cmbindx(c,:),:); end -if hasnyq, +if hasnyq N1 = N; else N1 = N + 1; % the highest frequency needs to be represented twice, for symmetry purposes end -Sarr(:,:,N1:N2,:) = flipdim(Sarr(:,:,2:N,:),3); +Sarr(:,:,N1:N2,:) = flip(Sarr(:,:,2:N,:),3); Sarr(2,1,N1:N2,:) = conj(Sarr(2,1,N1:N2,:)); Sarr(1,2,N1:N2,:) = conj(Sarr(1,2,N1:N2,:)); Sarr = permute(Sarr, [1 2 4 3]); @@ -132,10 +118,10 @@ Sarr(:,:,:,N) = Sarr(:,:,:,N).*2; end -%Step 2: Computing covariance matrices +% --- Step 2: Compute covariance matrices gam = real(reshape(ifft(reshape(Sarr, [4*m N2]), [], 2),[2 2 m N2])); -%Step 3: Initializing for iterations +% --- Step 3: Initialize for iterations gam0 = gam(:,:,:,1); h = complex(zeros(size(gam0))); @@ -144,7 +130,7 @@ case 'chol' [tmp, dum] = chol(gam0(:,:,k)); if dum - warning('initialization with ''chol'' for iterations did not work well, using arbitrary starting condition'); + ft_warning('initialization with ''chol'' for iterations did not work well, using arbitrary starting condition'); tmp = rand(2,2); %arbitrary initial condition tmp = triu(tmp); end @@ -152,7 +138,7 @@ tmp = rand(2,2); %arbitrary initial condition tmp = triu(tmp); otherwise - error('initialization method should be eithe ''chol'' or ''rand'''); + ft_error('initialization method should be eithe ''chol'' or ''rand'''); end h(:,:,k) = tmp; @@ -160,21 +146,21 @@ end psi = repmat(h, [1 1 1 N2]); -%Step 4: Iterating to get spectral factors +% --- Step 4: Iterations to get spectral factors ft_progress('init', fb, 'computing spectral factorization'); for iter = 1:Niterations ft_progress(iter./Niterations, 'computing iteration %d/%d\n', iter, Niterations); invpsi = inv2x2(psi); g = sandwich2x2(invpsi, Sarr) + I; - gp = PlusOperator2x2(g,m,N); %gp constitutes positive and half of zero lags + gp = PlusOperator2x2(g,m,N,stabilityfix); %gp constitutes positive and half of zero lags psi_old = psi; psi = mtimes2x2(psi, gp); - if checkflag, + if checkflag psierr = abs(psi-psi_old)./abs(psi); psierrf = mean(psierr(:)); - if(psierrf. +% +% $Id$ + +if nargin<9, stabilityfix = false; end +if nargin<8, checkflag = true; end +if nargin<7, init = 'chol'; end +if nargin<6, fb = 'none'; end +if nargin<5 + ft_error('FieldTrip:connectivity:sfactorization_wilson3x3', 'when requesting multiple triplet-wise spectral decomposition, ''cmbindx'' needs to be specified'); +end +if nargin<4, tol = 1e-8; end +if nargin<3, Niterations = 1000; end; + +dfreq = round(diff(freq)*1e5)./1e5; % allow for some numeric issues +if ~all(dfreq==dfreq(1)) + ft_error('FieldTrip:connectivity:sfactorization_wilson3x3', 'frequency axis is not evenly spaced'); +end + +if freq(1)~=0 + ft_warning('FieldTrip:connectivity:sfactorization_wilson3x3', 'when performing non-parametric spectral factorization, the frequency axis should ideally start at 0, zero padding the spectral density'); + dfreq = mean(dfreq); + npad = freq(1)./dfreq; + + % update the freq axis and keep track of the frequency bins that are + % expected in the output + selfreq = (1:numel(freq)) + npad; + freq = [(0:(npad-1))./dfreq freq]; + S = cat(3, zeros(size(S,1), size(S,1), npad), S); +else + selfreq = 1:numel(freq); +end + +% ensure input S is double (mex-files don't work with single) +S = double(S); + +% check whether the last frequency bin is strictly real-valued. +% if that's the case, then it is assumed to be the Nyquist frequency +% and the two-sided spectral density will have an even number of +% frequency bins. if not, in order to preserve hermitian symmetry, +% the number of frequency bins needs to be odd. +Send = S(:,:,end); +N = numel(freq); +m = size(cmbindx,1); +if all(imag(Send(:))a/c + +% Copyright (C) 2012, Donders Centre for Cognitive Neuroimaging, Nijmegen, NL +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +% the ordering for the triplet indices w.r.t. the duplet indices is crucial +% for the interpretation: +% +% abc - ab gives b->a, conditioned on c. If you want a->b, conditioned on +% c, one should also do a bac - ba computation +% +% Here, the cmbindx are taken, and the appropriately ordered corresponding +% cmbindx2 are generated, if necessary, by swapping the order + +if nargin<7 || isempty(cmbindx) + cmbindx = cmbindx3; +end + +% FIXME ensure that the number of frequency bins matches + +nfreq = size(H3,4); +Cij = zeros(size(cmbindx,1), nfreq); +for k = 1:size(cmbindx,1) + % triplet + sel3 = find(all(ismember(cmbindx3, cmbindx(k,:)),2)); + tmp = cmbindx3(sel3,:); + reorder3 = [find(tmp==cmbindx(k,1)) find(tmp==cmbindx(k,2)) find(tmp==cmbindx(k,3))]; + + h123 = reshape(H3(reorder3, reorder3, sel3, :), [3 3 nfreq]); + z123 = Z3(reorder3, reorder3, sel3); + + % normalization matrix 2->1/3 + tmp1 = -z123(2,1)/z123(1,1); + tmp2 = -z123(3,1)/z123(1,1); + tmp3 = -(z123(3,2)+tmp2*z123(1,2))/(z123(2,2)+tmp1*z123(1,2)); + + p1 = [1 0 0; + tmp1 1 0; + tmp2 0 1]; + p2 = [1 0 0; + 0 1 0; + 0 tmp3 1]; + + P = p2*p1; + invP = inv(P); + + %bivariate system + sel2 = find(all(ismember(cmbindx2, cmbindx(k,[1 3])),2)); + tmp = cmbindx2(sel2,:); + reorder2 = [find(tmp==cmbindx(k,1)) find(tmp==cmbindx(k,3))]; + + h2 = reshape(H2(reorder2, reorder2, sel2, :), [2 2 nfreq]); + z2 = Z2(reorder2, reorder2, sel2); + + Q = [1 0; + -z2(1,2)/z2(1,1) 1]; + numer = z2(1,1); + + invh2 = inv2x2(h2); + + HH = mtimes3x3(h123, invP(:,:,ones(size(h123,3),1))); + B = mtimes2x2(Q(:,:,ones(size(invh2,3),1)), invh2); + FF = shiftdim(B(1,1,:).*HH(1,1,:)+B(1,2,:).*HH(3,1,:),1); + denom = abs(FF.*conj(FF)).*z123(1,1); + Cij(k,:) = log(numer./denom); + +% % it seems only FF(1,1) is needed (as per the commented for-loop +% for kk = 1:size(h2,3) +% HH = h123(:,:,kk)/P; +% B = Q/h2(:,:,kk); +% FF = B(1,:)*HH([1 3],1); +% denom = abs(FF(1,1)*z123(1,1)*conj(FF(1,1))); +% +% Cij(k,kk) = log(numer./denom); +% +% end +% + +% for kk = 1:size(h2,3) +% HH = h123(:,:,kk)/P; +% Q = [1 0; +% -z2(1,2)/z2(1,1) 1]; +% B = Q/h2(:,:,kk); +% BB = [B(1,1) 0 B(1,2); +% 0 1 0; +% B(2,1) 0 B(2,2)]; +% FF = BB*HH; +% numer = z2(1,1); +% denom = abs(FF(1,1)*z123(1,1)*conj(FF(1,1))); +% +% Cij(k,kk) = log(numer./denom); +% end +end diff --git a/external/fieldtrip/connectivity/transfer2coeffs.m b/external/fieldtrip/connectivity/transfer2coeffs.m new file mode 100644 index 00000000..d60f5716 --- /dev/null +++ b/external/fieldtrip/connectivity/transfer2coeffs.m @@ -0,0 +1,160 @@ +function A = transfer2coeffs(H, freq, labelcmb, maxlag) + +% TRANSFER2COEFFS converts a spectral transfer matrix into the time domain +% equivalent multivariate autoregressive coefficients up to a specified +% lag, starting from lag 1. + +if nargin<3 + labelcmb = []; +end +if nargin<4 + maxlag = []; +end + +% do a check on the input data +siz = size(H); +if numel(siz)==3 && siz(1)==siz(2) + % assume chan_chan_freq + isfull = true; +elseif numel(siz)==2 + % assume chancmb_freq + isfull = false; + %assert(~isempty(labelcmb), 'input data appears to be chancmb_freq, but labelcmb is missing'); +else + error('dimensionality of input data is not supported'); +end + +dfreq = round(diff(freq)*1e5)./1e5; % allow for some numeric issues +if ~all(dfreq==dfreq(1)) + error('FieldTrip:transfer2iis', 'frequency axis is not evenly spaced'); +end + +if freq(1)~=0 + ft_warning('FieldTrip:transfer2iis', 'when converting the transfer function to coefficients, the frequency axis should ideally start at 0, zero padding the spectral density'); + dfreq = mean(dfreq); + npad = freq(1)./dfreq; + + % update the freq axis and keep track of the frequency bins that are + % expected in the output + selfreq = (1:numel(freq)) + npad; + freq = [(0:(npad-1))./dfreq freq]; + if isfull + H = cat(3, zeros(siz(1),siz(2),npad), H); + else + H = cat(2, zeros(siz(1),npad), H); + end +else + selfreq = 1:numel(freq); +end + +% ensure H to be double precision +H = double(H); + +% deal with the two different types of input +if isfull + % check whether the last frequency bin is strictly real-valued. + % if that's the case, then it is assumed to be the Nyquist frequency + % and the two-sided spectral density will have an even number of + % frequency bins. if not, in order to preserve hermitian symmetry, + % the number of frequency bins needs to be odd. + Hend = H(:,:,end); + N = numel(freq); + m = size(H,1); + if all(imag(Hend(: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 literal 13864 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 diff --git a/external/fieldtrip/external/stats/nanmean.mexw32 b/external/fieldtrip/external/stats/nanmean.mexw32 index b496982e3f4c353da2507d222d6e8c094bc12643..faee9eefec61fbc2a24457765c2a2efdd0623486 100755 GIT binary patch delta 33 mcmZn&Xb70_f+bYuS>(hwKFr*444bVPf69RcHd`p1UTp700;06;Q#;t diff --git a/external/fieldtrip/external/stats/nanmean.mexw64 b/external/fieldtrip/external/stats/nanmean.mexw64 index b8646fca688e7688b2b602e2932c038ed4c2c100..9e3821e48fd8f808325992a0da9cf4b57c94c3a2 100755 GIT binary patch delta 32 lcmZn&X$YC{fn~w-r;!uC_%Pir-0Z~2qyXk`_E6lx0RRJ`4$c4o delta 32 lcmZn&X$YC{fyIycbLhk`K1_iNH#;#hDS-K#Jrs9v007rG3>*Le diff --git a/external/fieldtrip/external/stats/nanstd.mexmaci64 b/external/fieldtrip/external/stats/nanstd.mexmaci64 index e74f23b3b8a9cb67549c8da5d4fde0113653ff89..5b7ef1fd47d7621c61453561d7c4d09aac6dba60 100755 GIT binary patch literal 13720 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 literal 13864 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 oA<(hoK1?a=HajsEDT4W%cPM$V0|4Uq4C4R* delta 32 lcmZn&X$YC{fyLq9r_hOCe3*Q)HajsEDT4W%cPM$V0|5614k-Wt diff --git a/external/fieldtrip/external/stats/nanstd.mexw64 b/external/fieldtrip/external/stats/nanstd.mexw64 index e7d3d8a01976edce58ce0ef170e6b56dd298d165..587745eb664dd1fd0c08b42d5480345c8b0cac15 100755 GIT binary patch delta 32 lcmZq3XvmoGfMwzHr;!t%_%Pk9-E73TNCV8@d_z-%3jhvN4}<^! delta 32 lcmZq3XvmoGfW@ErbLhk;K1}{=Hybf7(g5=}-_X?H0s!Ia4AKAq diff --git a/external/fieldtrip/external/stats/nansum.mexmaci64 b/external/fieldtrip/external/stats/nansum.mexmaci64 index 05ec3b670654e5593b08ebb5f238dc6402006109..e26818ba84c6ea6ae451116d353de1f871598008 100755 GIT binary patch literal 9624 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 n(hwK1`Oio2?jsNrCyBEo4rx0|4FL4B7wy delta 32 lcmZqhXz-Zug2n0Ir_hOSe3)b{H(N3Ok^=KLTgaSX2LSP84j2Fc diff --git a/external/fieldtrip/external/stats/nansum.mexw64 b/external/fieldtrip/external/stats/nansum.mexw64 index 4e28d447822c8183951572c80f8c70b4c416cedf..d0e81802ab7fc0ad850bab389a87233d207e53e1 100755 GIT binary patch delta 33 mcmZqhY4Dlwfo0+Ir;!uC_%K&~Vc6`<_)!`xu-QWP1P1^YrVq&g delta 33 mcmZqhY4DlwfhCanbLhk`KFpt$88vofk10u)t;KDj6W!s354Z;%4q!NY3t{oQ;vMpg}{S`?= zj1wm&wo@LesB_Y#^fYNXIrJRbZBNK1OIY?Km2K)TzKkJIaAHD|CiZ$a>)2Zx2toV1 zZ)RjkKzDn(e`=23d-vXV?|tvxcki9ioAJr3|9O43AQ)x{f{=k?LaCc62(4)8x(lT~ zO%UAf0!MKHCnZ+qL{!jl=oFwvpq4JTJLs(ss<4VD>f38n`|h9#;37O-1=TuTXo^SO z?m$o}4a7*v^ZVy)wac$@5N?QZW38ILSsG2%=dSQp)p;e2yR7NcrYR6kdvL4E?Jf%h{gpLaG=^k-S@YD6Ds7QEuIo#fD~N8lQuAbG zO}V?W##hVn#QkWRuS%}d6cC=QL+j#=+wHAz`~042uS!jxU%#ersU}4DpIR^Z-7t#V zZMPNJG$Crt8m#$AGEV+RdiA-w-8EJ2z_#kr+A4Ql(0@yPx;oMqKQHo+ze3S3x4X*o zr}UZ3D(4;Fcdj+A1 zv!J3l&Om!-T)!FkUI;`ig75(7WFP8ZdcPoih1z9;P=Wq00bYj^e-SU0taxG)-1c=r zSd>H~^llUyr}P_Tldt^h{*U&bE4&_B(a@d)nh8aiGglDi&K16<<3z(n=>SvavNX1S zt@PJdK_`UH0H}cm*kwLgm3HV7nm9oW)^DNpR#7}mkwW#xX z3+XA5|IuxMptm}2Rs6iZ3VvGWW!RneC0D}**qyG$DBKRfX}zf{Wr36hQWi*AAZ3A+ z1q7i`Vt=p|*}iKlv=uxmZU2uQFpA7h+Spl%P1x8qIrQ-GHBk_3&DYbPHZn)Q6n15^LZPE|@>yd40kNM47fs@Iv@Ma~z2l;3=BrRKTtJ%H3~Bojn)CN;8*CeGn{4il zoeuT~iEZ3NLOZ#Tl0$I43g1caW)-GE3TcoaaH7vcE3r-j7ZZscA@HjJ`DzzP%(0&@ z>n@PS#p0P?#!SY=C1Xx@$m=|3`G{!pl|R ze0?UH9*#oNN;6M`po* zWF#kRjM&4^80^+7;*TQY!HA6=v*jLfmHqc4;T3_##yOet>_zzMz>vPMbY#n%VjvUUq zDp^l&Et122lN5f+WM_R2ORvp(+Q#0Ix;sdjEILj(4HpdkQZzz}q}+aSeiO|_G_4sE zO`@2&dQ8l`U25(!OU>OVk!#9F5eC_Ks70 zb+KIbj?~_bu{az&1QS8G&k`2_~%?EgwjltOQjHZFA*KdvN}Zz7R*Iqc|>LQk27 z2UR5EuzaKs6esp`RqRd@`vr&FrO?Lxt%J@`m=;nyqfjG&kBtWSUsh&vAex3l+uVw?JcomGLWHu2Tp8OEeN z&|&OG2J0CYGXap)$5N=UAN1^wadE?GanT3k;-*Vr`4B8Q9qK^nIW{gn)(2Kd78}8u ziHaui2}HBn!O$lzIuFroQhx#c+3o72NGoJdK{kS}ERxOY7%lMO$`j|eV7BCS=Nnf^ zNQvXCp!t1GGr^bi89dgD{+@(>k<%h7Z7oaxM2;S@TR#+A-@8sb^)k6n>!9@ZHMF#c zKCyOV6TH5k*5M3QN5oy{@as`xm&4ye^va0dt~5*3x!{D@!oV+wSDcjEFU@d;3vLsf z;q1Ax^$VN0JL0mQL(?T$Vb|RqF6%`!osywlvR(#sM7Ew3ceh)jj+P6G!(r}HR@%*% zlm~rcU8mjBE6%smOiac;pG`Cs90y!{itrwvxB+F;DbO>sP9jj#BlKN0 zi7mM_+i?0-IqdubK-P6RyeyjgxvveIKsP1>+PN_JQEUYEBy*M?@ltaKBEKsmdQ>?x z@*z$+ny<`;@9hy=U%YwH(LqQ;(0u?3e4fYKFozvY6j$#8)^3>Zaj^R^8da7D%P%?e z408Gd9Mr;V6^>juD-SP(H|Ktev#6o9U1e88t4T#7V02g}wK2Geq>AvcTFc>BShcEQ zRfw>1A*>pk#9a)IK=;$fVajR$n;=(ygNIWlF;HN<$)hO^sGW`J(L}%%J({4$`27h) z(*zv#`&{S^iYCyrpPPW+PlzQ0D1#`yagl|)+PGM9jHI3;SJe2yhjDY>faE2xK!^t& z_7(eC0vzmoqHjVVYdhHbNHGcqF=b;WC4=H3#O@}-(bzD0rgHUjgv2uwY{!S?XF zVguT_F#OR8#3w9G@tMx`HFu!xO6T#J4`t5q%w_Q9P~$#{4Tb)Z{MgB^-0;*p@=xHE z*+t9XP3|}M@xC?uHuZNL?nDgiZ-tfl{YJglgmt@%yIv!MCfsk9VF&pA2F5TB(fy{O zoc&%62HqyzS&(wnJ4^dG__Kznru)H$)4n+G2Q@RNoBE7H=u>^%hPz59^%y%x@Ab9W zA9U?&{2Pv6)HxsP<@lhJrJt9goz{zDs~2X$-IC||D14~8Njjt_dvVw2I8h82A+bMV zz$4j$9B7lY@MKtE?du`woKYu29)pG&7I16 zIL7bnmVwxQQtCFI<_Y|?3CTN~GI;qZfE#{~@;=h|QIs>3%8lo!E;wgG5{BdSD;>z? zvh_2ur34d{@vtU^ji2H9a4L67_ZKyvo94hi$F*FZ7N5(bCzW?c?uIzhp}PHW7I-dC zh~Ff&Ox^c~I2_w|Eg|9=i$7<$a5q%?#a+V?hHK6&#La-;pI`=)@g<%Q=?VVkTMh{$ zvXGkowv$NKOH^k+4;TO6avvGydCuKTd5fT&mmqi3%ty@4qsyoBwZq!exEL~-#-EX- z5t5Jfa{Q;==|7<~lbF9We_5F1FTYWrvj(t4%~7WP2j;$}xs8H;1oUpWOxkZS?!Udv=2%P3Xo` z?$X&CJEIGWvH8)3CA{9i>rK4g%CMv&X+hsrJ?c z19^g6v(-~oS#B<`1R+paTVwXs`jgnq_b)M5D}kW7)N2lud8$1AJadt^a!W-pVBYF2 z3z9&T0*?KcK90Dc0*5@*o+_Sc(BIJ+8onbK>P-fdadt)fTU0SNoTL z)qby+utgkO;|=Clc>)31PPC;u&F%?$i10v+pdT>>bZsm3F1gyXMdz1vqKl;0>DXGr zies2kUF!9J+h@N)=jLPmv?tr1a_4%N89FCvKO)&E}upRTC5c0Tnr;ON%ng#09Yy^8Dl zg)K?=_9UF%Zi6|-|KlY5l_VT*?h^RBlJFBr_}L_UA_Lh%fipOkE0Br~kyZJZ%c=;>LLBUrT{M&r`4jrHR2>2>VAluW?Una^OC_IkQ zlJRN7wEr_$`TwcYERes&e2tJ>xZ5qAnL4Ju_~ywaM!g}epob?Ev~j6K#duQCz{F5j ziLu0?qAsk3l&sa;o2LnlN$ZRy2$ig*1|V8e;E0Vj_3&hh!*)bWL@kVUH=0G C9f|b- literal 13864 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 M7qh<_(fUgN1*p}Mf&c&j diff --git a/external/fieldtrip/external/stats/nanvar.mexw32 b/external/fieldtrip/external/stats/nanvar.mexw32 index 430fc0710176915e8a2c3479fb5e2fe189af3e0f..aa21c8575f6ec1af8599377a6ce573e71cb314d8 100755 GIT binary patch delta 33 mcmZpOXo#5bf+b7lS>(hwKFn<#1q diff --git a/external/fieldtrip/external/stats/nanvar.mexw64 b/external/fieldtrip/external/stats/nanvar.mexw64 index 09874e81427484a25660f1b5023ec5923e9a3a78..c507f05654e369ac5717a2587509d6faaaca5f10 100755 GIT binary patch delta 32 lcmZojXh@jwfo0M2r;!uC_%I!<-0Z|yqz2}1-l6Wn0RRj$4_E*I delta 32 lcmZojXh@jwfhCanbLhk`K1{YNH#;#Fse$>Mcc^=C007_)45|PC diff --git a/external/fieldtrip/external/stats/iscomplex.m b/external/fieldtrip/external/stats/private/iscomplex.m similarity index 100% rename from external/fieldtrip/external/stats/iscomplex.m rename to external/fieldtrip/external/stats/private/iscomplex.m diff --git a/external/fieldtrip/fieldtrip2besa.m b/external/fieldtrip/fieldtrip2besa.m index 7ebbc0b6..2741597f 100644 --- a/external/fieldtrip/fieldtrip2besa.m +++ b/external/fieldtrip/fieldtrip2besa.m @@ -82,7 +82,7 @@ function fieldtrip2besa(filename, data, varargin) besa_save2Avr(custom_path, file_name, data_matrix, time_samples, channel_labels, data_scale_factor, time_scale_factor); else - error('unsupported data structure'); + ft_error('unsupported data structure'); end case {'elec', 'grad'} @@ -137,6 +137,6 @@ function fieldtrip2besa(filename, data, varargin) besa_save2Elp(custom_path, filename, SphericalCoords, channel_labels, channel_type); otherwise - error('unsupported data structure'); + ft_error('unsupported data structure'); end % switch type diff --git a/external/fieldtrip/fieldtrip2bis.m b/external/fieldtrip/fieldtrip2bis.m new file mode 100644 index 00000000..2559c8e3 --- /dev/null +++ b/external/fieldtrip/fieldtrip2bis.m @@ -0,0 +1,47 @@ +function fieldtrip2bis(filename, elec, mrifile) + +% FIELDTRIP2BIS writes BioImage Suite .mgrid files with eletrode +% positions in 'xyz' coordinates using a elec datatype structure and the +% corresponding MRI volume +% +% Use as +% fieldtrip2bis('Subject_grid.mgrid', elec, 'Subject_MR.nii') +% +% See also BIS2FIELDTRIP, FT_WRITE_SENS, WRITE_BIOIMAGE_MGRID + +% Copyright (C) 2017, Arjen Stolk & Sandon Griffin +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +% convert mri head coordinates to ijk coordinates +mri = ft_read_mri(mrifile); +elec_ijk.elecpos = ft_warp_apply(inv(mri.transform), elec.elecpos); + +% adjust for bioimage suite indexing first voxel at [0 0 0] instead of [1 1 1] +elec_ijk.elecpos = elec_ijk.elecpos-1; + +% convert ijk coordinates to xyz coordinates +elec_xyz = keepfields(mri, {'unit', 'coordsys'}); +elec_xyz.label = elec.label; +elec_xyz.elecpos(:, 1) = elec_ijk.elecpos(:, 1)*mri.hdr.xsize; +elec_xyz.elecpos(:, 2) = elec_ijk.elecpos(:, 2)*mri.hdr.ysize; +elec_xyz.elecpos(:, 3) = elec_ijk.elecpos(:, 3)*mri.hdr.zsize; + +% export to .mgrid file +ft_write_sens(filename, elec_xyz, 'format', 'bioimage_mgrid'); diff --git a/external/fieldtrip/fieldtrip2ctf.m b/external/fieldtrip/fieldtrip2ctf.m index ae51babc..bb3f079e 100644 --- a/external/fieldtrip/fieldtrip2ctf.m +++ b/external/fieldtrip/fieldtrip2ctf.m @@ -57,14 +57,14 @@ function fieldtrip2ctf(filename, data, varargin) fprintf(fid, 'Name:\t%s\n', montage.labelnew{i}); fprintf(fid, 'Unit:\n'); for j=1:numel(sel) - fprintf(fid, 'Ref:\t%s,%f\n', montage.labelorg{sel(j)}, montage.tra(i,sel(j))); + fprintf(fid, 'Ref:\t%s,%f\n', montage.labelold{sel(j)}, montage.tra(i,sel(j))); end fprintf(fid, '}\n'); end % case 'event' % if ~ft_filetype(filename, 'ctf_ds') - % error('you should specify the directory name of a CTF dataset to which the MarkerFile.mrk will be added'); + % ft_error('you should specify the directory name of a CTF dataset to which the MarkerFile.mrk will be added'); % end % % The MarkerFile.mrk file requires exact line spacing, otherwise the software @@ -89,6 +89,6 @@ function fieldtrip2ctf(filename, data, varargin) % case 'dip' otherwise - error('unsuported data structure "%s" for exporting to CTF', type); + ft_error('unsuported data structure "%s" for exporting to CTF', type); end diff --git a/external/fieldtrip/fieldtrip2fiff.m b/external/fieldtrip/fieldtrip2fiff.m index 836e55ed..37fc8c25 100644 --- a/external/fieldtrip/fieldtrip2fiff.m +++ b/external/fieldtrip/fieldtrip2fiff.m @@ -46,10 +46,10 @@ function fieldtrip2fiff(filename, data) % ensure that the filename has the correct extension [pathstr, name, ext] = fileparts(filename); if ~strcmp(ext, '.fif') - error('if the filename is specified with extension, this should read .fif'); + ft_error('if the filename is specified with extension, this should read .fif'); end -fifffile = [pathstr filesep name '.fif']; -eventfile = [pathstr filesep name '-eve.fif']; +fifffile = fullfile(pathstr ,[name '.fif']); +eventfile = fullfile(pathstr ,[name '-eve.fif']); % ensure the mne-toolbox to be on the path ft_hastoolbox('mne', 1); @@ -140,7 +140,7 @@ function fieldtrip2fiff(filename, data) elseif isepch - error('fieldtrip2fiff:NotImplementedError', 'Function to write epochs to MNE not implemented yet') + ft_error('writing epochs to MNE is not implemented yet') for j = 1:length(data.trial) evoked(j).aspect_kind = 100; diff --git a/external/fieldtrip/fieldtrip2spss.m b/external/fieldtrip/fieldtrip2spss.m index f1025bf4..28d1dc25 100644 --- a/external/fieldtrip/fieldtrip2spss.m +++ b/external/fieldtrip/fieldtrip2spss.m @@ -3,12 +3,12 @@ function fieldtrip2spss(filename, labels, data) % FIELDTRIP2SPSS compiles data and correpsonding labels into a textfile, % suitable for import to SPSS. % -% Use as: -% fieldtrip2spss(filename, labels, data) +% Use as +% fieldtrip2spss(filename, labels, data) % % When exporting from MATLAB, set: % - filename; should be string (e.g. 'counts.txt') -% - labels; should be a cell array (e.g. {'ones','twos','threes'}) +% - labels; should be a cell array (e.g. {'ones', 'twos', 'threes'}) % - data; should be either a vector or matrix (e.g. [1 2 3; 1 2 3; 1 2 3]) % % When importing to SPSS, set; @@ -55,7 +55,7 @@ function fieldtrip2spss(filename, labels, data) % check whether data and labels have the same lengths if ~isequal(size(data,2),size(labels,2)) - warning('the data and labels have unequal number of columns'); + ft_warning('the data and labels have unequal number of columns'); end % print labels and append data diff --git a/external/fieldtrip/fileio/ft_chantype.m b/external/fieldtrip/fileio/ft_chantype.m index 569148ff..96ff6de8 100644 --- a/external/fieldtrip/fileio/ft_chantype.m +++ b/external/fieldtrip/fileio/ft_chantype.m @@ -123,7 +123,7 @@ label = input.label; numchan = length(label); else - error('the input that was provided to this function cannot be deciphered'); + ft_error('the input that was provided to this function cannot be deciphered'); end if isfield(input, 'chantype') @@ -212,7 +212,7 @@ others = [input.orig.chs(sel).logno] > 16; chantype(sel(others)) = {'other trigger'}; else - warning('There does not seem to be a suitable trigger channel.'); + ft_warning('There does not seem to be a suitable trigger channel.'); chantype(sel) = {'other trigger'}; end end @@ -269,20 +269,40 @@ chantype(sel) = {'megmag'}; elseif ft_senstype(input, 'ctf') && isheader - % According to one source of information meg channels are 5, refmag 0, - % refgrad 1, adcs 18, trigger 11, eeg 9. + % The following is according to "CTF MEG(TM) File Formats" pdf, Release 5.2.1 % - % According to another source of information it is as follows - % refMagnetometers: 0 - % refGradiometers: 1 - % meg_sens: 5 - % eeg_sens: 9 - % adc: 10 - % stim_ref: 11 - % video_time: 12 - % sam: 15 - % virtual_channels: 16 - % sclk_ref: 17 + % eMEGReference 0 Reference magnetometer channel + % eMEGReference1 1 Reference 1st-order gradiometer channel + % eMEGReference2 2 Reference 2nd-order gradiometer channel + % eMEGReference3 3 Reference 3rd-order gradiometer channel + % eMEGSensor 4 Sensor magnetometer channel located in head shell + % eMEGSensor1 5 Sensor 1st-order gradiometer channel located in head shell + % eMEGSensor2 6 Sensor 2nd-order gradiometer channel located in head shell + % eMEGSensor3 7 Sensor 3rd-order gradiometer channel located in head shell + % eEEGRef 8 EEG unipolar sensors not on the scalp + % eEEGSensor 9 EEG unipolar sensors on the scalp + % eADCRef 10 (see eADCAmpRef below) + % eADCAmpRef 10 ADC amp channels from HLU or PIU (old electronics) + % eStimRef 11 Stimulus channel for MEG41 + % eTimeRef 12 Time reference coming from video channel + % ePositionRef 13 Not used + % eDACRef 14 DAC channel from ECC or HLU + % eSAMSensor 15 SAM channel derived through data analysis + % eVirtualSensor 16 Virtual channel derived by combining two or more physical channels + % eSystemTimeRef 17 System time showing elapsed time since trial started + % eADCVoltRef 18 ADC volt channels from ECC + % eStimAnalog 19 Analog trigger channels + % eStimDigital 20 Digital trigger channels + % eEEGBipolar 21 EEG bipolar sensor not on the scalp + % eEEGAflg 22 EEG ADC over range flags + % eMEGReset 23 MEG resets (counts sensor jumps for crosstalk purposes) + % eDipSrc 24 Dipole source + % eSAMSensorNorm 25 Normalized SAM channel derived through data analy- sis + % eAngleRef 26 Orientation of head localization field + % eExtractionRef 27 Extracted signal from each sensor of field generated by each localization coil + % eFitErr 28 Fit error from each head localization coil + % eOtherRef 29 Any other type of sensor not mentioned but still valid + % eInvalidType 30 An invalid sensor % start with an empty one origSensType = []; @@ -300,42 +320,44 @@ end if isempty(origSensType) - warning('could not determine channel chantype from the CTF header'); + ft_warning('could not determine channel chantype from the CTF header'); end - for sel=find(origSensType(:)==5)' - chantype{sel} = 'meggrad'; - end for sel=find(origSensType(:)==0)' chantype{sel} = 'refmag'; end for sel=find(origSensType(:)==1)' chantype{sel} = 'refgrad'; end - for sel=find(origSensType(:)==18)' - chantype{sel} = 'adc'; + for sel=find(origSensType(:)==5)' + chantype{sel} = 'meggrad'; + end + for sel=find(origSensType(:)==9)' + chantype{sel} = 'eeg'; end for sel=find(origSensType(:)==11)' + % Stimulus channel for MEG41 chantype{sel} = 'trigger'; end + for sel=find(origSensType(:)==13)' + chantype{sel} = 'headloc'; % these represent the x, y, z position of the head coils + end for sel=find(origSensType(:)==17)' chantype{sel} = 'clock'; end - for sel=find(origSensType(:)==9)' - chantype{sel} = 'eeg'; - end - for sel=find(origSensType(:)==29)' - chantype{sel} = 'reserved'; % these are "reserved for future use", but relate to head localization + for sel=find(origSensType(:)==18)' + chantype{sel} = 'adc'; end - for sel=find(origSensType(:)==13)' - chantype{sel} = 'headloc'; % these represent the x, y, z position of the head coils + for sel=find(origSensType(:)==20)' + % Digital trigger channels + chantype{sel} = 'trigger'; end for sel=find(origSensType(:)==28)' chantype{sel} = 'headloc_gof'; % these represent the goodness of fit for the head coils end - % for sel=find(origSensType(:)==23)' - % chantype{sel} = 'SPLxxxx'; % I have no idea what these are - % end + for sel=find(origSensType(:)==29)' + chantype{sel} = 'reserved'; % these are "reserved for future use", but relate to head localization + end elseif ft_senstype(input, 'ctf') && isgrad % in principle it is possible to look at the number of coils, but here the channels are identified based on their name @@ -351,7 +373,7 @@ elseif ft_senstype(input, 'ctf') && islabel % the channels have to be identified based on their name alone sel = myregexp('^M[ZLR][A-Z][0-9][0-9]$', label); - chantype(sel) = {'meggrad'}; % normal gradiometer channels + chantype(sel) = {'meggrad'}; % normal gradiometer channels sel = myregexp('^S[LR][0-9][0-9]$', label); chantype(sel) = {'meggrad'}; % normal gradiometer channels in the 64 channel CTF system sel = myregexp('^B[GPR][0-9]$', label); @@ -413,9 +435,9 @@ selchan = find(strcmp('meg', gradtype)); for k = 1:length(selchan) ncoils = length(find(input.tra(selchan(k),:)==1)); - if ncoils==1, + if ncoils==1 gradtype{selchan(k)} = 'megmag'; - elseif ncoils==2, + elseif ncoils==2 gradtype{selchan(k)} = 'meggrad'; end end @@ -436,7 +458,7 @@ sel = find(strcmp('unknown', chantype)); if ~isempty(sel) % channels that start with E are assumed to be EEG - % channels that end with -1 are also assumed to be EEG, see http://bugzilla.fcdonders.nl/show_bug.cgi?id=2389 + % channels that end with -1 are also assumed to be EEG, see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2389 chantype(sel(cellfun(@(x) strcmp(x(end-1:end),'-1') || strcmp(x(1),'E'), label(sel)))) = {'eeg'}; end end @@ -453,7 +475,7 @@ chantype(origtype==32) = {'param'}; chantype(origtype==64) = {'digit'}; chantype(origtype==128) = {'flag'}; - % these are the channels that are visible to fieldtrip + % these are the channels that are visible to FieldTrip chansel = 1:input.orig.nchan; chantype = chantype(chansel); @@ -581,7 +603,7 @@ chantype(sel) = {'aux'}; sel = ([input.orig.ch.type]==64); chantype(sel) = {'digital'}; - % not all channels are actually processed by fieldtrip, so only return + % not all channels are actually processed by FieldTrip, so only return % the types fopr the ones that read_header and read_data return chantype = chantype(input.orig.chansel); diff --git a/external/fieldtrip/fileio/ft_chanunit.m b/external/fieldtrip/fileio/ft_chanunit.m index 2eb2fbff..af8bfb12 100644 --- a/external/fieldtrip/fileio/ft_chanunit.m +++ b/external/fieldtrip/fileio/ft_chanunit.m @@ -112,7 +112,7 @@ label = input.label; numchan = length(label); else - error('the input that was provided to this function cannot be deciphered'); + ft_error('the input that was provided to this function cannot be deciphered'); end if isfield(input, 'chanunit') @@ -170,13 +170,13 @@ sel = strcmp('megplanar', input.chantype); if any(sel) chanunit(sel) = {assumption}; - warning('assuming that planar MEG channel units are %s', assumption); + ft_warning('assuming that planar MEG channel units are %s', assumption); end else sel = strcmp('megplanar', input.chantype); if any(sel) chanunit(sel) = {'unknown'}; - warning('cannot determine the units for the planar MEG channels'); + ft_warning('cannot determine the units for the planar MEG channels'); end end end @@ -196,13 +196,13 @@ sel = strcmp('megplanar', input.chantype); if any(sel) chanunit(sel) = {assumption}; - warning('assuming that planar MEG channel units are %s, consistent with the geometrical units', assumption); + ft_warning('assuming that planar MEG channel units are %s, consistent with the geometrical units', assumption); end else sel = strcmp('megplanar', input.chantype); if any(sel) chanunit(strcmp('megplanar', input.chantype)) = {'unknown'}; - warning('cannot determine the units for the planar MEG channels'); + ft_warning('cannot determine the units for the planar MEG channels'); end end @@ -221,7 +221,7 @@ chanunit(strcmp('megplanar', input.chantype)) = {'T'}; % I am not sure whether it is T or T/m elseif ft_senstype(input, 'bti') && isfield(input, 'chantype') - chanunit(strcmp('meg', input.chantype)) = {'T'}; % this was the channel type until approx. 2 November 2012, see http://bugzilla.fcdonders.nl/show_bug.cgi?id=1807 + chanunit(strcmp('meg', input.chantype)) = {'T'}; % this was the channel type until approx. 2 November 2012, see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=1807 chanunit(strcmp('megmag', input.chantype)) = {'T'}; % applies for magnetometer 4D/BTi systems chanunit(strcmp('eeg', input.chantype)) = {'V'}; % seems to be true for the example I have (VL) chanunit(strcmp('meggrad', input.chantype)) = {'T'}; % this is the plain difference in the field at the two coils, i.e. in T diff --git a/external/fieldtrip/fileio/ft_create_buffer.m b/external/fieldtrip/fileio/ft_create_buffer.m index 0a8e9245..0b382551 100644 --- a/external/fieldtrip/fileio/ft_create_buffer.m +++ b/external/fieldtrip/fileio/ft_create_buffer.m @@ -40,7 +40,7 @@ function ft_create_buffer(port) pause(1); catch if ~isempty(strfind(lasterr, 'thread is already running')) - warning('thread is already running'); + ft_warning('thread is already running'); else rethrow(lasterror); end diff --git a/external/fieldtrip/fileio/ft_filetype.m b/external/fieldtrip/fileio/ft_filetype.m index 6f8cf1da..794cf847 100644 --- a/external/fieldtrip/fileio/ft_filetype.m +++ b/external/fieldtrip/fileio/ft_filetype.m @@ -36,6 +36,7 @@ % - Analyse % - Analyze/SPM % - BESA +% - Bioimage Suite (*.mgrid) % - BrainSuite % - BrainVisa % - BrainVision @@ -297,6 +298,10 @@ type = 'neuromag_fif'; manufacturer = 'Neuromag'; content = 'MEG header and data'; +elseif filetype_check_extension(filename, '.mesh') + type = 'neuromag_mesh'; + manufacturer = 'Neuromag'; + content = 'triangulated surface mesh'; elseif filetype_check_extension(filename, '.bdip') type = 'neuromag_bdip'; manufacturer = 'Neuromag'; @@ -393,13 +398,6 @@ type = '4d_el_ascii'; manufacturer = '4D/BTi'; content = 'electrode positions'; -elseif length(f)<=4 && filetype_check_dir(p, 'config')%&& ~isempty(p) && exist(fullfile(p,'config'), 'file') %&& exist(fullfile(p,'hs_file'), 'file') - % this could be a 4D file with non-standard/processed name - % it will be detected as a 4D file when there is a config file in the - % same directory as the specified file - type = '4d'; - manufacturer = '4D/BTi'; - content = ''; % known EEProbe file types elseif filetype_check_extension(filename, '.cnt') && (filetype_check_header(filename, 'RIFF') || filetype_check_header(filename, 'RF64')) @@ -1023,6 +1021,7 @@ type = 'freesurfer_annot'; manufacturer = 'FreeSurfer'; content = 'parcellation annotation'; + elseif filetype_check_extension(filename, '.txt') && numel(strfind(filename,'_nrs_')) == 1 % This may be improved by looking into the file, rather than assuming the % filename has "_nrs_" somewhere. Also, distinction by the different file @@ -1030,12 +1029,16 @@ type = 'bucn_nirs'; manufacturer = 'BUCN'; content = 'ascii formatted nirs data'; - - % Homer is MATLAB software for NIRS processing, see http://www.nmr.mgh.harvard.edu/DOT/resources/homer2/home.htm elseif filetype_check_extension(filename, '.nirs') && filetype_check_header(filename, 'MATLAB') + % Homer is MATLAB software for NIRS processing, see http://www.nmr.mgh.harvard.edu/DOT/resources/homer2/home.htm type = 'homer_nirs'; manufacturer = 'Homer'; content = '(f)NIRS data'; +elseif filetype_check_extension(filename, '.sd') && filetype_check_header(filename, 'MATLAB') + % Homer is MATLAB software for NIRS processing, see http://www.nmr.mgh.harvard.edu/DOT/resources/homer2/home.htm + type = 'homer_sd'; + manufacturer = 'Homer'; + content = 'source detector information'; % known Artinis file format elseif filetype_check_extension(filename, '.oxy3') @@ -1106,6 +1109,10 @@ content = 'annotation/metadata'; % some other known file types +elseif filetype_check_extension(filename, '.hdf5') + type = 'gtec_hdf5'; + manufacturer = 'Guger Technologies, http://www.gtec.at'; + content = 'EEG'; elseif length(filename)>4 && exist([filename(1:(end-4)) '.mat'], 'file') && exist([filename(1:(end-4)) '.bin'], 'file') % this is a self-defined FCDC data format, consisting of two files % there is a MATLAB V6 file with the header and a binary file with the data (multiplexed, ieee-le, double) @@ -1279,7 +1286,10 @@ type = 'nihonkohden_m00'; manufacturer = 'Nihon Kohden'; content = 'continuous EEG'; - +elseif filetype_check_extension(filename, '.mgrid') + type = 'bioimage_mgrid'; + manufacturer = 'Bioimage Suite'; + content = 'electrode positions'; end @@ -1289,9 +1299,9 @@ if strcmp(type, 'unknown') if ~exist(filename, 'file') && ~exist(filename, 'dir') - warning('file or directory "%s" does not exist, could not determine fileformat', filename); + ft_warning('file or directory "%s" does not exist, could not determine fileformat', filename); else - warning('could not determine filetype of %s', filename); + ft_warning('could not determine filetype of %s', filename); end end diff --git a/external/fieldtrip/fileio/ft_filter_event.m b/external/fieldtrip/fileio/ft_filter_event.m index b2d76097..4063093a 100644 --- a/external/fieldtrip/fileio/ft_filter_event.m +++ b/external/fieldtrip/fileio/ft_filter_event.m @@ -84,7 +84,7 @@ testmaxnumber = ~isempty(maxnumber) && isfield(event, 'number'); if (~isempty(minnumber) || ~isempty(maxnumber)) && ~isfield(event, 'number') - warning('the events are not numbered, assuming that the order corresponds to the original stream sequence'); + ft_warning('the events are not numbered, assuming that the order corresponds to the original stream sequence'); for i=1:length(event) event(i).number = i; end diff --git a/external/fieldtrip/fileio/ft_flush_data.m b/external/fieldtrip/fileio/ft_flush_data.m index 9ce5a8d9..b7deb982 100644 --- a/external/fieldtrip/fileio/ft_flush_data.m +++ b/external/fieldtrip/fileio/ft_flush_data.m @@ -52,10 +52,10 @@ function ft_flush_data(filename, varargin) case 'matlab' if exist(filename, 'file') - warning('deleting existing file ''%s''', filename); + ft_warning('deleting existing file ''%s''', filename); delete(filename); end otherwise - error('unsupported data format'); + ft_error('unsupported data format'); end diff --git a/external/fieldtrip/fileio/ft_flush_event.m b/external/fieldtrip/fileio/ft_flush_event.m index 187b9b71..c951e9d9 100644 --- a/external/fieldtrip/fileio/ft_flush_event.m +++ b/external/fieldtrip/fileio/ft_flush_event.m @@ -54,11 +54,11 @@ function ft_flush_event(filename, varargin) case 'matlab' if exist(filename, 'file') - warning('deleting existing file ''%s''', filename); + ft_warning('deleting existing file ''%s''', filename); delete(filename); end otherwise - error('unsupported data format'); + ft_error('unsupported data format'); end diff --git a/external/fieldtrip/fileio/ft_flush_header.m b/external/fieldtrip/fileio/ft_flush_header.m index 48259ed8..d8107ebf 100644 --- a/external/fieldtrip/fileio/ft_flush_header.m +++ b/external/fieldtrip/fileio/ft_flush_header.m @@ -53,10 +53,10 @@ function ft_flush_header(filename, varargin) case 'matlab' if exist(filename, 'file') - warning('deleting existing file ''%s''', filename); + ft_warning('deleting existing file ''%s''', filename); delete(filename); end otherwise - error('unsupported data format'); + ft_error('unsupported data format'); end diff --git a/external/fieldtrip/fileio/ft_read_atlas.m b/external/fieldtrip/fileio/ft_read_atlas.m index 2e4263b9..f07cf2b9 100644 --- a/external/fieldtrip/fileio/ft_read_atlas.m +++ b/external/fieldtrip/fileio/ft_read_atlas.m @@ -13,7 +13,7 @@ % % Additional options should be specified in key-value pairs and can include % 'format' = string, see below -% 'unit' = string, e.g. 'mm' (default is the native units of the file) +% 'unit' = string, e.g. 'mm' (default is to keep it in the native units of the file) % % For individual surface-based atlases from FreeSurfer you should specify two % filenames as a cell-array: the first points to the file that contains information @@ -54,7 +54,7 @@ filenamemesh = filename{2}; filename = filename{1}; else - error('with multiple filenames, only 2 files are allowed'); + ft_error('with multiple filenames, only 2 files are allowed'); end % if precisely two input files end % iscell @@ -81,11 +81,13 @@ l1 = fgetl(fid); if strcmp(l1(1),'[') && strcmp(l1(end),']') defaultformat = 'aal_ext'; + elseif strcmp(l1,'Brainnetome Atlas') + defaultformat= 'brainnetome'; else defaultformat = 'aal'; end fclose(fid); -elseif strcmp(x, '.mgz') && ~isempty(strfind(f, 'aparc')) && ~isempty(strfind(f, 'aseg')) +elseif strcmp(x, '.mgz') && ~isempty(strfind(f, 'aparc')) || ~isempty(strfind(f, 'aseg')) % individual volume based segmentation from freesurfer defaultformat = 'freesurfer_volume'; elseif ft_filetype(filename, 'caret_label') @@ -160,7 +162,31 @@ atlas.tissue = reshape(j-1, atlas.dim); atlas.tissuelabel = atlas.tissuelabel(a(a~=0)); end + case 'brainnetome' + + % Brainnetome Atlas + % L. Fan, et al.The Human Brainnetome Atlas: A New Brain Atlas Based on + % Connectional Architecture. Cereb Cortex 2016; 26 (8): 3508-3526. + % doi: 10.1093/cercor/bhw157 + atlas = ft_read_mri(filename); + atlas.tissue = atlas.anatomy; + atlas = rmfield(atlas, 'anatomy'); + atlas.coordsys = 'mni'; + + %Brainnetome atlas comes as radiological view convention. + %change to neurological view: patient Left->image Left. + atlas.transform(1,1)=-atlas.transform(1,1); + atlas.transform(1,4)=-atlas.transform(1,4); + %labels + atlas.tissuelabel = cell(1,246); + fid = fopen(labelfile, 'rt'); + lab = fgetl(fid);%lab='Brainnetome Atlas' + for label_i=1:246 + atlas.tissuelabel{1,label_i}=fgetl(fid); + end + fclose(fid); + case 'afni' % check whether the required AFNI toolbox is available ft_hastoolbox('afni', 1); @@ -642,7 +668,7 @@ else % the file does not exist - warning('cannot locate %s, making fake tissue labels', filename2); + ft_warning('cannot locate %s, making fake tissue labels', filename2); value = []; label = {}; for i=1:max(brick0(:)) @@ -1724,288 +1750,18 @@ ft_hastoolbox('freesurfer', 1); if strcmp(fileformat, 'freesurfer_a2009s') - lookuptable = 'Simple_surface_labels2009.txt'; parcelfield = 'a2009s'; - - index = (0:75)'; - - label = {'Unknown' - 'G_and_S_frontomargin' - 'G_and_S_occipital_inf' - 'G_and_S_paracentral' - 'G_and_S_subcentral' - 'G_and_S_transv_frontopol' - 'G_and_S_cingul-Ant' - 'G_and_S_cingul-Mid-Ant' - 'G_and_S_cingul-Mid-Post' - 'G_cingul-Post-dorsal' - 'G_cingul-Post-ventral' - 'G_cuneus' - 'G_front_inf-Opercular' - 'G_front_inf-Orbital' - 'G_front_inf-Triangul' - 'G_front_middle' - 'G_front_sup' - 'G_Ins_lg_and_S_cent_ins' - 'G_insular_short' - 'G_occipital_middle' - 'G_occipital_sup' - 'G_oc-temp_lat-fusifor' - 'G_oc-temp_med-Lingual' - 'G_oc-temp_med-Parahip' - 'G_orbital' - 'G_pariet_inf-Angular' - 'G_pariet_inf-Supramar' - 'G_parietal_sup' - 'G_postcentral' - 'G_precentral' - 'G_precuneus' - 'G_rectus' - 'G_subcallosal' - 'G_temp_sup-G_T_transv' - 'G_temp_sup-Lateral' - 'G_temp_sup-Plan_polar' - 'G_temp_sup-Plan_tempo' - 'G_temporal_inf' - 'G_temporal_middle' - 'Lat_Fis-ant-Horizont' - 'Lat_Fis-ant-Vertical' - 'Lat_Fis-post' - 'Medial_wall' - 'Pole_occipital' - 'Pole_temporal' - 'S_calcarine' - 'S_central' - 'S_cingul-Marginalis' - 'S_circular_insula_ant' - 'S_circular_insula_inf' - 'S_circular_insula_sup' - 'S_collat_transv_ant' - 'S_collat_transv_post' - 'S_front_inf' - 'S_front_middle' - 'S_front_sup' - 'S_interm_prim-Jensen' - 'S_intrapariet_and_P_trans' - 'S_oc_middle_and_Lunatus' - 'S_oc_sup_and_transversal' - 'S_occipital_ant' - 'S_oc-temp_lat' - 'S_oc-temp_med_and_Lingual' - 'S_orbital_lateral' - 'S_orbital_med-olfact' - 'S_orbital-H_Shaped' - 'S_parieto_occipital' - 'S_pericallosal' - 'S_postcentral' - 'S_precentral-inf-part' - 'S_precentral-sup-part' - 'S_suborbital' - 'S_subparietal' - 'S_temporal_inf' - 'S_temporal_sup' - 'S_temporal_transverse'}; - - rgb = [ 0 0 0 - 23 220 60 - 23 60 180 - 63 100 60 - 63 20 220 - 13 0 250 - 26 60 0 - 26 60 75 - 26 60 150 - 25 60 250 - 60 25 25 - 180 20 20 - 220 20 100 - 140 60 60 - 180 220 140 - 140 100 180 - 180 20 140 - 23 10 10 - 225 140 140 - 180 60 180 - 20 220 60 - 60 20 140 - 220 180 140 - 65 100 20 - 220 60 20 - 20 60 220 - 100 100 60 - 220 180 220 - 20 180 140 - 60 140 180 - 25 20 140 - 20 60 100 - 60 220 20 - 60 60 220 - 220 60 220 - 65 220 60 - 25 140 20 - 220 220 100 - 180 60 60 - 61 20 220 - 61 20 60 - 61 60 100 - 25 25 25 - 140 20 60 - 220 180 20 - 63 180 180 - 221 20 10 - 221 20 100 - 221 60 140 - 221 20 220 - 61 220 220 - 100 200 200 - 10 200 200 - 221 220 20 - 141 20 100 - 61 220 100 - 141 60 20 - 143 20 220 - 101 60 220 - 21 20 140 - 61 20 180 - 221 140 20 - 141 100 220 - 221 100 20 - 181 200 20 - 101 20 20 - 101 100 180 - 181 220 20 - 21 140 200 - 21 20 240 - 21 20 200 - 21 20 60 - 101 60 60 - 21 180 180 - 223 220 60 - 221 60 60]; - elseif strcmp(fileformat, 'freesurfer_aparc') - lookuptable = 'colortable_desikan_killiany.txt'; parcelfield = 'aparc'; - - index = (0:35)'; - - label = {'unknown' - 'bankssts' - 'caudalanteriorcingulate' - 'caudalmiddlefrontal' - 'corpuscallosum' - 'cuneus' - 'entorhinal' - 'fusiform' - 'inferiorparietal' - 'inferiortemporal' - 'isthmuscingulate' - 'lateraloccipital' - 'lateralorbitofrontal' - 'lingual' - 'medialorbitofrontal' - 'middletemporal' - 'parahippocampal' - 'paracentral' - 'parsopercularis' - 'parsorbitalis' - 'parstriangularis' - 'pericalcarine' - 'postcentral' - 'posteriorcingulate' - 'precentral' - 'precuneus' - 'rostralanteriorcingulate' - 'rostralmiddlefrontal' - 'superiorfrontal' - 'superiorparietal' - 'superiortemporal' - 'supramarginal' - 'frontalpole' - 'temporalpole' - 'transversetemporal' - 'insula'}; - - rgb = [ 25 5 25 - 25 100 40 - 125 100 160 - 100 25 0 - 120 70 50 - 220 20 100 - 220 20 10 - 180 220 140 - 220 60 220 - 180 40 120 - 140 20 140 - 20 30 140 - 35 75 50 - 225 140 140 - 200 35 75 - 160 100 50 - 20 220 60 - 60 220 60 - 220 180 140 - 20 100 50 - 220 60 20 - 120 100 60 - 220 20 20 - 220 180 220 - 60 20 220 - 160 140 180 - 80 20 140 - 75 50 125 - 20 220 160 - 20 180 140 - 140 220 220 - 80 160 20 - 100 0 100 - 70 20 170 - 150 150 200 - 255 192 32]; - elseif strcmp(fileformat, 'freesurfer_ba') - lookuptable = 'colortable_BA.txt'; parcelfield = 'BA'; - - index = (0:12)'; - - label = {'unknown' - 'BA1' - 'BA2' - 'BA3a' - 'BA3b' - 'BA4a' - 'BA4p' - 'BA6' - 'BA44' - 'BA45' - 'V1' - 'V2' - 'MT'}; - - rgb = [ - 25 5 25 - 0 92 23 - 131 148 255 - 0 0 255 - 255 102 51 - 196 255 20 - 255 51 204 - 1 38 153 - 153 0 38 - 115 153 0 - 153 15 0 - 0 214 129 - 155 0 153]; - else - error('unknown freesurfer parcellation method requested'); + ft_error('unknown freesurfer parcellation method requested'); %[index, label, rgb] = read_fscolorlut(lookuptable); %label = cellstr(label); %rgb = rand(length(label),3); end - - rgb = rgb(:,1) + rgb(:,2)*256 + rgb(:,3)*256*256; + %rgb = rgb(:,1) + rgb(:,2)*256 + rgb(:,3)*256*256; % read the labels switch ft_filetype(filename) @@ -2014,11 +1770,15 @@ % p = p.cdata; case 'freesurfer_annot' [v, p, c] = read_annotation(filename); + + label = c.struct_names; + rgba = c.table(:,1:4); + rgb = c.table(:,5); % compound value that is used for the indexing in vector p + index = ((1:c.numEntries)-1)'; otherwise - error('unsupported fileformat for parcel file'); + ft_error('unsupported fileformat for parcel file'); end - switch ft_filetype(filenamemesh) %case {'caret_surf' 'gifti'} % tmp = gifti(filenamemesh); @@ -2027,16 +1787,22 @@ % reindex = false; case 'freesurfer_triangle_binary' [pos, tri] = read_surf(filenamemesh); + + % ensure the triangles to be 1-indexed + if min(tri(:))==0 && max(tri(:))==size(pos,1)-1 + tri = tri+1; + end + bnd.pos = pos; bnd.tri = tri; reindex = true; otherwise - error('unsupported fileformat for surface mesh'); + ft_error('unsupported fileformat for surface mesh'); end % check the number of vertices if size(bnd.pos,1) ~= numel(p) - error('the number of vertices in the mesh does not match the number of elements in the parcellation'); + ft_error('the number of vertices in the mesh does not match the number of elements in the parcellation'); end % reindex the parcels, if needed: I am not fully sure about this, but the caret @@ -2046,7 +1812,7 @@ % this is then freesurfer convention, coding in rgb newp = zeros(size(p)); for k = 1:numel(label) - newp(p==rgb(k)) = index(k); + newp(p==rgb(k)) = index(k)+1; end else uniquep = unique(p); @@ -2059,19 +1825,27 @@ atlas.pos = bnd.pos; atlas.tri = bnd.tri; atlas.(parcelfield) = newp; - atlas.([parcelfield, 'label']) = label(2:end); - atlas = ft_convert_units(atlas); + atlas.([parcelfield, 'label']) = label; + atlas.rgba = rgba; + atlas = ft_determine_units(atlas); case 'caret_label' ft_hastoolbox('gifti', 1); g = gifti(filename); + rgba = []; if isfield(g, 'labels'), label = g.labels.name(:); key = g.labels.key(:); + if isfield(g.labels, 'rgba'), + rgba = g.labels.rgba; % I'm not sure whether this always exists + end else label = g.private.label.name(:); key = g.private.label.key(:); + if isfield(g.private.label, 'rgba') + rgba = g.private.label.rgba; % I'm not sure whether this always exists + end end %label = g.private.label.name; % provides the name of the parcel @@ -2085,6 +1859,7 @@ tmporig = g.cdata(:,k); tmpnew = nan(size(tmporig)); tmplabel = cell(0,1); + tmprgba = zeros(0,4); cnt = 0; for m = 1:numel(label) sel = find(tmporig==key(m)); @@ -2098,6 +1873,7 @@ else % add as a new label tmplabel{end+1,1} = label{m}; + if ~isempty(rgba), tmprgba(end+1,:) = rgba(m,:); end val = cnt; end tmpnew(tmporig==key(m)) = val; @@ -2110,7 +1886,7 @@ % if strcmp(g.private.data{k}.metadata(1).name, 'Name') % parcelfield = fixname(g.private.data{k}.metadata(1).value); % else - % error('could not determine parcellation name'); + % ft_error('could not determine parcellation name'); % end if size(g.cdata,2)>1 @@ -2121,13 +1897,14 @@ atlas.(parcelfield) = tmpnew; atlas.([parcelfield 'label']) = tmplabel; + if ~isempty(tmprgba), atlas.rgba = tmprgba; end end if exist('filenamemesh', 'var') tmp = ft_read_headshape(filenamemesh); atlas.pos = tmp.pos; atlas.tri = tmp.tri; - atlas = ft_convert_units(atlas); + atlas = ft_determine_units(atlas); elseif ~isfield(atlas, 'coordsys') atlas.coordsys = 'unknown'; end @@ -2201,24 +1978,35 @@ atlas.([name 'label']) = label; end elseif isfield(tmp, 'atlas') - % this applies to FieldTrip *.mat files + % this applies to most FieldTrip *.mat files atlas = tmp.atlas; + elseif numel(fieldnames(tmp))==1 + % just take whatever variable is contained in the file + fn = fieldnames(tmp); + atlas = tmp.(fn{1}); + if isstruct(atlas) + ft_warning('assuming that the variable "%s" in "%s" represents the atlas', fn{1}, filename); + else + ft_error('cannot read atlas structure from "%s"', filename); + end else - error('the mat-file %s does not contain a variable called ''atlas''',filename); + ft_error('the mat-file %s does not contain a variable called ''atlas''',filename); end otherwise - error('unsupported format "%s"', fileformat); -end % case + ft_error('unsupported format "%s"', fileformat); + +end % switch fileformat + -% this will add the units to the head shape and optionally convert if ~isempty(unit) - shape = ft_convert_units(shape, unit); + % ensure the atlas is in the desired units + atlas = ft_convert_units(atlas, unit); else + % ensure the units of the atlas are specified try - % ft_convert_units will fail for triangle-only gifties. - shape = ft_convert_units(shape); + atlas = ft_determine_units(atlas); catch + % ft_determine_units will fail for triangle-only gifties. end end - diff --git a/external/fieldtrip/fileio/ft_read_cifti.m b/external/fieldtrip/fileio/ft_read_cifti.m index f1179929..ef7e4758 100644 --- a/external/fieldtrip/fileio/ft_read_cifti.m +++ b/external/fieldtrip/fileio/ft_read_cifti.m @@ -94,7 +94,7 @@ % set the default for readdata if isempty(readdata) if filesize>1e9 - warning('Not reading data by default in case filesize>1GB. Please specify the ''readdata'' option.'); + ft_warning('Not reading data by default in case filesize>1GB. Please specify the ''readdata'' option.'); readdata = false; else readdata = true; @@ -104,7 +104,7 @@ fseek(fid, 540, 'bof'); hdrext = fread(fid, [1 4], 'int8'); if hdrext(1)~=1 - error('cifti requires a header extension'); + ft_error('cifti requires a header extension'); end % determine the size of the header extension @@ -114,13 +114,13 @@ hdrsize = 540; voxsize = filesize-hdr.vox_offset; if esize>(filesize-hdrsize-voxsize) - warning('the endianness of the header extension is inconsistent with the nifti-2 header'); + ft_warning('the endianness of the header extension is inconsistent with the nifti-2 header'); esize = swapbytes(esize); etype = swapbytes(etype); end if etype~=32 && etype~=swapbytes(int32(32)) % FIXME there is an endian problem - error('the header extension type is not cifti'); + ft_error('the header extension type is not cifti'); end % read the extension content, subtract the 8 bytes from esize and etype @@ -358,7 +358,7 @@ Surface(end ).SurfaceNumberOfVertices = MatrixIndicesMap(i).BrainModel(j).SurfaceNumberOfVertices; otherwise - error('unsupported cifti version'); + ft_error('unsupported cifti version'); end % switch version @@ -367,7 +367,7 @@ MatrixIndicesMap(i).BrainModel(j).VoxelIndicesIJK = reshape(tmp, 3, [])' + 1; % transpose, one offset otherwise - error('unsupported ModelType'); + ft_error('unsupported ModelType'); end % switch ModelType end % for each BrainModel end % for each MatrixIndicesMap @@ -386,7 +386,7 @@ case 64, [voxdata, nitemsread] = fread(fid, inf, 'double'); assert(nitemsread==prod(hdr.dim(2:end)), 'could not read all data'); case 512, [voxdata, nitemsread] = fread(fid, inf, 'ushort'); assert(nitemsread==prod(hdr.dim(2:end)), 'could not read all data'); case 768, [voxdata, nitemsread] = fread(fid, inf, 'uint'); assert(nitemsread==prod(hdr.dim(2:end)), 'could not read all data'); - otherwise, error('unsupported datatype'); + otherwise, ft_error('unsupported datatype'); end % hdr.dim(1) is the number of dimensions % hdr.dim(2) is reserved for the x-dimension @@ -474,7 +474,7 @@ % case 'METER' % case 'RADIAN' otherwise - error('unsupported SeriesUnit'); + ft_error('unsupported SeriesUnit'); end % switch SeriesUnit case 'CIFTI_INDEX_TYPE_SCALARS' @@ -501,11 +501,11 @@ Cifti.fsample = 1/str2double(MatrixIndicesMap(i).TimeStep); otherwise % other units should be trivial to implement - error('unsupported TimeStepUnits "%s"', MatrixIndicesMap(i).TimeStepUnits); + ft_error('unsupported TimeStepUnits "%s"', MatrixIndicesMap(i).TimeStepUnits); end % switch TimeStepUnits otherwise - error('unsupported IndicesMapToDataType'); + ft_error('unsupported IndicesMapToDataType'); end % switch IndicesMapToDataType end % for each MatrixIndicesMap @@ -541,7 +541,7 @@ greynodeIndex{i} = BrainModel(i).VertexIndices; brainstructureIndex{i} = 1:BrainModel(i).SurfaceNumberOfVertices; otherwise - error('unsupported cifti version'); + ft_error('unsupported cifti version'); end % switch sel = find(strcmp({Surface(:).BrainStructure}, BrainModel(i).BrainStructure)); @@ -554,7 +554,7 @@ surfaceIndex(i) = nan; % does not map onto surface otherwise - error('unsupported ModelType "%s"', BrainModel(i).ModelType); + ft_error('unsupported ModelType "%s"', BrainModel(i).ModelType); end end % for each BrainModel @@ -757,7 +757,7 @@ source.dimord = 'chan_chan_time'; otherwise - error('unsupported dimord %s', source.dimord); + ft_error('unsupported dimord %s', source.dimord); end % switch if isfield(Cifti, 'mapname') && isfield(Cifti, 'labeltable') && strcmp(mapname, 'array') @@ -766,11 +766,11 @@ allthesame = allthesame && isequal(Cifti.labeltable{1}, Cifti.labeltable{i}); end if allthesame - warning('using the same labels for all maps in the array'); + ft_warning('using the same labels for all maps in the array'); source.datalabel = Cifti.labeltable{1}; Cifti = rmfield(Cifti, 'labeltable'); else - error('multiple maps cannot be represented as array in the presence of different labeltables'); + ft_error('multiple maps cannot be represented as array in the presence of different labeltables'); end end @@ -795,7 +795,7 @@ source.data = dat; source.dimord = [source.dimord '_mapname']; otherwise - error('incorrect specification of mapname "%s"', mapname); + ft_error('incorrect specification of mapname "%s"', mapname); end % switch mapname else % the name of the data will be based on the filename @@ -840,7 +840,7 @@ geomodel = t{4}; content = t{5}; else - warning('cannot parse file name'); + ft_warning('cannot parse file name'); end if readsurface diff --git a/external/fieldtrip/fileio/ft_read_data.m b/external/fieldtrip/fileio/ft_read_data.m index d7d463e6..10849473 100644 --- a/external/fieldtrip/fileio/ft_read_data.m +++ b/external/fieldtrip/fileio/ft_read_data.m @@ -31,6 +31,9 @@ % % The list of supported file formats can be found in FT_READ_HEADER. % +% To use an external reading function, use key-value pair: 'dataformat', FUNCTION_NAME. +% (Function needs to be on the path, and take as input: filename, hdr, begsample, endsample, chanindx.) +% % See also FT_READ_HEADER, FT_READ_EVENT, FT_WRITE_DATA, FT_WRITE_EVENT % Copyright (C) 2003-2016 Robert Oostenveld @@ -61,7 +64,7 @@ end if iscell(filename) - ft_warning(sprintf('concatenating data from %d files', numel(filename))); + ft_warning('concatenating data from %d files', numel(filename)); % this only works if the data is indexed by means of samples, not trials assert(isempty(ft_getopt(varargin, 'begtrial'))); assert(isempty(ft_getopt(varargin, 'endtrial'))); @@ -143,7 +146,7 @@ % test whether the file or directory exists if ~any(strcmp(dataformat, {'fcdc_buffer', 'ctf_shm', 'fcdc_mysql'})) && ~exist(filename, 'file') - error('FILEIO:InvalidFileName', 'file or directory ''%s'' does not exist', filename); + ft_error('FILEIO:InvalidFileName', 'file or directory ''%s'' does not exist', filename); end % ensure that these are double precision and not integers, otherwise the subsequent computations will be messed up @@ -154,19 +157,19 @@ % ensure that the requested sample and trial numbers are integers if ~isempty(begsample) && mod(begsample, 1) - warning('rounding "begsample" to the nearest integer'); + ft_warning('rounding "begsample" to the nearest integer'); begsample = round(begsample); end if ~isempty(endsample) && ~isinf(endsample) && mod(endsample, 1) - warning('rounding "endsample" to the nearest integer'); + ft_warning('rounding "endsample" to the nearest integer'); endsample = round(endsample); end if ~isempty(begtrial) && mod(begtrial, 1) - warning('rounding "begtrial" to the nearest integer'); + ft_warning('rounding "begtrial" to the nearest integer'); begtrial = round(begtrial); end if ~isempty(endtrial) && mod(endtrial, 1) - warning('rounding "endtrial" to the nearest integer'); + ft_warning('rounding "endtrial" to the nearest integer'); endtrial = round(endtrial); end @@ -205,7 +208,7 @@ end % test whether the requested channels can be accomodated if min(chanindx)<1 || max(chanindx)>hdr.nChans - error('FILEIO:InvalidChanIndx', 'selected channels are not present in the data'); + ft_error('FILEIO:InvalidChanIndx', 'selected channels are not present in the data'); end end @@ -216,16 +219,16 @@ % test whether the requested data segment is not outside the file if any(begsample<1) - error('FILEIO:InvalidBegSample', 'cannot read data before the begin of the file'); + ft_error('FILEIO:InvalidBegSample', 'cannot read data before the begin of the file'); elseif any(endsample>(hdr.nSamples*hdr.nTrials)) && ~blocking - error('FILEIO:InvalidEndSample', 'cannot read data after the end of the file'); + ft_error('FILEIO:InvalidEndSample', 'cannot read data after the end of the file'); end requesttrials = isempty(begsample) && isempty(endsample); requestsamples = isempty(begtrial) && isempty(endtrial); if cache && requesttrials - error('caching is not supported when reading trials') + ft_error('caching is not supported when reading trials') end if isempty(begsample) && isempty(endsample) && isempty(begtrial) && isempty(endtrial) @@ -244,7 +247,7 @@ end if requesttrials && requestsamples - error('you cannot select both trials and samples at the same time'); + ft_error('you cannot select both trials and samples at the same time'); elseif requesttrials % this allows for support using a continuous reader if isinf(hdr.nSamples) && begtrial==1 @@ -258,17 +261,17 @@ begtrial = floor((begsample-1)/hdr.nSamples)+1; endtrial = floor((endsample-1)/hdr.nSamples)+1; else - error('you should either specify begin/end trial or begin/end sample'); + ft_error('you should either specify begin/end trial or begin/end sample'); end % test whether the requested data segment does not extend over a discontinuous trial boundary if checkboundary && hdr.nTrials>1 if begtrial~=endtrial - error('requested data segment extends over a discontinuous trial boundary'); + ft_error('requested data segment extends over a discontinuous trial boundary'); end end -if any(strcmp(dataformat, {'bci2000_dat', 'eyelink_asc', 'gtec_mat', 'mega_neurone'})) +if any(strcmp(dataformat, {'bci2000_dat', 'eyelink_asc', 'gtec_mat', 'gtec_hdf5', 'mega_neurone'})) % caching for these formats is handled in the main section and in ft_read_header else % implement the caching in a data-format independent way @@ -312,7 +315,7 @@ case 'double' samplesize = 8; otherwise - error('unsupported data format'); + ft_error('unsupported data format'); end % 4D/BTi MEG data is multiplexed, can be epoched/discontinuous offset = (begsample-1)*samplesize*hdr.nChans; @@ -321,7 +324,7 @@ if isfield(hdr.orig, 'ChannelUnitsPerBit') upb = hdr.orig.ChannelUnitsPerBit; else - warning('cannot determine ChannelUnitsPerBit'); + ft_warning('cannot determine ChannelUnitsPerBit'); upb = 1; end % jump to the desired data @@ -354,7 +357,7 @@ % only include the gain values in the calibration calib = diag(gain(chanindx)); otherwise - error('unsupported data format'); + ft_error('unsupported data format'); end % calibrate the data dat = double(full(sparse(calib)*dat)); @@ -412,7 +415,7 @@ % read and concatenate all required data epochs [orig, buf] = readbdf(orig, i, 0); if size(buf,2)~=hdr.nChans || size(buf,1)~=epochlength - error('error reading selected data from bdf-file'); + ft_error('error reading selected data from bdf-file'); else dat(:,((i-begepoch)*epochlength+1):((i-begepoch+1)*epochlength)) = buf(:,chanindx)'; end @@ -567,7 +570,7 @@ data_in_epoch(iEpoch) = length(intersect(begsamp_epoch:endsamp_epoch,begsample:endsample)); end if sum(data_in_epoch>1) > 1 - warning('The requested segment from %i to %i is spread out over multiple epochs with possibly discontinuous boundaries', begsample, endsample); + ft_warning('The requested segment from %i to %i is spread out over multiple epochs with possibly discontinuous boundaries', begsample, endsample); end end end @@ -575,7 +578,7 @@ % read in data in different signals binfiles = dir(fullfile(filename, 'signal*.bin')); if isempty(binfiles) - error('FieldTrip:read_mff_header:nobin', ['could not find any signal.bin in ' filename_mff ]) + ft_error('FieldTrip:read_mff_header:nobin', ['could not find any signal.bin in ' filename_mff ]) end % determine which channels are in which signal for iSig = 1:length(hdr.orig.signal) @@ -631,7 +634,7 @@ dat2=zeros(hdr.nChans,hdr.nSamples,hdr.nTrials); for i=1:hdr.nTrials dat2(:,:,i)=dat(:,hdr.orig.epochdef(i,1):hdr.orig.epochdef(i,2)); - end; + end dat=dat2; end @@ -647,7 +650,7 @@ for i=1:length(globalList) eval(['global ' globalList(i).name ';']); eval(['globalTemp{end+1}=' globalList(i).name ';']); - end; + end %%%%%%%%%%%%%%%%%%%%%% mff_setup; @@ -659,8 +662,8 @@ eval([globalList(i).name '=globalTemp{i};']); if ~any(strcmp(globalList(i).name,varNames)) %was global variable originally out of scope? eval(['clear ' globalList(i).name ';']); %clears link to global variable without affecting it - end; - end; + end + end clear globalTemp globalList varNames varList; %%%%%%%%%%%%%%%%%%%%%% @@ -711,7 +714,7 @@ nevents = 0; % disable waiting for events available = buffer_wait_dat([nsamples nevents timeout], host, port); if available.nsamplessize(dat,2) - warning('Simulation was not completed, reading in part of the data') + ft_warning('Simulation was not completed, reading in part of the data') endsample=size(dat,2); end dat = dat(chanindx,begsample:endsample); @@ -1160,13 +1181,13 @@ case 'neurosim_evolution' [hdr, dat] = read_neurosim_evolution(filename); if endsample>size(dat,2) - warning('Simulation was not completed, reading in part of the data') + ft_warning('Simulation was not completed, reading in part of the data') endsample=size(dat,2); end dat = dat(chanindx,begsample:endsample); case 'neurosim_spikes' - warning('Reading Neurosim spikes as continuous data, for better memory efficiency use spike structure provided by ft_read_spike instead.'); + ft_warning('Reading Neurosim spikes as continuous data, for better memory efficiency use spike structure provided by ft_read_spike instead.'); spike = ft_read_spike(filename); cfg = []; cfg.trialdef.triallength = inf; @@ -1175,9 +1196,9 @@ cfg.datafile=filename; cfg.hdr = ft_read_header(cfg.datafile); - warning('off','FieldTrip:ft_read_event:unsupported_event_format') + ft_warning('off','FieldTrip:ft_read_event:unsupported_event_format') cfg = ft_definetrial(cfg); - warning('on','FieldTrip:ft_read_event:unsupported_event_format') + ft_warning('on','FieldTrip:ft_read_event:unsupported_event_format') spiketrl = ft_spike_maketrials(cfg,spike); dat=ft_checkdata(spiketrl,'datatype', 'raw', 'fsample', spiketrl.hdr.Fs); @@ -1260,7 +1281,7 @@ end end if any(isnan(dat(:))) - warning('data has been padded with NaNs'); + ft_warning('data has been padded with NaNs'); end case 'plexon_plx' @@ -1279,7 +1300,7 @@ [spikeindx, spikesel] = match_str(spikelabel, hdr.label(chanindx)); if (length(contindx)+length(spikeindx)) hdr.nSamples - event(i).sample = hdr.nSamples; + event(i).sample = hdr.nSamples; end event(i).duration = hdr.orig.Events(i).duration*maxSampleRate; end - %Add boundary events to indicate segments - originalEventCount = length(hdr.orig.Events); + %Add boundary events to indicate segments + originalEventCount = length(hdr.orig.Events); boundaryEventCount = 1; - for i=2:length(hdr.orig.Segments) - event(originalEventCount+boundaryEventCount).type = 'boundary'; - event(originalEventCount+boundaryEventCount).value = 'boundary'; - event(originalEventCount+boundaryEventCount).offset = 0; - event(originalEventCount+boundaryEventCount).duration = 0; - event(originalEventCount+boundaryEventCount).sample = sum([hdr.orig.Segments(1:(i-1)).sampleCount]); - boundaryEventCount = boundaryEventCount+1; - end + for i=2:length(hdr.orig.Segments) + event(originalEventCount+boundaryEventCount).type = 'boundary'; + event(originalEventCount+boundaryEventCount).value = 'boundary'; + event(originalEventCount+boundaryEventCount).offset = 0; + event(originalEventCount+boundaryEventCount).duration = 0; + event(originalEventCount+boundaryEventCount).sample = sum([hdr.orig.Segments(1:(i-1)).sampleCount]); + boundaryEventCount = boundaryEventCount+1; + end case {'neuromag_eve'} % previously this was called babysquid_eve, now it is neuromag_eve - % see also http://bugzilla.fcdonders.nl/show_bug.cgi?id=2170 + % see also http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2170 [p, f, x] = fileparts(filename); evefile = fullfile(p, [f '.eve']); fiffile = fullfile(p, [f '.fif']); @@ -1379,7 +1402,7 @@ type(typ==0) = {'trigger'}; if any(typ~=0) % see the comments in read_neuromag_eve - warning('entries in the *.eve file with a type other than 0 are represented as ''unknown''') + ft_warning('entries in the *.eve file with a type other than 0 are represented as ''unknown''') end % convert to a structure array event = struct('type', type, 'value', value, 'sample', sample, 'offset', offset); @@ -1426,9 +1449,10 @@ if iscontinuous analogindx = find(strcmp(ft_chantype(hdr), 'analog trigger')); + otherindx = find(strcmp(ft_chantype(hdr), 'other trigger')); binaryindx = find(strcmp(ft_chantype(hdr), 'digital trigger')); - if isempty(binaryindx)&&isempty(analogindx) + if isempty(binaryindx) && isempty(analogindx) && isempty(otherindx) % included in case of problems with older systems and MNE reader: % use a predefined set of channel names binary = {'STI 014', 'STI 015', 'STI 016'}; @@ -1439,6 +1463,10 @@ trigger = read_trigger(filename, 'header', hdr, 'dataformat', dataformat, 'begsample', flt_minsample, 'endsample', flt_maxsample, 'chanindx', binaryindx, 'detectflank', detectflank, 'trigshift', trigshift, 'fixneuromag', false); event = appendevent(event, trigger); end + if ~isempty(otherindx) + trigger = read_trigger(filename, 'header', hdr, 'dataformat', dataformat, 'begsample', flt_minsample, 'endsample', flt_maxsample, 'chanindx', otherindx, 'detectflank', detectflank, 'trigshift', trigshift, 'fixneuromag', false); + event = appendevent(event, trigger); + end if ~isempty(analogindx) % add the triggers to the event structure based on trigger channels with the name "STI xxx" % there are some issues with noise on these analog trigger @@ -1504,7 +1532,7 @@ end elseif isepoched - error('Support for epoched *.fif data is not yet implemented.') + ft_error('Support for epoched *.fif data is not yet implemented.') end % check whether the *.fif file is accompanied by an *.eve file @@ -1552,7 +1580,7 @@ end if ~exist(ttlfile) && ~exist(tslfile) && ~exist(tshfile) % these files must be present in a splitted dma dataset - error('could not locate the individual ttl, tsl and tsh files'); + ft_error('could not locate the individual ttl, tsl and tsh files'); end % read the trigger values from the separate file ttl = read_neuralynx_bin(ttlfile, begsample, endsample); @@ -1686,7 +1714,7 @@ event = read_nmc_archive_k_event(filename); case 'netmeg' - warning('FieldTrip:ft_read_event:unsupported_event_format', 'reading of events for the netmeg format is not yet supported'); + ft_warning('FieldTrip:ft_read_event:unsupported_event_format', 'reading of events for the netmeg format is not yet supported'); event = []; case 'neuroshare' % NOTE: still under development @@ -1730,7 +1758,7 @@ % elseif hasmat % FIXME, do something here else - error('no event file found'); + ft_error('no event file found'); end % The sample number is missingin the code below, since it is not available @@ -1777,7 +1805,7 @@ case 'nexstim_nxe' event = read_nexstim_event(filename); - + case 'nihonkohden_m00' % in the data I tested the triggers are marked as DC offsets (deactivation of the DC channel) begsample = 1; @@ -1978,14 +2006,14 @@ if (idx==2) trigger(i).sample = trigger(i+1).sample; end - + trigger(i+1) = []; else i=i+1; last_trigger_sample = trigger(i).sample; end end - + event = appendevent(event, trigger); end @@ -1996,8 +2024,15 @@ event = read_spmeeg_event(filename, 'header', hdr); otherwise - warning('FieldTrip:ft_read_event:unsupported_event_format','unsupported event format (%s)', eventformat); - event = []; + % attempt to run eventformat as a function + % in case using an external read function was desired, this is where it is executed + % if it fails, the regular unsupported warning message is thrown + try + event = feval(eventformat,filename); + catch + ft_warning('FieldTrip:ft_read_event:unsupported_event_format','unsupported event format (%s)', eventformat); + event = []; + end end if ~isempty(hdr) && hdr.nTrials>1 && (isempty(event) || ~any(strcmp({event.type}, 'trial'))) @@ -2014,8 +2049,8 @@ if ~isempty(event) % make sure that all required elements are present - if ~isfield(event, 'type'), error('type field not defined for each event'); end - if ~isfield(event, 'sample'), error('sample field not defined for each event'); end + if ~isfield(event, 'type'), ft_error('type field not defined for each event'); end + if ~isfield(event, 'sample'), ft_error('sample field not defined for each event'); end if ~isfield(event, 'value'), for i=1:length(event), event(i).value = []; end; end if ~isfield(event, 'offset'), for i=1:length(event), event(i).offset = []; end; end if ~isfield(event, 'duration'), for i=1:length(event), event(i).duration = []; end; end diff --git a/external/fieldtrip/fileio/ft_read_header.m b/external/fieldtrip/fileio/ft_read_header.m index 8fbc766e..3e6855ff 100644 --- a/external/fieldtrip/fileio/ft_read_header.m +++ b/external/fieldtrip/fileio/ft_read_header.m @@ -33,6 +33,9 @@ % % For continuously recorded data, nSamplesPre=0 and nTrials=1. % +% To use an external reading function, use key-value pair: 'headerformat', FUNCTION_NAME. +% (Function needs to be on the path, and take as input: filename) +% % Depending on the file format, additional header information can be % returned in the hdr.orig subfield. % @@ -52,7 +55,7 @@ % BrainVision (*.eeg, *.seg, *.dat, *.vhdr, *.vmrk) % CED - Cambridge Electronic Design (*.smr) % EGI - Electrical Geodesics, Inc. (*.egis, *.ave, *.gave, *.ses, *.raw, *.sbin, *.mff) -% GTec (*.mat) +% GTec (*.mat, *.hdf5) % Generic data formats (*.edf, *.gdf) % Megis/BESA (*.avr, *.swf, *.besa) % NeuroScan (*.eeg, *.cnt, *.avg) @@ -60,7 +63,7 @@ % TMSi (*.Poly5) % Mega Neurone (directory) % Natus/Nicolet/Nervus (.e files) -% Nihon Kohden (*.m00) +% Nihon Kohden (*.m00) % % The following spike and LFP dataformats are supported % Neuralynx (*.ncs, *.nse, *.nts, *.nev, *.nrd, *.dma, *.log) @@ -113,7 +116,7 @@ if iscell(filename) % use recursion to read events from multiple files - ft_warning(sprintf('concatenating header from %d files', numel(filename))); + ft_warning('concatenating header from %d files', numel(filename)); hdr = cell(size(filename)); for i=1:numel(filename) hdr{i} = ft_read_header(filename{i}, varargin{:}); @@ -137,7 +140,7 @@ combined.nTrials = sum(ntrl); combined.nSamples = nsmp(1); else - error('cannot concatenate files'); + ft_error('cannot concatenate files'); end % return the header of the concatenated datafiles hdr = combined; @@ -191,7 +194,7 @@ else % check whether the file or directory exists if ~exist(filename, 'file') - error('FILEIO:InvalidFileName', 'file or directory ''%s'' does not exist', filename); + ft_error('FILEIO:InvalidFileName', 'file or directory ''%s'' does not exist', filename); end checkUniqueLabels = true; @@ -201,7 +204,7 @@ checkmaxfilter = ft_getopt(varargin, 'checkmaxfilter', true); if isempty(cache) - if any(strcmp(headerformat, {'bci2000_dat', 'eyelink_asc', 'gtec_mat', 'mega_neurone', 'smi_txt', 'biosig'})) + if any(strcmp(headerformat, {'bci2000_dat', 'eyelink_asc', 'gtec_mat', 'gtec_hdf5', 'mega_neurone', 'smi_txt', 'biosig'})) cache = true; else cache = false; @@ -243,7 +246,7 @@ % the support for head/dewar coordinates is still limited if strcmp(coordsys, 'dewar') && ~any(strcmp(headerformat, {'fcdc_buffer', 'ctf_ds', 'ctf_meg4', 'ctf_res4', 'neuromag_fif', 'neuromag_mne'})) - error('dewar coordinates are not supported for %s', headerformat); + ft_error('dewar coordinates are not supported for %s', headerformat); end % start with an empty header @@ -281,7 +284,7 @@ hdr.nTrials = orig.TotalEpochs; hdr.label = orig.ChannelOrder(:); [hdr.grad, elec] = bti2grad(orig); - if ~isempty(elec), + if ~isempty(elec) hdr.elec = elec; end @@ -342,11 +345,11 @@ else hdr = read_besa_besa(filename,[],1); if chanindx > hdr.orig.channel_info.orig_n_channels - error('FILEIO:InvalidChanIndx', 'selected channels are not present in the data'); + ft_error('FILEIO:InvalidChanIndx', 'selected channels are not present in the data'); else hdr = read_besa_besa(filename,[],chanindx); - end; - end; + end + end case 'besa_avr' orig = read_besa_avr(filename); @@ -384,7 +387,7 @@ case {'biosemi_bdf', 'bham_bdf'} hdr = read_biosemi_bdf(filename); if any(diff(hdr.orig.SampleRate)) - error('channels with different sampling rate not supported'); + ft_error('channels with different sampling rate not supported'); end if ~ft_senstype(hdr, 'ext1020') @@ -412,7 +415,7 @@ % this uses the openbdf and readbdf functions that were copied from EEGLAB orig = openbdf(filename); if any(orig.Head.SampleRate~=orig.Head.SampleRate(1)) - error('channels with different sampling rate not supported'); + ft_error('channels with different sampling rate not supported'); end hdr.Fs = orig.Head.SampleRate(1); hdr.nChans = orig.Head.NS; @@ -426,7 +429,7 @@ fclose(orig.Head.FILE.FID); case 'blackrock_nev' - error('this still needs some work'); + ft_error('this still needs some work'); case 'blackrock_nsx' ft_hastoolbox('NPMK', 1); @@ -478,20 +481,20 @@ % In Spike2, channels can have different sampling rates, units, length % etc. etc. Here, channels need to have to same properties. if length(unique([orig.samplerate]))>1, - error('channels with different sampling rates are not supported'); + ft_error('channels with different sampling rates are not supported'); else hdr.Fs = orig(1).samplerate; - end; + end hdr.nChans = length(orig); % nsamples of the channel with least samples hdr.nSamples = min([orig.nsamples]); hdr.nSamplesPre = 0; % only continuous data supported if sum(strcmpi({orig.mode},'continuous')) < hdr.nChans, - error('not all channels contain continuous data'); + ft_error('not all channels contain continuous data'); else hdr.nTrials = 1; - end; + end hdr.label = {orig.label}; case 'combined_ds' @@ -504,7 +507,7 @@ if isempty(orig) % this is to deal with data from the 64 channel system and the error % readCTFds: .meg4 file header=MEG4CPT Valid header options: MEG41CP MEG42CP - error('could not read CTF with this implementation, please try again with the ''ctf_old'' file format'); + ft_error('could not read CTF with this implementation, please try again with the ''ctf_old'' file format'); end hdr.Fs = orig.res4.sample_rate; hdr.nChans = orig.res4.no_channels; @@ -524,7 +527,7 @@ orig.BalanceCoefs.none.MEGlist = MEGlist; orig.BalanceCoefs.none.Refindex = Refindex; catch - warning('cannot read balancing coefficients for NONE'); + ft_warning('cannot read balancing coefficients for NONE'); end if any(~cellfun(@isempty,strfind(coeftype, 'G1BR'))) try @@ -533,7 +536,7 @@ orig.BalanceCoefs.G1BR.MEGlist = MEGlist; orig.BalanceCoefs.G1BR.Refindex = Refindex; catch - warning('cannot read balancing coefficients for G1BR'); + ft_warning('cannot read balancing coefficients for G1BR'); end end if any(~cellfun(@isempty,strfind(coeftype, 'G2BR'))) @@ -543,7 +546,7 @@ orig.BalanceCoefs.G2BR.MEGlist = MEGlist; orig.BalanceCoefs.G2BR.Refindex = Refindex; catch - warning('cannot read balancing coefficients for G2BR'); + ft_warning('cannot read balancing coefficients for G2BR'); end end if any(~cellfun(@isempty,strfind(coeftype, 'G3BR'))) @@ -553,7 +556,7 @@ orig.BalanceCoefs.G3BR.MEGlist = MEGlist; orig.BalanceCoefs.G3BR.Refindex = Refindex; catch - warning('cannot read balancing coefficients for G3BR'); + ft_warning('cannot read balancing coefficients for G3BR'); end end if any(~cellfun(@isempty,strfind(coeftype, 'G3AR'))) @@ -565,17 +568,23 @@ catch % May not want a warning here if these are not commonly used. % Already get a (fprintf) warning from getCTFBalanceCoefs.m - % warning('cannot read balancing coefficients for G3AR'); + % ft_warning('cannot read balancing coefficients for G3AR'); end end % add a gradiometer structure for forward and inverse modelling try - hdr.grad = ctf2grad(orig, strcmp(coordsys, 'dewar'), coilaccuracy); + [grad, elec] = ctf2grad(orig, strcmp(coordsys, 'dewar'), coilaccuracy); + if ~isempty(grad) + hdr.grad = grad; + end + if ~isempty(elec) + hdr.elec = elec; + end catch % this fails if the res4 file is not correctly closed, e.g. during realtime processing tmp = lasterror; disp(tmp.message); - warning('could not construct gradiometer definition from the header'); + ft_warning('could not construct gradiometer definition from the header'); end % for realtime analysis EOF chasing the res4 does not correctly @@ -607,7 +616,7 @@ % this fails if the res4 file is not correctly closed, e.g. during realtime processing tmp = lasterror; disp(tmp.message); - warning('could not construct gradiometer definition from the header'); + ft_warning('could not construct gradiometer definition from the header'); end % add the original header details hdr.orig = orig; @@ -635,7 +644,7 @@ % this fails if the res4 file is not correctly closed, e.g. during realtime processing tmp = lasterror; disp(tmp.message); - warning('could not construct gradiometer definition from the header'); + ft_warning('could not construct gradiometer definition from the header'); end % add the original header details hdr.orig = orig; @@ -682,7 +691,7 @@ else hdr = read_edf(filename,[],1); if chanindx > hdr.orig.NS - error('FILEIO:InvalidChanIndx', 'selected channels are not present in the data'); + ft_error('FILEIO:InvalidChanIndx', 'selected channels are not present in the data'); else hdr = read_edf(filename,[],chanindx); end @@ -768,22 +777,22 @@ [p, f, x] = fileparts(filename); if any(chdr(:,4)-chdr(1,4)) - error('Sample rate not the same for all cells.'); - end; + ft_error('Sample rate not the same for all cells.'); + end hdr.Fs = chdr(1,4); %making assumption that sample rate is same for all cells hdr.nChans = fhdr(19); for i = 1:hdr.nChans % this should be consistent with ft_senslabel hdr.label{i,1} = ['E' num2str(i)]; - end; + end %since NetStation does not properly set the fhdr(11) field, use the number of subjects from the chdr instead hdr.nTrials = chdr(1,2)*fhdr(18); %number of trials is numSubjects * numCells hdr.nSamplesPre = ceil(fhdr(14)/(1000/hdr.Fs)); if any(chdr(:,3)-chdr(1,3)) - error('Number of samples not the same for all cells.'); - end; + ft_error('Number of samples not the same for all cells.'); + end hdr.nSamples = chdr(1,3); %making assumption that number of samples is same for all cells @@ -800,15 +809,15 @@ [p, f, x] = fileparts(filename); if any(chdr(:,4)-chdr(1,4)) - error('Sample rate not the same for all cells.'); - end; + ft_error('Sample rate not the same for all cells.'); + end hdr.Fs = chdr(1,4); %making assumption that sample rate is same for all cells hdr.nChans = fhdr(19); for i = 1:hdr.nChans % this should be consistent with ft_senslabel hdr.label{i,1} = ['E' num2str(i)]; - end; + end hdr.nTrials = sum(chdr(:,2)); hdr.nSamplesPre = ceil(fhdr(14)/(1000/hdr.Fs)); % assuming that a utility was used to insert the correct baseline @@ -817,8 +826,8 @@ % does not use it when generating an EGIS session file. if any(chdr(:,3)-chdr(1,3)) - error('Number of samples not the same for all cells.'); - end; + ft_error('Number of samples not the same for all cells.'); + end hdr.nSamples = chdr(1,3); %making assumption that number of samples is same for all cells @@ -839,7 +848,7 @@ for i = 1:hdr.nChans % this should be consistent with ft_senslabel hdr.label{i,1} = ['E' num2str(i)]; - end; + end hdr.nTrials = header_array(15); hdr.nSamplesPre = preBaseline; @@ -860,7 +869,7 @@ % this function as 'egi_mff_v2'. if ~usejava('jvm') - error('the xml2struct requires MATLAB to be running with the Java virtual machine (JVM)'); + ft_error('the xml2struct requires MATLAB to be running with the Java virtual machine (JVM)'); % an alternative implementation which does not require the JVM but runs much slower is % available from http://www.mathworks.com/matlabcentral/fileexchange/6268-xml4mat-v2-0 end @@ -868,7 +877,7 @@ % get header info from .bin files binfiles = dir(fullfile(filename, 'signal*.bin')); if isempty(binfiles) - error('could not find any signal.bin in mff directory') + ft_error('could not find any signal.bin in mff directory') end orig = []; @@ -879,7 +888,7 @@ end % get hdr info from xml files - warning('off', 'MATLAB:REGEXP:deprecated') % due to some small code xml2struct + ws = warning('off', 'MATLAB:REGEXP:deprecated'); % due to some small code xml2struct xmlfiles = dir( fullfile(filename, '*.xml')); disp('reading xml files to obtain header info...') for i = 1:numel(xmlfiles) @@ -891,7 +900,7 @@ orig.xml.(fieldname) = xml2struct(filename_xml); end end - warning('on', 'MATLAB:REGEXP:deprecated') + warning(ws); % revert the warning state % epochs.xml seems the most common version, but epoch.xml might also % occur, so use only one name @@ -918,7 +927,7 @@ end if length(unique(Fs)) > 1 || length(unique(nSamples)) > 1 - error('Fs and nSamples should be the same in all signals') + ft_error('Fs and nSamples should be the same in all signals') end hdr.Fs = Fs(1); @@ -951,12 +960,13 @@ if length(hdr.label) == nChans(1) % good elseif length(hdr.label) > orig.signal(1).blockhdr(1).nsignals - warning('found more lables in xml.sensorLayout than channels in signal 1, thus can not use info in sensorLayout, creating labels on the fly') + ft_warning('found more lables in xml.sensorLayout than channels in signal 1, thus can not use info in sensorLayout, creating labels on the fly') for iSens = 1:orig.signal(1).blockhdr(1).nsignals % this should be consistent with ft_senslabel hdr.label{iSens} = ['E' num2str(iSens)]; end - else warning('found less lables in xml.sensorLayout than channels in signal 1, thus can not use info in sensorLayout, creating labels on the fly') + else + ft_warning('found less lables in xml.sensorLayout than channels in signal 1, thus can not use info in sensorLayout, creating labels on the fly') for iSens = 1:orig.signal(1).blockhdr(1).nsignals % this should be consistent with ft_senslabel hdr.label{iSens} = ['E' num2str(iSens)]; @@ -969,27 +979,28 @@ for iSens = 1:numel(orig.xml.pnsSet.sensors) hdr.label{nbEEGchan+iSens} = num2str(orig.xml.pnsSet.sensors(iSens).sensor.name); end - if length(hdr.label) == orig.signal(2).blockhdr(1).nsignals + orig.signal(2).blockhdr(1).nsignals + if length(hdr.label) == orig.signal(1).blockhdr(1).nsignals + orig.signal(2).blockhdr(1).nsignals % good elseif length(hdr.label) < orig.signal(1).blockhdr(1).nsignals + orig.signal(2).blockhdr(1).nsignals - warning('found less lables in xml.pnsSet than channels in signal 2, labeling with s2_unknownN instead') + ft_warning('found less lables in xml.pnsSet than channels in signal 2, labeling with s2_unknownN instead') for iSens = length(hdr.label)+1 : orig.signal(1).blockhdr(1).nsignals + orig.signal(2).blockhdr(1).nsignals hdr.label{iSens} = ['s2_unknown', num2str(iSens)]; end - else warning('found more lables in xml.pnsSet than channels in signal 2, thus can not use info in pnsSet, and labeling with s2_eN instead') + else + ft_warning('found more lables in xml.pnsSet than channels in signal 2, thus can not use info in pnsSet, and labeling with s2_eN instead') for iSens = orig.signal(1).blockhdr(1).nsignals+1 : orig.signal(1).blockhdr(1).nsignals + orig.signal(2).blockhdr(1).nsignals hdr.label{iSens} = ['s2_E', num2str(iSens)]; end end else % signal2 is not PIBbox - warning('creating channel labels for signal 2 on the fly') + ft_warning('creating channel labels for signal 2 on the fly') for iSens = 1:orig.signal(2).blockhdr(1).nsignals hdr.label{end+1} = ['s2_E', num2str(iSens)]; end end elseif length(orig.signal) > 2 % loop over signals and label channels accordingly - warning('creating channel labels for signal 2 to signal N on the fly') + ft_warning('creating channel labels for signal 2 to signal N on the fly') for iSig = 2:length(orig.signal) for iSens = 1:orig.signal(iSig).blockhdr(1).nsignals if iSig == 1 && iSens == 1 @@ -1001,7 +1012,7 @@ end end else % no xml.sensorLayout present - warning('no sensorLayout found in xml files, creating channel labels on the fly') + ft_warning('no sensorLayout found in xml files, creating channel labels on the fly') for iSig = 1:length(orig.signal) for iSens = 1:orig.signal(iSig).blockhdr(1).nsignals if iSig == 1 && iSens == 1 @@ -1037,10 +1048,10 @@ epochdef(iEpoch,1) = ((epochdef(iEpoch,1)-1)/1000)+1; epochdef(iEpoch,2) = epochdef(iEpoch,2)/1000; epochdef(iEpoch,3) = epochdef(iEpoch,3)/1000; - end; - warning('mff apparently generated by NetStation 4.5.4. Adjusting time scale to microseconds from nanoseconds.'); + end + ft_warning('mff apparently generated by NetStation 4.5.4. Adjusting time scale to microseconds from nanoseconds.'); else - error('number of samples in all epochs do not add up to total number of samples') + ft_error('number of samples in all epochs do not add up to total number of samples') end end @@ -1050,7 +1061,7 @@ hdr.nTrials = length(epochLengths); else - warning('the data contains multiple epochs with variable length, possibly causing discontinuities in the data') + ft_warning('the data contains multiple epochs with variable length, possibly causing discontinuities in the data') % sanity check if epochdef(end,2) ~= hdr.nSamples % check for NS 4.5.4 picosecond timing @@ -1059,15 +1070,15 @@ epochdef(iEpoch,1)=((epochdef(iEpoch,1)-1)/1000)+1; epochdef(iEpoch,2)=epochdef(iEpoch,2)/1000; epochdef(iEpoch,3)=epochdef(iEpoch,3)/1000; - end; + end disp('mff apparently generated by NetStation 4.5.4. Adjusting time scale to microseconds from nanoseconds.'); else - error('number of samples in all epochs do not add up to total number of samples') - end; + ft_error('number of samples in all epochs do not add up to total number of samples') + end end end orig.epochdef = epochdef; - end; + end hdr.orig = orig; case 'egi_mff_v2' @@ -1083,7 +1094,7 @@ for i=1:length(globalList) eval(['global ' globalList(i).name ';']); eval(['globalTemp{end+1}=' globalList(i).name ';']); - end; + end %%%%%%%%%%%%%%%%%%%%%% mff_setup; @@ -1096,8 +1107,8 @@ eval([globalList(i).name '=globalTemp{i};']); if ~any(strcmp(globalList(i).name,varNames)) %was global variable originally out of scope? eval(['clear ' globalList(i).name ';']); %clears link to global variable without affecting it - end; - end; + end + end clear globalTemp globalList varNames varList; %%%%%%%%%%%%%%%%%%%%%% @@ -1121,7 +1132,7 @@ % try reading the header, catch the error and retry orig = buffer('get_hdr', [], host, port); catch - warning('could not read header from %s, retrying in 1 second', filename); + ft_warning('could not read header from %s, retrying in 1 second', filename); pause(1); end end % while @@ -1138,7 +1149,7 @@ hdr.nTrials = 1; % since continuous hdr.orig = []; % this will contain the chunks (if present) - % add the contents of attached FIF_header chunk after decoding to MATLAB structure + % add the contents of attached NEUROMAG_HEADER chunk after decoding to MATLAB structure if isfield(orig, 'neuromag_header') if isempty(cachechunk) % this only needs to be decoded once @@ -1167,7 +1178,7 @@ hdr.orig = cachechunk; end - % add the contents of attached RES4 chunk after decoding to MATLAB structure + % add the contents of attached CTF_RES4 chunk after decoding to MATLAB structure if isfield(orig, 'ctf_res4') if isempty(cachechunk) % this only needs to be decoded once @@ -1180,7 +1191,7 @@ % get the same selection of channels from the two chunks [selbuf, selres4] = match_str(orig.channel_names, cachechunk.label); if length(selres4)= hdr.nChans); + + for i=1:hdr.nChans + hdr.label{i} = num2str(i); + end + + hdr.chantype = repmat({'nirs'}, hdr.nChans, 1); + hdr.chanunit = repmat({'unknown'}, hdr.nChans, 1); + + % convert the measurement configuration details to an optode structure + try + end + hdr.opto = homer2opto(orig.SD); + + % keep the header details + hdr.orig.SD = orig.SD; + case {'itab_raw' 'itab_mhd'} % read the full header information frtom the binary header structure header_info = read_itab_mhd(headerfile); - % these are the channels that are visible to fieldtrip + % these are the channels that are visible to FieldTrip chansel = 1:header_info.nchan; % convert the header information into a FieldTrip compatible format @@ -1366,7 +1436,7 @@ hdr.nSamples = header_info.ntpdata; hdr.nSamplesPre = 0; % it is a single continuous trial hdr.nTrials = 1; % it is a single continuous trial - % keep the original details AND the list of channels as used by fieldtrip + % keep the original details AND the list of channels as used by FieldTrip hdr.orig = header_info; hdr.orig.chansel = chansel; % add the gradiometer definition @@ -1461,7 +1531,7 @@ try hdr.label = { EEG.chanlocs.labels }'; catch - warning('creating default channel names'); + ft_warning('creating default channel names'); for i=1:hdr.nChans hdr.label{i} = sprintf('chan%03d', i); end @@ -1571,7 +1641,7 @@ % construct the gradiometer structure from the complete header information hdr.grad = netmeg2grad(hdr); - + case 'nervus_eeg' hdr = read_nervus_header(filename); checkUniqueLabels = false; @@ -1698,7 +1768,7 @@ % no error message from fiff_setup_read_raw? Then maxshield % was applied, but maxfilter wasn't, so return this error: if istrue(checkmaxfilter) - error('Maxshield data should be corrected using Maxfilter prior to importing in FieldTrip.'); + ft_error('Maxshield data should be corrected using Maxfilter prior to importing in FieldTrip.'); else ft_warning('Maxshield data should be corrected using Maxfilter prior to importing in FieldTrip.'); end @@ -1716,12 +1786,12 @@ info.epochs = epochs; % this is used by read_data to get the actual data, i.e. to prevent re-reading elseif isaverage - try, + try evoked_data = fiff_read_evoked_all(filename); vartriallength = any(diff([evoked_data.evoked.first])) || any(diff([evoked_data.evoked.last])); if vartriallength % there are trials averages with variable durations in the file - warning('EVOKED FILE with VARIABLE TRIAL LENGTH! - check data have been processed accurately'); + ft_warning('EVOKED FILE with VARIABLE TRIAL LENGTH! - check data have been processed accurately'); hdr.nSamples = 0; for i=1:length(evoked_data.evoked) hdr.nSamples = hdr.nSamples + size(evoked_data.evoked(i).epochs, 2); @@ -1747,7 +1817,7 @@ % this happens if fiff_read_evoked_all cannot find evoked % responses, in which case it errors due to not assigning the % output variable "data" - warning('%s does not contain data', filename); + ft_warning('%s does not contain data', filename); hdr.nSamples = 0; hdr.nSamplesPre = 0; hdr.nTrials = 0; @@ -1885,10 +1955,10 @@ case 'neurosim_spikes' headerOnly = true; hdr = read_neurosim_spikes(filename, headerOnly); - + case 'nihonkohden_m00' - hdr = read_nihonkohden_hdr(filename); - + hdr = read_nihonkohden_hdr(filename); + case 'nimh_cortex' cortex = read_nimh_cortex(filename, 'epp', 'no', 'eog', 'no'); % look at the first trial to determine whether it contains data in the EPP and EOG channels @@ -1896,7 +1966,7 @@ hasepp = ~isempty(trial1.epp); haseog = ~isempty(trial1.eog); if hasepp - warning('EPP channels are not yet supported'); + ft_warning('EPP channels are not yet supported'); end % at the moment only the EOG channels are supported here if haseog @@ -1991,7 +2061,7 @@ hdr.nTrials = 1; % continuous hdr.label = cell(1,hdr.nChans); % give this warning only once - warning('creating fake channel names'); + ft_warning('creating fake channel names'); for i=1:hdr.nChans hdr.label{i} = sprintf('%d', i); end @@ -2004,7 +2074,7 @@ numsmp = cell2mat({orig.varheader.numsmp}); adindx = find(cell2mat({orig.varheader.typ})==5); if isempty(adindx) - error('file does not contain continuous channels'); + ft_error('file does not contain continuous channels'); end hdr.nChans = length(orig.varheader); hdr.Fs = orig.varheader(adindx(1)).wfrequency; % take the sampling frequency from the first A/D channel @@ -2023,7 +2093,7 @@ numsmp = cell2mat({orig.VarHeader.NPointsWave}); adindx = find(cell2mat({orig.VarHeader.Type})==5); if isempty(adindx) - error('file does not contain continuous channels'); + ft_error('file does not contain continuous channels'); end hdr.nChans = length(orig.VarHeader); hdr.Fs = orig.VarHeader(adindx(1)).WFrequency; % take the sampling frequency from the first A/D channel @@ -2042,11 +2112,11 @@ case 'plexon_plx' orig = read_plexon_plx(filename); if orig.NumSlowChannels==0 - error('file does not contain continuous channels'); + ft_error('file does not contain continuous channels'); end fsample = [orig.SlowChannelHeader.ADFreq]; if any(fsample~=fsample(1)) - error('different sampling rates in continuous data not supported'); + ft_error('different sampling rates in continuous data not supported'); end for i=1:length(orig.SlowChannelHeader) label{i} = deblank(orig.SlowChannelHeader(i).Name); @@ -2110,8 +2180,8 @@ hdr.Fs = 1000/hdr.TimeStampPerSample; % these timestamps are in miliseconds end - if hdr.nChans ~= size(smi.label,1); - error('data and header have different number of channels'); + if hdr.nChans ~= size(smi.label,1) + ft_error('data and header have different number of channels'); else hdr.label = smi.label; end @@ -2123,7 +2193,7 @@ hdr.orig = smi; end % add channel units when possible. - for i=1:hdr.nChans; + for i=1:hdr.nChans chanunit = regexp(hdr.label{i,1},'(?<=\[).+?(?=\])','match'); if ~isempty(chanunit) hdr.chanunit{i,1} = chanunit{1}; @@ -2185,7 +2255,7 @@ % for j=1:length(code) % codesel = false(size(tsq)); % for k=1:numel(codesel) - % codesel(k) = identical(tsq(k).code, code{j}); + % codesel(k) = isequal(tsq(k).code, code{j}); % end % % find the first instance of this logical channel % this = find(chansel(:) & codesel(:), 1); @@ -2196,7 +2266,7 @@ % tsqorig(k) = tsq(this); % end % end - error('not yet implemented'); + ft_error('not yet implemented'); case {'yokogawa_ave', 'yokogawa_con', 'yokogawa_raw', 'yokogawa_mrk'} % header can be read with two toolboxes: Yokogawa MEG Reader and Yokogawa MEG160 (old inofficial toolbox) @@ -2213,11 +2283,12 @@ end case 'riff_wave' - [y, fs, nbits, opts] = wavread(filename, 1); % read one sample - siz = wavread(filename,'size'); - hdr.Fs = fs; - hdr.nChans = siz(2); - hdr.nSamples = siz(1); + % prior to MATLAB R2015b this used to be done with "wavread" + % but the audioinfo/audioread function are at least available from 2012b up + info = audioinfo(filename); + hdr.Fs = info.SampleRate; + hdr.nChans = info.NumChannels; + hdr.nSamples = info.TotalSamples; hdr.nSamplesPre = 0; hdr.nTrials = 1; [p, f, x] = fileparts(filename); @@ -2232,7 +2303,7 @@ hdr.chantype{1,1} = 'audio'; end % remember the details - hdr.orig = opts; + hdr.orig = info; case 'videomeg_aud' hdr = read_videomeg_aud(filename); @@ -2242,10 +2313,17 @@ checkUniqueLabels = false; otherwise - if strcmp(fallback, 'biosig') && ft_hastoolbox('BIOSIG', 1) - hdr = read_biosig_header(filename); - else - error('unsupported header format "%s"', headerformat); + % attempt to run headerformat as a function + % in case using an external read function was desired, this is where it is executed + % if it fails, the regular unsupported error message is thrown + try + hdr = feval(headerformat,filename); + catch + if strcmp(fallback, 'biosig') && ft_hastoolbox('BIOSIG', 1) + hdr = read_biosig_header(filename); + else + ft_error('unsupported header format "%s"', headerformat); + end end end % switch headerformat @@ -2255,20 +2333,20 @@ % functions. See for example bug #1572. % First, make sure that there are enough (potentially empty) labels: if numel(hdr.label) < hdr.nChans - warning('low-level reading function did not supply enough channel labels'); + ft_warning('low-level reading function did not supply enough channel labels'); hdr.label{hdr.nChans} = []; end % Now, replace all empty labels with new name: if any(cellfun(@isempty, hdr.label)) - warning('channel labels should not be empty, creating unique labels'); + ft_warning('channel labels should not be empty, creating unique labels'); hdr.label = fix_empty(hdr.label); end if checkUniqueLabels if length(hdr.label)~=length(unique(hdr.label)) % all channels must have unique names - warning('all channels must have unique labels, creating unique labels'); + ft_warning('all channels must have unique labels, creating unique labels'); megflag = ft_chantype(hdr, 'meg'); eegflag = ft_chantype(hdr, 'eeg'); for i=1:hdr.nChans @@ -2352,7 +2430,7 @@ function [siz] = filesize(filename) l = dir(filename); if l.isdir - error('"%s" is not a file', filename); + ft_error('"%s" is not a file', filename); end siz = l.bytes; @@ -2380,7 +2458,7 @@ end catch thishdr = []; - warning(lasterr); + ft_warning(lasterr); fprintf('while reading %s\n\n', lst{i}); end if ~isempty(thishdr) @@ -2407,6 +2485,6 @@ % SUBFUNCTION to fill in empty labels %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function labels = fix_empty(labels) -for i = find(cellfun(@isempty, {labels{:}})); +for i = find(cellfun(@isempty, {labels{:}})) labels{i} = sprintf('%d', i); end diff --git a/external/fieldtrip/fileio/ft_read_headshape.m b/external/fieldtrip/fileio/ft_read_headshape.m index 03968acf..1155436d 100644 --- a/external/fieldtrip/fileio/ft_read_headshape.m +++ b/external/fieldtrip/fileio/ft_read_headshape.m @@ -32,16 +32,18 @@ % 'stl' STereoLithography file format, for use with CAD and/or generic 3D mesh editing programs % 'vtk' Visualization ToolKit file format, for use with Paraview % 'mne_*' MNE surface description in ASCII format ('mne_tri') or MNE source grid in ascii format, described as 3D points ('mne_pos') +% 'obj' Wavefront .obj file obtained with the structure.io +% 'off' +% 'ply' +% 'itab_asc' % 'ctf_*' % '4d_*' -% 'itab_asc' % 'neuromag_*' -% 'mne_source' % 'yokogawa_*' % 'polhemus_*' -% 'spmeeg_mat' -% 'off' % 'freesurfer_*' +% 'mne_source' +% 'spmeeg_mat' % 'netmeg' % 'vista' % 'tet' @@ -53,11 +55,10 @@ % 'caret_spec' % 'brainvisa_mesh' % 'brainsuite_dfs' -% 'obj' Wavefront .obj file obtained with the structure.io % % See also FT_READ_VOL, FT_READ_SENS, FT_READ_ATLAS, FT_WRITE_HEADSHAPE -% Copyright (C) 2008-2016 Robert Oostenveld +% Copyright (C) 2008-2017 Robert Oostenveld % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -106,7 +107,7 @@ if numel(filename)>1 && all(haspos==1) && strcmp(concatenate, 'yes') if length(bnd)>2 - error('Cannot concatenate more than two files') % no more than two files are taken for cancatenation + ft_error('Cannot concatenate more than two files') % no more than two files are taken for cancatenation else fprintf('Concatenating the meshes in %s and %s\n', filename{1}, filename{2}); @@ -119,7 +120,7 @@ elseif ~isfield(bnd(1), 'tri') && ~isfield(bnd(2), 'tri') % this is ok else - error('not all input files seem to contain a triangulation'); + ft_error('not all input files seem to contain a triangulation'); end % concatenate any other fields @@ -130,7 +131,7 @@ elseif ~isfield(bnd(1), fnames{k}) && ~isfield(bnd(2), fnames{k}) % this is ok else - error('not all input files seem to contain a "%s"', fnames{k}); + ft_error('not all input files seem to contain a "%s"', fnames{k}); end end @@ -166,7 +167,7 @@ end elseif numel(filename)>1 && ~all(haspos==1) if numel(bnd)>2 - error('Cannot combine more than two files') % no more than two files are taken for cancatenation + ft_error('Cannot combine more than two files') % no more than two files are taken for cancatenation else shape = []; if sum(haspos==1)==1 @@ -174,14 +175,14 @@ shape.pos = bnd(haspos==1).pos; shape.unit = bnd(haspos==1).unit; else - error('Don''t know what to do'); + ft_error('Don''t know what to do'); end if sum(hastri==1)==1 fprintf('Using the faces definition from %s\n', filename{find(hastri==1)}); shape.tri = bnd(hastri==1).tri; end if max(shape.tri(:))~=size(shape.pos,1) - error('mismatch in number of points in pos and tri'); + ft_error('mismatch in number of points in pos and tri'); end end @@ -194,12 +195,12 @@ end % if iscell % checks if there exists a .jpg file of 'filename' - [pathstr,name] = fileparts(filename); - if exist(fullfile(pathstr,[name,'.jpg'])) - image = fullfile(pathstr,[name,'.jpg']); - hasimage = 1; - end - +[pathstr,name] = fileparts(filename); +if exist(fullfile(pathstr,[name,'.jpg'])) + image = fullfile(pathstr,[name,'.jpg']); + hasimage = 1; +end + % optionally get the data from the URL and make a temporary local copy filename = fetch_url(filename); @@ -210,7 +211,7 @@ end if ~isempty(annotationfile) && ~strcmp(fileformat, 'mne_source') - error('at present extracting annotation information only works in conjunction with mne_source files'); + ft_error('at present extracting annotation information only works in conjunction with mne_source files'); end % start with an empty structure @@ -242,7 +243,7 @@ shape.fid.pos = cell2mat(struct2cell(orig.dewar)); shape.coordsys = 'dewar'; otherwise - error('incorrect coordsys specified'); + ft_error('incorrect coordsys specified'); end shape.fid.label = fieldnames(orig.head); @@ -288,7 +289,7 @@ ft_hastoolbox('gifti', 1); g = gifti(filename); if ~isfield(g, 'vertices') - error('%s does not contain a tesselated surface', filename); + ft_error('%s does not contain a tesselated surface', filename); end shape.pos = ft_warp_apply(g.mat, g.vertices); shape.tri = g.faces; @@ -339,7 +340,7 @@ if exist(strrep(tmpfilename, 'sulc', 'curvature'), 'file'), g = gifti(strrep(tmpfilename, 'sulc', 'curvature')); shape.curv = g.cdata; end if exist(strrep(tmpfilename, 'sulc', 'thickness'), 'file'), g = gifti(strrep(tmpfilename, 'sulc', 'thickness')); shape.thickness = g.cdata; end if exist(strrep(tmpfilename, 'sulc', 'atlasroi'), 'file'), g = gifti(strrep(tmpfilename, 'sulc', 'atlasroi')); shape.atlasroi = g.cdata; end - end + end case 'caret_spec' [spec, headerinfo] = read_caret_spec(filename); @@ -367,7 +368,7 @@ % quick and dirty sanity check to see whether the indexing of the % points in the topology matches the number of points if max(tmp2.tri(:))~=size(tmp1.pos,1) - error('there''s a mismatch between the number of points used in the topology, and described by the coordinates'); + ft_error('there''s a mismatch between the number of points used in the topology, and described by the coordinates'); end shape.pos = tmp1.pos; @@ -393,7 +394,7 @@ if ~isempty(annotationfile) ft_hastoolbox('freesurfer', 1); if numel(annotationfile)~=2 - error('two annotationfiles expected, one for each hemisphere'); + ft_error('two annotationfiles expected, one for each hemisphere'); end for k = 1:numel(annotationfile) [v{k}, label{k}, c(k)] = read_annotation(annotationfile{k}, 1); @@ -407,10 +408,10 @@ src(1).labelindx = label{2}; src(2).labelindx = label{1}; else - warning('incompatible annotation with triangulations, not using annotation information'); + ft_warning('incompatible annotation with triangulations, not using annotation information'); end if ~isequal(c(1),c(2)) - error('the annotation tables differ, expecting equal tables for the hemispheres'); + ft_error('the annotation tables differ, expecting equal tables for the hemispheres'); end c = c(1); end @@ -493,7 +494,7 @@ end shape.coordsys = orig.dewar.coordsys; otherwise - error('incorrect coordinates specified'); + ft_error('incorrect coordinates specified'); end case {'yokogawa_mrk', 'yokogawa_ave', 'yokogawa_con', 'yokogawa_raw' } @@ -527,7 +528,7 @@ shape.fid.pos(1:3,:)= shape.fid.pos(sw_ind, :); shape.fid.label = {'nas'; 'lpa'; 'rpa'; 'Marker4'; 'Marker5'}; else - error('no coil information found in Yokogawa file'); + ft_error('no coil information found in Yokogawa file'); end % convert to the units of the grad, the desired default for yokogawa is centimeter. @@ -552,7 +553,7 @@ end end if size(shape.fid.label,1) ~= 5 - error('Wrong number of coils'); + ft_error('Wrong number of coils'); end sw_ind = [3 1 2]; @@ -637,7 +638,7 @@ if isfield(tmp.D, 'fiducials') && ~isempty(tmp.D.fiducials) shape = tmp.D.fiducials; else - error('no headshape found in SPM EEG file'); + ft_error('no headshape found in SPM EEG file'); end case 'matlab' @@ -648,6 +649,8 @@ shape = tmp.shape; elseif isfield(tmp, 'headshape') shape = tmp.headshape; + elseif isfield(tmp, 'surface') + shape = tmp.surface; elseif isfield(tmp, 'bnd') % the variable in the file is most likely a precomputed triangulation of some sort shape = tmp.bnd; @@ -666,7 +669,7 @@ shape = copyfields(tmp, shape, {'Faces', 'Curvature', 'SulciMap'}); shape = renamefields(shape, {'Faces', 'Curvature', 'SulciMap'}, {'tri', 'curv', 'sulc'}); else - error('no headshape found in MATLAB file'); + ft_error('no headshape found in MATLAB file'); end case {'freesurfer_triangle_binary', 'freesurfer_quadrangle'} @@ -710,28 +713,28 @@ shape.pos = pos; shape.tri = tri; - case 'obj' - ft_hastoolbox('wavefront', 1); - % Implemented for structure.io .obj thus far - obj = read_wobj(filename); - shape.pos = obj.vertices; - shape.pos = shape.pos - repmat(sum(shape.pos)/length(shape.pos),[length(shape.pos),1]); %centering vertices - shape.tri = obj.objects(2).data.vertices; - if (~isempty(image) && exist('hasimage','var')) - texture = obj.vertices_texture; - - %Refines the mesh and textures to increase resolution of the - %colormapping - for i = 1:1 - [shape.pos, shape.tri,texture] = refine(shape.pos,shape.tri,'banks',texture); - end - picture = imread(image); - color = uint8(zeros(length(shape.pos),3)); - for i=1:length(shape.pos) - color(i,1:3) = picture(floor((1-texture(i,2))*length(picture)),1+floor(texture(i,1)*length(picture)),1:3); - end - end - + case 'obj' + ft_hastoolbox('wavefront', 1); + % Implemented for structure.io .obj thus far + obj = read_wobj(filename); + shape.pos = obj.vertices; + shape.pos = shape.pos - repmat(sum(shape.pos)/length(shape.pos),[length(shape.pos),1]); %centering vertices + shape.tri = obj.objects(2).data.vertices; + if (~isempty(image) && exist('hasimage','var')) + texture = obj.vertices_texture; + + %Refines the mesh and textures to increase resolution of the + %colormapping + for i = 1:1 + [shape.pos, shape.tri,texture] = refine(shape.pos,shape.tri,'banks',texture); + end + picture = imread(image); + color = uint8(zeros(length(shape.pos),3)); + for i=1:length(shape.pos) + color(i,1:3) = picture(floor((1-texture(i,2))*length(picture)),1+floor(texture(i,1)*length(picture)),1:3); + end + end + case 'vtk' [pos, tri] = read_vtk(filename); shape.pos = pos; @@ -755,7 +758,7 @@ if isfield(hdr.orig, 'headshapedata') shape.pos = hdr.orig.Var.headshapedata; else - error('the NetMEG file "%s" does not contain headshape data', filename); + ft_error('the NetMEG file "%s" does not contain headshape data', filename); end case 'vista' @@ -767,7 +770,7 @@ elseif size(elements,2)==4 shape.tet = elements; else - error('unknown elements format') + ft_error('unknown elements format') end % representation of data is compatible with ft_datatype_parcellation shape.tissue = zeros(size(labels)); @@ -842,7 +845,7 @@ shape.pos = ft_warp_apply(transform, shape.pos); shape.unit = mri.unit; else - warning('could not find accompanying MRI file, returning vertices in voxel coordinates'); + ft_warning('could not find accompanying MRI file, returning vertices in voxel coordinates'); end case 'brainvisa_mesh' @@ -889,7 +892,7 @@ end if isempty(transform) - warning('cound not determine the coordinate transformation, returning vertices in voxel coordinates'); + ft_warning('cound not determine the coordinate transformation, returning vertices in voxel coordinates'); end case 'brainvoyager_srf' @@ -901,18 +904,18 @@ % FIXME do transform % FIXME remove vertices that are not in a triangle % FIXME add unit - - case 'besa_sfp' - [lab, pos] = read_besa_sfp(filename, 0); - shape.pos = pos; - - % assume that all non-'headshape' points are fiducial markers - hs = strmatch('headshape', lab); - lab(hs) = []; - pos(hs, :) = []; - shape.fid.label = lab; - shape.fid.pos = pos; - + + case 'besa_sfp' + [lab, pos] = read_besa_sfp(filename, 0); + shape.pos = pos; + + % assume that all non-'headshape' points are fiducial markers + hs = strmatch('headshape', lab); + lab(hs) = []; + pos(hs, :) = []; + shape.fid.label = lab; + shape.fid.pos = pos; + case 'asa_elc' elec = ft_read_sens(filename); @@ -929,6 +932,18 @@ shape.pos = pos; end + case 'neuromag_mesh' + fid = fopen(filename, 'rt'); + npos = fscanf(fid, '%d', 1); + pos = fscanf(fid, '%f', [6 npos])'; + ntri = fscanf(fid, '%d', 1); + tri = fscanf(fid, '%d', [3 ntri])'; + fclose(fid); + + shape.pos = pos(:,1:3); % vertex positions + shape.nrm = pos(:,4:6); % vertex normals + shape.tri = tri; + otherwise % try reading it from an electrode of volume conduction model file success = false; @@ -939,7 +954,7 @@ try elec = ft_read_sens(filename); if ~ft_senstype(elec, 'eeg') - error('headshape information can not be read from MEG gradiometer file'); + ft_error('headshape information can not be read from MEG gradiometer file'); else shape.fid.pos = elec.chanpos; shape.fid.label = elec.label; @@ -956,7 +971,7 @@ try headmodel = ft_read_vol(filename); if ~ft_voltype(headmodel, 'bem') - error('skin surface can only be extracted from boundary element model'); + ft_error('skin surface can only be extracted from boundary element model'); else if ~isfield(headmodel, 'skin') headmodel.skin = find_outermost_boundary(headmodel.bnd); @@ -971,7 +986,7 @@ end if ~success - error('unknown fileformat "%s" for head shape information', fileformat); + ft_error('unknown fileformat "%s" for head shape information', fileformat); end end % switch fileformat @@ -990,8 +1005,8 @@ shape = ft_convert_units(shape, unit); else try - % ft_convert_units will fail for triangle-only gifties. - shape = ft_convert_units(shape); + % ft_determine_units will fail for triangle-only gifties. + shape = ft_determine_units(shape); catch end end @@ -1002,6 +1017,5 @@ shape = ft_struct2double(shape); if (~isempty(image) && exist('hasimage','var')) - shape.color = color; -end - + shape.color = color; +end diff --git a/external/fieldtrip/fileio/ft_read_mri.m b/external/fieldtrip/fileio/ft_read_mri.m index 0d681b59..b2576d3c 100644 --- a/external/fieldtrip/fileio/ft_read_mri.m +++ b/external/fieldtrip/fileio/ft_read_mri.m @@ -83,7 +83,7 @@ % the following is added for backward compatibility of using 'format' rather than 'dataformat' format = ft_getopt(varargin, 'format'); if ~isempty(format) - warning('the option ''format'' will be deprecated soon, please use ''dataformat'' instead'); + ft_warning('the option ''format'' will be deprecated soon, please use ''dataformat'' instead'); if isempty(dataformat) dataformat = format; end @@ -105,7 +105,7 @@ % test whether the file exists if ~exist(filename, 'file') - error('file ''%s'' does not exist', filename); + ft_error('file ''%s'' does not exist', filename); end % test for the presence of some external functions from other toolboxes @@ -140,7 +140,7 @@ case 'minc' if ~(hasspm2 || hasspm5) fprintf('the SPM2 or SPM5 toolbox is required to read *.mnc files\n'); - ft_hastoolbox('spm2',1); + ft_hastoolbox('spm2', 1); end % use the functions from SPM hdr = spm_vol_minc(filename); @@ -150,7 +150,7 @@ case 'nifti_spm' if ~(hasspm5 || hasspm8 || hasspm12) fprintf('the SPM5 or newer toolbox is required to read *.nii files\n'); - ft_hastoolbox('spm8', 1); + ft_hastoolbox('spm8up', 1); end % use the functions from SPM hdr = spm_vol_nifti(filename); @@ -158,9 +158,9 @@ transform = hdr.mat; case {'analyze_img' 'analyze_hdr'} - if ~(hasspm8) - fprintf('the SPM8 toolbox is required to read analyze files\n'); - ft_hastoolbox('spm8', 1); + if ~(hasspm8 || hasspm12) + fprintf('the SPM8 or newer toolbox is required to read analyze files\n'); + ft_hastoolbox('spm8up', 1); end % use the image file instead of the header @@ -183,7 +183,7 @@ % neurological conventions and a right-handed coordinate system, hence % the first axis of the 3D volume (right-left) should be flipped to make % the coordinate system comparable to SPM - warning('flipping 1st dimension (L-R) to obtain volume in neurological convention'); + ft_warning('flipping 1st dimension (L-R) to obtain volume in neurological convention'); img = flipdim(img, 1); transform = diag(hdr.dime.pixdim(2:4)); @@ -195,12 +195,12 @@ [err, img, hdr, ErrMessage] = BrikLoad(filename); if err - error('could not read AFNI file'); + ft_error('could not read AFNI file'); end % FIXME: this should be checked, but I only have a single BRIK file % construct the homogenous transformation matrix that defines the axes - warning('homogenous transformation might be incorrect for AFNI file'); + ft_warning('homogenous transformation might be incorrect for AFNI file'); transform = eye(4); transform(1:3,4) = hdr.ORIGIN(:); transform(1,1) = hdr.DELTA(1); @@ -238,12 +238,12 @@ if (hdr.trans.from == 4) && (hdr.trans.to == 5) transform = hdr.trans.trans; else - warning('W: trans does not transform from 4 to 5.'); - warning('W: Please check the MRI fif-file'); + ft_warning('W: trans does not transform from 4 to 5.'); + ft_warning('W: Please check the MRI fif-file'); end else - warning('W: trans structure is not defined.'); - warning('W: Maybe coregistration is missing?'); + ft_warning('W: trans structure is not defined.'); + ft_warning('W: Maybe coregistration is missing?'); end if isfield(hdr, 'voxel_trans') && issubfield(hdr.voxel_trans, 'trans') % centers the coordinate system @@ -266,12 +266,12 @@ coordsys = 'neuromag'; mri.unit = 'm'; else - warning('W: voxel_trans does not transform from 2001 to 5.'); - warning('W: Please check the MRI fif-file'); + ft_warning('W: voxel_trans does not transform from 2001 to 5.'); + ft_warning('W: Please check the MRI fif-file'); end else - warning('W: voxel_trans structure is not defined.'); - warning('W: Please check the MRI fif-file'); + ft_warning('W: voxel_trans structure is not defined.'); + ft_warning('W: Please check the MRI fif-file'); end case 'neuromag_fif_old' @@ -322,13 +322,13 @@ if isempty(dirlist) % this is for the Philips data acquired at KI - warning('could not determine list of dicom files, trying with *.dcm'); + ft_warning('could not determine list of dicom files, trying with *.dcm'); dirlist = dir(fullfile(p, '*.dcm')); dirlist = {dirlist.name}; end if isempty(dirlist) - warning('could not determine list of dicom files, trying with *.ima'); + ft_warning('could not determine list of dicom files, trying with *.ima'); dirlist = dir(fullfile(p, '*.ima')); dirlist = {dirlist.name}; end @@ -387,7 +387,7 @@ case {'nifti', 'freesurfer_mgz', 'freesurfer_mgh', 'nifti_fsl'} if strcmp(dataformat, 'freesurfer_mgz') && ispc - error('Compressed .mgz files cannot be read on a PC'); + ft_error('Compressed .mgz files cannot be read on a PC'); end ft_hastoolbox('freesurfer', 1); @@ -422,13 +422,13 @@ hdr.normalize = normalize; hdr.besa_fiducial_point = besa_fiducial_point; - error('FIXME yokogawa_mri implementation is incomplete'); + ft_error('FIXME yokogawa_mri implementation is incomplete'); case 'matlab' mri = loadvar(filename, 'mri'); otherwise - error(sprintf('unrecognized filetype ''%s'' for ''%s''', dataformat, filename)); + ft_error('unrecognized filetype ''%s'' for ''%s''', dataformat, filename); end if exist('img', 'var') @@ -458,7 +458,7 @@ try % try to determine the units of the coordinate system - mri = ft_convert_units(mri); + mri = ft_determine_units(mri); end try diff --git a/external/fieldtrip/fileio/ft_read_sens.m b/external/fieldtrip/fileio/ft_read_sens.m index 08cd3dca..7998167f 100644 --- a/external/fieldtrip/fileio/ft_read_sens.m +++ b/external/fieldtrip/fileio/ft_read_sens.m @@ -65,12 +65,12 @@ % test whether the file exists if ~exist(filename, 'file') - error('file ''%s'' does not exist', filename); + ft_error('file ''%s'' does not exist', filename); end % get the options fileformat = ft_getopt(varargin, 'fileformat', ft_filetype(filename)); -senstype = ft_getopt(varargin, 'senstype', 'eeg'); % can be eeg or meg, this is used to decide what to return if both are present in a fif file +senstype = ft_getopt(varargin, 'senstype'); % can be eeg or meg, default is automatic when [] coordsys = ft_getopt(varargin, 'coordsys', 'head'); % this is used for ctf and neuromag_mne, it can be head or dewar coilaccuracy = ft_getopt(varargin, 'coilaccuracy'); % empty, or a number between 0 to 2 @@ -85,7 +85,7 @@ sens = read_brainvision_pos(filename); case 'besa_elp' - error('unknown fileformat for electrodes or gradiometers'); + ft_error('unknown fileformat for electrodes or gradiometers'); % the code below does not yet work fid = fopen(filename); % the ascii file contains: type, label, angle, angle @@ -102,7 +102,7 @@ case 'besa_pos' tmp = importdata(filename); if ~isnumeric(tmp) - error('unexpected file format for fileformat=besa_pos') + ft_error('unexpected file format for fileformat=besa_pos') end [nchan,nrow] = size(tmp); if nrow==3 @@ -115,18 +115,18 @@ sens.ori = [ori; ori]; sens.tra = [eye(nchan) -eye(nchan)]; else - error('unexpected file format for fileformat=besa_pos') + ft_error('unexpected file format for fileformat=besa_pos') end [p, f, x] = fileparts(filename); elpfile = fullfile(p, [f '.elp']); elafile = fullfile(p, [f '.ela']); if exist(elpfile, 'file') - warning('reading channel labels from %s', elpfile); + ft_warning('reading channel labels from %s', elpfile); % read the channel names from the accompanying ELP file lbl = importdata(elpfile); sens.label = strrep(lbl.textdata(:,2) ,'''', ''); elseif exist(elafile, 'file') - warning('reading channel labels from %s', elafile); + ft_warning('reading channel labels from %s', elafile); % read the channel names from the accompanying ELA file lbl = importdata(elafile); lbl = strrep(lbl, 'MEG ', ''); % remove the channel type @@ -134,7 +134,7 @@ sens.label = lbl; else % the file does not have channel labels in it - warning('creating fake channel names for besa_pos'); + ft_warning('creating fake channel names for besa_pos'); for i=1:nchan sens.label{i} = sprintf('%03d', i); end @@ -155,29 +155,36 @@ case 'besa_sfp' [lab, pos] = read_besa_sfp(filename); - sens.label = lab; sens.elecpos = pos; - + + case 'bioimage_mgrid' + sens = read_bioimage_mgrid(filename); + case {'ctf_ds', 'ctf_res4', 'ctf_old', 'neuromag_fif', 'neuromag_mne', '4d', '4d_pdf', '4d_m4d', '4d_xyz', 'yokogawa_ave', 'yokogawa_con', 'yokogawa_raw', 'itab_raw' 'itab_mhd', 'netmeg'} % gradiometer information is always stored in the header of the MEG dataset, hence uses the standard fieldtrip/fileio ft_read_header function hdr = ft_read_header(filename, 'headerformat', fileformat, 'coordsys', coordsys, 'coilaccuracy', coilaccuracy); % sometimes there can also be electrode position information in the header if isfield(hdr, 'elec') && isfield(hdr, 'grad') + if isempty(senstype) + % set the default + ft_warning('both electrode and gradiometer information is present, returning the electrode information by default'); + senstype = 'eeg'; + end switch lower(senstype) case 'eeg' - warning('both electrode and gradiometer information is present, returning the electrode information'); sens = hdr.elec; case 'meg' - warning('both electrode and gradiometer information is present, returning the gradiometer information'); sens = hdr.grad; + otherwise + ft_error('incorrect specification of senstype'); end - elseif ~isfield(hdr, 'elec') && ~isfield(hdr, 'grad') - error('neither electrode nor gradiometer information is present'); elseif isfield(hdr, 'grad') sens = hdr.grad; elseif isfield(hdr, 'elec') sens = hdr.elec; + else + ft_error('neither electrode nor gradiometer information is present'); end case 'neuromag_mne_grad' @@ -200,34 +207,29 @@ elseif isfield(hdr, 'elec') sens = hdr.elec; else - error('no electrodes or gradiometers found in the file') + ft_error('no electrodes or gradiometers found in the file') end case 'polhemus_fil' % these are created at the FIL in London with a polhemus tracker [sens.fid.pnt, sens.pnt, sens.fid.label] = read_polhemus_fil(filename, 0); % the file does not have channel labels in it - warning('no channel names in polhemus file, using numbers instead'); + ft_warning('no channel names in polhemus file, using numbers instead'); for i=1:size(sens.pnt, 1) sens.label{i} = sprintf('%03d', i); end case 'matlab' - % MATLAB files can contain either electrodes or gradiometers + % MATLAB files can contain all sensor arrays matfile = filename; % this solves a problem with the MATLAB compiler v3 - ws = warning('off', 'MATLAB:load:variableNotFound'); - tmp = load(matfile, 'elec', 'grad', 'sens', 'elc'); - warning(ws); - if isfield(tmp, 'grad') - sens = tmp.grad; - elseif isfield(tmp, 'elec') - sens = tmp.elec; - elseif isfield(tmp, 'sens') - sens = tmp.sens; - elseif isfield(tmp, 'elc') - sens = tmp.elc; + var = whos('-file', filename); + sel = intersect({'elec', 'grad', 'opto', 'sens', 'elc'}, {var(:).name}); + if numel(sel)==1 + % read the specific variable + sens = loadvar(matfile, sel{1}); else - error('no electrodes or gradiometers found in MATLAB file'); + % read whatever variable is in the file, this will error if the file contains multiple variables + sens = loadvar(matfile); end case 'zebris_sfp' @@ -312,7 +314,7 @@ y(i,1) = str2double(ytemp{i}(8:end-1)); z(i,1) = str2double(ztemp{i}(8:end-3)); lbl{i,1} = labtemp{i}(14:end-1); - end; + end % Create and fill sens structure sens = []; @@ -333,11 +335,11 @@ sens.elecpos(i,2) = str2double(tmp(i).Marker.ColVec3D.data1); sens.elecpos(i,3) = str2double(tmp(i).Marker.ColVec3D.data2); sens.label{i} = tmp(i).Marker.description; - end; - end; + end + end sens.chanpos = sens.elecpos; - end; + end case 'easycap_txt' % Read the file and store all contents in cells of strings @@ -352,7 +354,7 @@ theta = cellfun(@str2double, tmp{2}(2:end)); phi = cellfun(@str2double, tmp{3}(2:end)); radians = @(x) pi*x/180; - warning('assuming a head radius of 85 mm'); + ft_warning('assuming a head radius of 85 mm'); x = 85*cos(radians(phi)).*sin(radians(theta)); y = 85*sin(radians(theta)).*sin(radians(phi)); z = 85*cos(radians(theta)); @@ -370,9 +372,18 @@ end otherwise - error('unknown fileformat for electrodes or gradiometers'); -end + ft_error('unknown fileformat for electrodes or gradiometers'); +end % switch fileformat % ensure that the sensor description is up-to-date % this will also add chantype and units to the sensor array if missing sens = ft_datatype_sens(sens); + +% ensure that the output is consistent with the type requested by the user +if strcmpi(senstype, 'meg') + assert(isfield(sens,'coilpos'), 'cannot read gradiometer information from %s', filename); +elseif strcmpi(senstype, 'eeg') + assert(isfield(sens,'elecpos'), 'cannot read electrode information from %s', filename); +else + % it is empty if not specified by the user, in that case either one is fine +end diff --git a/external/fieldtrip/fileio/ft_read_spike.m b/external/fieldtrip/fileio/ft_read_spike.m index c31bd775..7791a8aa 100644 --- a/external/fieldtrip/fileio/ft_read_spike.m +++ b/external/fieldtrip/fileio/ft_read_spike.m @@ -56,7 +56,7 @@ filename = fetch_url(filename); if ~exist(filename,'file') - error('File or directory does not exist') + ft_error('File or directory does not exist') end % get the options @@ -68,7 +68,7 @@ case {'neuralynx_ncs' 'plexon_ddt'} % these files only contain continuous data - error('file does not contain spike timestamps or waveforms'); + ft_error('file does not contain spike timestamps or waveforms'); case 'matlab' % plain MATLAB file with a single variable in it @@ -263,7 +263,7 @@ % the times are defined in s, convert to original time stamps timestamps = c{k}(sel,1) * hdr.orig.rates.wideband; if any(abs(timestamps-round(timestamps))>1e-5), - error('there seems to be a mismatch between the spike times and the expected integer-valued timestamps'); + ft_error('there seems to be a mismatch between the spike times and the expected integer-valued timestamps'); end spike.timestamp{k} = round(timestamps(:))'; @@ -273,7 +273,7 @@ end otherwise - error(['unsupported data format (' spikeformat ')']); + ft_error(['unsupported data format (' spikeformat ')']); end % add the waveform diff --git a/external/fieldtrip/fileio/ft_read_vol.m b/external/fieldtrip/fileio/ft_read_vol.m index b25f5e84..e4268b1d 100644 --- a/external/fieldtrip/fileio/ft_read_vol.m +++ b/external/fieldtrip/fileio/ft_read_vol.m @@ -40,7 +40,7 @@ % test whether the file exists if ~exist(filename) - error(sprintf('file ''%s'' does not exist', filename)); + ft_error('file ''%s'' does not exist', filename); end % get the options @@ -63,7 +63,7 @@ headmodel = ama2vol(ama); otherwise - error('unknown fileformat for volume conductor model'); + ft_error('unknown fileformat for volume conductor model'); end % this will ensure that the structure is up to date, e.g. that the type is correct and that it has units diff --git a/external/fieldtrip/fileio/ft_write_cifti.m b/external/fieldtrip/fileio/ft_write_cifti.m index 3d74790d..e9776dab 100644 --- a/external/fieldtrip/fileio/ft_write_cifti.m +++ b/external/fieldtrip/fileio/ft_write_cifti.m @@ -163,7 +163,7 @@ function ft_write_cifti(filename, source, varargin) intent_name = 'ConnUnknown'; otherwise - error('unsupported dimord "%s"', dimord); + ft_error('unsupported dimord "%s"', dimord); end % switch % determine each of the dimensions @@ -387,7 +387,7 @@ function ft_write_cifti(filename, source, varargin) case 'm' MeterExponent = 0; otherwise - error('unsupported source.unit') + ft_error('unsupported source.unit') end % case [tree, uid] = add(tree, branch, 'element', 'Volume'); @@ -461,7 +461,7 @@ function ft_write_cifti(filename, source, varargin) case 'm' MeterExponent = 0; otherwise - error('unsupported source.unit') + ft_error('unsupported source.unit') end % case [tree, uid] = add(tree, branch, 'element', 'Volume'); @@ -640,7 +640,7 @@ function ft_write_cifti(filename, source, varargin) case 'int64' hdr.datatype = 1024; otherwise - error('unsupported precision "%s"', precision); + ft_error('unsupported precision "%s"', precision); end switch precision @@ -657,7 +657,7 @@ function ft_write_cifti(filename, source, varargin) case 'double' hdr.bitpix = 8*8; otherwise - error('unsupported precision "%s"', precision); + ft_error('unsupported precision "%s"', precision); end % dim(1) represents the number of dimensions @@ -681,7 +681,7 @@ function ft_write_cifti(filename, source, varargin) case 'scalar' hdr.dim(5+i) = 1; otherwise - error('unsupported dimord "%s"', dimord) + ft_error('unsupported dimord "%s"', dimord) end end diff --git a/external/fieldtrip/fileio/ft_write_data.m b/external/fieldtrip/fileio/ft_write_data.m index ee6d96bb..fe3b972c 100644 --- a/external/fieldtrip/fileio/ft_write_data.m +++ b/external/fieldtrip/fileio/ft_write_data.m @@ -194,12 +194,12 @@ function ft_write_data(filename, dat, varargin) if ~isempty(strfind(lasterr, 'Buffer size N must be an integer-valued scalar double.')) % this happens if the MATLAB75/toolbox/signal/signal/buffer % function is used instead of the FieldTrip buffer - error('the FieldTrip buffer mex file was not found on your path, it should be in fieldtrip/fileio/private'); + ft_error('the FieldTrip buffer mex file was not found on your path, it should be in fieldtrip/fileio/private'); elseif ~isempty(strfind(lasterr, 'failed to create socket')) && (strcmp(host, 'localhost') || strcmp(host, '127.0.0.1')) % start a local instance of the TCP server - warning('starting FieldTrip buffer on %s:%d', host, port); + ft_warning('starting FieldTrip buffer on %s:%d', host, port); buffer('tcpserver', 'init', host, port); pause(1); @@ -257,7 +257,7 @@ function ft_write_data(filename, dat, varargin) % combination of *.eeg and *.vhdr file %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% if append - error('appending data is not yet supported for this data format'); + ft_error('appending data is not yet supported for this data format'); end if nchans~=hdr.nChans && length(chanindx)==nchans @@ -352,7 +352,7 @@ function ft_write_data(filename, dat, varargin) try s.msg = mxSerialize(hdr); catch - warning(lasterr); + ft_warning(lasterr); end db_insert('fieldtrip.header', s); end @@ -377,7 +377,7 @@ function ft_write_data(filename, dat, varargin) try s.data = mxSerialize(reshape(dat(i,:,:), dim(2:end))); catch - warning(lasterr); + ft_warning(lasterr); end % insert the structure into the database db_insert('fieldtrip.data', s); @@ -385,7 +385,7 @@ function ft_write_data(filename, dat, varargin) end else - error('you should specify either the header or the data when writing to a MySQL database'); + ft_error('you should specify either the header or the data when writing to a MySQL database'); end case 'matlab' @@ -398,7 +398,7 @@ function ft_write_data(filename, dat, varargin) % read the previous header and data from MATLAB file prev = load(filename); if ~isempty(hdr) && ~isequal(hdr, prev.hdr) - error('inconsistent header'); + ft_error('inconsistent header'); else % append the new data to that from the MATLAB file dat = cat(2, prev.dat, dat); @@ -406,7 +406,7 @@ function ft_write_data(filename, dat, varargin) elseif append && ~exist(filename, 'file') % file does not yet exist, which is not a problem elseif ~append && exist(filename, 'file') - warning('deleting existing file ''%s''', filename); + ft_warning('deleting existing file ''%s''', filename); delete(filename); elseif ~append && ~exist(filename, 'file') % file does not yet exist, which is not a problem @@ -497,7 +497,7 @@ function ft_write_data(filename, dat, varargin) case 'uint32' buf = uint32(buf); otherwise - error('unsupported format conversion'); + ft_error('unsupported format conversion'); end end @@ -518,7 +518,7 @@ function ft_write_data(filename, dat, varargin) % outside the range [-1,+1] are clipped %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% if append - error('appending data is not yet supported for this data format'); + ft_error('appending data is not yet supported for this data format'); end if nchans~=hdr.nChans && length(chanindx)==nchans @@ -528,22 +528,22 @@ function ft_write_data(filename, dat, varargin) hdr.nChans = length(chanindx); end if nchans~=1 - error('this format only supports single channel continuous data'); + ft_error('this format only supports single channel continuous data'); end - wavwrite(dat, hdr.Fs, nbits, filename); + audiowrite(filename, dat, hdr.Fs, 'BitsPerSample', nbits); case 'plexon_nex' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % single or mulitple channel Plexon NEX file %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% if append - error('appending data is not yet supported for this data format'); + ft_error('appending data is not yet supported for this data format'); end [path, file] = fileparts(filename); filename = fullfile(path, [file, '.nex']); if nchans~=1 - error('only supported for single-channel data'); + ft_error('only supported for single-channel data'); end % construct a NEX structure with the required parts of the header nex.hdr.VarHeader.Type = 5; % continuous @@ -553,7 +553,7 @@ function ft_write_data(filename, dat, varargin) nex.hdr.FileHeader.Frequency = hdr.Fs * hdr.TimeStampPerSample; nex.var.ts = hdr.FirstTimeStamp; else - warning('no timestamp information available'); + ft_warning('no timestamp information available'); nex.hdr.FileHeader.Frequency = nan; nex.var.ts = nan; end @@ -572,11 +572,11 @@ function ft_write_data(filename, dat, varargin) % single channel Neuralynx NCS file %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% if append - error('appending data is not yet supported for this data format'); + ft_error('appending data is not yet supported for this data format'); end if nchans>1 - error('only supported for single-channel data'); + ft_error('only supported for single-channel data'); end [path, file, ext] = fileparts(filename); @@ -593,7 +593,7 @@ function ft_write_data(filename, dat, varargin) ADCHANNEL = -1; % unknown LABEL = hdr.label{1}; % single channel else - error('cannot determine channel label'); + ft_error('cannot determine channel label'); end FSAMPLE = hdr.Fs; @@ -646,7 +646,7 @@ function ft_write_data(filename, dat, varargin) % multiple channel GDF file %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% if append - error('appending data is not yet supported for this data format'); + ft_error('appending data is not yet supported for this data format'); end if ~isempty(chanindx) % assume that the header corresponds to the original multichannel @@ -661,7 +661,7 @@ function ft_write_data(filename, dat, varargin) % multiple channel European Data Format file %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% if append - error('appending data is not yet supported for this data format'); + ft_error('appending data is not yet supported for this data format'); end if ~isempty(chanindx) % assume that the header corresponds to the original multichannel @@ -672,5 +672,5 @@ function ft_write_data(filename, dat, varargin) write_edf(filename, hdr, dat); otherwise - error('unsupported data format'); + ft_error('unsupported data format'); end % switch dataformat diff --git a/external/fieldtrip/fileio/ft_write_event.m b/external/fieldtrip/fileio/ft_write_event.m index a65a3ca9..85a7ca57 100644 --- a/external/fieldtrip/fileio/ft_write_event.m +++ b/external/fieldtrip/fileio/ft_write_event.m @@ -153,7 +153,7 @@ function ft_write_event(filename, event, varargin) fifo = filetype_check_uri(filename); if ~exist(fifo,'file') - warning('the FIFO %s does not exist; attempting to create it', fifo); + ft_warning('the FIFO %s does not exist; attempting to create it', fifo); system(sprintf('mkfifo -m 0666 %s',fifo)); end @@ -165,11 +165,11 @@ function ft_write_event(filename, event, varargin) msg = mxSerialize(event(i)); num = fwrite(fid, msg, 'uint8'); catch - warning(lasterr); + ft_warning(lasterr); end if num~=length(msg) - error('problem writing to FIFO %s', fifo); + ft_error('problem writing to FIFO %s', fifo); end end fclose(fid); @@ -197,7 +197,7 @@ function ft_write_event(filename, event, varargin) pnet(con,'printf','\n'); end % catch -% warning(lasterr); +% ft_warning(lasterr); end pnet(con,'close'); @@ -224,7 +224,7 @@ function ft_write_event(filename, event, varargin) end catch - warning(lasterr); + ft_warning(lasterr); end pnet(udp,'close'); end @@ -260,6 +260,6 @@ function ft_write_event(filename, event, varargin) save(filename, 'event', '-v6'); end else - error('unsupported file type') + ft_error('unsupported file type') end end diff --git a/external/fieldtrip/fileio/ft_write_headshape.m b/external/fieldtrip/fileio/ft_write_headshape.m index 432ae8f3..d0d46a5f 100644 --- a/external/fieldtrip/fileio/ft_write_headshape.m +++ b/external/fieldtrip/fileio/ft_write_headshape.m @@ -138,10 +138,10 @@ function ft_write_headshape(filename, bnd, varargin) elseif isfield(bnd,'tet') write_vista_mesh(filename,bnd.pnt,bnd.tet,bnd.index); else - error('unknown format') + ft_error('unknown format') end else - error('You need Simbio/Vista toolbox to write a .v file') + ft_error('You need Simbio/Vista toolbox to write a .v file') end case 'tetgen' @@ -215,10 +215,10 @@ function ft_write_headshape(filename, bnd, varargin) ix = find(n==size(tmp.vertices,1)); tmp.private.data{ix}.metadata = metadata; else - error('the metadata structure should contain the fields ''name'' and ''value'''); + ft_error('the metadata structure should contain the fields ''name'' and ''value'''); end else - error('metadata should be provided as a struct-array'); + ft_error('metadata should be provided as a struct-array'); end end @@ -229,9 +229,9 @@ function ft_write_headshape(filename, bnd, varargin) write_surf(filename, bnd.pnt, bnd.tri); case [] - error('you must specify the output format'); + ft_error('you must specify the output format'); otherwise - error('unsupported output format "%s"', fileformat); + ft_error('unsupported output format "%s"', fileformat); end diff --git a/external/fieldtrip/fileio/ft_write_mri.m b/external/fieldtrip/fileio/ft_write_mri.m index 40c471d6..75e90af5 100644 --- a/external/fieldtrip/fileio/ft_write_mri.m +++ b/external/fieldtrip/fileio/ft_write_mri.m @@ -54,23 +54,18 @@ dataformat = ft_filetype(filename); end -% if strcmp(dataformat, 'nifti') && strcmp(spmversion, 'SPM2') -% error('nifti can only be written by SPM5 or later'); -% end - if nargout>0 % start with an empty output argument, it will only be returned by the SPM formats V = []; end switch dataformat - case {'analyze_img' 'analyze_hdr' 'analyze' 'nifti_spm'} % analyze data, using SPM V = volumewrite_spm(filename, dat, transform, spmversion); case {'freesurfer_mgz' 'mgz' 'mgh'} - % mgz-volume using freesurfer + % mgz data, using Freesurfer ft_hastoolbox('freesurfer', 1); % in MATLAB the transformation matrix assumes the voxel indices to be 1-based @@ -79,8 +74,8 @@ save_mgh(dat, filename, transform); case {'nifti'} - ft_hastoolbox('freesurfer', 1); % nifti data, using Freesurfer + ft_hastoolbox('freesurfer', 1); datatype = class(dat); switch(datatype) @@ -97,7 +92,7 @@ case 'logical' datatype = 'uchar'; otherwise - error('unsupported datatype to write to Nifti'); + ft_error('unsupported datatype to write to Nifti'); end ndims = numel(size(dat)); @@ -123,5 +118,5 @@ write_vista_vol(size(dat), dat, filename); otherwise - error('unsupported data format'); + ft_error('unsupported format "%s"', dataformat); end % switch dataformat diff --git a/external/fieldtrip/fileio/ft_write_sens.m b/external/fieldtrip/fileio/ft_write_sens.m new file mode 100644 index 00000000..7d92b80a --- /dev/null +++ b/external/fieldtrip/fileio/ft_write_sens.m @@ -0,0 +1,54 @@ +function ft_write_sens(filename, sens, varargin) + +% FT_WRITE_SENS writes electrode information to an external file for further processing in external software. +% +% Use as +% ft_write_sens(filename, sens, ...) +% +% The specified filename can already contain the filename extention, +% but that is not required since it will be added automatically. +% +% Additional options should be specified in key-value pairs and can be +% 'format' string, see below +% +% The supported file formats are +% bioimage_mgrid +% +% See also FT_READ_SENS, FT_DATATYPE_SENS + +% Copyright (C) 2017, Robert Oostenveld +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +% get the options +format = ft_getopt(varargin, 'format'); + +% ensure the input is according to the latest standards +sens = ft_datatype_sens(sens); + +switch format + case 'bioimage_mgrid' + [p, f, x] = fileparts(filename); + filename = fullfile(p, [f '.mgrid']); + write_bioimage_mgrid(filename, sens); + + otherwise + ft_error('unsupported format "%s"', format); +end % switch format + diff --git a/external/fieldtrip/fileio/ft_write_spike.m b/external/fieldtrip/fileio/ft_write_spike.m index cd94e26d..6e02d8b3 100644 --- a/external/fieldtrip/fileio/ft_write_spike.m +++ b/external/fieldtrip/fileio/ft_write_spike.m @@ -73,7 +73,7 @@ function ft_write_spike(filename, spike, varargin) [path, file, ext] = fileparts(filename); filename = fullfile(path, [file, '.nts']); if nchans>1 - error('only supported for single-channel data'); + ft_error('only supported for single-channel data'); end label = spike.label{1}; @@ -104,7 +104,7 @@ function ft_write_spike(filename, spike, varargin) [path, file, ext] = fileparts(filename); filename = fullfile(path, [file, '.nse']); if nchans>1 - error('only supported for single-channel data'); + ft_error('only supported for single-channel data'); end label = spike.label{1}; @@ -145,7 +145,7 @@ function ft_write_spike(filename, spike, varargin) [path, file, ext] = fileparts(filename); filename = fullfile(path, [file, '.nex']); if nchans>1 - error('only supported for single-channel data'); + ft_error('only supported for single-channel data'); end nex = []; @@ -164,6 +164,6 @@ function ft_write_spike(filename, spike, varargin) end otherwise - error('not implemented'); + ft_error('not implemented'); end % switch dataformat diff --git a/external/fieldtrip/fileio/private/ReadHeader.m b/external/fieldtrip/fileio/private/ReadHeader.m index bd6fcfe8..bbcee8f5 100644 --- a/external/fieldtrip/fileio/private/ReadHeader.m +++ b/external/fieldtrip/fileio/private/ReadHeader.m @@ -54,7 +54,7 @@ H{1} = headerLine; - while ~feof(fp) & ~strcmp(headerLine, endheader) + while ~feof(fp) && ~strcmp(headerLine, endheader) headerLine = fgetl(fp); iH = iH+1; diff --git a/external/fieldtrip/fileio/private/avw_hdr_read.m b/external/fieldtrip/fileio/private/avw_hdr_read.m index 09fa24dd..a34606aa 100644 --- a/external/fieldtrip/fileio/private/avw_hdr_read.m +++ b/external/fieldtrip/fileio/private/avw_hdr_read.m @@ -45,8 +45,7 @@ end if ~exist('fileprefix','var'), - msg = sprintf('...no input fileprefix - see help avw_hdr_read\n\n'); - error(msg); + ft_error('...no input fileprefix - see help avw_hdr_read\n\n'); end if ~exist('machine','var'), machine = 'ieee-le'; end @@ -83,18 +82,16 @@ avw.fileprefix = fileprefix; fclose(fid); end - if ~isequal(avw.hdr.hk.sizeof_hdr,348), + if ~isequal(avw.hdr.hk.sizeof_hdr,348) % Now throw an error if verbose, fprintf('...failed.\n'); end - msg = sprintf('...size of header not equal to 348 bytes!\n\n'); - error(msg); + ft_error('...size of header not equal to 348 bytes!\n\n'); end else - msg = sprintf('...cannot find file %s.hdr\n\n',file); - error(msg); + ft_error('...cannot find file %s.hdr\n\n',file); end -if verbose, +if verbose t=toc; fprintf('...done (%5.2f sec).\n',t); end diff --git a/external/fieldtrip/fileio/private/avw_img_read.m b/external/fieldtrip/fileio/private/avw_img_read.m index bed8c31c..ce1cbce8 100644 --- a/external/fieldtrip/fileio/private/avw_img_read.m +++ b/external/fieldtrip/fileio/private/avw_img_read.m @@ -95,7 +95,7 @@ if ~exist('fileprefix','var'), msg = sprintf('...no input fileprefix - see help avw_img_read\n\n'); - error(msg); + ft_error(msg); end if findstr('.hdr',fileprefix), fileprefix = strrep(fileprefix,'.hdr',''); @@ -122,7 +122,7 @@ fid = fopen(sprintf('%s.img',avw.fileprefix),'r',machine); if fid < 0, msg = sprintf('...cannot open file %s.img\n\n',avw.fileprefix); - error(msg); + ft_error(msg); end if verbose, @@ -212,17 +212,17 @@ % perhaps to indicate flipped orientation? If so, this code below % will NOT handle the flip correctly! if PixelSz < 0, - warning('X pixdim < 0 !!! resetting to abs(avw.hdr.dime.pixdim(2))'); + ft_warning('X pixdim < 0 !!! resetting to abs(avw.hdr.dime.pixdim(2))'); PixelSz = abs(PixelSz); avw.hdr.dime.pixdim(2) = single(PixelSz); end if RowSz < 0, - warning('Y pixdim < 0 !!! resetting to abs(avw.hdr.dime.pixdim(3))'); + ft_warning('Y pixdim < 0 !!! resetting to abs(avw.hdr.dime.pixdim(3))'); RowSz = abs(RowSz); avw.hdr.dime.pixdim(3) = single(RowSz); end if SliceSz < 0, - warning('Z pixdim < 0 !!! resetting to abs(avw.hdr.dime.pixdim(4))'); + ft_warning('Z pixdim < 0 !!! resetting to abs(avw.hdr.dime.pixdim(4))'); SliceSz = abs(SliceSz); avw.hdr.dime.pixdim(4) = single(SliceSz); end @@ -259,8 +259,8 @@ 'for volumes with dimensionality greater than 3. Set ', ... 'avw.hdr.hist.orient = 0 and flip your volume after ', ... 'calling this function' ]; - msg = sprintf( '%s (%s).', msg, mfilename ); - error( msg ); + msg = ft_error( '%s (%s).', msg, mfilename ); + ft_error( msg ); end switch double(avw.hdr.hist.orient), @@ -493,7 +493,7 @@ otherwise - error('unknown value in avw.hdr.hist.orient, try explicit IMGorient option.'); + ft_error('unknown value in avw.hdr.hist.orient, try explicit IMGorient option.'); end diff --git a/external/fieldtrip/fileio/private/bounding_mesh.m b/external/fieldtrip/fileio/private/bounding_mesh.m index e0e2bb95..22b9c25c 100644 --- a/external/fieldtrip/fileio/private/bounding_mesh.m +++ b/external/fieldtrip/fileio/private/bounding_mesh.m @@ -30,12 +30,11 @@ % You should have received a copy of the GNU General Public License % along with FieldTrip. If not, see . % -% $Id$ % this can be used for printing detailled user feedback fb = false; -% this is a work-around for http://bugzilla.fcdonders.nl/show_bug.cgi?id=2369 +% this is a work-around for http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2369 pos = double(pos); pnt = double(pnt); tri = double(tri); diff --git a/external/fieldtrip/fileio/private/bti2grad.m b/external/fieldtrip/fileio/private/bti2grad.m index 68c21203..c28713e3 100644 --- a/external/fieldtrip/fileio/private/bti2grad.m +++ b/external/fieldtrip/fileio/private/bti2grad.m @@ -43,7 +43,7 @@ % for backward compatibility issues FIXME check whether anyone actually uses this code if isfield(hdr, 'Meg_pos'), - warning('using outdated code. this does not necessarily lead to correct output'); + ft_warning('using outdated code. this does not necessarily lead to correct output'); elec = []; grad = []; @@ -115,7 +115,7 @@ ori = cat(2,hdr.config.channel_data(n).device_data.loop_data.direction)'; % determine the number of coils for this channel if numcoils(n) ~= size(pos,1) - error('number of coils does not correspond with number of coil positions'); + ft_error('number of coils does not correspond with number of coil positions'); end % add the coils of this channel to the gradiometer array grad.tra(i, cnt+1:cnt+numcoils(n)) = 1; @@ -141,7 +141,7 @@ ori = cat(2,hdr.config.channel_data(n).device_data.loop_data.direction)'; % determine the number of coils for this channel if numcoils(n) ~= size(pos,1) - error('number of coils does not correspond with number of coil positions'); + ft_error('number of coils does not correspond with number of coil positions'); end % add the coils of this channel to the gradiometer array grad.tra(numMEG+i, cnt+1:cnt+numcoils(n)) = 1; %FIXME check whether ori is OK for gradiometers @@ -181,7 +181,7 @@ weights = hdr.user_block_data{ubsel}; if hdr.user_block_data{ubsel}.version==1, % the user_block does not contain labels to the channels and references - % warning('the weight table does not contain contain labels to the channels and references: assuming the channel order as they occur in the header and the refchannel order M.A M.aA G.A'); + % ft_warning('the weight table does not contain contain labels to the channels and references: assuming the channel order as they occur in the header and the refchannel order M.A M.aA G.A'); label = {hdr.config.channel_data(:).name}'; meglabel = ft_channelselection('MEG', label); imeg = match_str(label, meglabel); @@ -197,7 +197,7 @@ end nmeg = length(meglabel); nref = length(reflabel); - montage.labelorg = cat(1, meglabel, reflabel); + montage.labelold = cat(1, meglabel, reflabel); montage.labelnew = cat(1, meglabel, reflabel); montage.tra = [eye(nmeg, nmeg), -weights.dweights(:,order); zeros(nref, nmeg), eye(nref, nref)]; balance = struct(weights.position, montage); diff --git a/external/fieldtrip/fileio/private/channelposition.m b/external/fieldtrip/fileio/private/channelposition.m index 25f8db11..1eecb56a 100644 --- a/external/fieldtrip/fileio/private/channelposition.m +++ b/external/fieldtrip/fileio/private/channelposition.m @@ -110,7 +110,7 @@ dist(selrest,sum(~isinf(dist(selmode,:)))>0) = inf; numcoils = sum(isfinite(dist),2); if niter>500 - error('Failed to extract the positions of the channels. This is most likely due to the balancing matrix being rank deficient. Please replace data.grad with the original grad-structure obtained after reading the header.'); + ft_error('Failed to extract the positions of the channels. This is most likely due to the balancing matrix being rank deficient. Please replace data.grad with the original grad-structure obtained after reading the header.'); end end else @@ -332,5 +332,5 @@ % do a sanity check on the number of positions nchan = numel(sens.label); if length(lab)~=nchan || size(pnt,1)~=nchan || size(ori,1)~=nchan - warning('the positions were not determined for all channels'); + ft_warning('the positions were not determined for all channels'); end diff --git a/external/fieldtrip/fileio/private/cstructdecode.m b/external/fieldtrip/fileio/private/cstructdecode.m index d50385f9..b4edac8f 100644 --- a/external/fieldtrip/fileio/private/cstructdecode.m +++ b/external/fieldtrip/fileio/private/cstructdecode.m @@ -25,7 +25,7 @@ % $Id$ if ~isa(buf, 'uint8') - error('incorrect type of input data, should be uint8'); + ft_error('incorrect type of input data, should be uint8'); end nbytes = numel(buf); @@ -66,7 +66,7 @@ wordsize(i) = 1; end else - error('incorrect type specification'); + ft_error('incorrect type specification'); end end end diff --git a/external/fieldtrip/fileio/private/ctf2grad.m b/external/fieldtrip/fileio/private/ctf2grad.m index 52be35c6..30c48ea6 100644 --- a/external/fieldtrip/fileio/private/ctf2grad.m +++ b/external/fieldtrip/fileio/private/ctf2grad.m @@ -1,11 +1,11 @@ -function [grad] = ctf2grad(hdr, dewar, coilaccuracy) +function [grad, elec] = ctf2grad(hdr, dewar, coilaccuracy) % CTF2GRAD converts a CTF header to a gradiometer structure that can be understood by % the FieldTrip low-level forward and inverse routines. The fieldtrip/fileio % read_header function can use three different implementations of the low-level code % for CTF data. Each of these implementations is dealt with here. % -% Use as +% Use as % grad = ctf2grad(hdr, dewar, coilaccuracy) % where % dewar = boolean, whether to return it in dewar or head coordinates (default is head coordinates) @@ -14,7 +14,7 @@ % See also BTI2GRAD, FIF2GRAD, MNE2GRAD, ITAB2GRAD, YOKOGAWA2GRAD, % FT_READ_SENS, FT_READ_HEADER -% Copyright (C) 2004-2016, Robert Oostenveld +% Copyright (C) 2004-2017, Robert Oostenveld % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -41,19 +41,22 @@ if nargin<3 || isempty(coilaccuracy) % if empty it will use the original code % otherwise it will use the specified accuracy coil definition from the MNE coil_def.dat - coilaccuracy = []; + coilaccuracy = []; end if isfield(hdr, 'orig') hdr = hdr.orig; % use the original CTF header, not the FieldTrip header end -% start with empty gradiometer +% start with empty gradiometer structure grad = []; grad.coilpos = []; grad.coilori = []; grad.tra = []; +% start with empty electrode structure +elec = []; + % meg channels are 5, refmag 0, refgrad 1, ADCs 18 % UPPT001 is 11 % UTRG001 is 11 @@ -69,7 +72,7 @@ if ~isempty(coilaccuracy) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % use the coil definitions from the MNE coil_def.dat file - % these allow for varying accuracy which is specified by + % these allow for varying accuracy which is specified by % coilaccuracy = 0, 1 or 2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -80,11 +83,11 @@ k = 1; for i=1:length(hdr.res4.senres) switch hdr.res4.senres(i).sensorTypeIndex - case 5; % 5001 + case 5 % 5001 thisdef = def([def.id]==5001 & [def.accuracy]==coilaccuracy); - case 0; % 5002 + case 0 % 5002 thisdef = def([def.id]==5002 & [def.accuracy]==coilaccuracy); - case 1; % 5003 + case 1 % 5003 thisdef = def([def.id]==5003 & [def.accuracy]==coilaccuracy); otherwise % do not add this as sensor to the gradiometer definition @@ -171,10 +174,13 @@ sensType = [hdr.res4.senres.sensorTypeIndex]; selMEG = find(sensType==5); selREF = find(sensType==0 | sensType==1); + selEEG = find(sensType==9); selMEG = selMEG(:)'; selREF = selREF(:)'; + selEEG = selEEG(:)'; numMEG = length(selMEG); numREF = length(selREF); + numEEG = length(selEEG); % determine the number of channels and coils coilcount = 0; @@ -186,6 +192,26 @@ grad.coilori = zeros(coilcount, 3); % this will hold the orientation of each coil grad.tra = zeros(chancount, coilcount); % this describes how each coil contributes to each channel + if numEEG>0 + for i=1:numEEG + n = selEEG(i); + if dewar + pos = hdr.res4.senres(n).pos0'; + else + pos = hdr.res4.senres(n).pos'; + end + if hdr.res4.senres(n).numCoils~=1 + ft_error('unexpected number of electrode positions in EEG channel'); + end + % add this position + elec.elecpos(i ,:) = pos(1,:); + end + % add the electrode names + elec.label = cellstr(hdr.res4.chanNames(selEEG,:)); + else + elec = []; + end + % combine the bottom and top coil of each MEG channel for i=1:numMEG n = selMEG(i); @@ -198,7 +224,7 @@ ori = hdr.res4.senres(n).ori'; end if hdr.res4.senres(n).numCoils~=2 - error('unexpected number of coils in MEG channel'); + ft_error('unexpected number of coils in MEG channel'); end % add the coils of this channel to the gradiometer array grad.coilpos(i ,:) = pos(1,:); @@ -257,7 +283,7 @@ reflabel = label(hdr.BalanceCoefs.G1BR.Refindex); nmeg = length(meglabel); nref = length(reflabel); - montage.labelorg = cat(1, meglabel, reflabel); + montage.labelold = cat(1, meglabel, reflabel); montage.labelnew = cat(1, meglabel, reflabel); montage.tra = [eye(nmeg, nmeg), -hdr.BalanceCoefs.G1BR.alphaMEG'; zeros(nref, nmeg), eye(nref, nref)]; grad.balance.G1BR = montage; @@ -268,7 +294,7 @@ reflabel = label(hdr.BalanceCoefs.G2BR.Refindex); nmeg = length(meglabel); nref = length(reflabel); - montage.labelorg = cat(1, meglabel, reflabel); + montage.labelold = cat(1, meglabel, reflabel); montage.labelnew = cat(1, meglabel, reflabel); montage.tra = [eye(nmeg, nmeg), -hdr.BalanceCoefs.G2BR.alphaMEG'; zeros(nref, nmeg), eye(nref, nref)]; grad.balance.G2BR = montage; @@ -279,7 +305,7 @@ reflabel = label(hdr.BalanceCoefs.G3BR.Refindex); nmeg = length(meglabel); nref = length(reflabel); - montage.labelorg = cat(1, meglabel, reflabel); + montage.labelold = cat(1, meglabel, reflabel); montage.labelnew = cat(1, meglabel, reflabel); montage.tra = [eye(nmeg, nmeg), -hdr.BalanceCoefs.G3BR.alphaMEG'; zeros(nref, nmeg), eye(nref, nref)]; grad.balance.G3BR = montage; @@ -290,7 +316,7 @@ reflabel = label(hdr.BalanceCoefs.G3AR.Refindex); nmeg = length(meglabel); nref = length(reflabel); - montage.labelorg = cat(1, meglabel, reflabel); + montage.labelold = cat(1, meglabel, reflabel); montage.labelnew = cat(1, meglabel, reflabel); montage.tra = [eye(nmeg, nmeg), -hdr.BalanceCoefs.G3AR.alphaMEG'; zeros(nref, nmeg), eye(nref, nref)]; grad.balance.G3AR = montage; @@ -307,7 +333,7 @@ elseif all([hdr.res4.senres(selMEG).grad_order_no]==13) grad.balance.current = 'G3AR'; else - warning('cannot determine balancing of CTF gradiometers'); + ft_warning('cannot determine balancing of CTF gradiometers'); grad = rmfield(grad, 'balance'); end @@ -345,7 +371,7 @@ % determine the number of coils for this channel numcoils = sum(sum(pos.^2, 2)~=0); if numcoils~=2 - error('unexpected number of coils in MEG channel'); + ft_error('unexpected number of coils in MEG channel'); end % add the coils of this channel to the gradiometer array grad.coilpos(i ,:) = pos(1,:); @@ -394,7 +420,7 @@ if dewar % this does not work for Daren Webers implementation - error('cannot return the gradiometer definition in dewar coordinates'); + ft_error('cannot return the gradiometer definition in dewar coordinates'); end % only work on the MEG channels @@ -416,7 +442,7 @@ % assume that the orientation of the upper coil is opposite to the lower coil ori = [ori; -ori]; else - error('do not know how to deal with higher order gradiometer hardware') + ft_error('do not know how to deal with higher order gradiometer hardware') end % add this channels coil positions and orientations @@ -434,14 +460,14 @@ grad.tra(i,end+1) = 1; grad.tra(i,end+1) = 1; else - error('do not know how to deal with higher order gradiometer hardware') + ft_error('do not know how to deal with higher order gradiometer hardware') end end % prefer to have the labels in a column vector grad.label = grad.label(:); grad.unit = 'cm'; % the res4 file represents it in centimeter - + % reorder the coils, such that the bottom coils are at the first N % locations and the top coils at the last N positions. This makes it % easier to use a selection of the coils for topographic plotting @@ -454,5 +480,5 @@ end else - error('unknown header to contruct gradiometer definition'); + ft_error('unknown header to contruct gradiometer definition'); end diff --git a/external/fieldtrip/fileio/private/dataset2files.m b/external/fieldtrip/fileio/private/dataset2files.m index 65fb4ab7..fae0883f 100644 --- a/external/fieldtrip/fileio/private/dataset2files.m +++ b/external/fieldtrip/fileio/private/dataset2files.m @@ -106,7 +106,7 @@ elseif exist(fullfile(path, [file '.dat']), 'file') datafile = fullfile(path, [file '.dat']); else - error('cannot determine the data file that corresponds to %s', filename); + ft_error('cannot determine the data file that corresponds to %s', filename); end case 'brainvision_eeg' [path, file, ext] = fileparts(filename); diff --git a/external/fieldtrip/fileio/private/db_insert.m b/external/fieldtrip/fileio/private/db_insert.m index cf8c677b..358cf386 100644 --- a/external/fieldtrip/fileio/private/db_insert.m +++ b/external/fieldtrip/fileio/private/db_insert.m @@ -60,7 +60,7 @@ function db_insert(tablename, s) end otherwise - error('unsuported data type in structure'); + ft_error('unsuported data type in structure'); end cmd = [cmd ', ']; end diff --git a/external/fieldtrip/fileio/private/db_open.m b/external/fieldtrip/fileio/private/db_open.m index c597b487..d507bd21 100644 --- a/external/fieldtrip/fileio/private/db_open.m +++ b/external/fieldtrip/fileio/private/db_open.m @@ -42,7 +42,7 @@ function db_open(user, password, server, port, database) % combine the settings in a string of the form mysql://:@: filename = sprintf('mysql://<%s>:<%s>@<%s>:<%d>/<%s>', user, password, server, port, database); otherwise - error('incorrect input arguments'); + ft_error('incorrect input arguments'); end if ~strcmp(filename, prev_filename) @@ -64,7 +64,7 @@ function db_open(user, password, server, port, database) prev_filename = filename; catch prev_filename = []; - warning(lasterr); + ft_warning(lasterr); end end diff --git a/external/fieldtrip/fileio/private/db_select.m b/external/fieldtrip/fileio/private/db_select.m index 9527c689..75221975 100644 --- a/external/fieldtrip/fileio/private/db_select.m +++ b/external/fieldtrip/fileio/private/db_select.m @@ -48,7 +48,7 @@ case 9 [t{1}, t{2}, t{3}, t{4}, t{5}, t{6}, t{7}, t{8}, t{9}] = mysql(cmd); otherwise - error('unsupported number of fields'); + ft_error('unsupported number of fields'); end % convert the output into a structure array diff --git a/external/fieldtrip/fileio/private/decode_nifti1.m b/external/fieldtrip/fileio/private/decode_nifti1.m index f64083ac..6f61961b 100644 --- a/external/fieldtrip/fileio/private/decode_nifti1.m +++ b/external/fieldtrip/fileio/private/decode_nifti1.m @@ -28,7 +28,7 @@ H = []; magic = char(blob(345:347)); -if blob(348)~=0 | magic~='ni1' & magic~='n+1' +if blob(348)~=0 || magic~='ni1' && magic~='n+1' error 'Not a NIFTI-1 header!'; end diff --git a/external/fieldtrip/fileio/private/defaultId.m b/external/fieldtrip/fileio/private/defaultId.m new file mode 100644 index 00000000..f4e1ee99 --- /dev/null +++ b/external/fieldtrip/fileio/private/defaultId.m @@ -0,0 +1,57 @@ +function id = defaultId + +% DEFAULTID returns a string that can serve as warning or error identifier, +% for example 'FieldTip:ft_read_header:line345'. +% +% See also WARNING, ERROR, FT_NOTICE, FT_INFO, FT_DEBUG + +% Copyright (C) 2017, Robert Oostenveld +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +stack = dbstack('-completenames'); + +% remove the functions that pertain to the notification system itself +keep = true(size(stack)); +keep(strcmp({stack.name}, 'defaultId')) = false; % this function itself +keep(strcmp({stack.name}, 'ft_notification')) = false; % this one is doing the work underneath ft_error/ft_warning/ft_notice/etc. +keep(strcmp({stack.name}, 'ft_error')) = false; +keep(strcmp({stack.name}, 'ft_warning')) = false; +keep(strcmp({stack.name}, 'ft_notice')) = false; +keep(strcmp({stack.name}, 'ft_info')) = false; +keep(strcmp({stack.name}, 'ft_debug')) = false; +stack = stack(keep); + +% remove the non-FieldTrip functions from the path, these should not be part of the default message identifier +keep = true(size(stack)); +[v, p] = ft_version; +for i=1:numel(stack) + keep(i) = strncmp(p, stack(i).file, length(p)); +end +stack = stack(keep); + +if ~isempty(stack) + % it is called from within a function + stack = flipud(stack); + name = {stack.name}; + id = ['FieldTrip' sprintf(':%s', name{:}) ':line' num2str(stack(end).line)]; +else + % it is called from the command line + id = 'FieldTrip:commandline'; +end diff --git a/external/fieldtrip/fileio/private/dimlength.m b/external/fieldtrip/fileio/private/dimlength.m index 4f207f3c..f318db55 100644 --- a/external/fieldtrip/fileio/private/dimlength.m +++ b/external/fieldtrip/fileio/private/dimlength.m @@ -122,7 +122,7 @@ if isfield(data, 'individual'), n = [n size(data.individual, 1)]; end if isfield(data, 'stat'), n = [n size(data.stat, 1)]; end if ~all(n==n(1)) - error('inconsistent number of repetitions for dim "%s"', seldim); + ft_error('inconsistent number of repetitions for dim "%s"', seldim); end n = n(1); @@ -156,7 +156,7 @@ if isfield(data, 'trial'), n = [n size(data.trial, 1)]; end if isfield(data, 'fourierspctrm'), n = [n size(data.fourierspctrm, 1)]; end if ~all(n==n(1)) - error('inconsistent number of repetitions for dim "%s"', seldim); + ft_error('inconsistent number of repetitions for dim "%s"', seldim); end n = n(1); @@ -175,7 +175,7 @@ if isfield(data, 'powspctrm'), n = [n size(data.powspctrm, 1)]; end if isfield(data, 'trial'), n = [n size(data.trial, 1)]; end - if ~all(n==n(1)), error('inconsistent number of repetitions for dim "%s"', seldim); end + if ~all(n==n(1)), ft_error('inconsistent number of repetitions for dim "%s"', seldim); end n = n(1); case 'chan' @@ -225,7 +225,7 @@ end otherwise - error('unsupported dim "%s"', seldim); + ft_error('unsupported dim "%s"', seldim); end end % if nargin diff --git a/external/fieldtrip/fileio/private/elproj.m b/external/fieldtrip/fileio/private/elproj.m index 94ff2578..1fb7f3be 100644 --- a/external/fieldtrip/fileio/private/elproj.m +++ b/external/fieldtrip/fileio/private/elproj.m @@ -61,7 +61,7 @@ num = length(find(z<0)); str = sprintf('%d electrodes may be folded inwards in orthographic projection\n', num); if num - warning(str); + ft_warning(str); end proj = [xp yp]; @@ -77,7 +77,7 @@ num = length(find(th==pi/2 | z<0)); str = sprintf('removing %d electrodes from gnomic projection\n', num); if num - warning(str); + ft_warning(str); end xp(find(th==pi/2 | z<0)) = NaN; yp(find(th==pi/2 | z<0)) = NaN; @@ -94,7 +94,7 @@ num = length(find(th==pi/2 | z<0)); str = sprintf('removing %d electrodes from stereographic projection\n', num); if num - warning(str); + ft_warning(str); end xp(find(th==pi/2 | z<0)) = NaN; yp(find(th==pi/2 | z<0)) = NaN; @@ -113,5 +113,5 @@ proj = [x, y]; else - error('unsupported method (%s)', method); + ft_error('unsupported method (%s)', method); end diff --git a/external/fieldtrip/fileio/private/fif2grad.m b/external/fieldtrip/fileio/private/fif2grad.m index 74bf6382..e6fd0299 100644 --- a/external/fieldtrip/fileio/private/fif2grad.m +++ b/external/fieldtrip/fileio/private/fif2grad.m @@ -63,10 +63,10 @@ kCoil = kCoil+1; grad.label{k} = deblank(s(k,:)); else - error('unknown sensor type'); + ft_error('unknown sensor type'); end end catch - warning('gradiometer information could not be extracted from file, returning an empty grad structure'); + ft_warning('gradiometer information could not be extracted from file, returning an empty grad structure'); return; end diff --git a/external/fieldtrip/fileio/private/fiff_open_le.m b/external/fieldtrip/fileio/private/fiff_open_le.m index 84b08121..0d31b8d2 100644 --- a/external/fieldtrip/fileio/private/fiff_open_le.m +++ b/external/fieldtrip/fileio/private/fiff_open_le.m @@ -48,24 +48,24 @@ fid = fopen(fname,'rb','ieee-le'); % Arjen Stolk: this is 'ieee-be' in fiff_open.m if (fid < 0) - error(me,'Cannot open file %s', fname); + ft_error(me,'Cannot open file %s', fname); end; % % Check that this looks like a fif file % tag = fiff_read_tag_info(fid); if tag.kind ~= FIFF.FIFF_FILE_ID - error(me,'file does not start with a file id tag'); + ft_error(me,'file does not start with a file id tag'); end if tag.type ~= FIFF.FIFFT_ID_STRUCT - error(me,'file does not start with a file id tag'); + ft_error(me,'file does not start with a file id tag'); end if tag.size ~= 20 - error(me,'file does not start with a file id tag'); + ft_error(me,'file does not start with a file id tag'); end tag = fiff_read_tag(fid); if tag.kind ~= FIFF.FIFF_DIR_POINTER - error(me,'file does have a directory pointer'); + ft_error(me,'file does have a directory pointer'); end if nargout == 1 fseek(fid,0,'bof'); diff --git a/external/fieldtrip/fileio/private/filetype_check_header.m b/external/fieldtrip/fileio/private/filetype_check_header.m index 5706361c..ea211f93 100644 --- a/external/fieldtrip/fileio/private/filetype_check_header.m +++ b/external/fieldtrip/fileio/private/filetype_check_header.m @@ -61,7 +61,7 @@ % read the first few bytes from the file and compare them to the desired header fid = fopen(filename, 'rb'); if fid<0 - ft_warning(sprintf('could not open %s', filename)); + ft_warning('could not open %s', filename); val = false; else fseek(fid, offset, 'cof'); @@ -82,7 +82,7 @@ [str, siz] = fread(fid, length(head), 'uint8=>char'); fclose(fid); if siz~=length(head) - ft_warning(sprintf('could not read the header from %s', filename)); + ft_warning('could not read the header from %s', filename); val = false; else val = all(str(:)==head(:)); diff --git a/external/fieldtrip/fileio/private/filetype_check_uri.m b/external/fieldtrip/fileio/private/filetype_check_uri.m index c19c049e..d3fa3fa7 100644 --- a/external/fieldtrip/fileio/private/filetype_check_uri.m +++ b/external/fieldtrip/fileio/private/filetype_check_uri.m @@ -179,7 +179,7 @@ varargout{3} = filename((8+1+length(tok0{1})):end); otherwise - error('unsupported scheme in URI') + ft_error('unsupported scheme in URI') end end diff --git a/external/fieldtrip/fileio/private/fixdimord.m b/external/fieldtrip/fileio/private/fixdimord.m index 3786e1a8..b2b05928 100644 --- a/external/fieldtrip/fileio/private/fixdimord.m +++ b/external/fieldtrip/fileio/private/fixdimord.m @@ -50,7 +50,7 @@ % % if any(ft_datatype(data, {'source', 'volume'})) && isfield(data, 'dimord') && ~keepsourcedimord % % the old source data representation does not have a dimord, whereas the new source data representation does have a dimord -% warning(sprintf('removing dimord "%s" from source representation data', data.dimord)); +% ft_warning(sprintf('removing dimord "%s" from source representation data', data.dimord)); % data = rmfield(data, 'dimord'); % return % else @@ -68,24 +68,17 @@ elseif ft_datatype(data, 'volume') % it is volume data, which does not have a dimord -> this is ok return + elseif ft_datatype(data, 'source') || ft_datatype(data, 'parcellation') + % it is old-style source data -> this is ok + return else + % find the XXXdimord fields fn = fieldnames(data); sel = true(size(fn)); for i=1:length(fn) sel(i) = ~isempty(strfind(fn{i}, 'dimord')); end df = fn(sel); - - if isempty(df) - if ft_datatype(data, 'source') || ft_datatype(data, 'parcellation') - % it is old-style source data -> this is ok - % ft_checkdata will convert it to new-style - return - else - error('the data does not contain a dimord, but it also does not resemble raw or component data'); - end - end - % use this function recursively on the XXXdimord fields for i=1:length(df) data.dimord = data.(df{i}); @@ -96,7 +89,7 @@ % after the recursive call it should be ok return end -end +end % if no dimord if strcmp(data.dimord, 'voxel') % this means that it is position @@ -155,12 +148,12 @@ case {'{pos}' '{pos}_rpt' '{pos}_rpttap'} % this is for source data on a 3-d grid, a cortical sheet, or unstructured positions % the data itself is represented in a cell-array, e.g. source.mom or source.leadfield - + case {'{pos_pos}'} % this is for bivariate source data on a 3-d grid, a cortical sheet, or unstructured positions otherwise - error(sprintf('unexpected dimord "%s"', data.dimord)); + ft_error('unexpected dimord "%s"', data.dimord); end % switch dimtok end % for length dimtok @@ -217,4 +210,3 @@ for i=2:length(dimtok) data.dimord = [data.dimord '_' dimtok{i}]; end - diff --git a/external/fieldtrip/fileio/private/fixname.m b/external/fieldtrip/fileio/private/fixname.m index 96a345ec..76fd5951 100644 --- a/external/fieldtrip/fileio/private/fixname.m +++ b/external/fieldtrip/fileio/private/fixname.m @@ -1,19 +1,20 @@ -function str = fixname(str) +function str = fixname(str, version) % FIXNAME changes all inappropriate characters in a sting into '_' -% such that it can be used as a filename or as a structure field name. If -% the string begins with a numeric digit, an 'x' is prepended. +% so that it can be used as a filename or as a field name in a structure. +% If the string begins with a digit, an 'x' is prepended. % % Use as % str = fixname(str) % % MATLAB 2014a introduces the matlab.lang.makeValidName and -% matlab.lang.makeUniqueStrings functions for constructing unique MATLAB identifiers, -% but this particular implementation also works with older MATLAB versions. +% matlab.lang.makeUniqueStrings functions for constructing unique +% identifiers, but this particular implementation also works with +% older MATLAB versions. % % See also DEBLANK -% Copyright (C) 2012-2016, Robert Oostenveld +% Copyright (C) 2012-2017, Robert Oostenveld % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -33,19 +34,48 @@ % % $Id$ -str = lower(str); -str(regexp(str,'\W')) = '_'; - -while(str(1) == '_'), str = str(2:end); end; % remove all underscore at the begin of the string -while(str(end) == '_'), str = str(1:end-1); end; % remove all underscore at the end of the string - -if int8(str(1))<58 && int8(str(1))>47 - % the string begins with a digit, prepend an 'x' - str = ['x' str]; +if nargin<2 + version = 'default'; end -% truncate the string if it's too long: MATLAB maximizes the string length to 63 characters (and throws a warning when truncating) -if numel(str)>63 - str = str(1:63); - ft_warning(sprintf('%s exceeds MATLAB''s maximum name length of 63 characters and has been truncated to %s', str, str(1:63))); +switch version + case 'default' + if isempty(str) + str='x'; + end + str = lower(str); + str(regexp(str,'\W')) = '_'; + while(str(1) == '_'), str = str(2:end); end % remove all underscore at the begin of the string + while(str(end) == '_'), str = str(1:end-1); end % remove all underscore at the end of the string + if int8(str(1))<58 && int8(str(1))>47 + % the string begins with a digit, prepend an 'x' + str = ['x' str]; + end + % truncate the string if it's too long: MATLAB maximizes the string length to 63 characters (and throws a warning when truncating) + if numel(str)>63 + str = str(1:63); + warning('%s exceeds MATLAB''s maximum name length of 63 characters and has been truncated to %s', str, str(1:63)); + end + + case '2014a' + str = matlab.lang.makeValidName(str); + + case 'X_base64encode_X' + % this uses some code from Mathworks file exchange + ft_hastoolbox('fileexchange', 1); + % the following is an encoding that can be reverted + str = strtrim(base64encode(str)); + str(str=='=') = '_'; % replace the '=' sign with '_' + str = ['X' str 'X']; % start and end with an 'X' + + case 'X_base64decode_X' + % this uses some code from Mathworks file exchange + ft_hastoolbox('fileexchange', 1); + % revert the encoding + str = str(2:end-1); % it starts and ends with 'X' + str(str=='_') = '='; % the '=' sign has been replaced with '_' + str = char(base64decode(str)); + + otherwise + error('unsupported version "%s"', version); end diff --git a/external/fieldtrip/fileio/private/fixoldorg.m b/external/fieldtrip/fileio/private/fixoldorg.m new file mode 100644 index 00000000..93174b7a --- /dev/null +++ b/external/fieldtrip/fileio/private/fixoldorg.m @@ -0,0 +1,36 @@ +function input = fixoldorg(input, revert) + +% FIXOLDORG use "old/new" instead of "org/new" + +if nargin<2 + revert = false; +end + +if ~(isstruct(input) && numel(input)==1) + % this does not look like a montage or a sensor description + return +end + +if ~revert + from = {'labelorg', 'chantypeorg', 'chanunitorg', 'chanposorg', 'chanoriorg'}; + to = {'labelold', 'chantypeold', 'chanunitold', 'chanposold', 'chanoriold'}; +else + to = {'labelorg', 'chantypeorg', 'chanunitorg', 'chanposorg', 'chanoriorg'}; + from = {'labelold', 'chantypeold', 'chanunitold', 'chanposold', 'chanoriold'}; +end + +% replace the fields +for i=1:numel(from) + if isfield(input, from{i}) + input.(to{i}) = input.(from{i}); + input = rmfield(input, from{i}); + end +end + +% use recursion to update the subfields +fn = fieldnames(input); +for i=1:numel(fn) + if isstruct(input.(fn{i})) + input.(fn{i}) = fixoldorg(input.(fn{i}), revert); + end +end diff --git a/external/fieldtrip/fileio/private/fixpos.m b/external/fieldtrip/fileio/private/fixpos.m index 31cee40f..88408288 100644 --- a/external/fieldtrip/fileio/private/fixpos.m +++ b/external/fieldtrip/fileio/private/fixpos.m @@ -10,7 +10,7 @@ % convert to structure, otherwise the code below won't work properly ws = warning('off', 'MATLAB:structOnObject'); mesh = struct(mesh); - warning(ws); + ft_warning(ws); end if ~isa(mesh, 'struct') @@ -42,7 +42,7 @@ case 8 mesh.hex = mesh.ConnectivityList; otherwise - error('unsupported ConnectivityList') + ft_error('unsupported ConnectivityList') end % switch mesh = removefields(mesh, {'Points', 'ConnectivityList', 'Constraints', 'UnderlyingObj'}); end diff --git a/external/fieldtrip/fileio/private/ft_apply_montage.m b/external/fieldtrip/fileio/private/ft_apply_montage.m index 2b5e73ee..5262952b 100644 --- a/external/fieldtrip/fileio/private/ft_apply_montage.m +++ b/external/fieldtrip/fileio/private/ft_apply_montage.m @@ -18,7 +18,7 @@ % montage.labelnew = Mx1 cell-array % % As an example, a bipolar montage could look like this -% bipolar.labelold = {'1', '2', '3', '4'} +% bipolar.labelold = {'1', '2', '3', '4'} % bipolar.labelnew = {'1-2', '2-3', '3-4'} % bipolar.tra = [ % +1 -1 0 0 @@ -75,8 +75,8 @@ end % use "old/new" instead of "org/new" -montage = fixmontage(montage); -input = fixmontage(input); % the input might also be a montage +montage = fixoldorg(montage); +input = fixoldorg(input); % the input might be a montage or a sensor array % get optional input arguments keepunused = ft_getopt(varargin, 'keepunused', 'no'); @@ -99,7 +99,7 @@ if ~isfield(montage, 'chantypeold') montage.chantypeold = repmat({'unknown'}, size(montage.labelold)); if isfield(input, 'chantype') && ~istrue(inverse) - warning('copying input chantype to montage'); + ft_warning('copying input chantype to montage'); [sel1, sel2] = match_str(montage.labelold, input.label); montage.chantypeold(sel1) = input.chantype(sel2); end @@ -108,7 +108,7 @@ if ~isfield(montage, 'chantypenew') montage.chantypenew = repmat({'unknown'}, size(montage.labelnew)); if isfield(input, 'chantype') && istrue(inverse) - warning('copying input chantype to montage'); + ft_warning('copying input chantype to montage'); [sel1, sel2] = match_str(montage.labelnew, input.label); montage.chantypenew(sel1) = input.chantype(sel2); end @@ -117,7 +117,7 @@ if ~isfield(montage, 'chanunitold') montage.chanunitold = repmat({'unknown'}, size(montage.labelold)); if isfield(input, 'chanunit') && ~istrue(inverse) - warning('copying input chanunit to montage'); + ft_warning('copying input chanunit to montage'); [sel1, sel2] = match_str(montage.labelold, input.label); montage.chanunitold(sel1) = input.chanunit(sel2); end @@ -126,7 +126,7 @@ if ~isfield(montage, 'chanunitnew') montage.chanunitnew = repmat({'unknown'}, size(montage.labelnew)); if isfield(input, 'chanunit') && istrue(inverse) - warning('copying input chanunit to montage'); + ft_warning('copying input chanunit to montage'); [sel1, sel2] = match_str(montage.labelnew, input.label); montage.chanunitnew(sel1) = input.chanunit(sel2); end @@ -162,19 +162,19 @@ % check the consistency of the montage if ~iscell(montage.labelold) || ~iscell(montage.labelnew) - error('montage labels need to be specified in cell-arrays'); + ft_error('montage labels need to be specified in cell-arrays'); end % check the consistency of the montage if ~all(isfield(montage, {'tra', 'labelold', 'labelnew'})) - error('the second input argument does not correspond to a montage'); + ft_error('the second input argument does not correspond to a montage'); end % check the consistency of the montage if size(montage.tra,1)~=length(montage.labelnew) - error('the number of channels in the montage is inconsistent'); + ft_error('the number of channels in the montage is inconsistent'); elseif size(montage.tra,2)~=length(montage.labelold) - error('the number of channels in the montage is inconsistent'); + ft_error('the number of channels in the montage is inconsistent'); end % use a default unit transfer from sensors to channels if not otherwise specified @@ -212,15 +212,14 @@ end % select and keep the columns that are non-empty, i.e. remove the empty columns -selcol = find(~all(montage.tra==0, 1)); -montage.tra = montage.tra(:,selcol); -montage.labelold = montage.labelold(selcol); +selcol = find(~all(montage.tra==0, 1)); +montage.tra = montage.tra(:,selcol); +montage.labelold = montage.labelold(selcol); montage.chantypeold = montage.chantypeold(selcol); montage.chanunitold = montage.chanunitold(selcol); clear selcol -% select and remove the columns corresponding to channels that are not present in the -% original data +% select and remove the columns corresponding to channels that are not present in the original data remove = setdiff(montage.labelold, intersect(montage.labelold, inputlabel)); selcol = match_str(montage.labelold, remove); % we cannot just remove the colums, all rows that depend on it should also be removed @@ -259,15 +258,15 @@ % use an anonymous function to test for the presence of NaNs in the input data hasnan = @(x) any(isnan(x(:))); if any(cellfun(hasnan, data_unused.trial)) - error('FieldTrip:NaNsinInputData', ['Your input data contains NaNs in channels that are unused '... + ft_error('FieldTrip:NaNsinInputData', ['Your input data contains NaNs in channels that are unused '... 'in the supplied montage. This would result in undesired NaNs in the '... 'output data. Please remove these channels from the input data (using '... 'ft_selectdata) before attempting to apply the montage.']); end end + if istrue(keepunused) - % add the channels that are not rereferenced to the input and output of the - % montage + % add the channels that are not rereferenced to the input and output of the montage montage.tra((m+(1:k)),(n+(1:k))) = eye(k); montage.labelold = cat(1, montage.labelold(:), addlabel(:)); montage.labelnew = cat(1, montage.labelnew(:), addlabel(:)); @@ -288,15 +287,15 @@ m = size(montage.tra,1); n = size(montage.tra,2); if length(unique(montage.labelnew))~=m - error('not all output channels of the montage are unique'); + ft_error('not all output channels of the montage are unique'); end if length(unique(montage.labelold))~=n - error('not all input channels of the montage are unique'); + ft_error('not all input channels of the montage are unique'); end % determine whether all channels that have to be rereferenced are available if length(intersect(inputlabel, montage.labelold))~=length(montage.labelold) - error('not all channels that are required in the montage are available in the data'); + ft_error('not all channels that are required in the montage are available in the data'); end % reorder the columns of the montage matrix @@ -331,9 +330,9 @@ end if isfield(input, 'chantype') && ~isequal(input.chantype, montage.chantypeold) - error('inconsistent chantype in data and montage'); + ft_error('inconsistent chantype in data and montage'); elseif isfield(input, 'chantypenew') && ~isequal(input.chantypenew, montage.chantypeold) - error('inconsistent chantype in data and montage'); + ft_error('inconsistent chantype in data and montage'); end if isfield(input, 'labelold') && isfield(input, 'labelnew') @@ -374,11 +373,13 @@ sens.tra = montage.tra * sens.tra; end - % The montage operates on the coil weights in sens.tra, but the output channels - % can be different. If possible, we want to keep the original channel positions - % and orientations. + % The montage operates on the coil weights in sens.tra, but the output channels can be different. + % If possible, we want to keep the original channel positions and orientations. [sel1, sel2] = match_str(montage.labelnew, inputlabel); - keepchans = length(sel1)==length(montage.labelnew); + keepchans = isequal(sel1(:)', 1:numel(montage.labelnew)); + + posweight = abs(montage.tra); + posweight = diag(1./sum(posweight,2)) * posweight; if isfield(sens, 'chanpos') if keepchans @@ -386,9 +387,14 @@ else if ~isfield(sens, 'chanposold') % add a chanposold only if it is not there yet - sens.chanposold = sens.chanpos; + sens.chanposold = sens.chanpos; + % also keep the old label, type and unit for reference + sens.labelold = inputlabel; + sens.chantypeold = inputchantype; + sens.chanunitold = inputchanunit; end - sens.chanpos = nan(numel(montage.labelnew),3); + % compute the channel positions as a weighted sum of the original ones + sens.chanpos = posweight * sens.chanpos; end end @@ -399,7 +405,8 @@ if ~isfield(sens, 'chanoriold') sens.chanoriold = sens.chanori; end - sens.chanori = nan(numel(montage.labelnew),3); + % compute the channel orientations as a weighted sum of the original ones + sens.chanori = posweight * sens.chanori; end end @@ -407,20 +414,6 @@ sens.chantype = montage.chantypenew; sens.chanunit = montage.chanunitnew; - % keep the - % original label, - % type and unit - % for reference - if ~isfield(sens, 'labelold') - sens.labelold = inputlabel; - end - if ~isfield(sens, 'chantypeold') - sens.chantypeold = inputchantype; - end - if ~isfield(sens, 'chanunitold') - sens.chanunitold = inputchanunit; - end - % keep track of the order of the balancing and which one is the current one if istrue(inverse) if isfield(sens, 'balance')% && isfield(sens.balance, 'previous') @@ -434,14 +427,14 @@ sens.balance.current = 'none'; end end - elseif ~istrue(inverse) && ~isempty(bname) - if isfield(sens, 'balance'), + elseif ~istrue(inverse) && ~isempty(bname) + if isfield(sens, 'balance') % check whether a balancing montage with name bname already exist, % and if so, how many mnt = fieldnames(sens.balance); sel = strmatch(bname, mnt); - if numel(sel)==0, + if numel(sel)==0 % bname can stay the same elseif numel(sel)==1 % the original should be renamed to 'bname1' and the new one should @@ -477,8 +470,8 @@ input = sens; clear sens - case 'raw'; - % apply the montage to the raw data that was preprocessed using fieldtrip + case 'raw' + % apply the montage to the raw data that was preprocessed using FieldTrip data = input; clear input @@ -533,7 +526,7 @@ end freq.fourierspctrm = output; % replace the original Fourier spectrum else - error('unsupported dimord in frequency data (%s)', freq.dimord); + ft_error('unsupported dimord in frequency data (%s)', freq.dimord); end freq.label = montage.labelnew; @@ -545,7 +538,7 @@ clear freq otherwise - error('unrecognized input'); + ft_error('unrecognized input'); end % switch inputtype % only retain the chantype and/or chanunit if they were present in the input @@ -563,30 +556,9 @@ y = false(1,n); y(x) = true; -function nowarning(varargin) -return - -function s = removefields(s, fn) -for i=1:length(fn) - if isfield(s, fn{i}) - s = rmfield(s, fn{i}); - end -end - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% HELPER FUNCTION use "old/new" instead of "org/new" +% HELPER FUNCTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -function montage = fixmontage(montage) -if isfield(montage, 'labelorg') - montage.labelold = montage.labelorg; - montage = rmfield(montage, 'labelorg'); -end -if isfield(montage, 'chantypeorg') - montage.chantypeold = montage.chantypeorg; - montage = rmfield(montage, 'chantypeorg'); -end -if isfield(montage, 'chanunitorg') - montage.chanunitold = montage.chanunitorg; - montage = rmfield(montage, 'chanunitorg'); -end +function nowarning(varargin) +return diff --git a/external/fieldtrip/fileio/private/ft_checkdata.m b/external/fieldtrip/fileio/private/ft_checkdata.m index ac130dee..d0ee2d49 100644 --- a/external/fieldtrip/fileio/private/ft_checkdata.m +++ b/external/fieldtrip/fileio/private/ft_checkdata.m @@ -1,25 +1,25 @@ function [data] = ft_checkdata(data, varargin) -% FT_CHECKDATA checks the input data of the main FieldTrip functions, e.g. whether -% the type of data strucure corresponds with the required data. If neccessary -% and possible, this function will adjust the data structure to the input -% requirements (e.g. change dimord, average over trials, convert inside from -% index into logical). +% FT_CHECKDATA checks the input data of the main FieldTrip functions, e.g. whether the +% type of data strucure corresponds with the required data. If neccessary and possible, +% this function will adjust the data structure to the input requirements (e.g. change +% dimord, average over trials, convert inside from index into logical). % -% If the input data does NOT correspond to the requirements, this function -% is supposed to give a elaborate warning message and if applicable point -% the user to external documentation (link to website). +% If the input data does NOT correspond to the requirements, this function will give a +% warning message and if applicable point the user to external documentation (link to +% website). % % Use as % [data] = ft_checkdata(data, ...) % % Optional input arguments should be specified as key-value pairs and can include % feedback = yes, no -% datatype = raw, freq, timelock, comp, spike, source, dip, volume, segmentation, parcellation +% datatype = raw, freq, timelock, comp, spike, source, mesh, dip, volume, segmentation, parcellation % dimord = any combination of time, freq, chan, refchan, rpt, subj, chancmb, rpttap, pos % senstype = ctf151, ctf275, ctf151_planar, ctf275_planar, neuromag122, neuromag306, bti148, bti248, bti248_planar, magnetometer, electrode % inside = logical, index % ismeg = yes, no +% iseeg = yes, no % isnirs = yes, no % hasunit = yes, no % hascoordsys = yes, no @@ -36,6 +36,8 @@ % For some options you can specify multiple values, e.g. % [data] = ft_checkdata(data, 'senstype', {'ctf151', 'ctf275'}), e.g. in megrealign % [data] = ft_checkdata(data, 'datatype', {'timelock', 'freq'}), e.g. in sourceanalysis +% +% See also FT_DATATYPE_XXX for each of the respective data types. % Copyright (C) 2007-2015, Robert Oostenveld % Copyright (C) 2010-2012, Martin Vinck @@ -66,6 +68,7 @@ % fixinside % fixprecision % fixvolume +% fixpos % data2raw % raw2data % grid2transform @@ -93,6 +96,7 @@ dimord = ft_getopt(varargin, 'dimord'); stype = ft_getopt(varargin, 'senstype'); % senstype is a function name which should not be masked ismeg = ft_getopt(varargin, 'ismeg'); +iseeg = ft_getopt(varargin, 'iseeg'); isnirs = ft_getopt(varargin, 'isnirs'); inside = ft_getopt(varargin, 'inside'); % can be 'logical' or 'index' hastrials = ft_getopt(varargin, 'hastrials'); @@ -112,12 +116,11 @@ % check whether people are using deprecated stuff depHastrialdef = ft_getopt(varargin, 'hastrialdef'); if (~isempty(depHastrialdef)) - ft_warning('ft_checkdata option ''hastrialdef'' is deprecated; use ''hassampleinfo'' instead'); + ft_warning('ft_checkdata option ''hastrialdef'' is deprecated; please use ''hassampleinfo'' instead'); hassampleinfo = depHastrialdef; end % determine the type of input data -% this can be raw, freq, timelock, comp, spike, source, volume, dip israw = ft_datatype(data, 'raw'); isfreq = ft_datatype(data, 'freq'); istimelock = ft_datatype(data, 'timelock'); @@ -134,46 +137,71 @@ ismesh = ft_datatype(data, 'mesh'); % FIXME use the istrue function on ismeg and hasxxx options -if ~isequal(feedback, 'no') +if ~isequal(feedback, 'no') % can be 'yes' or 'text' if iscomp % it can be comp and raw/timelock/freq at the same time, therefore this has to go first nchan = size(data.topo,1); ncomp = size(data.topo,2); - fprintf('the input is component data with %d components and %d original channels\n', ncomp, nchan); - end + ft_info('the input is component data with %d components and %d original channels\n', ncomp, nchan); + end % if iscomp + + if ismesh + % it can be comp and source at the same time, therefore this has to go first + data = fixpos(data); + npos = 0; + ntri = 0; + nhex = 0; + ntet = 0; + % the data can contain multiple surfaces + for i=1:numel(data) + npos = npos+size(data.pos,1); + if isfield(data, 'tri'), ntri = ntri+size(data.tri,1); end + if isfield(data, 'hex'), nhex = nhex+size(data.hex,1); end + if isfield(data, 'tet'), ntet = ntet+size(data.tet,1); end + end + if isfield(data,'tri') + ft_info('the input is mesh data with %d vertices and %d triangles\n', npos, ntri); + elseif isfield(data,'hex') + ft_info('the input is mesh data with %d vertices and %d hexahedrons\n', npos, nhex); + elseif isfield(data,'tet') + ft_info('the input is mesh data with %d vertices and %d tetrahedrons\n', npos, ntet); + else + ft_info('the input is mesh data with %d vertices', npos); + end + end % if ismesh if israw nchan = length(data.label); ntrial = length(data.trial); - fprintf('the input is raw data with %d channels and %d trials\n', nchan, ntrial); + ft_info('the input is raw data with %d channels and %d trials\n', nchan, ntrial); elseif istimelock nchan = length(data.label); ntime = length(data.time); - fprintf('the input is timelock data with %d channels and %d timebins\n', nchan, ntime); + ft_info('the input is timelock data with %d channels and %d timebins\n', nchan, ntime); elseif isfreq if isfield(data, 'label') nchan = length(data.label); nfreq = length(data.freq); if isfield(data, 'time'), ntime = num2str(length(data.time)); else ntime = 'no'; end - fprintf('the input is freq data with %d channels, %d frequencybins and %s timebins\n', nchan, nfreq, ntime); + ft_info('the input is freq data with %d channels, %d frequencybins and %s timebins\n', nchan, nfreq, ntime); elseif isfield(data, 'labelcmb') nchan = length(data.labelcmb); nfreq = length(data.freq); if isfield(data, 'time'), ntime = num2str(length(data.time)); else ntime = 'no'; end - fprintf('the input is freq data with %d channel combinations, %d frequencybins and %s timebins\n', nchan, nfreq, ntime); + ft_info('the input is freq data with %d channel combinations, %d frequencybins and %s timebins\n', nchan, nfreq, ntime); else - error('cannot infer freq dimensions'); + ft_error('cannot infer freq dimensions'); end elseif isspike nchan = length(data.label); - fprintf('the input is spike data with %d channels\n', nchan); + ft_info('the input is spike data with %d channels\n', nchan); elseif isvolume if issegmentation subtype = 'segmented volume'; else subtype = 'volume'; end - fprintf('the input is %s data with dimensions [%d %d %d]\n', subtype, data.dim(1), data.dim(2), data.dim(3)); + ft_info('the input is %s data with dimensions [%d %d %d]\n', subtype, data.dim(1), data.dim(2), data.dim(3)); clear subtype elseif issource data = fixpos(data); % ensure that positions are in pos, not in pnt @@ -184,43 +212,26 @@ subtype = 'source'; end if isfield(data, 'dim') - fprintf('the input is %s data with %d brainordinates on a [%d %d %d] grid\n', subtype, nsource, data.dim(1), data.dim(2), data.dim(3)); - elseif isfield(data, 'tri') - fprintf('the input is %s data with %d vertex positions and %d triangles\n', subtype, nsource, size(data.tri, 1)); + ft_info('the input is %s data with %d brainordinates on a [%d %d %d] grid\n', subtype, nsource, data.dim(1), data.dim(2), data.dim(3)); else - fprintf('the input is %s data with %d brainordinates\n', subtype, nsource); + ft_info('the input is %s data with %d brainordinates\n', subtype, nsource); end clear subtype elseif isdip - fprintf('the input is dipole data\n'); + ft_info('the input is dipole data\n'); elseif ismvar - fprintf('the input is mvar data\n'); + ft_info('the input is mvar data\n'); elseif isfreqmvar - fprintf('the input is freqmvar data\n'); + ft_info('the input is freqmvar data\n'); elseif ischan nchan = length(data.label); if isfield(data, 'brainordinate') - fprintf('the input is parcellated data with %d parcels\n', nchan); + ft_info('the input is parcellated data with %d parcels\n', nchan); else - fprintf('the input is chan data with %d channels\n', nchan); + ft_info('the input is chan data with %d channels\n', nchan); end - end -elseif ismesh - data = fixpos(data); - if numel(data)==1 - if isfield(data,'tri') - fprintf('the input is mesh data with %d vertices and %d triangles\n', size(data.pos,1), size(data.tri,1)); - elseif isfield(data,'hex') - fprintf('the input is mesh data with %d vertices and %d hexahedrons\n', size(data.pos,1), size(data.hex,1)); - elseif isfield(data,'tet') - fprintf('the input is mesh data with %d vertices and %d tetrahedrons\n', size(data.pos,1), size(data.tet,1)); - else - fprintf('the input is mesh data with %d vertices', size(data.pos,1)); - end - else - fprintf('the input is mesh data multiple surfaces\n'); - end -end % give feedback + end % if israw etc. +end % give feedback if issource && isvolume % it should be either one or the other: the choice here is to represent it as volume description since that is simpler to handle @@ -270,6 +281,8 @@ okflag = okflag + (isfreq & iscomp); case 'timelock+comp' okflag = okflag + (istimelock & iscomp); + case 'source+mesh' + okflag = okflag + (issource & ismesh); case 'raw' okflag = okflag + (israw & ~iscomp); case 'freq' @@ -333,15 +346,24 @@ issource = 1; okflag = 1; elseif isequal(dtype(iCell), {'volume'}) && (ischan || istimelock || isfreq) - data = parcellated2source(data); - data = ft_datatype_volume(data); - ischan = 0; + if isfield(data, 'brainordinate') + data = parcellated2source(data); + data = ft_datatype_volume(data); + else + ft_error('cannot convert channel-level data to volumetric representation'); + end + ischan = 0; istimelock = 0; isfreq = 0; isvolume = 1; okflag = 1; elseif isequal(dtype(iCell), {'source'}) && (ischan || istimelock || isfreq) - data = parcellated2source(data); - data = ft_datatype_source(data); - ischan = 0; + if isfield(data, 'brainordinate') + data = parcellated2source(data); + data = ft_datatype_source(data); + else + data = chan2source(data); + data = ft_datatype_source(data); + end % converting channel data + ischan = 0; istimelock = 0; isfreq = 0; issource = 1; okflag = 1; elseif isequal(dtype(iCell), {'volume'}) && issource @@ -357,6 +379,13 @@ iscomp = 1; israw = 1; okflag = 1; + elseif isequal(dtype(iCell), {'timelock+comp'}) && israw && iscomp + data = raw2timelock(data); + data = ft_datatype_timelock(data); + istimelock = 1; + iscomp = 1; + israw = 0; + okflag = 1; elseif isequal(dtype(iCell), {'raw'}) && issource data = source2raw(data); data = ft_datatype_raw(data, 'hassampleinfo', hassampleinfo); @@ -373,19 +402,19 @@ istimelock = 0; israw = 1; okflag = 1; - elseif isequal(dtype(iCell), {'comp'}) && israw + elseif isequal(dtype(iCell), {'comp'}) && israw && iscomp data = keepfields(data, {'label', 'topo', 'topolabel', 'unmixing', 'elec', 'grad', 'cfg'}); % these are the only relevant fields data = ft_datatype_comp(data); israw = 0; iscomp = 1; okflag = 1; - elseif isequal(dtype(iCell), {'comp'}) && istimelock + elseif isequal(dtype(iCell), {'comp'}) && istimelock && iscomp data = keepfields(data, {'label', 'topo', 'topolabel', 'unmixing', 'elec', 'grad', 'cfg'}); % these are the only relevant fields data = ft_datatype_comp(data); istimelock = 0; iscomp = 1; okflag = 1; - elseif isequal(dtype(iCell), {'comp'}) && isfreq + elseif isequal(dtype(iCell), {'comp'}) && isfreq && iscomp data = keepfields(data, {'label', 'topo', 'topolabel', 'unmixing', 'elec', 'grad', 'cfg'}); % these are the only relevant fields data = ft_datatype_comp(data); isfreq = 0; @@ -469,13 +498,18 @@ if ~okflag % construct an error message - if length(dtype)>1 - str = sprintf('%s, ', dtype{1:(end-2)}); - str = sprintf('%s%s or %s', str, dtype{end-1}, dtype{end}); + typestr = printor(dtype, true); + helpfun = cell(size(dtype)); + for i=1:numel(dtype) + helpfun{i} = sprintf('ft_datatype_%s', dtype{i}); + end + helpfun = helpfun(cellfun(@exist, helpfun)>0); + if ~isempty(helpfun) + helpstr = printor(helpfun); + ft_error('This function requires %s data as input, see %s.', typestr, helpstr); else - str = dtype{1}; + ft_error('This function requires %s data as input.', typestr); end - error('This function requires %s data as input.', str); end % if okflag end @@ -492,13 +526,7 @@ if ~okflag % construct an error message - if length(dimord)>1 - str = sprintf('%s, ', dimord{1:(end-2)}); - str = sprintf('%s%s or %s', str, dimord{end-1}, dimord{end}); - else - str = dimord{1}; - end - error('This function requires data with a dimord of %s.', str); + ft_error('This function requires data with a dimord of %s.', printor(dimord, true)); end % if okflag end @@ -516,17 +544,14 @@ else okflag = 0; end + else + % the data does not contain a sensor array + okflag = 0; end if ~okflag % construct an error message - if length(stype)>1 - str = sprintf('%s, ', stype{1:(end-2)}); - str = sprintf('%s%s or %s', str, stype{end-1}, stype{end}); - else - str = stype{1}; - end - error('This function requires %s data as input, but you are giving %s data.', str, ft_senstype(data)); + ft_error('This function requires data with an %s sensor array.', printor(stype, true)); end % if okflag end @@ -538,9 +563,23 @@ end if ~okflag && isequal(ismeg, 'yes') - error('This function requires MEG data with a ''grad'' field'); + ft_error('This function requires MEG data with a ''grad'' field'); elseif ~okflag && isequal(ismeg, 'no') - error('This function should not be given MEG data with a ''grad'' field'); + ft_error('This function should not be given MEG data with a ''grad'' field'); + end % if okflag +end + +if ~isempty(iseeg) + if isequal(iseeg, 'yes') + okflag = isfield(data, 'grad'); + elseif isequal(iseeg, 'no') + okflag = ~isfield(data, 'grad'); + end + + if ~okflag && isequal(iseeg, 'yes') + ft_error('This function requires EEG data with an ''elec'' field'); + elseif ~okflag && isequal(iseeg, 'no') + ft_error('This function should not be given EEG data with an ''elec'' field'); end % if okflag end @@ -552,15 +591,15 @@ end if ~okflag && isequal(isnirs, 'yes') - error('This function requires NIRS data with an ''opto'' field'); + ft_error('This function requires NIRS data with an ''opto'' field'); elseif ~okflag && isequal(isnirs, 'no') - error('This function should not be given NIRS data with an ''opto'' field'); + ft_error('This function should not be given NIRS data with an ''opto'' field'); end % if okflag end if ~isempty(inside) if strcmp(inside, 'index') - warning('the indexed representation of inside/outside source locations is deprecated'); + ft_warning('the indexed representation of inside/outside source locations is deprecated'); end % TODO absorb the fixinside function into this code data = fixinside(data, inside); @@ -568,13 +607,13 @@ if ~okflag % construct an error message - error('This function requires data with an ''inside'' field.'); + ft_error('This function requires data with an ''inside'' field.'); end % if okflag end if istrue(hasunit) && ~isfield(data, 'unit') % calling convert_units with only the input data adds the units without converting - data = ft_convert_units(data); + data = ft_determine_units(data); end % if hasunit if istrue(hascoordsys) && ~isfield(data, 'coordsys') @@ -582,16 +621,23 @@ end % if hascoordsys if isequal(hastrials, 'yes') - okflag = isfield(data, 'trial'); - if ~okflag && isfield(data, 'dimord') + hasrpt = isfield(data, 'trial'); + if ~hasrpt && isfield(data, 'dimord') % instead look in the dimord for rpt or subj - okflag = ~isempty(strfind(data.dimord, 'rpt')) || ... + hasrpt = ~isempty(strfind(data.dimord, 'rpt')) || ... ~isempty(strfind(data.dimord, 'rpttap')) || ... ~isempty(strfind(data.dimord, 'subj')); end - if ~okflag - error('This function requires data with a ''trial'' field'); - end % if okflag + if ~hasrpt + ft_error('This function requires data with a ''trial'' field'); + end % if hasrpt +elseif isequal(hastrials, 'no') && istimelock + if ~isfield(data, 'avg') && (isfield(data, 'trial') || isfield(data, 'individual')) + % average on the fly + tmpcfg = []; + tmpcfg.keeptrials = 'no'; + data = ft_timelockanalysis(tmpcfg, data); + end end if strcmp(hasdim, 'yes') && ~isfield(data, 'dim') @@ -601,13 +647,13 @@ end % if hasdim if strcmp(hascumtapcnt, 'yes') && ~isfield(data, 'cumtapcnt') - error('This function requires data with a ''cumtapcnt'' field'); + ft_error('This function requires data with a ''cumtapcnt'' field'); elseif strcmp(hascumtapcnt, 'no') && isfield(data, 'cumtapcnt') data = rmfield(data, 'cumtapcnt'); end % if hascumtapcnt if strcmp(hasdof, 'yes') && ~isfield(data, 'dof') - error('This function requires data with a ''dof'' field'); + ft_error('This function requires data with a ''dof'' field'); elseif strcmp(hasdof, 'no') && isfield(data, 'dof') data = rmfield(data, 'dof'); end % if hasdof @@ -620,7 +666,7 @@ elseif isfreqmvar data = fixcsd(data, cmbrepresentation, channelcmb); else - error('This function requires data with a covariance, coherence or cross-spectrum'); + ft_error('This function requires data with a covariance, coherence or cross-spectrum'); end end % cmbrepresentation @@ -645,16 +691,16 @@ current = 'sparse'; end else - error('Could not determine the current representation of the covariance matrix'); + ft_error('Could not determine the current representation of the covariance matrix'); end if isequal(current, desired) % nothing to do elseif strcmp(current, 'full') && strcmp(desired, 'sparse') % FIXME should be implemented - error('not yet implemented'); + ft_error('not yet implemented'); elseif strcmp(current, 'sparse') && strcmp(desired, 'full') % FIXME should be implemented - error('not yet implemented'); + ft_error('not yet implemented'); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -680,7 +726,7 @@ elseif isfield(data, 'labelcmb') current = 'sparse'; else - error('Could not determine the current representation of the %s matrix', param); + ft_error('Could not determine the current representation of the %s matrix', param); end % first go from univariate fourier to the required bivariate representation @@ -689,7 +735,7 @@ elseif strcmp(current, 'fourier') && strcmp(desired, 'sparsewithpow') dimtok = tokenize(data.dimord, '_'); - if ~isempty(strmatch('rpttap', dimtok)), + if ~isempty(strmatch('rpttap', dimtok)) nrpt = size(data.cumtapcnt,1); flag = 0; else @@ -713,7 +759,7 @@ powspctrm = powspctrm./ntap; else % different amount of tapers - powspctrm = zeros(nrpt,nchan,nfrq,ntim)+i.*zeros(nrpt,nchan,nfrq,ntim); + powspctrm = zeros(nrpt,nchan,nfrq,ntim) + zeros(nrpt,nchan,nfrq,ntim)*1i; sumtapcnt = [0;cumsum(data.cumtapcnt(:))]; for p = 1:nrpt indx = (sumtapcnt(p)+1):sumtapcnt(p+1); @@ -723,14 +769,14 @@ end %create cross-spectra - if ~isempty(channelcmb), + if ~isempty(channelcmb) ncmb = size(channelcmb,1); cmbindx = zeros(ncmb,2); labelcmb = cell(ncmb,2); for k = 1:ncmb ch1 = find(strcmp(data.label, channelcmb(k,1))); ch2 = find(strcmp(data.label, channelcmb(k,2))); - if ~isempty(ch1) && ~isempty(ch2), + if ~isempty(ch1) && ~isempty(ch2) cmbindx(k,:) = [ch1 ch2]; labelcmb(k,:) = data.label([ch1 ch2])'; end @@ -757,17 +803,17 @@ end data.powspctrm = powspctrm; data = rmfield(data, 'fourierspctrm'); - if ntim>1, + if ntim>1 data.dimord = 'chan_freq_time'; else data.dimord = 'chan_freq'; end - if nrpt>1, + if nrpt>1 data.dimord = ['rpt_',data.dimord]; end - if flag, + if flag siz = size(data.powspctrm); data.powspctrm = reshape(data.powspctrm, [siz(2:end) 1]); if isfield(data, 'crsspctrm') @@ -777,9 +823,9 @@ end elseif strcmp(current, 'fourier') && strcmp(desired, 'sparse') - if isempty(channelcmb), error('no channel combinations are specified'); end + if isempty(channelcmb), ft_error('no channel combinations are specified'); end dimtok = tokenize(data.dimord, '_'); - if ~isempty(strmatch('rpttap', dimtok)), + if ~isempty(strmatch('rpttap', dimtok)) nrpt = size(data.cumtapcnt,1); flag = 0; else @@ -795,7 +841,7 @@ for k = 1:ncmb ch1 = find(strcmp(data.label, channelcmb(k,1))); ch2 = find(strcmp(data.label, channelcmb(k,2))); - if ~isempty(ch1) && ~isempty(ch2), + if ~isempty(ch1) && ~isempty(ch2) cmbindx(k,:) = [ch1 ch2]; labelcmb(k,:) = data.label([ch1 ch2])'; end @@ -844,20 +890,22 @@ data.labelcmb = labelcmb; data = rmfield(data, 'fourierspctrm'); data = rmfield(data, 'label'); - if ntim>1, + if ntim>1 data.dimord = 'chancmb_freq_time'; else data.dimord = 'chancmb_freq'; end - if nrpt>1, + if nrpt>1 data.dimord = ['rpt_',data.dimord]; end - if flag, - % deal with the singleton 'rpt', i.e. remove it - siz = size(data.powspctrm); - data.powspctrm = reshape(data.powspctrm, [siz(2:end) 1]); + if flag + if isfield(data,'powspctrm') + % deal with the singleton 'rpt', i.e. remove it + siz = size(data.powspctrm); + data.powspctrm = reshape(data.powspctrm, [siz(2:end) 1]); + end if isfield(data,'crsspctrm') % this conditional statement is needed in case there's a single channel siz = size(data.crsspctrm); @@ -868,7 +916,7 @@ % this is how it is currently and the desired functionality of prepare_freq_matrices dimtok = tokenize(data.dimord, '_'); - if ~isempty(strmatch('rpttap', dimtok)), + if ~isempty(strmatch('rpttap', dimtok)) nrpt = size(data.cumtapcnt, 1); flag = 0; else @@ -878,7 +926,7 @@ if ~isempty(strmatch('rpttap',dimtok)), nrpt=size(data.cumtapcnt, 1); else nrpt = 1; end if ~isempty(strmatch('freq', dimtok)), nfrq=length(data.freq); else nfrq = 1; end if ~isempty(strmatch('time', dimtok)), ntim=length(data.time); else ntim = 1; end - if any(data.cumtapcnt(1,:) ~= data.cumtapcnt(1,1)), error('this only works when all frequencies have the same number of tapers'); end + if any(data.cumtapcnt(1,:) ~= data.cumtapcnt(1,1)), ft_error('this only works when all frequencies have the same number of tapers'); end nchan = length(data.label); crsspctrm = zeros(nrpt,nchan,nchan,nfrq,ntim); sumtapcnt = [0;cumsum(data.cumtapcnt(:,1))]; @@ -933,10 +981,10 @@ data.dimord = 'chan_chan_freq'; end - if isfield(data, 'trialinfo'), data = rmfield(data, 'trialinfo'); end; - if isfield(data, 'sampleinfo'), data = rmfield(data, 'sampleinfo'); end; - if isfield(data, 'cumsumcnt'), data = rmfield(data, 'cumsumcnt'); end; - if isfield(data, 'cumtapcnt'), data = rmfield(data, 'cumtapcnt'); end; + if isfield(data, 'trialinfo'), data = rmfield(data, 'trialinfo'); end + if isfield(data, 'sampleinfo'), data = rmfield(data, 'sampleinfo'); end + if isfield(data, 'cumsumcnt'), data = rmfield(data, 'cumsumcnt'); end + if isfield(data, 'cumtapcnt'), data = rmfield(data, 'cumtapcnt'); end end % convert to the requested bivariate representation @@ -948,10 +996,10 @@ (strcmp(current, 'sparse') && strcmp(desired, 'fourier')) || ... (strcmp(current, 'sparsewithpow') && strcmp(desired, 'fourier')) % this is not possible - error('converting the cross-spectrum into a Fourier representation is not possible'); + ft_error('converting the cross-spectrum into a Fourier representation is not possible'); elseif strcmp(current, 'full') && strcmp(desired, 'sparsewithpow') - error('not yet implemented'); + ft_error('not yet implemented'); elseif strcmp(current, 'sparse') && strcmp(desired, 'sparsewithpow') % convert back to crsspctrm/powspctrm representation: useful for plotting functions etc @@ -996,8 +1044,8 @@ % reshape all possible fields fn = fieldnames(data); for ii=1:numel(fn) - if numel(data.(fn{ii})) == nrpt*ncmb*nfrq*ntim; - if nrpt>1, + if numel(data.(fn{ii})) == nrpt*ncmb*nfrq*ntim + if nrpt>1 data.(fn{ii}) = reshape(data.(fn{ii}), nrpt, ncmb, nfrq, ntim); else data.(fn{ii}) = reshape(data.(fn{ii}), ncmb, nfrq, ntim); @@ -1009,19 +1057,19 @@ try data = rmfield(data, 'dof'); end % replace updated fields data.labelcmb = labelcmb; - if ntim>1, + if ntim>1 data.dimord = 'chancmb_freq_time'; else data.dimord = 'chancmb_freq'; end - if nrpt>1, + if nrpt>1 data.dimord = ['rpt_',data.dimord]; end elseif strcmp(current, 'sparsewithpow') && strcmp(desired, 'sparse') % this representation for sparse data contains autospectra as e.g. {'A' 'A'} in labelcmb - if isfield(data, 'crsspctrm'), + if isfield(data, 'crsspctrm') dimtok = tokenize(data.dimord, '_'); catdim = match_str(dimtok, {'chan' 'chancmb'}); data.crsspctrm = cat(catdim, data.powspctrm, data.crsspctrm); @@ -1060,7 +1108,7 @@ for k = 1:size(data.labelcmb,1) ch1 = find(strcmp(data.label, data.labelcmb(k,1))); ch2 = find(strcmp(data.label, data.labelcmb(k,2))); - if ~isempty(ch1) && ~isempty(ch2), + if ~isempty(ch1) && ~isempty(ch2) cmbindx(ch1,ch2) = k; end end @@ -1074,8 +1122,8 @@ fn = fieldnames(data); for ii=1:numel(fn) - if numel(data.(fn{ii})) == nrpt*ncmb*nfrq*ntim; - if nrpt==1, + if numel(data.(fn{ii})) == nrpt*ncmb*nfrq*ntim + if nrpt==1 data.(fn{ii}) = reshape(data.(fn{ii}), [nrpt ncmb nfrq ntim]); end @@ -1099,7 +1147,7 @@ end % for j % replace the data in the old representation with the new representation - if nrpt>1, + if nrpt>1 data.(fn{ii}) = tmpall; else data.(fn{ii}) = reshape(tmpall, [nchan nchan nfrq ntim]); @@ -1107,13 +1155,13 @@ end % if numel end % for ii - if ntim>1, + if ntim>1 data.dimord = 'chan_chan_freq_time'; else data.dimord = 'chan_chan_freq'; end - if nrpt>1, + if nrpt>1 data.dimord = ['rpt_',data.dimord]; end @@ -1134,7 +1182,7 @@ for k = 1:size(data.labelcmb,1) ch1 = find(strcmp(data.label, data.labelcmb(k,1))); ch2 = find(strcmp(data.label, data.labelcmb(k,2))); - if ~isempty(ch1) && ~isempty(ch2), + if ~isempty(ch1) && ~isempty(ch2) cmbindx(ch1,ch2) = k; end end @@ -1143,8 +1191,8 @@ fn = fieldnames(data); for ii=1:numel(fn) - if numel(data.(fn{ii})) == nrpt*ncmb*nfrq*ntim; - if nrpt==1, + if numel(data.(fn{ii})) == nrpt*ncmb*nfrq*ntim + if nrpt==1 data.(fn{ii}) = reshape(data.(fn{ii}), [nrpt ncmb nfrq ntim]); end @@ -1166,7 +1214,7 @@ end % for k % replace the data in the old representation with the new representation - if nrpt>1, + if nrpt>1 data.(fn{ii}) = tmpall; else data.(fn{ii}) = reshape(tmpall, [nchan nchan nfrq ntim]); @@ -1179,15 +1227,14 @@ try data = rmfield(data, 'labelcmb'); end try data = rmfield(data, 'dof'); end - if ntim>1, + if ntim>1 data.dimord = 'chan_chan_freq_time'; else data.dimord = 'chan_chan_freq'; end elseif strcmp(current, 'sparsewithpow') && any(strcmp(desired, {'full', 'fullfast'})) - % recursively call ft_checkdata, but ensure channel order to be the same - % as the original input. + % recursively call ft_checkdata, but ensure channel order to be the same as the original input. origlabelorder = data.label; % keep track of the original order of the channels data = ft_checkdata(data, 'cmbrepresentation', 'sparse'); data.label = origlabelorder; % this avoids the labels to be alphabetized in the next call @@ -1196,12 +1243,79 @@ end % convert from one to another bivariate representation +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% convert between datatypes +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function [source] = chan2source(data) +chanpos = zeros(0,3); +chanlab = cell(0,1); +posunit = []; +if isfield(data, 'elec') + chanpos = cat(1, chanpos, data.elec.chanpos); + chanlab = cat(1, chanlab, data.elec.label); + if isfield(data.elec, 'unit') + posunit = data.elec.unit; + end +end +if isfield(data, 'grad') + chanpos = cat(1, chanpos, data.grad.chanpos); + chanlab = cat(1, chanlab, data.grad.label); + if isfield(data.grad, 'unit') + posunit = data.grad.unit; + end +end +if isfield(data, 'opto') + chanpos = cat(1, chanpos, data.opto.chanpos); + chanlab = cat(1, chanlab, data.opto.label); + if isfield(data.opto, 'unit') + posunit = data.opto.unit; + end +end + +fn = fieldnames(data); +fn = setdiff(fn, {'label', 'time', 'freq', 'hdr', 'cfg', 'grad', 'elec', 'dimord', 'unit'}); % remove irrelevant fields +fn(~cellfun(@isempty, regexp(fn, 'dimord$'))) = []; % remove irrelevant (dimord) fields +sel = false(size(fn)); +for i=1:numel(fn) + try + sel(i) = ismember(getdimord(data, fn{i}), {'chan', 'chan_time', 'chan_freq', 'chan_freq_time', 'chan_chan'}); + end +end +parameter = fn(sel); + +% determine the channel indices for which the position is known +[datsel, possel] = match_str(data.label, chanlab); + +source = []; +source.pos = chanpos(possel, :); +if ~isempty(posunit) + source.unit = posunit; +end +for i=1:numel(parameter) + dat = data.(parameter{i}); + dimord = getdimord(data, parameter{i}); + dimtok = tokenize(dimord, '_'); + for dim=1:numel(dimtok) + if strcmp(dimtok{dim}, 'chan') + dat = dimindex(dat, dim, {datsel}); + dimtok{dim} = 'pos'; + end + end + dimord = sprintf('%s_', dimtok{:}); + dimord = dimord(1:end-1); % remove the last '_' + % copy the data to the source representation + source.(parameter{i}) = dat; + source.([parameter{i} 'dimord']) = dimord; +end +% copy the descriptive fields, these are necessary for visualising the data in ft_sourceplot +source = copyfields(data, source, {'time', 'freq'}); + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % convert between datatypes %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function [source] = parcellated2source(data) if ~isfield(data, 'brainordinate') - error('projecting parcellated data onto the full brain model geometry requires the specification of brainordinates'); + ft_error('projecting parcellated data onto the full brain model geometry requires the specification of brainordinates'); end % the main structure contains the functional data on the parcels % the brainordinate sub-structure contains the original geometrical model @@ -1230,7 +1344,7 @@ end parcelparam = fn(sel); if numel(parcelparam)~=1 - error('cannot determine which parcellation to use'); + ft_error('cannot determine which parcellation to use'); else parcelparam = parcelparam{1}(1:(end-5)); % minus the 'label' end @@ -1239,7 +1353,7 @@ source.(parameter{i}) = unparcellate(data, source, parameter{i}, parcelparam); end -% copy over fields (these are necessary for visualising the data in ft_sourceplot) +% copy the descriptive fields, these are necessary for visualising the data in ft_sourceplot source = copyfields(data, source, {'time', 'freq'}); @@ -1271,7 +1385,7 @@ %an ordered way which allows for the extraction of a transformation matrix %i.e. slice by slice try - if isfield(data, 'dim'), + if isfield(data, 'dim') data.dim = pos2dim(data.pos, data.dim); else data.dim = pos2dim(data); @@ -1280,7 +1394,7 @@ end end -if isfield(data, 'dim') && length(data.dim)>=3, +if isfield(data, 'dim') && length(data.dim)>=3 data.transform = pos2transform(data.pos, data.dim); end @@ -1301,7 +1415,7 @@ elseif isfield(freq, 'fourierspctrm') param = 'fourierspctrm'; else - error('not supported for this data representation'); + ft_error('not supported for this data representation'); end if strcmp(freq.dimord, 'rpt_chan_freq_time') || strcmp(freq.dimord, 'rpttap_chan_freq_time') @@ -1310,7 +1424,7 @@ dat = freq.(param); dat = reshape(dat, [1 size(dat)]); % add a singleton dimension else - error('not supported for dimord %s', freq.dimord); + ft_error('not supported for dimord %s', freq.dimord); end nrpt = size(dat,1); @@ -1330,7 +1444,7 @@ for i=1:nrpt data.time{i} = freq.time; data.trial{i} = reshape(dat(i,:,:,:), nchan*nfreq, ntime); - if any(isnan(data.trial{i}(1,:))), + if any(isnan(data.trial{i}(1,:))) tmp = data.trial{i}(1,:); begsmp = find(isfinite(tmp),1, 'first'); endsmp = find(isfinite(tmp),1, 'last' ); @@ -1339,31 +1453,32 @@ end end -if isfield(freq, 'trialinfo'), data.trialinfo = freq.trialinfo; end; +if isfield(freq, 'trialinfo'), data.trialinfo = freq.trialinfo; end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % convert between datatypes %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -function [data] = raw2timelock(data) +function [tlck] = raw2timelock(data) -nsmp = cellfun('size',data.time,2); data = ft_checkdata(data, 'hassampleinfo', 'yes'); ntrial = numel(data.trial); nchan = numel(data.label); + if ntrial==1 - data.time = data.time{1}; - data.avg = data.trial{1}; - data = rmfield(data, 'trial'); - data.dimord = 'chan_time'; -else + tlck.time = data.time{1}; + tlck.avg = data.trial{1}; + tlck.label = data.label; + tlck.dimord = 'chan_time'; + tlck = copyfields(data, tlck, {'grad', 'elec', 'opto', 'cfg', 'trialinfo', 'topo', 'unmixing', 'topolabel'}); - % code below tries to construct a general time-axis where samples of all trials can fall on - % find earliest beginning and latest ending - begtime = min(cellfun(@min,data.time)); - endtime = max(cellfun(@max,data.time)); +else + % the code below tries to construct a general time-axis where samples of all trials can fall on + % find the earliest beginning and latest ending + begtime = min(cellfun(@min, data.time)); + endtime = max(cellfun(@max, data.time)); % find 'common' sampling rate - fsample = 1./mean(cellfun(@mean,cellfun(@diff,data.time,'uniformoutput',false))); + fsample = 1./mean(cellfun(@mean, cellfun(@diff,data.time, 'uniformoutput', false))); % estimate number of samples nsmp = round((endtime-begtime)*fsample) + 1; % numerical round-off issues should be dealt with by this round, as they will/should never cause an extra sample to appear % construct general time-axis @@ -1380,20 +1495,12 @@ tmptrial(i,:,begsmp(i):endsmp(i)) = data.trial{i}; end - % update the sampleinfo - begpad = begsmp - min(begsmp); - endpad = max(endsmp) - endsmp; - if isfield(data, 'sampleinfo') - data.sampleinfo = data.sampleinfo + [-begpad(:) endpad(:)]; - end - % construct the output timelocked data - % data.avg = reshape(nanmean(tmptrial, 1), nchan, length(tmptime)); - % data.var = reshape(nanvar (tmptrial, [], 1), nchan, length(tmptime)) - % data.dof = reshape(sum(~isnan(tmptrial), 1), nchan, length(tmptime)); - data.trial = tmptrial; - data.time = time; - data.dimord = 'rpt_chan_time'; + tlck.trial = tmptrial; + tlck.time = time; + tlck.dimord = 'rpt_chan_time'; + tlck.label = data.label; + tlck = copyfields(data, tlck, {'grad', 'elec', 'opto', 'cfg', 'trialinfo', 'topo', 'unmixing', 'topolabel'}); end @@ -1401,47 +1508,61 @@ % convert between datatypes %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function [data] = timelock2raw(data) -switch data.dimord - case 'chan_time' - data.trial{1} = data.avg; - data.time = {data.time}; - data = rmfield(data, 'avg'); - case 'rpt_chan_time' - tmptrial = {}; - tmptime = {}; - ntrial = size(data.trial,1); - nchan = size(data.trial,2); - ntime = size(data.trial,3); - for i=1:ntrial - tmptrial{i} = reshape(data.trial(i,:,:), [nchan, ntime]); - tmptime{i} = data.time; - end - data = rmfield(data, 'trial'); - data.trial = tmptrial; - data.time = tmptime; - case 'subj_chan_time' - tmptrial = {}; - tmptime = {}; - ntrial = size(data.individual,1); - nchan = size(data.individual,2); - ntime = size(data.individual,3); - for i=1:ntrial - tmptrial{i} = reshape(data.individual(i,:,:), [nchan, ntime]); - tmptime{i} = data.time; - end - data = rmfield(data, 'individual'); - data.trial = tmptrial; - data.time = tmptime; - otherwise - error('unsupported dimord'); +fn = getdatfield(data); +if any(ismember(fn, {'trial', 'individual', 'avg'})) + % trial, individual and avg (in that order) should be preferred over all other data fields + % see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2965#c12 + fn = fn(ismember(fn, {'trial', 'individual', 'avg'})); end -% remove the unwanted fields -if isfield(data, 'avg'), data = rmfield(data, 'avg'); end -if isfield(data, 'var'), data = rmfield(data, 'var'); end -if isfield(data, 'cov'), data = rmfield(data, 'cov'); end -if isfield(data, 'dimord'), data = rmfield(data, 'dimord'); end -if isfield(data, 'numsamples'), data = rmfield(data, 'numsamples'); end -if isfield(data, 'dof'), data = rmfield(data, 'dof'); end +dimord = cell(size(fn)); +for i=1:numel(fn) + % determine the dimensions of each of the data fields + dimord{i} = getdimord(data, fn{i}); +end +% the fields trial, individual and avg (with their corresponding default dimord) are preferred +if sum(strcmp(dimord, 'rpt_chan_time'))==1 + fn = fn{strcmp(dimord, 'rpt_chan_time')}; + ft_info('constructing trials from "%s"\n', fn); + dimsiz = getdimsiz(data, fn); + ntrial = dimsiz(1); + nchan = dimsiz(2); + ntime = dimsiz(3); + tmptrial = {}; + tmptime = {}; + for j=1:ntrial + tmptrial{j} = reshape(data.(fn)(j,:,:), [nchan, ntime]); + tmptime{j} = data.time; + end + data = rmfield(data, fn); + data.trial = tmptrial; + data.time = tmptime; +elseif sum(strcmp(dimord, 'subj_chan_time'))==1 + fn = fn{strcmp(dimord, 'subj_chan_time')}; + ft_info('constructing trials from "%s"\n', fn); + dimsiz = getdimsiz(data, fn); + nsubj = dimsiz(1); + nchan = dimsiz(2); + ntime = dimsiz(3); + tmptrial = {}; + tmptime = {}; + for j=1:nsubj + tmptrial{j} = reshape(data.(fn)(j,:,:), [nchan, ntime]); + tmptime{j} = data.time; + end + data = rmfield(data, fn); + data.trial = tmptrial; + data.time = tmptime; +elseif sum(strcmp(dimord, 'chan_time'))==1 + fn = fn{strcmp(dimord, 'chan_time')}; + ft_info('constructing single trial from "%s"\n', fn); + data.time = {data.time}; + data.trial = {data.(fn)}; + data = rmfield(data, fn); +else + ft_error('unsupported data structure'); +end +% remove unwanted fields +data = removefields(data, {'avg', 'var', 'cov', 'dimord', 'numsamples' ,'dof'}); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % convert between datatypes @@ -1463,13 +1584,13 @@ % convert between datatypes %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function [spike] = raw2spike(data) -fprintf('converting raw data into spike data\n'); +ft_info('converting raw data into spike data\n'); nTrials = length(data.trial); [spikelabel] = detectspikechan(data); spikesel = match_str(data.label, spikelabel); nUnits = length(spikesel); if nUnits==0 - error('cannot convert raw data to spike format since the raw data structure does not contain spike channels'); + ft_error('cannot convert raw data to spike format since the raw data structure does not contain spike channels'); end trialTimes = zeros(nTrials,2); @@ -1506,7 +1627,7 @@ if nargin<2 || isempty(fsample) timeDiff = abs(diff(sort([spike.time{:}]))); fsample = 1/min(timeDiff(timeDiff>0)); - warning('Desired sampling rate for spike data not specified, automatically resampled to %f', fsample); + ft_warning('Desired sampling rate for spike data not specified, automatically resampled to %f', fsample); end % get some sizes @@ -1632,4 +1753,3 @@ % before adding these times, first remove the old ones spikeTimes(multiSpikes) = []; spikeTimes = sort([spikeTimes(:); addTimes(:)]); - diff --git a/external/fieldtrip/fileio/private/ft_convert_units.m b/external/fieldtrip/fileio/private/ft_convert_units.m index e81f9502..47279027 100644 --- a/external/fieldtrip/fileio/private/ft_convert_units.m +++ b/external/fieldtrip/fileio/private/ft_convert_units.m @@ -19,7 +19,7 @@ % are specified, this function will only determine the native geometrical % units of the object. % -% See also FT_ESTIMATE_UNITS, FT_READ_VOL, FT_READ_SENS +% See also FT_DETERMINE_UNITS, FT_CONVERT_COORDSYS, FT_DETERMINE_COODSYS % Copyright (C) 2005-2016, Robert Oostenveld % @@ -46,16 +46,28 @@ % 2) determine the requested scaling factor to obtain the output units % 3) try to apply the scaling to the known geometrical elements in the input object +% ensure the correct number of input and output arguments +% narginchk(2,inf); % see below +% nargoutchk(0,1); + +% the "target" input argument has been made required in Aug 2017 +% prior to that it was also possible to use this function to estimate units +% the backward compatibility support can be removed in Aug 2018 +if nargin<2 + ft_warning('calling this function only to determine units is deprecated, please use FT_DETERMINE_COORDSYS instead'); + obj = ft_determine_units(obj); + return +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% parse input options feedback = ft_getopt(varargin, 'feedback', false); if isstruct(obj) && numel(obj)>1 % deal with a structure array for i=1:numel(obj) - if nargin>1 - tmp(i) = ft_convert_units(obj(i), target, varargin{:}); - else - tmp(i) = ft_convert_units(obj(i)); - end + tmp(i) = ft_convert_units(obj(i), target, varargin{:}); end obj = tmp; return @@ -69,119 +81,29 @@ end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% determine the unit-of-dimension of the input object +% determine the units of the input object %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -if isfield(obj, 'unit') && ~isempty(obj.unit) - % use the units specified in the object - unit = obj.unit; - -elseif isfield(obj, 'bnd') && isfield(obj.bnd, 'unit') - - unit = unique({obj.bnd.unit}); - if ~all(strcmp(unit, unit{1})) - error('inconsistent units in the individual boundaries'); - else - unit = unit{1}; - end - - % keep one representation of the units rather than keeping it with each boundary - % the units will be reassigned further down - obj.bnd = rmfield(obj.bnd, 'unit'); - -else - % try to determine the units by looking at the size of the object - if isfield(obj, 'chanpos') && ~isempty(obj.chanpos) - siz = norm(idrange(obj.chanpos)); - unit = ft_estimate_units(siz); - - elseif isfield(obj, 'elecpos') && ~isempty(obj.elecpos) - siz = norm(idrange(obj.elecpos)); - unit = ft_estimate_units(siz); - - elseif isfield(obj, 'coilpos') && ~isempty(obj.coilpos) - siz = norm(idrange(obj.coilpos)); - unit = ft_estimate_units(siz); - - elseif isfield(obj, 'pnt') && ~isempty(obj.pnt) - siz = norm(idrange(obj.pnt)); - unit = ft_estimate_units(siz); - - elseif isfield(obj, 'pos') && ~isempty(obj.pos) - siz = norm(idrange(obj.pos)); - unit = ft_estimate_units(siz); - - elseif isfield(obj, 'transform') && ~isempty(obj.transform) - % construct the corner points of the volume in voxel and in head coordinates - [pos_voxel, pos_head] = cornerpoints(obj.dim, obj.transform); - siz = norm(idrange(pos_head)); - unit = ft_estimate_units(siz); - - elseif isfield(obj, 'fid') && isfield(obj.fid, 'pnt') && ~isempty(obj.fid.pnt) - siz = norm(idrange(obj.fid.pnt)); - unit = ft_estimate_units(siz); - - elseif isfield(obj, 'fid') && isfield(obj.fid, 'pos') && ~isempty(obj.fid.pos) - siz = norm(idrange(obj.fid.pos)); - unit = ft_estimate_units(siz); - - elseif ft_voltype(obj, 'infinite') - % this is an infinite medium volume conductor, which does not care about units - unit = 'm'; - - elseif ft_voltype(obj,'singlesphere') - siz = obj.r; - unit = ft_estimate_units(siz); - - elseif ft_voltype(obj,'localspheres') - siz = median(obj.r); - unit = ft_estimate_units(siz); - - elseif ft_voltype(obj,'concentricspheres') - siz = max(obj.r); - unit = ft_estimate_units(siz); - - elseif isfield(obj, 'bnd') && isstruct(obj.bnd) && isfield(obj.bnd(1), 'pnt') && ~isempty(obj.bnd(1).pnt) - siz = norm(idrange(obj.bnd(1).pnt)); - unit = ft_estimate_units(siz); - - elseif isfield(obj, 'bnd') && isstruct(obj.bnd) && isfield(obj.bnd(1), 'pos') && ~isempty(obj.bnd(1).pos) - siz = norm(idrange(obj.bnd(1).pos)); - unit = ft_estimate_units(siz); - - elseif isfield(obj, 'nas') && isfield(obj, 'lpa') && isfield(obj, 'rpa') - pnt = [obj.nas; obj.lpa; obj.rpa]; - siz = norm(idrange(pnt)); - unit = ft_estimate_units(siz); - - else - error('cannot determine geometrical units'); - - end % recognized type of volume conduction model or sensor array -end % determine input units - -if nargin<2 || isempty(target) - % just remember the units in the output and return - obj.unit = unit; - return -elseif strcmp(unit, target) - % no conversion is needed - obj.unit = unit; - return -end +obj = ft_determine_units(obj); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % compute the scaling factor from the input units to the desired ones %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -scale = ft_scalingfactor(unit, target); + +if isequal(obj.unit, target) + % there is nothing to do + return +end if istrue(feedback) % give some information about the conversion - fprintf('converting units from ''%s'' to ''%s''\n', unit, target) + fprintf('converting units from ''%s'' to ''%s''\n', obj.unit, target) end + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % apply the scaling factor %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +scale = ft_scalingfactor(obj.unit, target); % volume conductor model if isfield(obj, 'r'), obj.r = scale * obj.r; end @@ -225,7 +147,7 @@ elseif strcmp(obj.chanunit{i}, 'unknown') % assume that it is T or V, don't do anything else - error('unexpected units %s', obj.chanunit{i}); + ft_error('unexpected units %s', obj.chanunit{i}); end end % for end % if @@ -243,12 +165,12 @@ if isfield(obj, 'zgrid') && ~ischar(obj.zgrid), obj.zgrid = scale * obj.zgrid; end % anatomical MRI or functional volume -if isfield(obj, 'transform'), +if isfield(obj, 'transform') H = diag([scale scale scale 1]); obj.transform = H * obj.transform; end -if isfield(obj, 'transformorig'), +if isfield(obj, 'transformorig') H = diag([scale scale scale 1]); obj.transformorig = H * obj.transformorig; end @@ -266,15 +188,3 @@ % remember the unit obj.unit = target; - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% IDRANGE interdecile range for more robust range estimation -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -function r = idrange(x) -keeprow=true(size(x,1),1); -for l=1:size(x,2) - keeprow = keeprow & isfinite(x(:,l)); -end -sx = sort(x(keeprow,:), 1); -ii = round(interp1([0, 1], [1, size(x(keeprow,:), 1)], [.1, .9])); % indices for 10 & 90 percentile -r = diff(sx(ii, :)); diff --git a/external/fieldtrip/fileio/private/ft_datatype.m b/external/fieldtrip/fileio/private/ft_datatype.m index 56ea128f..fbcdeacb 100644 --- a/external/fieldtrip/fileio/private/ft_datatype.m +++ b/external/fieldtrip/fileio/private/ft_datatype.m @@ -39,7 +39,7 @@ % determine the type of input data israw = isfield(data, 'label') && isfield(data, 'time') && isa(data.time, 'cell') && isfield(data, 'trial') && isa(data.trial, 'cell') && ~isfield(data,'trialtime'); -isfreq = (isfield(data, 'label') || isfield(data, 'labelcmb')) && isfield(data, 'freq') && ~isfield(data,'trialtime') && ~isfield(data,'origtrial'); %&& (isfield(data, 'powspctrm') || isfield(data, 'crsspctrm') || isfield(data, 'cohspctrm') || isfield(data, 'fourierspctrm') || isfield(data, 'powcovspctrm')); +isfreq = ((isfield(data, 'label') && ~isfield(data, 'pos')) || isfield(data, 'labelcmb')) && isfield(data, 'freq') && ~isfield(data,'trialtime') && ~isfield(data,'origtrial'); %&& (isfield(data, 'powspctrm') || isfield(data, 'crsspctrm') || isfield(data, 'cohspctrm') || isfield(data, 'fourierspctrm') || isfield(data, 'powcovspctrm')); istimelock = isfield(data, 'label') && isfield(data, 'time') && ~isfield(data, 'freq') && ~isfield(data,'timestamp') && ~isfield(data,'trialtime') && ~(isfield(data, 'trial') && iscell(data.trial)) && ~isfield(data, 'pos'); %&& ((isfield(data, 'avg') && isnumeric(data.avg)) || (isfield(data, 'trial') && isnumeric(data.trial) || (isfield(data, 'cov') && isnumeric(data.cov)))); iscomp = isfield(data, 'label') && isfield(data, 'topo') || isfield(data, 'topolabel'); isvolume = isfield(data, 'transform') && isfield(data, 'dim') && ~isfield(data, 'pos'); @@ -51,8 +51,9 @@ ischan = check_chan(data); issegmentation = check_segmentation(data); isparcellation = check_parcellation(data); -ismontage = isfield(data, 'labelorg') && isfield(data, 'labelnew') && isfield(data, 'tra'); +ismontage = isfield(data, 'labelold') && isfield(data, 'labelnew') && isfield(data, 'tra'); isevent = isfield(data, 'type') && isfield(data, 'value') && isfield(data, 'sample') && isfield(data, 'offset') && isfield(data, 'duration'); +islayout = all(isfield(data, {'label', 'pos', 'width', 'height'})); % mask and outline are optional isheadmodel = false; % FIXME this is not yet implemented if issource && isstruct(data) && numel(data)>1 @@ -74,6 +75,7 @@ % check if it is a sensor array isgrad = isfield(data, 'label') && isfield(data, 'coilpos') && isfield(data, 'coilori'); iselec = isfield(data, 'label') && isfield(data, 'elecpos'); +isopto = isfield(data, 'label') && isfield(data, 'optopos'); if isspike type = 'spike'; @@ -82,7 +84,7 @@ elseif istimelock && iscomp type = 'timelock+comp'; elseif isfreq && iscomp - type = 'freq+comp'; + type = 'freq+comp'; elseif israw type = 'raw'; elseif iscomp @@ -105,23 +107,29 @@ type = 'volume'; elseif ismesh && isparcellation type = 'mesh+label'; -elseif ismesh - type = 'mesh'; elseif issource && isparcellation type = 'source+label'; +elseif issource && ismesh + type = 'source+mesh'; +elseif ismesh + type = 'mesh'; elseif issource type = 'source'; elseif ischan % this results from avgovertime/avgoverfreq after timelockstatistics or freqstatistics type = 'chan'; -elseif iselec - type = 'elec'; elseif isgrad type = 'grad'; +elseif iselec + type = 'elec'; +elseif isopto + type = 'opto'; elseif ismontage type = 'montage'; elseif isevent type = 'event'; +elseif islayout + type = 'layout'; else type = 'unknown'; end @@ -140,16 +148,16 @@ case 'volume' type = any(strcmp(type, {'volume', 'volume+label'})); case 'source' - type = any(strcmp(type, {'source', 'source+label', 'mesh', 'mesh+label'})); % a single mesh qualifies as source structure + type = any(strcmp(type, {'source', 'source+label', 'mesh', 'mesh+label', 'source+mesh'})); % a single mesh does qualify as source structure type = type && isstruct(data) && numel(data)==1; % an array of meshes does not qualify case 'mesh' - type = any(strcmp(type, {'mesh', 'mesh+label'})); + type = any(strcmp(type, {'mesh', 'mesh+label', 'source+mesh'})); case 'segmentation' - type = strcmp(type, 'volume+label'); + type = any(strcmp(type, {'segmentation', 'volume+label'})); case 'parcellation' - type = any(strcmp(type, {'source+label' 'mesh+label'})); + type = any(strcmp(type, {'parcellation', 'source+label' 'mesh+label'})); case 'sens' - type = any(strcmp(type, {'elec', 'grad'})); + type = any(strcmp(type, {'grad', 'elec', 'opto'})); otherwise type = strcmp(type, desired); end % switch diff --git a/external/fieldtrip/fileio/private/ft_datatype_comp.m b/external/fieldtrip/fileio/private/ft_datatype_comp.m index 164733a5..15466a69 100644 --- a/external/fieldtrip/fileio/private/ft_datatype_comp.m +++ b/external/fieldtrip/fileio/private/ft_datatype_comp.m @@ -11,12 +11,12 @@ % An example of a decomposed raw data structure with 100 components that resulted from % a 151-channel MEG recording is shown here: % -% unmixing: [100x151 double] the compoment unmixing matrix % topo: [151x100 double] the compoment topographies +% unmixing: [100x151 double] the compoment unmixing matrix % topolabel: {151x1 cell} the channel labels (e.g. 'MRC13') -% time: {1x10 cell} the timeaxis [1*Ntime double] per trial -% trial: {1x10 cell} the numeric data [151*Ntime double] per trial % label: {100x1 cell} the component labels (e.g. 'runica001') +% time: {1x10 cell} the time axis [1*Ntime double] per trial +% trial: {1x10 cell} the numeric data [151*Ntime double] per trial % grad: [1x1 struct] information about the sensor array (for EEG it is called elec) % cfg: [1x1 struct] the configuration used by the function that generated this data structure % @@ -33,7 +33,7 @@ % - cfg, all fields from FT_DATATYPE_RAW, FT_DATATYPE_TIMELOCK or FT_DATATYPE_FREQ % % Historical fields: -% - cfg, offset, fsample, grad, elec, label, sampleinfo, time, topo, topolabel, trial, unmixing, see bug2513 +% - offset, fsample % % Revision history: % (2014) The combination of comp with raw, timelock or freq has been defined explicitly. @@ -96,47 +96,37 @@ end end + if isfield(comp, 'unmixing') && ~isfield(comp, 'unmixingdimord') + comp.unmixingdimord = 'chan_topochan'; + end + + if isfield(comp, 'topo') && ~isfield(comp, 'topodimord') + comp.topodimord = 'topochan_chan'; + end + % convert it into a raw data structure and update it to the latest version if ft_datatype(comp, 'raw') - raw = comp; - raw = rmfield(raw, 'topo'); - raw = rmfield(raw, 'unmixing'); - raw = rmfield(raw, 'topolabel'); + raw = removefields(comp, {'topo', 'topodimord', 'unmixing', 'unmixingdimord', 'topolabel'}); raw = ft_datatype_raw(raw, 'version', rawversion, 'hassampleinfo', hassampleinfo, 'hastrialinfo', hastrialinfo); % add the component specific fields again - raw.unmixing = comp.unmixing; - raw.topo = comp.topo; - raw.topolabel = comp.topolabel; - comp = raw; + comp = copyfields(comp, raw, {'topo', 'topodimord', 'unmixing', 'unmixingdimord', 'topolabel'}); clear raw elseif ft_datatype(comp, 'timelock') - timelock = comp; - timelock = rmfield(timelock, 'topo'); - timelock = rmfield(timelock, 'unmixing'); - timelock = rmfield(timelock, 'topolabel'); + timelock = removefields(comp, {'topo', 'topodimord', 'unmixing', 'unmixingdimord', 'topolabel'}); timelock = ft_datatype_timelock(timelock, 'version', timelockversion); % add the component specific fields again - timelock.unmixing = comp.unmixing; - timelock.topo = comp.topo; - timelock.topolabel = comp.topolabel; - comp = timelock; + comp = copyfields(comp, timelock, {'topo', 'topodimord', 'unmixing', 'unmixingdimord', 'topolabel'}); clear timelock elseif ft_datatype(comp, 'freq') - freq = comp; - freq = rmfield(freq, 'topo'); - freq = rmfield(freq, 'unmixing'); - freq = rmfield(freq, 'topolabel'); + freq = removefields(comp, {'topo', 'topodimord', 'unmixing', 'unmixingdimord', 'topolabel'}); freq = ft_datatype_freq(freq, 'version', freqversion); % add the component specific fields again - freq.unmixing = comp.unmixing; - freq.topo = comp.topo; - freq.topolabel = comp.topolabel; - comp = freq; + comp = copyfields(comp, freq, {'topo', 'topodimord', 'unmixing', 'unmixingdimord', 'topolabel'}); clear freq end % raw, timelock or freq @@ -167,7 +157,7 @@ otherwise %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - error('unsupported version "%s" for comp datatype', version); + ft_error('unsupported version "%s" for comp datatype', version); end diff --git a/external/fieldtrip/fileio/private/ft_datatype_freq.m b/external/fieldtrip/fileio/private/ft_datatype_freq.m index 1ac38670..77321874 100644 --- a/external/fieldtrip/fileio/private/ft_datatype_freq.m +++ b/external/fieldtrip/fileio/private/ft_datatype_freq.m @@ -107,7 +107,7 @@ freq.time = freq.time'; end if ~isfield(freq, 'label') && ~isfield(freq, 'labelcmb') - warning('data structure is incorrect since it has no channel labels'); + ft_warning('data structure is incorrect since it has no channel labels'); end switch version @@ -128,12 +128,22 @@ freq.freq = freq.foi; freq = rmfield(freq, 'foi'); end - + if isfield(freq, 'toi') && ~isfield(freq, 'time') % this was still the case in early 2006 freq.time = freq.toi; freq = rmfield(freq, 'toi'); end + + if isfield(freq, 'cumtapcnt') && isvector(freq.cumtapcnt) + % ensure that it is a column vector + freq.cumtapcnt = freq.cumtapcnt(:); + end + + if isfield(freq, 'cumsumcnt') && isvector(freq.cumsumcnt) + % ensure that it is a column vector + freq.cumsumcnt = freq.cumsumcnt(:); + end case '2008' % there are no known conversions for backward or forward compatibility support @@ -149,5 +159,5 @@ otherwise %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - error('unsupported version "%s" for freq datatype', version); + ft_error('unsupported version "%s" for freq datatype', version); end diff --git a/external/fieldtrip/fileio/private/ft_datatype_headmodel.m b/external/fieldtrip/fileio/private/ft_datatype_headmodel.m index 8fe3ac83..4d332ed6 100644 --- a/external/fieldtrip/fileio/private/ft_datatype_headmodel.m +++ b/external/fieldtrip/fileio/private/ft_datatype_headmodel.m @@ -132,7 +132,7 @@ elseif isfield(headmodel, 'cond') && isfield(headmodel, 'c') && isequal(headmodel.cond, headmodel.c) headmodel = rmfield(headmodel, 'c'); elseif isfield(headmodel, 'cond') && isfield(headmodel, 'c') && ~isequal(headmodel.cond, headmodel.c) - error('inconsistent specification of conductive properties for %s model', headmodel.type); + ft_error('inconsistent specification of conductive properties for %s model', headmodel.type); end case '2012' @@ -165,9 +165,9 @@ elseif strcmp(headmodel.type, 'fdm_fns') headmodel.type = 'fns'; elseif strcmp(headmodel.type, 'bem') - error('not able to convert the original ''bem'' volume type, try using headmodel.type=''dipoli'''); + ft_error('not able to convert the original ''bem'' volume type, try using headmodel.type=''dipoli'''); elseif strcmp(headmodel.type, 'avo') - error('this format is not supported anymore'); + ft_error('this format is not supported anymore'); end end @@ -183,15 +183,13 @@ elseif isfield(headmodel, 'cond') && isfield(headmodel, 'c') && isequal(headmodel.cond, headmodel.c) headmodel = rmfield(headmodel, 'cond'); elseif isfield(headmodel, 'cond') && isfield(headmodel, 'c') && ~isequal(headmodel.cond, headmodel.c) - error('inconsistent specification of conductive properties for %s model', headmodel.type); + ft_error('inconsistent specification of conductive properties for %s model', headmodel.type); end end % ensure that the geometrical units are specified - if ~isfield(headmodel, 'unit') - headmodel = ft_convert_units(headmodel); - end + headmodel = ft_determine_units(headmodel); otherwise - error('converting to version "%s" is not supported', version); + ft_error('converting to version "%s" is not supported', version); end diff --git a/external/fieldtrip/fileio/private/ft_datatype_mvar.m b/external/fieldtrip/fileio/private/ft_datatype_mvar.m index 33b002d5..3ddef362 100644 --- a/external/fieldtrip/fileio/private/ft_datatype_mvar.m +++ b/external/fieldtrip/fileio/private/ft_datatype_mvar.m @@ -102,5 +102,5 @@ otherwise %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - error('unsupported version "%s" for mvar datatype', version); + ft_error('unsupported version "%s" for mvar datatype', version); end diff --git a/external/fieldtrip/fileio/private/ft_datatype_raw.m b/external/fieldtrip/fileio/private/ft_datatype_raw.m index b32d60ac..98940c87 100644 --- a/external/fieldtrip/fileio/private/ft_datatype_raw.m +++ b/external/fieldtrip/fileio/private/ft_datatype_raw.m @@ -98,12 +98,12 @@ hassampleinfo = 'yes'; % if it's already there, consider keeping it numsmp = data.sampleinfo(:,2)-data.sampleinfo(:,1)+1; for i=1:length(data.trial) - if size(data.trial{i},2)~=numsmp(i); + if size(data.trial{i},2)~=numsmp(i) % it does not make sense, so don't keep it hassampleinfo = 'no'; % the actual removal will be done further down - warning('removing inconsistent sampleinfo'); - break; + ft_warning('removing inconsistent sampleinfo'); + break end end end @@ -116,7 +116,7 @@ if size(data.trialinfo,1)~=numel(data.trial) % it does not make sense, so don't keep it hastrialinfo = 'no'; - warning('removing inconsistent trialinfo'); + ft_warning('removing inconsistent trialinfo'); end end end @@ -156,7 +156,7 @@ end end if isnan(data.fsample) - warning('cannot determine sampling frequency'); + ft_warning('cannot determine sampling frequency'); end end @@ -252,13 +252,13 @@ otherwise %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - error('unsupported version "%s" for raw datatype', version); + ft_error('unsupported version "%s" for raw datatype', version); end % Numerical inaccuracies in the binary representations of floating point % values may accumulate. The following code corrects for small inaccuracies -% in the time axes of the trials. See http://bugzilla.fcdonders.nl/show_bug.cgi?id=1390 +% in the time axes of the trials. See http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=1390 data = fixtimeaxes(data); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/external/fieldtrip/fileio/private/ft_datatype_sens.m b/external/fieldtrip/fileio/private/ft_datatype_sens.m index 27597439..a3c1d2ec 100644 --- a/external/fieldtrip/fileio/private/ft_datatype_sens.m +++ b/external/fieldtrip/fileio/private/ft_datatype_sens.m @@ -129,11 +129,11 @@ scaling = ft_getopt(varargin, 'scaling'); % should be 'amplitude' or 'amplitude/distance', the default depends on the senstype if ~isempty(amplitude) && ~any(strcmp(amplitude, {'V' 'uV' 'T' 'mT' 'uT' 'nT' 'pT' 'fT'})) - error('unsupported unit of amplitude "%s"', amplitude); + ft_error('unsupported unit of amplitude "%s"', amplitude); end if ~isempty(distance) && ~any(strcmp(distance, {'m' 'dm' 'cm' 'mm'})) - error('unsupported unit of distance "%s"', distance); + ft_error('unsupported unit of distance "%s"', distance); end if strcmp(version, 'latest') @@ -157,31 +157,12 @@ % update it to the previous standard version sens = ft_datatype_sens(sens, 'version', '2011v2'); + % rename from org to old (reverse = false) + sens = fixoldorg(sens, false); + % ensure that all numbers are represented in double precision sens = ft_struct2double(sens); - % use "old/new" rather than "org/new" - if isfield(sens, 'labelorg') - sens.labelold = sens.labelorg; - sens = rmfield(sens, 'labelorg'); - end - if isfield(sens, 'chantypeorg') - sens.chantypeold = sens.chantypeorg; - sens = rmfield(sens, 'chantypeorg'); - end - if isfield(sens, 'chanuniteorg') - sens.chanunitold = sens.chanunitorg; - sens = rmfield(sens, 'chanunitorg'); - end - if isfield(sens, 'chanposorg') - sens.chanposold = sens.chanposorg; - sens = rmfield(sens, 'chanposorg'); - end - if isfield(sens, 'chanoriorg') - sens.chanoriold = sens.chanoriorg; - sens = rmfield(sens, 'chanoriorg'); - end - % in version 2011v2 this was optional, now it is required if ~isfield(sens, 'chantype') || all(strcmp(sens.chantype, 'unknown')) sens.chantype = ft_chantype(sens); @@ -213,7 +194,7 @@ sens.tra(i,:) = sens.tra(i,:) * ft_scalingfactor(sens.chanunit{i}, amplitude); sens.chanunit{i} = amplitude; else - error('unexpected channel unit "%s" in channel %d', sens.chanunit{i}, i); + ft_error('unexpected channel unit "%s" in channel %d', sens.chanunit{i}, i); end end else @@ -244,13 +225,13 @@ sel_mm = ~cellfun(@isempty, regexp(sens.chanunit, '/mm$')); if strcmp(sens.unit, 'm') && (any(sel_dm) || any(sel_cm) || any(sel_mm)) - error('inconsistent units in input gradiometer'); + ft_error('inconsistent units in input gradiometer'); elseif strcmp(sens.unit, 'dm') && (any(sel_m) || any(sel_cm) || any(sel_mm)) - error('inconsistent units in input gradiometer'); + ft_error('inconsistent units in input gradiometer'); elseif strcmp(sens.unit, 'cm') && (any(sel_m) || any(sel_dm) || any(sel_mm)) - error('inconsistent units in input gradiometer'); + ft_error('inconsistent units in input gradiometer'); elseif strcmp(sens.unit, 'mm') && (any(sel_m) || any(sel_dm) || any(sel_cm)) - error('inconsistent units in input gradiometer'); + ft_error('inconsistent units in input gradiometer'); end % the default should be amplitude/distance for neuromag and amplitude for all others @@ -258,7 +239,7 @@ if ft_senstype(sens, 'neuromag') scaling = 'amplitude/distance'; elseif ft_senstype(sens, 'yokogawa440') - warning('asuming that the default scaling should be amplitude rather than amplitude/distance'); + ft_warning('asuming that the default scaling should be amplitude rather than amplitude/distance'); scaling = 'amplitude'; else scaling = 'amplitude'; @@ -272,7 +253,7 @@ % this channel is expressed as amplitude per distance coil = find(abs(sens.tra(i,:))~=0); if length(coil)~=2 - error('unexpected number of coils contributing to channel %d', i); + ft_error('unexpected number of coils contributing to channel %d', i); end baseline = norm(sens.coilpos(coil(1),:) - sens.coilpos(coil(2),:)); sens.tra(i,:) = sens.tra(i,:)*baseline; % scale with the baseline distance @@ -281,7 +262,7 @@ % no conversion needed else % see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=3144 - ft_warning(sprintf('unexpected channel unit "%s" in channel %d', sens.chanunit{i}, i)); + ft_warning('unexpected channel unit "%s" in channel %d', sens.chanunit{i}, i); end % if end % for @@ -294,7 +275,7 @@ % this is a magnetometer channel, no conversion needed continue elseif length(coil)~=2 - error('unexpected number of coils (%d) contributing to channel %s (%d)', length(coil), sens.label{i}, i); + ft_error('unexpected number of coils (%d) contributing to channel %s (%d)', length(coil), sens.label{i}, i); end baseline = norm(sens.coilpos(coil(1),:) - sens.coilpos(coil(2),:)); sens.tra(i,:) = sens.tra(i,:)/baseline; % scale with the baseline distance @@ -303,7 +284,7 @@ % no conversion needed else % see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=3144 - ft_warning(sprintf('unexpected channel unit "%s" in channel %d', sens.chanunit{i}, i)); + ft_warning('unexpected channel unit "%s" in channel %d', sens.chanunit{i}, i); end % if end % for @@ -315,16 +296,19 @@ sel_cm = ~cellfun(@isempty, regexp(sens.chanunit, '/cm$')); sel_mm = ~cellfun(@isempty, regexp(sens.chanunit, '/mm$')); if any(sel_m | sel_dm | sel_cm | sel_mm) - error('scaling of amplitude/distance has not been considered yet for EEG'); + ft_error('scaling of amplitude/distance has not been considered yet for EEG'); end end % if iseeg or ismeg %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% case '2011v2' - + + % rename from old to org (reverse = true) + sens = fixoldorg(sens, true); + if ~isempty(amplitude) || ~isempty(distance) || ~isempty(scaling) - warning('amplitude, distance and scaling are not supported for version "%s"', version); + ft_warning('amplitude, distance and scaling are not supported for version "%s"', version); end % This speeds up subsequent calls to ft_senstype and channelposition. @@ -357,7 +341,7 @@ sens.chanpos(selsens,:) = chanpos(selpos,:); sens.chanori(selsens,:) = chanori(selpos,:); if length(selsens)~=length(sens.label) - warning('cannot determine the position and orientation for all channels'); + ft_warning('cannot determine the position and orientation for all channels'); end else % sensor description is something else, EEG/ECoG etc @@ -369,7 +353,7 @@ % insert the determined position/orientation on the appropriate rows sens.chanpos(selsens,:) = chanpos(selpos,:); if length(selsens)~=length(sens.label) - warning('cannot determine the position and orientation for all channels'); + ft_warning('cannot determine the position and orientation for all channels'); end end end @@ -384,7 +368,7 @@ if ~isfield(sens, 'unit') % this should be done prior to calling ft_chanunit, since ft_chanunit uses this for planar neuromag channels - sens = ft_convert_units(sens); + sens = ft_determine_units(sens); end if ~isfield(sens, 'chanunit') || all(strcmp(sens.chanunit, 'unknown')) @@ -397,7 +381,7 @@ if any(strcmp(sens.type, {'meg', 'eeg', 'magnetometer', 'electrode', 'unknown'})) % this is not sufficiently informative, so better remove it - % see also http://bugzilla.fcdonders.nl/show_bug.cgi?id=1806 + % see also http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=1806 sens = rmfield(sens, 'type'); end @@ -408,7 +392,7 @@ isfield(sens, 'tra') && isfield(sens, 'coilori') && size(sens.tra,2)~=size(sens.coilori,1) || ... isfield(sens, 'chanpos') && size(sens.chanpos,1)~=length(sens.label) || ... isfield(sens, 'chanori') && size(sens.chanori,1)~=length(sens.label) - error('inconsistent number of channels in sensor description'); + ft_error('inconsistent number of channels in sensor description'); end if ismeg @@ -465,7 +449,7 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% otherwise - error('converting to version %s is not supported', version); + ft_error('converting to version %s is not supported', version); end % switch diff --git a/external/fieldtrip/fileio/private/ft_datatype_source.m b/external/fieldtrip/fileio/private/ft_datatype_source.m index bc6f4c31..f1ac33ba 100644 --- a/external/fieldtrip/fileio/private/ft_datatype_source.m +++ b/external/fieldtrip/fileio/private/ft_datatype_source.m @@ -244,7 +244,7 @@ try source.(fn{i}) = reshape(source.(fn{i}), [prod(dimsiz(1:3)) dimsiz(4:end) 1]); catch - warning('could not reshape %s to the expected dimensions', fn{i}); + ft_warning('could not reshape %s to the expected dimensions', fn{i}); end end end @@ -332,7 +332,7 @@ otherwise %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - error('unsupported version "%s" for source datatype', version); + ft_error('unsupported version "%s" for source datatype', version); end function pos = grid2pos(xgrid, ygrid, zgrid) diff --git a/external/fieldtrip/fileio/private/ft_datatype_spike.m b/external/fieldtrip/fileio/private/ft_datatype_spike.m index eae78c48..2830560d 100644 --- a/external/fieldtrip/fileio/private/ft_datatype_spike.m +++ b/external/fieldtrip/fileio/private/ft_datatype_spike.m @@ -158,7 +158,7 @@ if isfield(spike,'origtrial') && isfield(spike,'origtime') % this was the old spiketriggered spectrum output - warning('The spike datatype format you are using is depreciated. Converting to newer spike format'); + ft_warning('The spike datatype format you are using is depreciated. Converting to newer spike format'); spike.trial = {spike.origtrial}; spike = rmfield(spike,'origtrial'); spike.time = {spike.origtime}; @@ -168,7 +168,7 @@ end if ~isfield(spike, 'trialtime') % determine from the data itself - warning('Reconstructing the field trialtime from spike.origtime and spike.origtrial. This is not the original representation'); + ft_warning('Reconstructing the field trialtime from spike.origtime and spike.origtrial. This is not the original representation'); tmax = nanmax(spike.trial{1}); tsmin = nanmin(spike.time{1}); tsmax = nanmax(spike.time{1}); @@ -181,7 +181,7 @@ try spike.label = spike.spikechannel; catch - {'unit1'}; %default + spike.label = {'unit1'}; %default end end spike.dimord = '{chan}_spike_lfpchan_freq'; @@ -206,7 +206,7 @@ nSpikes = length(spike.timestamp{iUnit}); % check what's the spike dimension from the timestamps spikedim = dim==nSpikes; if isempty(spikedim) - error('waveforms contains data but number of waveforms does not match number of spikes'); + ft_error('waveforms contains data but number of waveforms does not match number of spikes'); end if spikedim==1 spike.waveform{iUnit} = permute(spike.waveform{iUnit},[3 2 1]); @@ -221,10 +221,10 @@ leaddim = dim<6 & dim~=nSpikes; sampdim = dim>=6 & dim~=nSpikes; if isempty(spikedim) - error('waveforms contains data but number of waveforms does not match number of spikes'); + ft_error('waveforms contains data but number of waveforms does not match number of spikes'); end - if sum(leaddim)~=1 | sum(sampdim)~=1, continue,end % in this case we do not know what to do - if find(spikedim)~=3 & find(leaddim)~=1 & find(sampdim)~=2 + if sum(leaddim)~=1 || sum(sampdim)~=1, continue,end % in this case we do not know what to do + if find(spikedim)~=3 && find(leaddim)~=1 && find(sampdim)~=2 spike.waveform{iUnit} = permute(spike.waveform{iUnit}, [find(leaddim) find(sampdim) find(spikedim)]); end end @@ -270,7 +270,7 @@ otherwise %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - error('unsupported version "%s" for spike datatype', version); + ft_error('unsupported version "%s" for spike datatype', version); end diff --git a/external/fieldtrip/fileio/private/ft_datatype_timelock.m b/external/fieldtrip/fileio/private/ft_datatype_timelock.m index 0c443b19..a9a507e7 100644 --- a/external/fieldtrip/fileio/private/ft_datatype_timelock.m +++ b/external/fieldtrip/fileio/private/ft_datatype_timelock.m @@ -36,7 +36,10 @@ % % Revision history: % -% (2011v2/latest) The description of the sensors has changed, see FT_DATATYPE_SENS +% (2017/latest) The data structure cannot contain an average and simultaneously single +% trial information any more, i.e. avg/var/dof and trial/individual are mutually exclusive. +% +% (2011v2) The description of the sensors has changed, see FT_DATATYPE_SENS % for further information. % % (2011) The field 'fsample' was removed, as it was redundant. @@ -69,7 +72,7 @@ version = ft_getopt(varargin, 'version', 'latest'); if strcmp(version, 'latest') - version = '2011v2'; + version = '2017'; end if isempty(timelock) @@ -91,27 +94,55 @@ timelock.time = timelock.time'; end if ~isfield(timelock, 'label') - warning('data structure is incorrect since it has no channel labels'); + ft_warning('data structure is incorrect since it has no channel labels'); end switch version + case '2017' + timelock = ft_datatype_timelock(timelock, 'version', '2011v2'); + fn = fieldnames(timelock); + fn = setdiff(fn, ignorefields('appendtimelock')); + dimord = cell(size(fn)); + hasrpt = false(size(fn)); + for i=1:numel(fn) + dimord{i} = getdimord(timelock, fn{i}); + hasrpt(i) = ~isempty(strfind(dimord{i}, 'rpt')) || ~isempty(strfind(dimord{i}, 'subj')); + end + if any(hasrpt) && ~all(hasrpt) + ft_warning('timelock structure contains field with and without repetitions'); + str = sprintf('%s, ', fn{hasrpt}); + str = str(1:end-2); + ft_notice('selecting these fields that have repetitions: %s', str); + str = sprintf('%s, ', fn{~hasrpt}); + str = str(1:end-2); + ft_notice('removing these fields that do not have repetitions: %s', str); + timelock = removefields(timelock, fn(~hasrpt)); + if isfield(timelock, 'dimord') && ~ismember(timelock.dimord, dimord(hasrpt)) + % the dimord does not apply to any of the existing fields any more + timelock = rmfield(timelock, 'dimord'); + end + end + case '2011v2' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% if isfield(timelock, 'grad') % ensure that the gradiometer structure is up to date timelock.grad = ft_datatype_sens(timelock.grad); end - + if isfield(timelock, 'elec') % ensure that the electrode structure is up to date timelock.elec = ft_datatype_sens(timelock.elec); end - + + % these fields can be present in raw data, but not desired in timelock data + timelock = removefields(timelock, {'sampleinfo', 'fsample'}); + case '2003' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % there are no known conversions for backward or forward compatibility support - + otherwise %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - error('unsupported version "%s" for timelock datatype', version); + ft_error('unsupported version "%s" for timelock datatype', version); end diff --git a/external/fieldtrip/fileio/private/ft_datatype_vol.m b/external/fieldtrip/fileio/private/ft_datatype_vol.m index ad3a0742..406e67f0 100644 --- a/external/fieldtrip/fileio/private/ft_datatype_vol.m +++ b/external/fieldtrip/fileio/private/ft_datatype_vol.m @@ -97,6 +97,6 @@ otherwise %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - error('unsupported version "%s" for freq datatype', version); + ft_error('unsupported version "%s" for freq datatype', version); end diff --git a/external/fieldtrip/fileio/private/ft_determine_units.m b/external/fieldtrip/fileio/private/ft_determine_units.m new file mode 100644 index 00000000..8c5864a3 --- /dev/null +++ b/external/fieldtrip/fileio/private/ft_determine_units.m @@ -0,0 +1,171 @@ +function [obj] = ft_determine_units(obj) + +% FT_DETERMINE_UNITS tries to determine the units of a geometrical object by +% looking at its size and by relating this to the approximate size of the +% human head according to the following table: +% from 0.050 to 0.500 -> meter +% from 0.500 to 5.000 -> decimeter +% from 5.000 to 50.000 -> centimeter +% from 50.000 to 500.000 -> millimeter +% +% Use as +% dataout = ft_determine_units(datain) +% where the input obj structure can be +% - an anatomical MRI +% - an electrode or gradiometer definition +% - a volume conduction model of the head +% or most other FieldTrip structures that represent geometrical information. +% +% See also FT_CONVERT_UNITS, FT_DETERMINE_COODSYS, FT_CONVERT_COORDSYS + +% Copyright (C) 2005-2017, Robert Oostenveld +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +% ensure the correct number of input and output arguments +% narginchk(1,1); +% nargoutchk(0,1); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +if isstruct(obj) && numel(obj)>1 + % deal with a structure array + for i=1:numel(obj) + tmp(i) = ft_determine_units(obj(i)); + end + obj = tmp; + return +elseif iscell(obj) && numel(obj)>1 + % deal with a cell array + % this might represent combined EEG, ECoG and/or MEG + for i=1:numel(obj) + obj{i} = ft_determine_units(obj{i}); + end + return +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +if isfield(obj, 'unit') && ~isempty(obj.unit) + % use the units specified in the object + unit = obj.unit; + +elseif isfield(obj, 'bnd') && isfield(obj.bnd, 'unit') + + unit = unique({obj.bnd.unit}); + if ~all(strcmp(unit, unit{1})) + ft_error('inconsistent units in the individual boundaries'); + else + unit = unit{1}; + end + + % keep one representation of the units rather than keeping it with each boundary + % the units will be reassigned further down + obj.bnd = rmfield(obj.bnd, 'unit'); + +else + % try to determine the units by looking at the size of the object + if isfield(obj, 'chanpos') && ~isempty(obj.chanpos) + siz = norm(idrange(obj.chanpos)); + unit = ft_estimate_units(siz); + + elseif isfield(obj, 'elecpos') && ~isempty(obj.elecpos) + siz = norm(idrange(obj.elecpos)); + unit = ft_estimate_units(siz); + + elseif isfield(obj, 'coilpos') && ~isempty(obj.coilpos) + siz = norm(idrange(obj.coilpos)); + unit = ft_estimate_units(siz); + + elseif isfield(obj, 'pnt') && ~isempty(cat(1, obj.pnt)) + % the obj can be a struct.array, hence the concatenation + siz = norm(idrange(cat(1, obj.pnt))); + unit = ft_estimate_units(siz); + + elseif isfield(obj, 'pos') && ~isempty(cat(1, obj.pos)) + % the obj can be a struct.array, hence the concatenation + siz = norm(idrange(cat(1, obj.pos))); + unit = ft_estimate_units(siz); + + elseif isfield(obj, 'transform') && ~isempty(obj.transform) + % construct the corner points of the volume in voxel and in head coordinates + [pos_voxel, pos_head] = cornerpoints(obj.dim, obj.transform); + siz = norm(idrange(pos_head)); + unit = ft_estimate_units(siz); + + elseif isfield(obj, 'fid') && isfield(obj.fid, 'pnt') && ~isempty(obj.fid.pnt) + siz = norm(idrange(obj.fid.pnt)); + unit = ft_estimate_units(siz); + + elseif isfield(obj, 'fid') && isfield(obj.fid, 'pos') && ~isempty(obj.fid.pos) + siz = norm(idrange(obj.fid.pos)); + unit = ft_estimate_units(siz); + + elseif ft_voltype(obj, 'infinite') + % this is an infinite medium volume conductor, which does not care about units + unit = 'm'; + + elseif ft_voltype(obj,'singlesphere') + siz = obj.r; + unit = ft_estimate_units(siz); + + elseif ft_voltype(obj,'localspheres') + siz = median(obj.r); + unit = ft_estimate_units(siz); + + elseif ft_voltype(obj,'concentricspheres') + siz = max(obj.r); + unit = ft_estimate_units(siz); + + elseif isfield(obj, 'bnd') && isstruct(obj.bnd) && isfield(obj.bnd(1), 'pnt') && ~isempty(obj.bnd(1).pnt) + siz = norm(idrange(obj.bnd(1).pnt)); + unit = ft_estimate_units(siz); + + elseif isfield(obj, 'bnd') && isstruct(obj.bnd) && isfield(obj.bnd(1), 'pos') && ~isempty(obj.bnd(1).pos) + siz = norm(idrange(obj.bnd(1).pos)); + unit = ft_estimate_units(siz); + + elseif isfield(obj, 'nas') && isfield(obj, 'lpa') && isfield(obj, 'rpa') + pnt = [obj.nas; obj.lpa; obj.rpa]; + siz = norm(idrange(pnt)); + unit = ft_estimate_units(siz); + + else + ft_error('cannot determine geometrical units'); + + end % recognized type of volume conduction model or sensor array +end % determine input units + +% add the units to the output object +for i=1:numel(obj) + % obj can be a struct-array, hence the loop + obj(i).unit = unit; +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% IDRANGE interdecile range for more robust range estimation +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function r = idrange(x) +keeprow=true(size(x,1),1); +for l=1:size(x,2) + keeprow = keeprow & isfinite(x(:,l)); +end +sx = sort(x(keeprow,:), 1); +ii = round(interp1([0, 1], [1, size(x(keeprow,:), 1)], [.1, .9])); % indices for 10 & 90 percentile +r = diff(sx(ii, :)); diff --git a/external/fieldtrip/fileio/private/ft_estimate_units.m b/external/fieldtrip/fileio/private/ft_estimate_units.m index ce0b457f..d44dc8ae 100644 --- a/external/fieldtrip/fileio/private/ft_estimate_units.m +++ b/external/fieldtrip/fileio/private/ft_estimate_units.m @@ -46,14 +46,14 @@ if indx>length(unit) indx = length(unit); - warning('assuming that the units are "%s"', unit{indx}); + ft_warning('assuming that the units are "%s"', unit{indx}); elseif indx<1 indx = 1; - warning('assuming that the units are "%s"', unit{indx}); + ft_warning('assuming that the units are "%s"', unit{indx}); elseif abs((est-floor(est)) - 0.5)<0.1 % the size estimate falls within the expected range, but is not very decisive % for example round(1.49) results in meter, but round(1.51) results in decimeter - warning('the estimated units are not very decisive, assuming that the units are "%s"', unit{indx}); + ft_warning('the estimated units are not very decisive, assuming that the units are "%s"', unit{indx}); end unit = unit{indx}; diff --git a/external/fieldtrip/fileio/private/ft_fetch_data.m b/external/fieldtrip/fileio/private/ft_fetch_data.m index 595a38fb..a374bfdc 100644 --- a/external/fieldtrip/fileio/private/ft_fetch_data.m +++ b/external/fieldtrip/fileio/private/ft_fetch_data.m @@ -48,7 +48,7 @@ end if isempty(begsample) || isempty(endsample) - error('begsample and endsample must be specified'); + ft_error('begsample and endsample must be specified'); end if isempty(chanindx) @@ -59,14 +59,14 @@ if isfield(data, 'sampleinfo') trl = data.sampleinfo; else - error('data does not contain a consistent trial definition, fetching data is not possible'); + ft_error('data does not contain a consistent trial definition, fetching data is not possible'); end trlnum = length(data.trial); % start with the output data being all NaN dat = nan(numel(chanindx), endsample-begsample+1); -if trlnum>1, +if trlnum>1 % original implementation, used when the input data has multiple trials trllen = zeros(trlnum,1); @@ -76,15 +76,15 @@ % check whether data.trial is consistent with trl if size(trl,1)~=length(data.trial) - error('trial definition is not internally consistent') + ft_error('trial definition is not internally consistent') elseif any(trllen~=(trl(:,2)-trl(:,1)+1)) - error('trial definition is not internally consistent') + ft_error('trial definition is not internally consistent') end minchan = min(chanindx); maxchan = max(chanindx); if minchan<1 || maxchan>hdr.nChans - error('selected channels are not present in the data') + ft_error('selected channels are not present in the data') end % these are for bookkeeping @@ -127,7 +127,7 @@ % check if all samples are present and are not present twice or more if any(count>1) if ~allowoverlap - % error('some of the requested samples occur twice in the data'); + % ft_error('some of the requested samples occur twice in the data'); % this can be considered OK if the overlap has exactly identical values sel = find(count>1); % must be row vector for smplop=sel @@ -137,17 +137,17 @@ for i=2:length(seltrl) % compare all occurences to the first one if ~all(data.trial{seltrl(i)}(:,selsmp(i)) == data.trial{seltrl(1)}(:,selsmp(1))) - error('some of the requested samples occur twice in the data and have conflicting values'); + ft_error('some of the requested samples occur twice in the data and have conflicting values'); end end end else - warning('samples present in multiple trials, using only the last occurence of each sample') + ft_warning('samples present in multiple trials, using only the last occurence of each sample') end end % if any(count==0) - % warning('not all requested samples are present in the data, filling with NaNs'); + % ft_warning('not all requested samples are present in the data, filling with NaNs'); % end % construct the output data array @@ -167,7 +167,7 @@ utrl = unique(trialnum); utrl(~isfinite(utrl)) = 0; utrl(utrl==0) = []; - if length(utrl)==1, + if length(utrl)==1 ok = trialnum==utrl; smps = samplenum(ok); dat(:,ok) = data.trial{utrl}(chanindx,smps); @@ -185,14 +185,18 @@ % get the indices begindx = begsample - trl(1) + 1; endindx = endsample - trl(1) + 1; - + if endindx<=0 || begindx>size(data.trial{1},2) + % requested data samples outside the data present + return; + end + tmptrl = trl([1 2]) - [trl(1) trl(1)]+1; % ignore offset in case it's present datbegindx = max(1, trl(1)-begsample+1); datendindx = min(endsample-begsample+1, trl(2)-begsample+1); % if begsampletrl(2) - % warning('not all requested samples are present in the data, filling with NaNs'); + % ft_warning('not all requested samples are present in the data, filling with NaNs'); % end if begsample >= trl(1) && begsample <= trl(2) diff --git a/external/fieldtrip/fileio/private/ft_findcfg.m b/external/fieldtrip/fileio/private/ft_findcfg.m index ea39b132..7dfce3c2 100644 --- a/external/fieldtrip/fileio/private/ft_findcfg.m +++ b/external/fieldtrip/fileio/private/ft_findcfg.m @@ -48,11 +48,11 @@ status = 1; elseif issubfield(cfg, 'previous'); [val, status] = ft_findcfg(cfg.previous, var); - if status, break; end; + if status, break; end elseif iscell(cfg) for i=1:length(cfg) [val, status] = ft_findcfg(cfg{i}, var); - if status, break; end; + if status, break; end end else status = -1; diff --git a/external/fieldtrip/fileio/private/ft_getopt.m b/external/fieldtrip/fileio/private/ft_getopt.m index 21ed892a..0d433115 100644 --- a/external/fieldtrip/fileio/private/ft_getopt.m +++ b/external/fieldtrip/fileio/private/ft_getopt.m @@ -8,19 +8,19 @@ % where the input values are % s = structure or cell-array % key = string -% default = any valid MATLAB data type +% default = any valid MATLAB data type (optional, default = []) % emptymeaningful = boolean value (optional, default = 0) % -% If the key is present as field in the structure, or as key-value -% pair in the cell-array, the corresponding value will be returned. +% If the key is present as field in the structure, or as key-value pair in the +% cell-array, the corresponding value will be returned. % -% If the key is not present, ft_getopt will return an empty array. +% If the key is not present, ft_getopt will return the default, or an empty array +% when no default was specified. % -% If the key is present but has an empty value, then the emptymeaningful -% flag specifies whether the empty value or the default value should -% be returned. If emptymeaningful==true, then an empty array will be -% returned. If emptymeaningful==false, then the specified default will -% be returned. +% If the key is present but has an empty value, then the emptymeaningful flag +% specifies whether the empty value or the default value should be returned. +% If emptymeaningful==true, then the empty array will be returned. +% If emptymeaningful==false, then the specified default will be returned. % % See also FT_SETOPT, FT_CHECKOPT @@ -60,27 +60,27 @@ else val = opt.(key); end - + elseif isa(opt, 'cell') % get the key-value from the cell-array if mod(length(opt),2) error('optional input arguments should come in key-value pairs, i.e. there should be an even number'); end - + % the 1st, 3rd, etc. contain the keys, the 2nd, 4th, etc. contain the values keys = opt(1:2:end); vals = opt(2:2:end); - + % the following may be faster than cellfun(@ischar, keys) valid = false(size(keys)); for i=1:numel(keys) valid(i) = ischar(keys{i}); end - + if ~all(valid) error('optional input arguments should come in key-value pairs, the optional input argument %d is invalid (should be a string)', i); end - + hit = find(strcmpi(key, keys)); if isempty(hit) % the requested key was not found @@ -91,7 +91,7 @@ else error('multiple input arguments with the same name'); end - + elseif isempty(opt) % no options are specified, return default val = default; diff --git a/external/fieldtrip/fileio/private/ft_getopt.mexmaci64 b/external/fieldtrip/fileio/private/ft_getopt.mexmaci64 index 1e499c9421e1062ba1178bd37b44ea26728740c3..48fecb34b3878cd01301ebf956190ce9f9db8af2 100755 GIT binary patch literal 9680 zcmeHNU2Ggz6~62II6tOd2d6cn&}peFm;BizC~4BB-r7!g!A>3Qv=Ly&v+G&!(Al5N z&ZO(eiL5v-ow`P*DWyVHu+#@C1P>r2A_3K+w3vrLO?Zhah$=*rvD`|9LO?BKIp3W- z-q|rmec%brmG3?0JLlYU&zyVbdiKt|{{A~R>lurzVT^5{8l@_&V{D2j%Ezd-)iEZ^ zgFVLvxu~{52Y(Tmd@^#w)(f31n`+6d8V3DIn_QhiW1#@Aby>Gv%O?C#mW!s9EG~5vnU$5nrlk8d`2t*a!Xn zN%;Gg2+G64yw*1fW!cI-q2)$oEtk%7Tst4*jc(6=;Q+WMJ|XvrEUOtgZ75mQl?3Bk z5dPXl2Vks`)e6>$Lsgc$V}miDmA5`tp;#yI>%}U|IbAM}Ws`YbE||uu{ycYBu>QC( zpUuAEWm#ALo4=@VG$;B1`~4xlTYdg;opGwN+?zQ3`JV2CcTY&d$O}y11>6Kw;K#rI z?qY1B9SX_4?=}!^0TxA)7`s3nuH4DkK9V6n(8sCcZA6FfW~@N^&BXUp^%vNpZuJWT z{Dn_3_UV8O@Z(f5&K*m?xNY{K{lk;j=I^`O*|eL6<9h?!NH^xDO}wvnsib1K-EckV zi?O}ZX%rMQvrE^K+0xFDF`};KL)feS4lC_T+Sw#chQB&Kt?d%YPzaxgyg**W;SPKvW-vp+F?E5-C2iF)l* zWzxX<18R@6drY1N*gQSDwbu__thAOWluGMK-j4J3G;b$(dxp1X zdHW=9pW^M)ynTkZn1xC!=C{)NEN?OGmDcBZ`vPyV&MK`~yOq}S)Y6R4eBy7kzG4HF z*0+exW*}U=R;g4nc;s6AJ-EH#E`#d>_bYIChF*LH+(~dh1~&`td*FTmZVp@--1FcT zz&!)*O>k$x{TW;dTpdl;Vh-F^a3kQ_z*`#Vn`Lv|v3YIA;#;BE5b7qm58C7~*9g~WgyrqvwNmVKq)RdOi)DcN3 zN{S?Y&1mVWVtc@gq-G1|SXNbX^t&f*={{$Qq~}Mql%h*{15v1kmXb~=x}~yIK9|-; z8R>NT<&{i5UfiSY-aBUOmQzn8gIIb1fmkWCEns->0hZEL#gGE>1N_R;no%@GwACx5 zi=sevx>WAcGSt&pQ9<@|Z$mI%iFP}A6o>FyvhhiAY7%sj#7H&y)J5>}v zrM1U@|L!4*dJYe>RKR1QHqaAxv-^}C8HO=E*#7p|I=EZ@?Griq1r{kqBhiNX4YQuSdM}Ca=hP2I8Rdx1ryzPNvW0S|mU;}MuQ)nLpFfar))Ue>QZ=0~2q~rDQN_>{%I9O6 znRz7nRXVmqw>e?ZZ!H@@{BoqZlP1kbDMdAvEs)475sXZqbkrTPaw${G=h*hNMkj3Q zaZ5AQ5v8D=P>mwwbn-jbOb1I7c(*;*{3g98W$gW{4R~|CohrwWQQ>DyMBP&-->Y&6 z8cFMY$AQlWfG5P+72Y)y^!o94vwr+=K(7SwaTik;x10&!7X$eF0sKk;|2lyG5Ws&8 z;0TTE{*i*p<^aY)tzRz%@U{TPiND{zCxDN*csch&0gUe)@S+3X>};e;Z{_*707y5E z%5I^GIfzniqPm6ZN2%go$0Xn!5zaBm_)b840!{s#yu*x#5y;C@<-Xehi z`QCuWe^ad3tVpoRHbt764GOq+Ya)q%Q*vQ-J96=gjmQ;?Er@{Fd|VFOj?3{4hqLZh X!&z^W;lSHoI1u}a|88HgWi$3~)uY>q literal 9832 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 delta 33 mcmZp0X>eJ<$YTBPQ|M$CMjxgvZ#D-pCP{(?Ht&$~U! delta 32 lcmZqhXz-ZugT=2, get_spm_version()<95}; + %This is to avoid crashes when trying to add SPM to the path + fallback_toolbox = 'SPM8'; case 'SPM5' dependency = {'spm', get_spm_version()==5}; + case 'SPM5UP' % version 5 or later, but not SPM 9X + dependency = {'spm', get_spm_version()>=5, get_spm_version()<95}; + %This is to avoid crashes when trying to add SPM to the path + fallback_toolbox = 'SPM5'; case 'SPM8' dependency = {'spm', get_spm_version()==8}; case 'SPM8UP' % version 8 or later, but not SPM 9X dependency = {'spm', get_spm_version()>=8, get_spm_version()<95}; - %This is to avoid crashes when trying to add SPM to the path fallback_toolbox = 'SPM8'; case 'SPM12' dependency = {'spm', get_spm_version()==12}; + case 'SPM12UP' % version 12 or later, but not SPM 9X + dependency = {'spm', get_spm_version()>=12, get_spm_version()<95}; + %This is to avoid crashes when trying to add SPM to the path + fallback_toolbox = 'SPM12'; case 'MEG-PD' dependency = {'rawdata', 'channames'}; case 'MEG-CALC' @@ -205,8 +220,7 @@ case 'MRI' % other functions in the mri section dependency = {'avw_hdr_read', 'avw_img_read'}; case 'NEUROSHARE' - dependency = {'ns_OpenFile', 'ns_SetLibrary', ... - 'ns_GetAnalogData'}; + dependency = {'ns_OpenFile', 'ns_SetLibrary', 'ns_GetAnalogData'}; case 'ARTINIS' dependency = {'read_artinis_oxy3'}; case 'BESA' @@ -234,21 +248,21 @@ case '4D-VERSION' dependency = {'read4d', 'read4dhdr'}; case {'STATS', 'STATISTICS'} - dependency = has_license('statistics_toolbox'); % check the availability of a toolbox license + dependency = has_license('statistics_toolbox'); % also check the availability of a toolbox license case {'OPTIM', 'OPTIMIZATION'} - dependency = has_license('optimization_toolbox'); % check the availability of a toolbox license + dependency = has_license('optimization_toolbox'); % also check the availability of a toolbox license case {'SPLINES', 'CURVE_FITTING'} - dependency = has_license('curve_fitting_toolbox'); % check the availability of a toolbox license + dependency = has_license('curve_fitting_toolbox'); % also check the availability of a toolbox license case 'COMM' dependency = {has_license('communication_toolbox'), 'de2bi'}; % also check the availability of a toolbox license case 'SIGNAL' - dependency = {has_license('signal_toolbox'), 'window'}; % also check the availability of a toolbox license - case 'IMAGE' - dependency = has_license('image_toolbox'); % check the availability of a toolbox license + dependency = {has_license('signal_toolbox'), 'window'}; % also check the availability of a toolbox license + case 'IMAGES' + dependency = has_license('image_toolbox'); % also check the availability of a toolbox license case {'DCT', 'DISTCOMP'} - dependency = has_license('distrib_computing_toolbox'); % check the availability of a toolbox license + dependency = has_license('distrib_computing_toolbox'); % also check the availability of a toolbox license case 'COMPILER' - dependency = has_license('compiler'); % check the availability of a toolbox license + dependency = has_license('compiler'); % also check the availability of a toolbox license case 'FASTICA' dependency = 'fpica'; case 'BRAINSTORM' @@ -260,8 +274,7 @@ case 'BCI2000' dependency = {'load_bcidat'}; case 'NLXNETCOM' - dependency = {'MatlabNetComClient', 'NlxConnectToServer', ... - 'NlxGetNewCSCData'}; + dependency = {'MatlabNetComClient', 'NlxConnectToServer', 'NlxGetNewCSCData'}; case 'DIPOLI' dependency = {'dipoli.maci', 'file'}; case 'MNE' @@ -323,17 +336,17 @@ dependency = {'plx_adchan_gains', 'mexPlex'}; case '35625-INFORMATION-THEORY-TOOLBOX' dependency = {'conditionalEntropy', 'entropy', 'jointEntropy',... - 'mutualInformation' 'nmi' 'nvi' 'relativeEntropy'}; + 'mutualInformation' 'nmi' 'nvi' 'relativeEntropy'}; case '29046-MUTUAL-INFORMATION' dependency = {'MI', 'license.txt'}; case '14888-MUTUAL-INFORMATION-COMPUTATION' dependency = {'condentropy', 'demo_mi', 'estcondentropy.cpp',... - 'estjointentropy.cpp', 'estpa.cpp', ... - 'findjointstateab.cpp', 'makeosmex.m',... - 'mutualinfo.m', 'condmutualinfo.m',... - 'entropy.m', 'estentropy.cpp',... - 'estmutualinfo.cpp', 'estpab.cpp',... - 'jointentropy.m' 'mergemultivariables.m' }; + 'estjointentropy.cpp', 'estpa.cpp', ... + 'findjointstateab.cpp', 'makeosmex.m',... + 'mutualinfo.m', 'condmutualinfo.m',... + 'entropy.m', 'estentropy.cpp',... + 'estmutualinfo.cpp', 'estpab.cpp',... + 'jointentropy.m' 'mergemultivariables.m' }; case 'PLOT2SVG' dependency = {'plot2svg.m', 'simulink2svg.m'}; case 'BRAINSUITE' @@ -352,11 +365,16 @@ dependency = {'write_wobj' 'read_wobj'}; case 'NEURONE' dependency = {'readneurone' 'readneuronedata' 'readneuroneevents'}; - + case 'BREWERMAP' + dependency = {'brewermap' 'brewermap_view'}; + case 'GTEC' + dependency = {'ghdf5read' 'ghdf5fileimport'}; + case 'MARS' + dependency = {'spm_mars_mrf'}; + % the following are FieldTrip modules/toolboxes case 'FILEIO' - dependency = {'ft_read_header', 'ft_read_data', ... - 'ft_read_event', 'ft_read_sens'}; + dependency = {'ft_read_header', 'ft_read_data', 'ft_read_event', 'ft_read_sens'}; case 'FORWARD' dependency = {'ft_compute_leadfield', 'ft_prepare_vol_sens'}; case 'PLOTTING' @@ -369,33 +387,35 @@ dependency = {'ft_spiketriggeredaverage', 'ft_spiketriggeredspectrum'}; case 'FILEEXCHANGE' dependency = is_subdir_in_fieldtrip_path('/external/fileexchange'); + case 'CELLFUNCTION' + dependency = {'cellmean', 'cellvecadd', 'cellcat'}; case {'INVERSE', 'REALTIME', 'SPECEST', 'PREPROC', ... - 'COMPAT', 'STATFUN', 'TRIALFUN', 'UTILITIES/COMPAT', ... - 'FILEIO/COMPAT', 'PREPROC/COMPAT', 'FORWARD/COMPAT', ... - 'PLOTTING/COMPAT', 'TEMPLATE/LAYOUT', 'TEMPLATE/ANATOMY' ,... - 'TEMPLATE/HEADMODEL', 'TEMPLATE/ELECTRODE', ... - 'TEMPLATE/NEIGHBOURS', 'TEMPLATE/SOURCEMODEL'} + 'COMPAT', 'STATFUN', 'TRIALFUN', 'UTILITIES/COMPAT', ... + 'FILEIO/COMPAT', 'PREPROC/COMPAT', 'FORWARD/COMPAT', ... + 'PLOTTING/COMPAT', 'TEMPLATE/LAYOUT', 'TEMPLATE/ANATOMY' ,... + 'TEMPLATE/HEADMODEL', 'TEMPLATE/ELECTRODE', ... + 'TEMPLATE/NEIGHBOURS', 'TEMPLATE/SOURCEMODEL'} dependency = is_subdir_in_fieldtrip_path(toolbox); otherwise - if ~silent, warning('cannot determine whether the %s toolbox is present', toolbox); end + if ~silent, ft_warning('cannot determine whether the %s toolbox is present', toolbox); end dependency = false; end status = is_present(dependency); if ~status && ~isempty(fallback_toolbox) - % in case of SPM8UP + % in case of SPMxUP toolbox = fallback_toolbox; end % try to determine the path of the requested toolbox if autoadd>0 && ~status - + % for core FieldTrip modules prefix = fileparts(which('ft_defaults')); if ~status status = myaddpath(fullfile(prefix, lower(toolbox)), silent); end - + % for external FieldTrip modules prefix = fullfile(fileparts(which('ft_defaults')), 'external'); if ~status @@ -407,37 +427,37 @@ feval(licensefile); end end - + % for contributed FieldTrip extensions prefix = fullfile(fileparts(which('ft_defaults')), 'contrib'); if ~status status = myaddpath(fullfile(prefix, lower(toolbox)), silent); licensefile = [lower(toolbox) '_license']; if status && exist(licensefile, 'file') - % this will execute openmeeg_license and mne_license - % which display the license on screen for three seconds + % this will execute openmeeg_license, mne_license and artinis_license + % which display the license on screen for a few seconds feval(licensefile); end end - + % for linux computers in the Donders Centre for Cognitive Neuroimaging prefix = '/home/common/matlab'; if ~status && isdir(prefix) status = myaddpath(fullfile(prefix, lower(toolbox)), silent); end - + % for windows computers in the Donders Centre for Cognitive Neuroimaging prefix = 'h:\common\matlab'; if ~status && isdir(prefix) status = myaddpath(fullfile(prefix, lower(toolbox)), silent); end - + % use the MATLAB subdirectory in your homedirectory, this works on linux and mac prefix = fullfile(getenv('HOME'), 'matlab'); if ~status && isdir(prefix) status = myaddpath(fullfile(prefix, lower(toolbox)), silent); end - + if ~status % the toolbox is not on the path and cannot be added sel = find(strcmp(url(:,1), toolbox)); @@ -447,7 +467,7 @@ msg = sprintf('the %s toolbox is not installed', toolbox); end if autoadd==1 - error(msg); + ft_error(msg); elseif autoadd==2 ft_warning(msg); else @@ -458,30 +478,35 @@ % this function is called many times in FieldTrip and associated toolboxes % use efficient handling if the same toolbox has been investigated before -if status - previous.(fixname(toolbox)) = status; -end +% if status +% previous.(fixname(toolbox)) = status; +% end % remember the previous path, allows us to determine on the next call % whether the path has been modified outise of this function -previouspath = path; +% previouspath = path; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % helper function %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function status = myaddpath(toolbox, silent) if isdeployed - warning('cannot change path settings for %s in a compiled application', toolbox); + ft_warning('cannot change path settings for %s in a compiled application', toolbox); status = 1; elseif exist(toolbox, 'dir') - if ~silent, - ws = warning('backtrace', 'off'); - warning('adding %s toolbox to your MATLAB path', toolbox); - warning(ws); % return to the previous warning level + if ~silent + ft_warning('off','backtrace'); + ft_warning('adding %s toolbox to your MATLAB path', toolbox); + ft_warning('on','backtrace'); + end + if any(~cellfun(@isempty, regexp(toolbox, {'spm2', 'spm5', 'spm8', 'spm12'}))) + % SPM needs to be added with the subdirectories + addpath(genpath(toolbox)); + else + addpath(toolbox); end - addpath(toolbox); status = 1; -elseif (~isempty(regexp(toolbox, 'spm5$', 'once')) || ~isempty(regexp(toolbox, 'spm8$', 'once')) || ~isempty(regexp(toolbox, 'spm12$', 'once'))) && exist([toolbox 'b'], 'dir') +elseif (~isempty(regexp(toolbox, 'spm2$', 'once')) || ~isempty(regexp(toolbox, 'spm5$', 'once')) || ~isempty(regexp(toolbox, 'spm8$', 'once')) || ~isempty(regexp(toolbox, 'spm12$', 'once'))) && exist([toolbox 'b'], 'dir') status = myaddpath([toolbox 'b'], silent); else status = 0; @@ -511,9 +536,9 @@ m = lasterror; if strcmp(m.identifier, 'MATLAB:license:checkouterror') if nargin>1 - warning('the %s toolbox is available, but you don''t have a license for it', toolbox); + ft_warning('the %s toolbox is available, but you don''t have a license for it', toolbox); else - warning('the function ''%s'' is available, but you don''t have a license for it', funname); + ft_warning('the function ''%s'' is available, but you don''t have a license for it', funname); end status = false; elseif strcmp(m.identifier, 'MATLAB:UndefinedFunction') @@ -529,65 +554,65 @@ % helper function %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function status = is_subdir_in_fieldtrip_path(toolbox_name) - fttrunkpath = unixpath(fileparts(which('ft_defaults'))); - fttoolboxpath = fullfile(fttrunkpath, lower(toolbox_name)); +fttrunkpath = unixpath(fileparts(which('ft_defaults'))); +fttoolboxpath = fullfile(fttrunkpath, lower(toolbox_name)); - needle=[pathsep fttoolboxpath pathsep]; - haystack = [pathsep path() pathsep]; +needle=[pathsep fttoolboxpath pathsep]; +haystack = [pathsep path() pathsep]; - status = ~isempty(findstr(needle, haystack)); +status = ~isempty(findstr(needle, haystack)); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % helper function %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function status = has_mex(name) - full_name=[name '.' mexext]; - status = (exist(full_name, 'file')==3); +full_name=[name '.' mexext]; +status = (exist(full_name, 'file')==3); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % helper function %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function v = get_spm_version() - if ~is_present('spm') - v=NaN; - return - end +if ~is_present('spm') + v=NaN; + return +end - version_str = spm('ver'); - token = regexp(version_str,'(\d*)','tokens'); - v = str2num([token{:}{:}]); +version_str = spm('ver'); +token = regexp(version_str,'(\d*)','tokens'); +v = str2num([token{:}{:}]); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % helper function %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function status = has_license(toolbox_name) - status = license('checkout', toolbox_name)==1; +status = license('checkout', toolbox_name)==1; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % helper function %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function status = is_present(dependency) - if iscell(dependency) - % use recursion - status = all(cellfun(@is_present,dependency)); - elseif islogical(dependency) - % boolean - status = all(dependency); - elseif ischar(dependency) - % name of a function - status = is_function_present_in_search_path(dependency); - elseif isa(dependency, 'function_handle') - status = dependency(); - else - assert(false,'this should not happen'); - end +if iscell(dependency) + % use recursion + status = all(cellfun(@is_present,dependency)); +elseif islogical(dependency) + % boolean + status = all(dependency); +elseif ischar(dependency) + % name of a function + status = is_function_present_in_search_path(dependency); +elseif isa(dependency, 'function_handle') + status = dependency(); +else + assert(false,'this should not happen'); +end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % helper function %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function status = is_function_present_in_search_path(function_name) - w = which(function_name); +w = which(function_name); - % must be in path and not a variable - status = ~isempty(w) && ~isequal(w, 'variable'); +% must be in path and not a variable +status = ~isempty(w) && ~isequal(w, 'variable'); diff --git a/external/fieldtrip/fileio/private/ft_headcoordinates.m b/external/fieldtrip/fileio/private/ft_headcoordinates.m index 2c6cd04c..66751a8f 100644 --- a/external/fieldtrip/fileio/private/ft_headcoordinates.m +++ b/external/fieldtrip/fileio/private/ft_headcoordinates.m @@ -50,6 +50,7 @@ % according to FTG conventions: coordsys = 'ftg' % according to Talairach conventions: coordsys = 'tal' % according to SPM conventions: coordsys = 'spm' +% according to ACPC conventions: coordsys = 'acpc' % according to PAXINOS conventions: coordsys = 'paxinos' % If coordsys is not specified, it will default to 'ctf'. % @@ -59,7 +60,7 @@ % the Y-axis goes approximately towards lpa, orthogonal to X and in the plane spanned by the fiducials % the Z-axis goes approximately towards the vertex, orthogonal to X and Y % -% The TALAIRACH and SPM coordinate systems are defined as: +% The TALAIRACH, SPM and ACPC coordinate systems are defined as: % the origin corresponds with the anterior commissure % the Y-axis is along the line from the posterior commissure to the anterior commissure % the Z-axis is towards the vertex, in between the hemispheres @@ -88,7 +89,7 @@ % the y-axis points from dorsal to ventral, i.e. from inferior to superior % the z-axis passes through bregma and lambda and points from cranial to caudal, i.e. from anterior to posterior % -% See also FT_ELECTRODEREALIGN, FT_VOLUMEREALIGN, FT_INTERACTIVEREALIGN +% See also FT_ELECTRODEREALIGN, FT_VOLUMEREALIGN, FT_INTERACTIVEREALIGN, COORDSYS2LABEL % Copyright (C) 2003-2014 Robert Oostenveld % @@ -122,19 +123,19 @@ elseif nargin==5 % do nothing else - error('incorrect specification of input parameters'); + ft_error('incorrect specification of input parameters'); end if isnumeric(coordsys) % these are for backward compatibility, but should preferably not be used any more - if coordsys==0, + if coordsys==0 coordsys = 'ctf'; - elseif coordsys==1, + elseif coordsys==1 coordsys = 'asa'; - elseif coordsys==2, + elseif coordsys==2 coordsys = 'ftg'; else - error('if coordsys is numeric, it should assume one of the values 0/1/2'); + ft_error('if coordsys is numeric, it should assume one of the values 0/1/2'); end end @@ -154,7 +155,7 @@ % compute the origin and direction of the coordinate axes in MRI coordinates switch coordsys - case {'als_ctf' 'ctf' 'bti' '4d' 'yokogawa'} + case {'ctf' 'bti' '4d' 'yokogawa'} % rename the marker points for convenience nas = fid1; lpa = fid2; rpa = fid3; extrapoint = fid4; clear fid* origin = (lpa+rpa)/2; @@ -164,7 +165,7 @@ dirx = dirx/norm(dirx); diry = diry/norm(diry); dirz = dirz/norm(dirz); - case {'als_asa' 'asa'} + case {'asa'} % rename the marker points for convenience nas = fid1; lpa = fid2; rpa = fid3; extrapoint = fid4; clear fid* dirz = cross(nas-rpa, lpa-rpa); @@ -174,7 +175,7 @@ diry = diry/norm(diry); dirz = dirz/norm(dirz); origin = rpa + dot(nas-rpa,diry)*diry; - case {'ras_itab' 'itab' 'neuromag'} + case {'itab' 'neuromag'} % rename the fiducials nas = fid1; lpa = fid2; rpa = fid3; extrapoint = fid4; clear fid* dirz = cross(rpa-lpa,nas-lpa); @@ -195,7 +196,7 @@ dirx = dirx/norm(dirx); diry = diry/norm(diry); dirz = dirz/norm(dirz); - case {'ras_tal' 'tal' 'spm'} + case {'tal' 'spm' 'acpc'} % rename the marker points for convenience ac = fid1; pc = fid2; midsagittal = fid3; extrapoint = fid4; clear fid* origin = ac; @@ -217,27 +218,27 @@ diry = diry/norm(diry); dirz = dirz/norm(dirz); otherwise - error('unrecognized headcoordinate system "%s"', coordsys); + ft_error('unrecognized headcoordinate system "%s"', coordsys); end % use the extra point to validate that it is a right-handed coordinate system if ~isempty(extrapoint) dirq = extrapoint-origin; dirq = dirq/norm(dirq); - if any(strcmp(coordsys, {'als_ctf' 'ctf' 'bti' '4d' 'yokogawa' 'ras_itab' 'itab' 'neuromag'})) + if any(strcmp(coordsys, {'ctf' 'bti' '4d' 'yokogawa' 'itab' 'neuromag'})) phi = dirq(:)'*dirz(:); if sign(phi)<0 - warning('the input coordinate system seems left-handed, flipping z-axis to keep the transformation matrix consistent'); + ft_warning('the input coordinate system seems left-handed, flipping z-axis to keep the transformation matrix consistent'); dirz = -dirz; end - elseif any(strcmp(coordsys, {'ras_tal' 'tal' 'spm'})) + elseif any(strcmp(coordsys, {'tal' 'spm' 'acpc'})) phi = dirq(:)'*dirx(:); if sign(phi)<0 - warning('the input coordinate system seems left-handed, flipping x-axis to keep the transformation matrix consistent'); + ft_warning('the input coordinate system seems left-handed, flipping x-axis to keep the transformation matrix consistent'); dirx = -dirx; end else - warning('the extra input coordinate is not used with coordsys "%s"', coordsys); + ft_warning('the extra input coordinate is not used with coordsys "%s"', coordsys); end end diff --git a/external/fieldtrip/fileio/private/ft_notification.m b/external/fieldtrip/fileio/private/ft_notification.m new file mode 100644 index 00000000..dc9b7369 --- /dev/null +++ b/external/fieldtrip/fileio/private/ft_notification.m @@ -0,0 +1,482 @@ +function [varargout] = ft_notification(varargin) + +% FT_NOTIFICATION works mostly like the WARNING and ERROR commands in MATLAB and +% is called by FT_ERROR, FT_WARNING, FT_NOTICE, FT_INFO, FT_DEBUG. Note that you +% should not call this function directly. +% +% Some examples: +% ft_info on +% ft_info on msgId +% ft_info off +% ft_info off msgId +% ft_info once +% ft_info once msgId +% ft_info on backtrace +% ft_info off backtrace +% ft_info on verbose +% ft_info off verbose +% +% ft_info query % shows the status of all notifications +% ft_info last % shows the last notification +% ft_info clear % clears the status of all notifications +% ft_info timeout 10 % sets the timeout (for 'once') to 10 seconds +% +% See also DEFAULTID + +% Copyright (C) 2012-2017, Robert Oostenveld, J?rn M. Horschig +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +global ft_default + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% determine who is calling + +stack = dbstack('-completenames'); +% st(1) is this function +% st(2) is the calling function +switch stack(2).name + case 'ft_debug' + level = 'debug'; + case 'ft_info' + level = 'info'; + case 'ft_notice' + level = 'notice'; + case 'ft_warning' + level = 'warning'; + case 'ft_error' + level = 'error'; + otherwise + error('this function cannot be called from %s', stack(2).name); +end + +% remove this function itself and the ft_xxx calling function +stack = stack(3:end); + +% remove the non-FieldTrip functions from the path, these should not be part of the default message identifier +keep = true(size(stack)); +p = fileparts(which('ft_defaults')); +for i=1:numel(stack) + keep(i) = strncmp(p, stack(i).file, length(p)); +end +stack = stack(keep); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% handle the defaults + +if isfield(ft_default, 'notification') && isfield(ft_default.notification, level) + % this would be error, warning, notice, info, debug + s = ft_default.notification.(level); +else + s = []; +end + +% start with an empty state structure +if isempty(s) + s = struct('identifier', {}, 'state', {}, 'timestamp', {}); +end + +% set the default notification state +if ~ismember('all', {s.identifier}) + s = setstate(s, 'all', 'on'); +end + +% set the default backtrace state +defaultbacktrace = false; +if ~ismember('backtrace', {s.identifier}) + switch level + case {'debug' 'info' 'notice'} + s = setstate(s, 'backtrace', 'off'); + case 'warning' + defaultbacktrace = true; + t = warning('query', 'backtrace'); % get the default state + s = setstate(s, 'backtrace', t.state); + case 'error' + s = setstate(s, 'backtrace', 'on'); + end % switch +end + +% set the default verbose state +defaultverbose = false; +if ~ismember('verbose', {s.identifier}) + switch level + case 'warning' + defaultverbose = true; + t = warning('query', 'verbose');% get the default state + s = setstate(s, 'verbose', t.state); + otherwise + s = setstate(s, 'verbose', 'off'); + end +end + +% set the default timeout +if ~ismember('timeout', {s.identifier}) + s = setstate(s, 'timeout', 60); +end + +% set the last notification to empty +if ~ismember('last', {s.identifier}) + state.message = ''; + state.identifier = ''; + state.stack = struct('file', {}, 'name', {}, 'line', {}); + s = setstate(s, 'last', state); +end + +if strcmp(level, 'warning') + ws = warning; + % warnings should be on in general + warning on + % the backtrace is handled by this function + warning off backtrace + % the verbose message is handled by this function + warning off verbose +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% set the notification state according to the input + +if numel(varargin)>0 && (isstruct(varargin{1}) || isempty(varargin{1})) + ft_default.notification.(level) = varargin{1}; + return +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% act according to the first input argument + +if isempty(varargin) + varargin{1} = 'query'; +end + +switch varargin{1} + case 'on' + if numel(varargin)>1 + % switch a specific item on + msgId = varargin{2}; + s = setstate(s, msgId, 'on'); + if strcmp(msgId, 'backtrace') + defaultbacktrace = false; + end + if strcmp(msgId, 'verbose') + defaultverbose = false; + end + % return the message state of all + varargout{1} = getreturnstate(s, msgId); + else + % switch all on + s = setstate(s, 'all', 'on'); + % return the message state of all + varargout{1} = getreturnstate(s); + end + + case 'off' + if numel(varargin)>1 + % switch a specific item off + msgId = varargin{2}; + s = setstate(s, msgId, 'off'); + if strcmp(msgId, 'backtrace') + defaultbacktrace = false; + end + if strcmp(msgId, 'verbose') + defaultverbose = false; + end + % return the specific message state + varargout{1} = getreturnstate(s, msgId); + else + % switch all off + s = setstate(s, 'all', 'off'); + % return the message state of all + varargout{1} = getreturnstate(s); + end + + case 'once' + if numel(varargin)>1 + % switch a specific item to once + msgId = varargin{2}; + s = setstate(s, msgId, 'once'); + % return the specific message state + varargout{1} = getreturnstate(s, msgId); + else + % switch all to once + s = setstate(s, 'all', 'once'); + % return the message state of all + varargout{1} = getreturnstate(s); + end + + case 'timeout' + % set the timeout, this is used for 'once' + if ischar(varargin{2}) + s = setstate(s, 'timeout', str2double(varargin{2})); + else + s = setstate(s, 'timeout', varargin{2}); + end + + case {'last' '-last'} + % return the last notification + varargout{1} = getstate(s, 'last'); + + case {'clear' '-clear'} + % reset the notification system + s = []; + + case {'query' '-query'} + if numel(varargin)>1 + % select a specific item + msgId = varargin{2}; + if ~ismember(msgId, {s.identifier}) + error('Unknown setting or incorrect message identifier ''%s''.', msgId); + end + msgState = getstate(s, msgId); + if nargout + varargout{1} = getreturnstate(s, msgId); + elseif strcmp(msgId, 'verbose') + if istrue(msgState) + fprintf('%s output is verbose.\n', level); + else + fprintf('%s output is terse.\n', level); + end + elseif strcmp(msgId, 'backtrace') + if istrue(msgState) + fprintf('%s backtraces are enabled.\n', level); + else + fprintf('%s backtraces are disabled.\n', level); + end + else + fprintf('The state of %s ''%s'' is ''%s''\n', level, msgId, msgState); + end + else + % return all items + r = getreturnstate(s); + + if nargout + % return the state of all items + varargout{1} = r; + else + % show the state of all items that are different from the default + default = getstate(s, 'all'); + fprintf('The default %s state is ''%s''.', level, default); + r = r(~strcmp({r.state}, default)); + % don't show these + r(strcmp('verbose', {r.identifier})) = []; + r(strcmp('backtrace', {r.identifier})) = []; + if ~isempty(r) + fprintf(' Items not set to the default are\n\n'); + end + for i=1:numel(r) + fprintf(' %4s %s\n', r(i).state, r(i).identifier); + end + fprintf('\n'); + end + end + + otherwise + + if nargout + varargout{1} = getreturnstate(s); + end + + % first input might be msgId + if numel(varargin)>1 && ~isempty(regexp(varargin{1}, '^\w*:', 'once')) + msgId = varargin{1}; + varargin = varargin(2:end); % shift them all by one + else + msgId = defaultId; + end + + % get the state for this notification, it will default to the 'all' state + msgState = getstate(s, msgId); + + % errors are always to be printed + if strcmp(level, 'error') + msgState = 'on'; + end + + if strcmp(msgState, 'once') + timeout = getstate(s, 'timeout'); + since = elapsed(gettimestamp(s, msgId)); + if (since>timeout) + % the timeout has passed, update the timestamp and print the message + s = settimestamp(s, msgId, tic); + msgState = 'on'; + else + % the timeout has not yet passed, do not print the message + msgState = 'off'; + end + end + + % use an automatically generated default identifier + if isempty(msgId) + msgId = defaultId; + end + + % store the last notification + state.message = strtrim(sprintf(varargin{:})); % remove the trailing newline + state.identifier = msgId; + state.stack = stack; + s = setstate(s, 'last', state); + + if strcmp(msgState, 'on') + + if strcmp(level, 'error') + % update the global variable, we won't return here after the error + ft_default.notification.(level) = s; + % the remainder is fully handled by the ERROR function + if ~isempty(msgId) + error(msgId, varargin{:}); + else + error(varargin{:}); + end + + elseif strcmp(level, 'warning') + if ~isempty(msgId) + warning(msgId, varargin{:}); + else + warning(varargin{:}); + end + + else + % ensure there is a line end + if isempty(regexp(varargin{1}, '\\n$', 'once')) % note the double \\ + varargin{1} = [varargin{1} '\n']; + end + fprintf(varargin{:}); + + end % if level=error, warning or otherwise + + % decide whether the stack trace should be shown + if istrue(getstate(s, 'backtrace')) + for i=1:numel(stack) + % show the deepest and lowest-level function first + [p, f, x] = fileparts(stack(i).file); + if isequal(f, stack(i).name) + funname = stack(i).name; + else + funname = sprintf('%s>%s', f, stack(i).name); + end + filename = stack(i).file; + if isempty(fileparts(filename)) + % it requires the full path + filename = fullfile(pwd, filename); + end + if ft_platform_supports('html') + fprintf(' In %s at line %d\n', filename, stack(i).line, funname, stack(i).line); + else + fprintf(' In ''%s'' at line %d\n', filename, stack(i).line); + end + end + fprintf('\n'); + end + + % decide whether a verboe message should be shown + if istrue(getstate(s, 'verbose')) + if ~isempty(msgId) + fprintf('Type "ft_%s off %s" to suppress this message.\n', level, msgId) + else + fprintf('Type "ft_%s off" to suppress this message.\n', level) + end + end + + end % if msgState is on + +end % switch varargin{1} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% update the global variable +if defaultbacktrace && ~isempty(s) + % do not keep the default, it will be determined again on the next call + s = s(~strcmp({s.identifier}, 'backtrace')); +end +if defaultverbose && ~isempty(s) + % do not keep the default, it will be determined again on the next call + s = s(~strcmp({s.identifier}, 'verbose')); +end +ft_default.notification.(level) = s; + +if strcmp(level, 'warning') + % return to the original warning state + warning(ws); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTIONS +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +function r = getreturnstate(s, msgId) +if nargin<2 + r = s; + % don't return these + r(strcmp('timeout', {r.identifier})) = []; + r(strcmp('last', {r.identifier})) = []; + % don't return the timestamps + r = rmfield(r, 'timestamp'); +else + msgState = getstate(s, msgId); + r = struct('identifier', msgId, 'state', msgState); +end + +function state = getstate(s, msgId) +identifier = {s.identifier}; +sel = find(strcmp(identifier, msgId)); +if numel(sel)==1 + state = s(sel).state; + if isempty(state) + state = getstate(s, 'all'); + end +else + state = getstate(s, 'all'); +end + +function timestamp = gettimestamp(s, msgId) +identifier = {s.identifier}; +sel = find(strcmp(identifier, msgId)); +if numel(sel)==1 + timestamp = s(sel).timestamp; +else + timestamp = nan; +end + +function s = setstate(s, msgId, state) +if isempty(msgId), return; end % this happens from the command line +identifier = {s.identifier}; +sel = find(strcmp(identifier, msgId)); +if numel(sel)==1 + s(sel).state = state; +else + s(end+1).identifier = msgId; + s(end ).state = state; + s(end ).timestamp = nan; +end + +function s = settimestamp(s, msgId, timestamp) +if isempty(msgId), return; end % this happens from the command line +identifier = {s.identifier}; +sel = find(strcmp(identifier, msgId)); +if numel(sel)==1 + s(sel).timestamp = timestamp; +else + s(end+1).identifier = msgId; + s(end ).state = []; + s(end ).timestamp = timestamp; +end + +function t = elapsed(start) +if isempty(start) || isnan(start) + t = inf; +else + t = toc(start); +end diff --git a/external/fieldtrip/fileio/private/ft_platform_supports.m b/external/fieldtrip/fileio/private/ft_platform_supports.m index 0770d385..c0676b62 100644 --- a/external/fieldtrip/fileio/private/ft_platform_supports.m +++ b/external/fieldtrip/fileio/private/ft_platform_supports.m @@ -3,41 +3,43 @@ % FT_PLATFORM_SUPPORTS returns a boolean indicating whether the current platform % supports a specific capability % -% Usage: -% tf = ft_platform_supports(what) -% tf = ft_platform_supports('matlabversion', min_version, max_version) +% Use as +% status = ft_platform_supports(what) +% or +% status = ft_platform_supports('matlabversion', min_version, max_version) % -% The following values are allowed for the 'what' parameter: -% value means that the following is supported: +% The following values are allowed for the 'what' parameter, which means means that +% the specific feature explained on the right is supported: % % 'which-all' which(...,'all') -% 'exists-in-private-directory' exists(...) will look in the /private -% subdirectory to see if a file exists +% 'exists-in-private-directory' exists(...) will look in the /private subdirectory to see if a file exists % 'onCleanup' onCleanup(...) % 'alim' alim(...) % 'int32_logical_operations' bitand(a,b) with a, b of type int32 % 'graphics_objects' graphics sysem is object-oriented -% 'libmx_c_interface' libmx is supported through mex in the -% C-language (recent Matlab versions only -% support C++) -% 'stats' all statistical functions in -% FieldTrip's external/stats directory +% 'libmx_c_interface' libmx is supported through mex in the C-language (recent MATLAB versions only support C++) +% 'images' all image processing functions in FieldTrip's external/images directory +% 'signal' all signal processing functions in FieldTrip's external/signal directory +% 'stats' all statistical functions in FieldTrip's external/stats directory % 'program_invocation_name' program_invocation_name() (GNU Octave) -% 'singleCompThread' start Matlab with -singleCompThread -% 'nosplash' -nosplash -% 'nodisplay' -nodisplay -% 'nojvm' -nojvm +% 'singleCompThread' start MATLAB with -singleCompThread +% 'nosplash' start MATLAB with -nosplash +% 'nodisplay' start MATLAB with -nodisplay +% 'nojvm' start MATLAB with -nojvm % 'no-gui' start GNU Octave with --no-gui % 'RandStream.setGlobalStream' RandStream.setGlobalStream(...) % 'RandStream.setDefaultStream' RandStream.setDefaultStream(...) % 'rng' rng(...) % 'rand-state' rand('state') % 'urlread-timeout' urlread(..., 'Timeout', t) -% 'griddata-vector-input' griddata(...,...,...,a,b) with a and b -% vectors -% 'griddata-v4' griddata(...,...,...,...,...,'v4'), -% that is v4 interpolation support +% 'griddata-vector-input' griddata(...,...,...,a,b) with a and b vectors +% 'griddata-v4' griddata(...,...,...,...,...,'v4') with v4 interpolation support % 'uimenu' uimenu(...) +% 'weboptions' weboptions(...) +% 'parula' parula(...) +% 'html' html rendering in desktop +% +% See also FT_VERSION, VERSION, VER, VERLESSTHAN if ~ischar(what) error('first argument must be a string'); @@ -60,30 +62,42 @@ tf = is_matlab(); case 'int32_logical_operations' - % earlier version of Matlab don't support bitand (and similar) + % earlier version of MATLAB don't support bitand (and similar) % operations on int32 - tf = is_octave() || ~matlabversion(-inf, '2012a'); + tf = is_octave() || ~matlabversion(-Inf, '2012a'); case 'graphics_objects' - % introduced in Matlab 2014b, graphics is handled through objects; + % introduced in MATLAB 2014b, graphics is handled through objects; % previous versions use numeric handles tf = is_matlab() && matlabversion('2014b', Inf); case 'libmx_c_interface' % removed after 2013b - tf = matlabversion(-Inf, '2013b'); + tf = is_matlab() && matlabversion(-Inf, '2013b'); + + case 'images' + root_dir = fileparts(which('ft_defaults')); + external_stats_dir = fullfile(root_dir, 'external', 'images'); + + tf = has_all_functions_in_dir(external_stats_dir, {}); + + case 'signal' + root_dir = fileparts(which('ft_defaults')); + external_stats_dir = fullfile(root_dir, 'external', 'signal'); + + tf = has_all_functions_in_dir(external_stats_dir, {}); case 'stats' - root_dir=fileparts(which('ft_defaults')); - external_stats_dir=fullfile(root_dir,'external','stats'); + root_dir = fileparts(which('ft_defaults')); + external_stats_dir = fullfile(root_dir, 'external', 'stats'); - % these files are only used by other functions in the external/stats - % directory - exclude_mfiles={'common_size.m',... - 'iscomplex.m',... - 'lgamma.m'}; + % these files are only used by other functions in the external/stats directory + exclude_mfiles = { + 'common_size.m' + 'iscomplex.m' + }; - tf = has_all_functions_in_dir(external_stats_dir,exclude_mfiles); + tf = has_all_functions_in_dir(external_stats_dir, exclude_mfiles); case 'program_invocation_name' % Octave supports program_invocation_name, which returns the path @@ -91,10 +105,10 @@ tf = is_octave(); case 'singleCompThread' - tf = is_matlab() && matlabversion(7.8, inf); + tf = is_matlab() && matlabversion(7.8, Inf); - case {'nosplash','nodisplay','nojvm'} - % Only on Matlab + case {'nosplash', 'nodisplay', 'nojvm'} + % Only on MATLAB tf = is_matlab(); case 'no-gui' @@ -105,31 +119,46 @@ tf = is_matlab() && matlabversion('2008b', '2011b'); case 'RandStream.setGlobalStream' - tf = is_matlab() && matlabversion('2012a', inf); + tf = is_matlab() && matlabversion('2012a', Inf); case 'randomized_PRNG_on_startup' - tf = is_octave() || ~matlabversion(-Inf,'7.3'); + tf = is_octave() || ~matlabversion(-Inf, '7.3'); case 'rng' - % recent Matlab versions - tf = is_matlab() && matlabversion('7.12',Inf); + % recent MATLAB versions + tf = is_matlab() && matlabversion('7.12', Inf); case 'rand-state' % GNU Octave tf = is_octave(); case 'urlread-timeout' - tf = is_matlab() && matlabversion('2012b',Inf); + tf = is_matlab() && matlabversion('2012b', Inf); case 'griddata-vector-input' tf = is_matlab(); case 'griddata-v4' - tf = is_matlab() && matlabversion('2009a',Inf); + tf = is_matlab() && matlabversion('2009a', Inf); case 'uimenu' tf = is_matlab(); + case {'weboptions', 'webread', 'websave'} + tf = is_matlab() && matlabversion('2014b', Inf); + + case 'webwrite' + tf = is_matlab() && matlabversion('2015a', Inf); + + case 'boundary' + tf = is_matlab() && matlabversion('2014b', Inf); + + case 'parula' + tf = is_matlab() && matlabversion('2014b', Inf); + + case 'html' + tf = ~is_octave() && usejava('desktop') && desktop('-inuse'); + otherwise error('unsupported value for first argument: %s', what); @@ -148,7 +177,7 @@ % SUBFUNCTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function tf = is_octave() -persistent cached_tf; +persistent cached_tf if isempty(cached_tf) cached_tf = logical(exist('OCTAVE_VERSION', 'builtin')); @@ -161,21 +190,19 @@ % SUBFUNCTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function tf = has_all_functions_in_dir(in_dir, exclude_mfiles) -% returns true if all functions in in_dir are already provided by the -% platform -m_files=dir(fullfile(in_dir,'*.m')); -n=numel(m_files); +% returns true if all functions in in_dir are already provided by the platform +m_files = dir(fullfile(in_dir,'*.m')); +n = numel(m_files); -for k=1:n - m_filename=m_files(k).name; - if isempty(which(m_filename)) && ... - isempty(strmatch(m_filename,exclude_mfiles)) - tf=false; +for k = 1:n + m_filename = m_files(k).name; + if isempty(which(m_filename)) && isempty(strmatch(m_filename,exclude_mfiles)) + tf = false; return; end end -tf=true; +tf = true; end % function @@ -187,19 +214,19 @@ % MATLABVERSION checks if the current MATLAB version is within the interval % specified by min and max. % -% Use, e.g., as: -% if matlabversion(7.0, 7.9) -% % do something -% end +% Use as +% if matlabversion(7.0, 7.9) +% % do something +% end % % Both strings and numbers, as well as infinities, are supported, eg.: -% matlabversion(7.1, 7.9) % is version between 7.1 and 7.9? -% matlabversion(6, '7.10') % is version between 6 and 7.10? (note: '7.10', not 7.10) -% matlabversion(-Inf, 7.6) % is version <= 7.6? -% matlabversion('2009b') % exactly 2009b -% matlabversion('2008b', '2010a') % between two versions -% matlabversion('2008b', Inf) % from a version onwards -% etc. +% matlabversion(7.1, 7.9) % is version between 7.1 and 7.9? +% matlabversion(6, '7.10') % is version between 6 and 7.10? (note: '7.10', not 7.10) +% matlabversion(-Inf, 7.6) % is version <= 7.6? +% matlabversion('2009b') % exactly 2009b +% matlabversion('2008b', '2010a') % between two versions +% matlabversion('2008b', Inf) % from a version onwards +% etc. % % See also VERSION, VER, VERLESSTHAN @@ -209,22 +236,22 @@ % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. % -% FieldTrip is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. % -% FieldTrip is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. % -% You should have received a copy of the GNU General Public License -% along with FieldTrip. If not, see . +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . % % $Id$ -% this does not change over subsequent calls, making it persistent speeds it up +% the version does not change, making it persistent speeds up the subsequent calls persistent curVer if nargin<2 @@ -245,7 +272,9 @@ [maxY, maxAb] = parseMatlabRelease(max); inInterval = orderedComparison(minY, minAb, maxY, maxAb, year, ab); -else % perform comparison with respect to version number + +else + % perform comparison with respect to version number [major, minor] = parseMatlabVersion(curVer); [minMajor, minMinor] = parseMatlabVersion(min); [maxMajor, maxMinor] = parseMatlabVersion(max); @@ -255,6 +284,9 @@ end % function +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function [year, ab] = parseMatlabRelease(str) if (str == Inf) year = Inf; ab = Inf; @@ -266,6 +298,9 @@ end end % function +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function [major, minor] = parseMatlabVersion(ver) if (ver == Inf) major = Inf; minor = Inf; @@ -279,10 +314,13 @@ major = str2num(major); minor = str2num(strtok(rest, '.')); end -end % function +end % function -% checks if testA is in interval (lowerA,upperA); if at edges, checks if testB is in interval (lowerB,upperB). +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function inInterval = orderedComparison(lowerA, lowerB, upperA, upperB, testA, testB) +% checks if testA is in interval (lowerA,upperA); if at edges, checks if testB is in interval (lowerB,upperB). if (testA < lowerA || testA > upperA) inInterval = false; else @@ -295,5 +333,4 @@ inInterval = inInterval && (testB <= upperB); end end -end % function - +end % function diff --git a/external/fieldtrip/fileio/private/ft_progress.m b/external/fieldtrip/fileio/private/ft_progress.m index 559686aa..d7dce75e 100644 --- a/external/fieldtrip/fileio/private/ft_progress.m +++ b/external/fieldtrip/fileio/private/ft_progress.m @@ -27,6 +27,8 @@ function ft_progress(varargin) % pause(0.1); % end % ft_progress('close') +% +% See also WAITBAR % Copyright (C) 2004-2008, Robert Oostenveld % diff --git a/external/fieldtrip/fileio/private/ft_scalingfactor.m b/external/fieldtrip/fileio/private/ft_scalingfactor.m index 804871df..ad7a8512 100644 --- a/external/fieldtrip/fileio/private/ft_scalingfactor.m +++ b/external/fieldtrip/fileio/private/ft_scalingfactor.m @@ -87,7 +87,7 @@ end if ~isequal(class(old), class(new)) - error('the input arguments should be of the same class'); + ft_error('the input arguments should be of the same class'); end if iscell(old) @@ -178,7 +178,7 @@ eval(sprintf('oldunit = %s;', old)); eval(sprintf('newunit = %s;', new)); if ~isequal(oldunit, newunit) - error('cannot convert %s to %s', old, new); + ft_error('cannot convert %s to %s', old, new); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/external/fieldtrip/fileio/private/ft_senslabel.m b/external/fieldtrip/fileio/private/ft_senslabel.m index 4ab57989..85e062af 100644 --- a/external/fieldtrip/fileio/private/ft_senslabel.m +++ b/external/fieldtrip/fileio/private/ft_senslabel.m @@ -87,7 +87,7 @@ output = ft_getopt(varargin, 'output', 'normal'); % 'normal' or 'planarcombined' if ~exist(type, 'var') - error('the requested sensor type "%s" is not supported', type); + ft_error('the requested sensor type "%s" is not supported', type); elseif isempty(eval(type)) % assign the list of channels only once, keep it as persistent variable @@ -3673,7 +3673,7 @@ label = ft_senslabel(type); otherwise - error('the requested sensor type "%s" is not supported', type); + ft_error('the requested sensor type "%s" is not supported', type); end % switch @@ -3700,6 +3700,6 @@ label = [planar(:,1:2) combined]; % magnetometers are in the 3rd column for neuromag306 otherwise - error('unsupported output "%s"', output); + ft_error('unsupported output "%s"', output); end diff --git a/external/fieldtrip/fileio/private/ft_senstype.m b/external/fieldtrip/fileio/private/ft_senstype.m index 1d91722d..b6753338 100644 --- a/external/fieldtrip/fileio/private/ft_senstype.m +++ b/external/fieldtrip/fileio/private/ft_senstype.m @@ -43,18 +43,27 @@ % 'biosemi64' % 'biosemi128' % 'biosemi256' +% 'ant128' % 'neuralynx' % 'plexon' % 'artinis' -% 'ext1020' this includes eeg1020, eeg1010 and eeg1005 -% 'eeg' this was called 'electrode' in older versions -% 'meg' this was called 'magnetometer' in older versions % 'nirs' +% 'meg' +% 'eeg' +% 'ieeg' +% 'seeg' +% 'ecog' +% 'eeg1020' +% 'eeg1010' +% 'eeg1005' +% 'ext1020' in case it is a small subset of eeg1020, eeg1010 or eeg1005 % % The optional input argument for the desired type can be any of the above, or any of % the following generic classes of acquisition systems % 'eeg' +% 'ieeg' % 'ext1020' +% 'ant' % 'biosemi' % 'egi' % 'meg' @@ -81,7 +90,7 @@ % % See also FT_SENSLABEL, FT_CHANTYPE, FT_READ_SENS, FT_COMPUTE_LEADFIELD, FT_DATATYPE_SENS -% Copyright (C) 2007-2016, Robert Oostenveld +% Copyright (C) 2007-2017, Robert Oostenveld % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -146,7 +155,8 @@ iselec = (isa(input, 'struct') && isfield(input, 'label') && isfield(input, 'elecpos')) || iselec; % new style isnirs = isa(input, 'struct') && isfield(input, 'label') && isfield(input, 'transceiver'); islabel = isa(input, 'cell') && ~isempty(input) && isa(input{1}, 'char'); -haslabel = isa(input, 'struct') && isfield(input, 'label'); +haslabel = isa(input, 'struct') && isfield(input, 'label'); +haschantype = isa(input, 'struct') && isfield(input, 'chantype'); if ~(isdata || isheader || isgrad || iselec || isnirs || islabel || haslabel) && isfield(input, 'hdr') input = input.hdr; @@ -211,8 +221,8 @@ elseif haslabel % it does not resemble anything that we had expected at this location, but it does have channel labels % the channel labels can be used to determine the type of sensor array - sens.label = input.label; - islabel = true; + sens = keepfields(input, {'label' 'chantype'}); + islabel = true; else sens = []; @@ -265,21 +275,18 @@ % start with unknown, then try to determine the proper type by looking at the labels type = 'unknown'; - if isgrad && isfield(sens, 'type') - type = sens.type; - - elseif isgrad + if isgrad % this looks like MEG + % revert the component balancing that was previously applied if isfield(sens, 'balance') && strcmp(sens.balance.current, 'comp') sens = undobalancing(sens); end - % determine the type of magnetometer/gradiometer system based on the channel names alone + % determine the particular type of acquisition system based on the channel names alone % this uses a recursive call to the "islabel" section further down type = ft_senstype(sens.label); - %sens_temp.type = type; - if strcmp(type, 'unknown') %|| ~ft_senstype(sens_temp,'meg') + if strcmp(type, 'unknown') % although we don't know the type, we do know that it is MEG type = 'meg'; end @@ -287,24 +294,33 @@ elseif iselec % this looks like EEG - % determine the type of eeg/acquisition system based on the channel names alone + % determine the particular type of acquisition system based on the channel names alone % this uses a recursive call to the "islabel" section further down type = ft_senstype(sens.label); - %sens_temp.type = type; - if strcmp(type, 'unknown') %|| ~ft_senstype(sens_temp,'eeg') - % although we don't know the type, we do know that it is EEG - type = 'eeg'; + if strcmp(type, 'unknown') + % although we don't know the type, we do know that it is EEG, IEEG, SEEG, or ECOG + if haschantype && all(strcmp(sens.chantype, 'eeg')) + type = 'eeg'; + elseif haschantype && all(strcmp(sens.chantype, 'seeg')) + type = 'seeg'; + elseif haschantype && all(strcmp(sens.chantype, 'ecog')) + type = 'ecog'; + elseif haschantype && all(ismember(sens.chantype, {'ieeg' 'seeg' 'ecog'})) + type = 'ieeg'; + else + % fall back to the most generic description + type = 'eeg'; + end end elseif isnirs % this looks like NIRS - % determine the type of eeg/acquisition system based on the channel names alone + % determine the particular type of acquisition system based on the channel names alone % this uses a recursive call to the "islabel" section further down type = ft_senstype(sens.label); - %sens_temp.type = type; - if strcmp(type, 'unknown') %|| ~ft_senstype(sens_temp,'eeg') - % although we don't know the type, we do know that it is EEG + if strcmp(type, 'unknown') + % although we don't know the type, we do know that it is NIRS type = 'nirs'; end @@ -382,7 +398,7 @@ elseif (mean(ismember(ft_senslabel('egi32'), sens.label)) > 0.8) type = 'egi32'; - % the following check on the fraction of channels in the user's data rather than on the fraction of channels in the predefined set + % the following check looks at the fraction of channels in the user's data rather than the fraction in the predefined set elseif (mean(ismember(sens.label, ft_senslabel('eeg1020'))) > 0.8) type = 'eeg1020'; elseif (mean(ismember(sens.label, ft_senslabel('eeg1010'))) > 0.8) @@ -390,12 +406,14 @@ elseif (mean(ismember(sens.label, ft_senslabel('eeg1005'))) > 0.8) type = 'eeg1005'; - elseif (sum(ismember(sens.label, ft_senslabel('eeg1005'))) > 10) % Otherwise it's not even worth recognizing + % the following check looks at the fraction of channels in the user's data rather than the fraction in the predefined set + % there is a minumum number of channels, otherwise it is not worth recognizing + elseif (sum(ismember(sens.label, ft_senslabel('eeg1005'))) > 10) type = 'ext1020'; % this will also cover small subsets of eeg1020, eeg1010 and eeg1005 - elseif any(ismember(ft_senslabel('btiref'), sens.label)) - type = 'bti'; % it might be 148 or 248 channels - elseif any(ismember(ft_senslabel('ctfref'), sens.label)) - type = 'ctf'; % it might be 151 or 275 channels + elseif (sum(ismember(ft_senslabel('btiref'), sens.label)) > 10) + type = 'bti'; % 23 in the reference set, it might be 148 or 248 channels + elseif (sum(ismember(ft_senslabel('ctfref'), sens.label)) > 10) + type = 'ctf'; % 29 in the reference set, it might be 151 or 275 channels end end % look at label, ori and/or pos @@ -432,26 +450,30 @@ if ~isempty(desired) % return a boolean flag switch desired + case {'eeg'} + type = any(strcmp(type, {'eeg' 'ieeg' 'seeg' 'ecog' 'ant128' 'biosemi64' 'biosemi128' 'biosemi256' 'egi32' 'egi64' 'egi128' 'egi256' 'ext1020' 'eeg1005' 'eeg1010' 'eeg1020'})); case 'ext1020' - type = any(strcmp(type, {'eeg1005' 'eeg1010' 'eeg1020' 'ext1020'})); - case {'eeg' 'electrode'} - type = any(strcmp(type, {'eeg' 'electrode' 'ant128' 'biosemi64' 'biosemi128' 'biosemi256' 'egi32' 'egi64' 'egi128' 'egi256' 'eeg1005' 'eeg1010' 'eeg1020' 'ext1020'})); + type = any(strcmp(type, {'ext1020' 'eeg1005' 'eeg1010' 'eeg1020'})); + case {'ieeg'} + type = any(strcmp(type, {'ieeg' 'seeg' 'ecog'})); + case 'ant' + type = any(strcmp(type, {'ant' 'ant128'})); case 'biosemi' - type = any(strcmp(type, {'biosemi64' 'biosemi128' 'biosemi256'})); + type = any(strcmp(type, {'biosemi' 'biosemi64' 'biosemi128' 'biosemi256'})); case 'egi' - type = any(strcmp(type, {'egi32' 'egi64' 'egi128' 'egi256'})); + type = any(strcmp(type, {'egi' 'egi32' 'egi64' 'egi128' 'egi256'})); case 'meg' - type = any(strcmp(type, {'meg' 'magnetometer' 'ctf' 'bti' 'ctf64' 'ctf151' 'ctf275' 'ctf151_planar' 'ctf275_planar' 'neuromag122' 'neuromag306' 'neuromag306_combined' 'bti148' 'bti148_planar' 'bti248' 'bti248_planar' 'bti248grad' 'bti248grad_planar' 'yokogawa9' 'yokogawa160' 'yokogawa160_planar' 'yokogawa64' 'yokogawa64_planar' 'yokogawa440' 'itab' 'itab28' 'itab153' 'itab153_planar'})); + type = any(strcmp(type, {'meg' 'ctf' 'ctf64' 'ctf151' 'ctf275' 'ctf151_planar' 'ctf275_planar' 'neuromag' 'neuromag122' 'neuromag306' 'neuromag306_combined' 'bti' 'bti148' 'bti148_planar' 'bti248' 'bti248_planar' 'bti248grad' 'bti248grad_planar' 'yokogawa' 'yokogawa9' 'yokogawa160' 'yokogawa160_planar' 'yokogawa64' 'yokogawa64_planar' 'yokogawa440' 'itab' 'itab28' 'itab153' 'itab153_planar' 'babysquid' 'babysquid74' 'artenis123' 'magview'})); case 'ctf' type = any(strcmp(type, {'ctf' 'ctf64' 'ctf151' 'ctf275' 'ctf151_planar' 'ctf275_planar'})); case 'bti' type = any(strcmp(type, {'bti' 'bti148' 'bti148_planar' 'bti248' 'bti248_planar' 'bti248grad' 'bti248grad_planar'})); case 'neuromag' - type = any(strcmp(type, {'neuromag122' 'neuromag306'})); + type = any(strcmp(type, {'neuromag' 'neuromag122' 'neuromag306'})); case 'babysquid' - type = any(strcmp(type, {'babysquid74' 'artenis123' 'magview'})); + type = any(strcmp(type, {'babysquid' 'babysquid74' 'artenis123' 'magview'})); case 'yokogawa' - type = any(strcmp(type, {'yokogawa160' 'yokogawa160_planar' 'yokogawa64' 'yokogawa64_planar' 'yokogawa440'})); + type = any(strcmp(type, {'yokogawa' 'yokogawa160' 'yokogawa160_planar' 'yokogawa64' 'yokogawa64_planar' 'yokogawa440'})); case 'itab' type = any(strcmp(type, {'itab' 'itab28' 'itab153' 'itab153_planar'})); case 'meg_axial' diff --git a/external/fieldtrip/fileio/private/ft_warning.m b/external/fieldtrip/fileio/private/ft_warning.m index 18b0ce00..58f3985e 100644 --- a/external/fieldtrip/fileio/private/ft_warning.m +++ b/external/fieldtrip/fileio/private/ft_warning.m @@ -1,39 +1,40 @@ -function [ws, warned] = ft_warning(varargin) +function varargout = ft_warning(varargin) -% FT_WARNING will throw a warning for every unique point in the -% stacktrace only, e.g. in a for-loop a warning is thrown only once. +% FT_WARNING prints a warning message on screen, depending on the verbosity +% settings of the calling high-level FieldTrip function. This function works +% similar to the standard WARNING function, but also features the "once" mode. % -% Use as one of the following -% ft_warning(string) -% ft_warning(id, string) -% Alternatively, you can use ft_warning using a timeout -% ft_warning(string, timeout) -% ft_warning(id, string, timeout) -% where timeout should be inf if you don't want to see the warning ever -% again. +% Use as +% ft_warning(...) +% with arguments similar to fprintf, or +% ft_warning(msgId, ...) +% with arguments similar to warning. % -% Use as ft_warning('-clear') to clear old warnings from the current -% stack +% You can switch of all warning messages using +% ft_warning off +% or for specific ones using +% ft_warning off msgId % -% It can be used instead of the MATLAB built-in function WARNING, thus as -% s = ft_warning(...) -% or as -% ft_warning(s) -% where s is a structure with fields 'identifier' and 'state', storing the -% state information. In other words, ft_warning accepts as an input the -% same structure it returns as an output. This returns or restores the -% states of warnings to their previous values. +% To switch them back on, you would use +% ft_warning on +% or for specific ones using +% ft_warning on msgId +% +% Warning messages are only printed once per timeout period using +% ft_warning timeout 60 +% ft_warning once +% or for specific ones using +% ft_warning once msgId % -% It can also be used as -% [s w] = ft_warning(...) -% where w is a boolean that indicates whether a warning as been thrown or not. +% You can see the most recent messages and identifier using +% ft_warning last % -% Please note that you can NOT use it like this -% ft_warning('the value is %d', 10) -% instead you should do -% ft_warning(sprintf('the value is %d', 10)) +% You can query the current on/off/once state for all messages using +% ft_warning query +% +% See also FT_ERROR, FT_WARNING, FT_NOTICE, FT_warning, FT_DEBUG, ERROR, WARNING -% Copyright (C) 2012-2016, Robert Oostenveld, J?rn M. Horschig +% Copyright (C) 2012-2017, Robert Oostenveld, J?rn M. Horschig % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -53,205 +54,12 @@ % % $Id$ -global ft_default -warned = false; -ws = []; - -stack = dbstack; -if any(strcmp({stack(2:end).file}, 'ft_warning.m')) - % don't call FT_WARNING recursively, see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=3068 - return; -end - -if nargin < 1 - error('You need to specify at least a warning message'); -end - -if isstruct(varargin{1}) - warning(varargin{1}); - return; -end - -if ~isfield(ft_default, 'warning') - ft_default.warning = []; -end -if ~isfield(ft_default.warning, 'stopwatch') - ft_default.warning.stopwatch = []; -end -if ~isfield(ft_default.warning, 'identifier') - ft_default.warning.identifier = []; -end -if ~isfield(ft_default.warning, 'ignore') - ft_default.warning.ignore = {}; -end - -% put the arguments we will pass to warning() in this cell array -warningArgs = {}; - -if nargin==3 - % calling syntax (id, msg, timeout) - - warningArgs = varargin(1:2); - msg = warningArgs{2}; - timeout = varargin{3}; - fname = [warningArgs{1} '_' warningArgs{2}]; - -elseif nargin==2 && isnumeric(varargin{2}) - % calling syntax (msg, timeout) - - warningArgs = varargin(1); - msg = warningArgs{1}; - timeout = varargin{2}; - fname = warningArgs{1}; - -elseif nargin==2 && isequal(varargin{1}, 'off') - - ft_default.warning.ignore = union(ft_default.warning.ignore, varargin{2}); - return - -elseif nargin==2 && isequal(varargin{1}, 'on') - - ft_default.warning.ignore = setdiff(ft_default.warning.ignore, varargin{2}); - return - -elseif nargin==2 && ~isnumeric(varargin{2}) - % calling syntax (id, msg) - - warningArgs = varargin(1:2); - msg = warningArgs{2}; - timeout = inf; - fname = [warningArgs{1} '_' warningArgs{2}]; - -elseif nargin==1 - % calling syntax (msg) - - warningArgs = varargin(1); - msg = warningArgs{1}; - timeout = inf; % default timeout in seconds - fname = [warningArgs{1}]; - -end - -if ismember(msg, ft_default.warning.ignore) - % do not show this warning - return; -end - -if isempty(timeout) - error('Timeout ill-specified'); -end - -if timeout ~= inf - fname = fixname(fname); % make a nice string that is allowed as fieldname in a structures - line = []; -else - % here, we create the fieldname functionA.functionB.functionC... - [tmpfname, ft_default.warning.identifier, line] = fieldnameFromStack(ft_default.warning.identifier); - if ~isempty(tmpfname), - fname = tmpfname; - clear tmpfname; - end -end - -if nargin==1 && ischar(varargin{1}) && strcmp('-clear', varargin{1}) - if strcmp(fname, '-clear') % reset all fields if called outside a function - ft_default.warning.identifier = []; - ft_default.warning.stopwatch = []; - else - if issubfield(ft_default.warning.identifier, fname) - ft_default.warning.identifier = rmsubfield(ft_default.warning.identifier, fname); - end - end - return; -end - -% and add the line number to make this unique for the last function -fname = horzcat(fname, line); - -if ~issubfield('ft_default.warning.stopwatch', fname) - ft_default.warning.stopwatch = setsubfield(ft_default.warning.stopwatch, fname, tic); -end - -now = toc(getsubfield(ft_default.warning.stopwatch, fname)); % measure time since first function call - -if ~issubfield(ft_default.warning.identifier, fname) || ... - (issubfield(ft_default.warning.identifier, fname) && now>getsubfield(ft_default.warning.identifier, [fname '.timeout'])) - - % create or reset field - ft_default.warning.identifier = setsubfield(ft_default.warning.identifier, fname, []); - - % warning never given before or timed out - ws = warning(warningArgs{:}); - ft_default.warning.identifier = setsubfield(ft_default.warning.identifier, [fname '.timeout'], now+timeout); - ft_default.warning.identifier = setsubfield(ft_default.warning.identifier, [fname '.ws'], msg); - warned = true; +if nargout + varargout{:} = ft_notification(varargin{:}); +elseif isequal(varargin, {'last'}) + % return an answer anyway + varargout{1} = ft_notification(varargin{:}); else - - % the warning has been issued before, but has not timed out yet - ws = getsubfield(ft_default.warning.identifier, [fname '.ws']); - -end - -end % function ft_warning - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% helper functions -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -function [fname, ft_previous_warnings, line] = fieldnameFromStack(ft_previous_warnings) -% stack(1) is this function, stack(2) is ft_warning -stack = dbstack('-completenames'); -if size(stack) < 3 - fname = []; - line = []; - return; -end -i0 = 3; -% ignore ft_preamble -while strfind(stack(i0).name, 'ft_preamble') - i0=i0+1; + ft_notification(varargin{:}); end -fname = horzcat(fixname(stack(end).name)); -if ~issubfield(ft_previous_warnings, fixname(stack(end).name)) - ft_previous_warnings.(fixname(stack(end).name)) = []; % iteratively build up structure fields -end - - -for i=numel(stack)-1:-1:(i0) - % skip postamble scripts - if strncmp(stack(i).name, 'ft_postamble', 12) - break; - end - - fname = horzcat(fname, '.', horzcat(fixname(stack(i).name))); % , stack(i).file - if ~issubfield(ft_previous_warnings, fname) % iteratively build up structure fields - setsubfield(ft_previous_warnings, fname, []); - end -end - -% line of last function call -line = ['.line', int2str(stack(i0).line)]; -end - -% function outcome = issubfield(strct, fname) -% substrindx = strfind(fname, '.'); -% if numel(substrindx) > 0 -% % separate the last fieldname from all former -% outcome = eval(['isfield(strct.' fname(1:substrindx(end)-1) ', ''' fname(substrindx(end)+1:end) ''')']); -% else -% % there is only one fieldname -% outcome = isfield(strct, fname); -% end -% end - -% function strct = rmsubfield(strct, fname) -% substrindx = strfind(fname, '.'); -% if numel(substrindx) > 0 -% % separate the last fieldname from all former -% strct = eval(['rmfield(strct.' fname(1:substrindx(end)-1) ', ''' fname(substrindx(end)+1:end) ''')']); -% else -% % there is only one fieldname -% strct = rmfield(strct, fname); -% end -% end diff --git a/external/fieldtrip/fileio/private/ft_warp_apply.m b/external/fieldtrip/fileio/private/ft_warp_apply.m index 980e1b88..fa7fa903 100644 --- a/external/fieldtrip/fileio/private/ft_warp_apply.m +++ b/external/fieldtrip/fileio/private/ft_warp_apply.m @@ -102,19 +102,19 @@ s = size(M); if s(1)~=3 - error('invalid size of nonlinear transformation matrix'); + ft_error('invalid size of nonlinear transformation matrix'); elseif strcmp(method, 'nonlin0') && s(2)~=1 - error('invalid size of nonlinear transformation matrix'); + ft_error('invalid size of nonlinear transformation matrix'); elseif strcmp(method, 'nonlin1') && s(2)~=4 - error('invalid size of nonlinear transformation matrix'); + ft_error('invalid size of nonlinear transformation matrix'); elseif strcmp(method, 'nonlin2') && s(2)~=10 - error('invalid size of nonlinear transformation matrix'); + ft_error('invalid size of nonlinear transformation matrix'); elseif strcmp(method, 'nonlin3') && s(2)~=20 - error('invalid size of nonlinear transformation matrix'); + ft_error('invalid size of nonlinear transformation matrix'); elseif strcmp(method, 'nonlin4') && s(2)~=35 - error('invalid size of nonlinear transformation matrix'); + ft_error('invalid size of nonlinear transformation matrix'); elseif strcmp(method, 'nonlin5') && s(2)~=56 - error('invalid size of nonlinear transformation matrix'); + ft_error('invalid size of nonlinear transformation matrix'); end if s(2)==1 @@ -143,7 +143,7 @@ yy = M(2,1) + M(2,2)*x + M(2,3)*y + M(2,4)*z + M(2,5)*x.*x + M(2,6)*x.*y + M(2,7)*x.*z + M(2,8)*y.*y + M(2,9)*y.*z + M(2,10)*z.*z + M(2,11)*x.*x.*x + M(2,12)*x.*x.*y + M(2,13)*x.*x.*z + M(2,14)*x.*y.*y + M(2,15)*x.*y.*z + M(2,16)*x.*z.*z + M(2,17)*y.*y.*y + M(2,18)*y.*y.*z + M(2,19)*y.*z.*z + M(2,20)*z.*z.*z + M(2,21)*x.*x.*x.*x + M(2,22)*x.*x.*x.*y + M(2,23)*x.*x.*x.*z + M(2,24)*x.*x.*y.*y + M(2,25)*x.*x.*y.*z + M(2,26)*x.*x.*z.*z + M(2,27)*x.*y.*y.*y + M(2,28)*x.*y.*y.*z + M(2,29)*x.*y.*z.*z + M(2,30)*x.*z.*z.*z + M(2,31)*y.*y.*y.*y + M(2,32)*y.*y.*y.*z + M(2,33)*y.*y.*z.*z + M(2,34)*y.*z.*z.*z + M(2,35)*z.*z.*z.*z + M(2,36)*x.*x.*x.*x.*x + M(2,37)*x.*x.*x.*x.*y + M(2,38)*x.*x.*x.*x.*z + M(2,39)*x.*x.*x.*y.*y + M(2,40)*x.*x.*x.*y.*z + M(2,41)*x.*x.*x.*z.*z + M(2,42)*x.*x.*y.*y.*y + M(2,43)*x.*x.*y.*y.*z + M(2,44)*x.*x.*y.*z.*z + M(2,45)*x.*x.*z.*z.*z + M(2,46)*x.*y.*y.*y.*y + M(2,47)*x.*y.*y.*y.*z + M(2,48)*x.*y.*y.*z.*z + M(2,49)*x.*y.*z.*z.*z + M(2,50)*x.*z.*z.*z.*z + M(2,51)*y.*y.*y.*y.*y + M(2,52)*y.*y.*y.*y.*z + M(2,53)*y.*y.*y.*z.*z + M(2,54)*y.*y.*z.*z.*z + M(2,55)*y.*z.*z.*z.*z + M(2,56)*z.*z.*z.*z.*z; zz = M(3,1) + M(3,2)*x + M(3,3)*y + M(3,4)*z + M(3,5)*x.*x + M(3,6)*x.*y + M(3,7)*x.*z + M(3,8)*y.*y + M(3,9)*y.*z + M(3,10)*z.*z + M(3,11)*x.*x.*x + M(3,12)*x.*x.*y + M(3,13)*x.*x.*z + M(3,14)*x.*y.*y + M(3,15)*x.*y.*z + M(3,16)*x.*z.*z + M(3,17)*y.*y.*y + M(3,18)*y.*y.*z + M(3,19)*y.*z.*z + M(3,20)*z.*z.*z + M(3,21)*x.*x.*x.*x + M(3,22)*x.*x.*x.*y + M(3,23)*x.*x.*x.*z + M(3,24)*x.*x.*y.*y + M(3,25)*x.*x.*y.*z + M(3,26)*x.*x.*z.*z + M(3,27)*x.*y.*y.*y + M(3,28)*x.*y.*y.*z + M(3,29)*x.*y.*z.*z + M(3,30)*x.*z.*z.*z + M(3,31)*y.*y.*y.*y + M(3,32)*y.*y.*y.*z + M(3,33)*y.*y.*z.*z + M(3,34)*y.*z.*z.*z + M(3,35)*z.*z.*z.*z + M(3,36)*x.*x.*x.*x.*x + M(3,37)*x.*x.*x.*x.*y + M(3,38)*x.*x.*x.*x.*z + M(3,39)*x.*x.*x.*y.*y + M(3,40)*x.*x.*x.*y.*z + M(3,41)*x.*x.*x.*z.*z + M(3,42)*x.*x.*y.*y.*y + M(3,43)*x.*x.*y.*y.*z + M(3,44)*x.*x.*y.*z.*z + M(3,45)*x.*x.*z.*z.*z + M(3,46)*x.*y.*y.*y.*y + M(3,47)*x.*y.*y.*y.*z + M(3,48)*x.*y.*y.*z.*z + M(3,49)*x.*y.*z.*z.*z + M(3,50)*x.*z.*z.*z.*z + M(3,51)*y.*y.*y.*y.*y + M(3,52)*y.*y.*y.*y.*z + M(3,53)*y.*y.*y.*z.*z + M(3,54)*y.*y.*z.*z.*z + M(3,55)*y.*z.*z.*z.*z + M(3,56)*z.*z.*z.*z.*z; else - error('invalid size of nonlinear transformation matrix'); + ft_error('invalid size of nonlinear transformation matrix'); end warped = [xx yy zz]; @@ -188,7 +188,7 @@ %error('individual2sn is not yet implemented'); warped = individual2sn(M, input); else - error('unrecognized transformation method'); + ft_error('unrecognized transformation method'); end if ~input3d diff --git a/external/fieldtrip/fileio/private/getdimord.m b/external/fieldtrip/fileio/private/getdimord.m index e87e1f11..50c59d3c 100644 --- a/external/fieldtrip/fileio/private/getdimord.m +++ b/external/fieldtrip/fileio/private/getdimord.m @@ -7,12 +7,16 @@ % % See also GETDIMSIZ, GETDATFIELD +% Please note that this function is called from many other FT functions. To avoid +% unwanted recursion, you should avoid (where possible) calling other FT functions +% inside this one. + if ~isfield(data, field) && isfield(data, 'avg') && isfield(data.avg, field) field = ['avg.' field]; elseif ~isfield(data, field) && isfield(data, 'trial') && isfield(data.trial, field) field = ['trial.' field]; elseif ~isfield(data, field) - error('field "%s" not present in data', field); + ft_error('field "%s" not present in data', field); end if strncmp(field, 'avg.', 4) @@ -90,11 +94,13 @@ nfreq = length(data.freq); end -if isfield(data, 'trial') && ft_datatype(data, 'raw') +if isfield(data, 'trial') && iscell(data.trial) + % raw data nrpt = length(data.trial); end -if isfield(data, 'trialtime') && ft_datatype(data, 'spike') +if isfield(data, 'trialtime') && isfield(data, 'timestamp') && isfield(data, 'label') + % spike data nrpt = size(data.trialtime,1); end @@ -108,7 +114,7 @@ % this happens after mtmconvol with keeptrials nrpttap = sum(data.cumtapcnt,2); if any(nrpttap~=nrpttap(1)) - warning('unexpected variation of the number of tapers over trials') + ft_warning('unexpected variation of the number of tapers over trials') nrpttap = nan; else nrpttap = nrpttap(1); @@ -156,7 +162,8 @@ nspike = length(data.timestamp{1}); % spike data: only for the first channel end -if ft_datatype(data, 'mvar') && isfield(data, 'coeffs') +if isfield(data, 'dimord') && ~isempty(strfind(data.dimord, 'lag')) && isfield(data, 'coeffs') + % mvar data nlag = size(data.coeffs,3); end @@ -316,7 +323,8 @@ if isequal(datsiz, [npos nfreq ntime]) dimord = 'pos_freq_time'; end - case {'pow'} + + case {'pow' 'noise' 'rv'} if isequal(datsiz, [npos ntime]) dimord = 'pos_time'; elseif isequal(datsiz, [npos nfreq]) @@ -341,7 +349,7 @@ dimord = 'rpt_pos_freq'; end - case {'mom','itc','aa','stat','pval','statitc','pitc'} + case {'mom' 'itc' 'aa' 'stat','pval' 'statitc' 'pitc'} if isequal(datsiz, [npos nori nrpt]) dimord = 'pos_ori_rpt'; elseif isequal(datsiz, [npos nori ntime]) @@ -360,6 +368,8 @@ dimord = 'pos_rpt'; elseif isequalwithoutnans(datsiz, [npos nori nrpt]) dimord = 'pos_ori_rpt'; + elseif isequalwithoutnans(datsiz, [npos nori nrpttap]) + dimord = 'pos_ori_rpttap'; elseif isequalwithoutnans(datsiz, [npos nori ntime]) dimord = 'pos_ori_time'; elseif isequalwithoutnans(datsiz, [npos nori nfreq]) @@ -417,7 +427,11 @@ end case {'cumtapcnt' 'cumsumcnt'} - if isequalwithoutnans(datsiz, [nrpt nan]) + if isequalwithoutnans(datsiz, [nrpt 1]) + dimord = 'rpt'; + elseif isequalwithoutnans(datsiz, [nrpt nfreq]) + dimord = 'rpt_freq'; + elseif isequalwithoutnans(datsiz, [nrpt nan]) dimord = 'rpt_other'; end @@ -431,18 +445,25 @@ dimord = 'chan_topochan'; end - case {'inside'} - if isequalwithoutnans(datsiz, [npos]) + case {'anatomy' 'inside'} + if isfield(data, 'dim') && isequal(datsiz, data.dim) + dimord = 'dim1_dim2_dim3'; + elseif isequalwithoutnans(datsiz, [npos 1]) || isequalwithoutnans(datsiz, [1 npos]) dimord = 'pos'; end - case {'timestamp' 'time'} - if ft_datatype(data, 'spike') && iscell(data.(field)) && datsiz(1)==nchan + case {'timestamp'} + if iscell(data.(field)) && isfield(data, 'label') && datsiz(1)==nchan dimord = '{chan}_spike'; - elseif ft_datatype(data, 'raw') && iscell(data.(field)) && datsiz(1)==nrpt + end + + case {'time'} + if iscell(data.(field)) && isfield(data, 'label') && datsiz(1)==nrpt dimord = '{rpt}_time'; elseif isvector(data.(field)) && isequal(datsiz, [1 ntime ones(1,numel(datsiz)-2)]) dimord = 'time'; + elseif iscell(data.(field)) && isfield(data, 'label') && isfield(data, 'timestamp') && isequal(getdimsiz(data, 'timestamp'), datsiz) && datsiz(1)==nchan + dimord = '{chan}_spike'; end case {'freq'} @@ -548,8 +569,7 @@ % if it does, it might help in diagnosis to have a very informative warning message % since there have been problems with trials not being selected correctly due to the warning going unnoticed % it is better to throw an error than a warning - warning('could not determine dimord of "%s" in the following data', field) - disp(data); + warning_dimord_could_not_be_determined(field,data); dimtok(cellfun(@isempty, dimtok)) = {'unknown'}; if all(~cellfun(@isempty, dimtok)) @@ -567,6 +587,43 @@ end % function +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function warning_dimord_could_not_be_determined(field,data) + msg=sprintf('could not determine dimord of "%s" in:',field); + + if isempty(which('evalc')) + % May not be available in Octave + content=sprintf('object of type ''%s''',class(data)); + else + % in Octave, disp typically shows full data arrays which can result in + % very long output. Here we take out the middle part of the output if + % the output is very long (more than 40 lines) + full_content=evalc('disp(data)'); + max_pre_post_lines=20; + + newline_pos=find(full_content==sprintf('\n')); + newline_pos=newline_pos(max_pre_post_lines:(end-max_pre_post_lines)); + + if numel(newline_pos)>=2 + pre_end=newline_pos(1)-1; + post_end=newline_pos(end)+1; + + content=sprintf('%s\n\n... long output omitted ...\n\n%s',... + full_content(1:pre_end),... + full_content(post_end:end)); + else + content=full_content; + end + end + + id = 'FieldTrip:getdimord:warning_dimord_could_not_be_determined'; + msg = sprintf('%s\n\n%s', msg, content); + ft_warning(id, msg); +end % function warning_dimord_could_not_be_determined + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % SUBFUNCTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -601,11 +658,11 @@ case 'chan' ok = numel(data.label)==1; otherwise - if isfield(data, dimtok{k}); % check whether field exists + if isfield(data, dimtok{k}) % check whether field exists ok = numel(data.(dimtok{k}))==1; - end; + end end - if ok, + if ok break; end end diff --git a/external/fieldtrip/fileio/private/getdimsiz.m b/external/fieldtrip/fileio/private/getdimsiz.m index 90e27771..11b17abe 100644 --- a/external/fieldtrip/fileio/private/getdimsiz.m +++ b/external/fieldtrip/fileio/private/getdimsiz.m @@ -22,7 +22,7 @@ elseif ~isfield(data, field) && isfield(data, 'trial') && isfield(data.trial, field) field = ['trial.' field]; elseif ~isfield(data, field) - error('field "%s" not present in data', field); + ft_error('field "%s" not present in data', field); end if strncmp(field, 'avg.', 4) diff --git a/external/fieldtrip/fileio/private/hasyokogawa.m b/external/fieldtrip/fileio/private/hasyokogawa.m index b98d91bb..cf309aab 100644 --- a/external/fieldtrip/fileio/private/hasyokogawa.m +++ b/external/fieldtrip/fileio/private/hasyokogawa.m @@ -74,7 +74,7 @@ elseif [0 2 2 5] == [rev_ADbitInfoM rev_ChannelInfoM rev_AmpGainM rev_MatchingInfoM] version='16bitBeta6'; else - warning('The version of the installed Yokogawa toolbox cannot be determined.'); + ft_warning('The version of the installed Yokogawa toolbox cannot be determined.'); end catch m = lasterror; diff --git a/external/fieldtrip/fileio/private/homer2opto.m b/external/fieldtrip/fileio/private/homer2opto.m new file mode 100644 index 00000000..1d1ed913 --- /dev/null +++ b/external/fieldtrip/fileio/private/homer2opto.m @@ -0,0 +1,99 @@ +function sens = homer2opto(SD) + +% HOMER2OPTO converts the Homer SD structure to a FieldTrip optode structure +% +% See also BTI2GRAD, CTF2GRAD, FIF2GRAD, ITAB2GRAD, MNE2GRAD, NETMEG2GRAD, YOKOGAWA2GRAD + +% Copyright (C) 2004-2016, Robert Oostenveld +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +% The Homer SD structure contains +% Lambda: [780 850] +% SrcPos: [16?3 double] +% DetPos: [16?3 double] +% DummyPos: [] +% nSrcs: 16 +% nDets: 16 +% nDummys: 0 +% MeasList: [76?4 double] +% SpringList: [] +% AnchorList: {} +% SrcMap: [2?16 double] +% vrnum: {'1.0' '2'} +% xmin: -14.5263 +% xmax: 254.5263 +% ymin: -14.5263 +% ymax: 224.5263 +% MeasListAct: [76?1 double] +% MeasListVis: [76?1 double] +% SpatialUnit: 'mm' +% +% where +% SD.MeasList column 1 = transmitter index +% SD.MeasList column 2 = receiver index +% SD.MeasList column 3 = ? +% SD.MeasList column 4 = wavelength index + +% The FieldTrip optode structure for NIRS channels contains +% sens.label = Cx1 cell-array with channel labels +% sens.chanpos = contains information about the position of the channels (i.e. average of optopos) +% sens.optopos = contains information about the position of the optodes +% sens.optotype = contains information about the type of optode (receiver or transmitter) +% sens.wavelength = 1xM vector of all wavelengths that were used +% sens.transmits = NxM matrix, boolean, where N is the number of optodes and M the number of wavelengths per transmitter. Specifies what optode is transmitting at what wavelength (or nothing at all, which indicates that it is a receiver) +% sens.laserstrength = 1xM vector of the strength of the emitted light of the lasers +% sens.tra = NxC matrix, boolean, contains information about how receiver and transmitter form channels + +N = SD.nSrcs + SD.nDets; % number of optodes +C = size(SD.MeasList,1); % number of channels +M = numel(SD.Lambda); % number of wavelengths + +sens.optopos = cat(1, SD.SrcPos, SD.DetPos); +sens.optotype = cat(1, repmat({'transmitter'}, [SD.nSrcs, 1]), repmat({'receiver'}, [SD.nDets, 1])); +sens.wavelength = SD.Lambda; + +% FIXME positions seem to be in degrees, not in mm + +if isfield(SD, 'SpatialUnit') + % not sure whether this is always present + sens.unit = SD.SpatialUnit; +end + +% laser strength is not known, this probably does not apply to diode based systems anyway +sens.laserstrength = nan(1,M); + +sens.transmits = false(N, M); +% the optodes are sorted: first transmitters, then receivers +for transmitter=1:SD.SrcPos + sel = SD.MeasList(:,1)==transmitter; + for wavelength=1:numel(SD.Lambda) + if any(SD.MeasList(sel,4)==wavelength) + sens.transmits(transmitter,wavelength) = true; + end + end % for all wavelengths +end % for all transmitters + +sens.tra = false(N, C); +for chan=1:C + transmitter = SD.MeasList(chan, 1); + receiver = SD.MeasList(chan, 2); + sens.tra(transmitter, chan) = true; + sens.tra(receiver, chan) = true; +end diff --git a/external/fieldtrip/fileio/private/in_fopen_manscan.m b/external/fieldtrip/fileio/private/in_fopen_manscan.m index 1ed3395c..7f220800 100644 --- a/external/fieldtrip/fileio/private/in_fopen_manscan.m +++ b/external/fieldtrip/fileio/private/in_fopen_manscan.m @@ -29,7 +29,7 @@ MbiFile = strrep(DataFile, '.mb2', '.mbi'); % If doesn't exist: error if ~exist(MbiFile, 'file') - error('Cannot open file: missing text file .mbi'); + ft_error('Cannot open file: missing text file .mbi'); end % Initialize header iEpoch = 1; @@ -164,7 +164,7 @@ % Check if all the epochs have the same channel list if (iEpoch > 1) && ~isequal(hdr.epoch(iEpoch).ChannelOrder, hdr.epoch(1).ChannelOrder) - error('Channel list must remain constant across epochs.'); + ft_error('Channel list must remain constant across epochs.'); end end % Extract global min/max for time and samples indices diff --git a/external/fieldtrip/fileio/private/in_fread_manscan.m b/external/fieldtrip/fileio/private/in_fread_manscan.m index 65d00b19..ded1ee94 100644 --- a/external/fieldtrip/fileio/private/in_fread_manscan.m +++ b/external/fieldtrip/fileio/private/in_fread_manscan.m @@ -109,7 +109,7 @@ elseif (sA(1) == sB(1)) && (sA(2) == sB(2)) && (sA(3) == 1) C = fun(repmat(A, [1, 1, sB(3)]), B); else - error('A and B must have enough common dimensions.'); + ft_error('A and B must have enough common dimensions.'); end % New Matlab version: use bsxfun else diff --git a/external/fieldtrip/fileio/private/inflate_file.m b/external/fieldtrip/fileio/private/inflate_file.m index 703aa27c..952ed73d 100644 --- a/external/fieldtrip/fileio/private/inflate_file.m +++ b/external/fieldtrip/fileio/private/inflate_file.m @@ -49,7 +49,7 @@ elseif filetype_check_extension(inputfile, 'gz') type = 'gzip'; else - error('unsupported compression type, only zip/gz/tar/tgz/tar.gz are supported'); + ft_error('unsupported compression type, only zip/gz/tar/tgz/tar.gz are supported'); end % determine temporary output folder diff --git a/external/fieldtrip/fileio/private/inifile.m b/external/fieldtrip/fileio/private/inifile.m index 25c1fe50..e5792842 100644 --- a/external/fieldtrip/fileio/private/inifile.m +++ b/external/fieldtrip/fileio/private/inifile.m @@ -117,42 +117,42 @@ % Checks the input arguments if nargin < 2 - error('Not enough input arguments'); + ft_error('Not enough input arguments'); end -if (strcmpi(operation,'read')) | (strcmpi(operation,'deletekeys')) +if (strcmpi(operation,'read')) || (strcmpi(operation,'deletekeys')) if nargin < 3 - error('Not enough input arguments.'); + ft_error('Not enough input arguments.'); end if ~exist(fileName) - error(['File ' fileName ' does not exist.']); + ft_error(['File ' fileName ' does not exist.']); end [m,n] = size(keys); if n > 5 - error('Keys argument has too many columns'); + ft_error('Keys argument has too many columns'); end for ii=1:m - if isempty(keys(ii,3)) | ~ischar(keys{ii,3}) - error('Empty or non-char keys are not allowed.'); + if isempty(keys(ii,3)) || ~ischar(keys{ii,3}) + ft_error('Empty or non-char keys are not allowed.'); end end -elseif (strcmpi(operation,'write')) | (strcmpi(operation,'writetext')) +elseif (strcmpi(operation,'write')) || (strcmpi(operation,'writetext')) if nargin < 3 - error('Not enough input arguments'); + ft_error('Not enough input arguments'); end [m,n] = size(keys); for ii=1:m - if isempty(keys(ii,3)) | ~ischar(keys{ii,3}) - error('Empty or non-char keys are not allowed.'); + if isempty(keys(ii,3)) || ~ischar(keys{ii,3}) + ft_error('Empty or non-char keys are not allowed.'); end end elseif (~strcmpi(operation,'new')) - error(['Unknown inifile operation: ''' operation '''']); + ft_error(['Unknown inifile operation: ''' operation '''']); end if nargin >= 3 for ii=1:m for jj=1:n if ~ischar(keys{ii,jj}) - error('All cells from keys must be given as strings, even the empty ones.'); + ft_error('All cells from keys must be given as strings, even the empty ones.'); end end end @@ -160,8 +160,8 @@ if nargin < 4 || isempty(style) style = 'plain'; else - if ~(strcmpi(style,'plain') | strcmpi(style,'tabbed')) | ~ischar(style) - error('Unsupported style given or style not given as a string'); + if ~(strcmpi(style,'plain') || strcmpi(style,'tabbed')) || ~ischar(style) + ft_error('Unsupported style given or style not given as a string'); end end @@ -179,7 +179,7 @@ if strcmpi(operation,'new') fh = fopen(fileName,'w'); if fh == -1 - error(['File: ''' fileName ''' can not be (re)created']); + ft_error(['File: ''' fileName ''' can not be (re)created']); end fclose(fh); return @@ -208,7 +208,7 @@ %---------------------------- elseif (strcmpi(operation,'write')) if m < 1 - error('At least one key is needed when writing keys'); + ft_error('At least one key is needed when writing keys'); end if ~exist(fileName) inifile(fileName,'new'); @@ -225,7 +225,7 @@ else - error('Unknown operation for INIFILE.'); + ft_error('Unknown operation for INIFILE.'); end @@ -266,7 +266,7 @@ fh = fopen(fileName,'r'); if fh == -1 - error(['File: ''' fileName ''' does not exist or can not be opened.']); + ft_error(['File: ''' fileName ''' does not exist or can not be opened.']); end try @@ -324,7 +324,7 @@ currKey = readValue; pos2 = ftell(fh); % the last-byte position of the read key - the total sum of chars read so far for ii=1:length(keyInd) - if strcmpi( keysIn(keyInd(ii),3),readKey ) & ~keysLocated(keyInd(ii)) + if strcmpi( keysIn(keyInd(ii),3),readKey ) && ~keysLocated(keyInd(ii)) keysExist(keyInd(ii)) = 1; startOffsets(keyInd(ii)) = pos1+1; endOffsets(keyInd(ii)) = pos2; @@ -349,7 +349,7 @@ fclose(fh); catch fclose(fh); - error(['Error parsing the file for keys: ' fileName ': ' lasterr]); + ft_error(['Error parsing the file for keys: ' fileName ': ' lasterr]); end %------------------------------------ @@ -370,7 +370,7 @@ function writekeys(fileName,keys,style) [m,n] = size(keys); if n < 4 - error('Keys to be written are given in an invalid format.'); + ft_error('Keys to be written are given in an invalid format.'); end % Get keys position first using findkeys @@ -380,20 +380,20 @@ function writekeys(fileName,keys,style) % Read the whole file's contents out fh = fopen(fileName,'r'); if fh == -1 - error(['File: ''' fileName ''' does not exist or can not be opened.']); + ft_error(['File: ''' fileName ''' does not exist or can not be opened.']); end try dataout = fscanf(fh,'%c'); catch fclose(fh); - error(lasterr); + ft_error(lasterr); end fclose(fh); %--- Rewriting the file -> writing the refined contents fh = fopen(fileName,'w'); if fh == -1 - error(['File: ''' fileName ''' does not exist or can not be opened.']); + ft_error(['File: ''' fileName ''' does not exist or can not be opened.']); end try tab1 = []; @@ -474,7 +474,7 @@ function writekeys(fileName,keys,style) datain = [datain dataout(from:to)]; % the lines before the key end - if length(datain) & (~(datain(end)==RETURN | datain(end)==NEWLINE)) + if length(datain) && (~(datain(end)==RETURN || datain(end)==NEWLINE)) datain = [datain, sprintf(NL_CHAR)]; end @@ -500,8 +500,8 @@ function writekeys(fileName,keys,style) subSecsExist(ind) = 1; end end - if secsExist(ii) & (~isempty(keysIn{ii,1})); tab = tab1; end; - if subSecsExist(ii) & (~isempty(keysIn{ii,2})); tab = [tab tab1]; end; + if secsExist(ii) && (~isempty(keysIn{ii,1})); tab = tab1; end; + if subSecsExist(ii) && (~isempty(keysIn{ii,2})); tab = [tab tab1]; end; datain = [datain sprintf(['%s' NL_CHAR],[tab keysIn{ii,3} ' = ' values{ii}])]; end from = eo(ii); @@ -515,7 +515,7 @@ function writekeys(fileName,keys,style) fprintf(fh,'%c',datain); catch fclose(fh); - error(['Error writing keys to file: ''' fileName ''' : ' lasterr]); + ft_error(['Error writing keys to file: ''' fileName ''' : ' lasterr]); end fclose(fh); %------------------------------------ @@ -529,7 +529,7 @@ function deletekeys(fileName,keys) [m,n] = size(keys); if n < 3 - error('Keys to be deleted are given in an invalid format.'); + ft_error('Keys to be deleted are given in an invalid format.'); end % Get keys position first @@ -539,20 +539,20 @@ function deletekeys(fileName,keys) % Read the whole file's contents out fh = fopen(fileName,'r'); if fh == -1 - error(['File: ''' fileName ''' does not exist or can not be opened.']); + ft_error(['File: ''' fileName ''' does not exist or can not be opened.']); end try dataout = fscanf(fh,'%c'); catch fclose(fh); - error(lasterr); + ft_error(lasterr); end fclose(fh); %--- Rewriting the file -> writing the refined contents fh = fopen(fileName,'w'); if fh == -1 - error(['File: ''' fileName ''' does not exist or can not be opened.']); + ft_error(['File: ''' fileName ''' does not exist or can not be opened.']); end try ind = find(keysExist); @@ -595,7 +595,7 @@ function deletekeys(fileName,keys) fprintf(fh,'%c',datain); catch fclose(fh); - error(['Error deleting keys from file: ''' fileName ''' : ' lasterr]); + ft_error(['Error deleting keys from file: ''' fileName ''' : ' lasterr]); end fclose(fh); %------------------------------------ @@ -621,12 +621,12 @@ function deletekeys(fileName,keys) if isempty(line) % empty line return end -if (line(1) == '[') & (line(end) == ']')... % section found - & (length(line) >= 3) +if (line(1) == '[') && (line(end) == ']')... % section found + && (length(line) >= 3) value = lower(line(2:end-1)); status = 1; -elseif (line(1) == '{') &... % subsection found - (line(end) == '}') & (length(line) >= 3) +elseif (line(1) == '{') &&... % subsection found + (line(end) == '}') && (length(line) >= 3) value = lower(line(2:end-1)); status = 2; else diff --git a/external/fieldtrip/fileio/private/istrue.m b/external/fieldtrip/fileio/private/istrue.m index 79631e32..742a0997 100644 --- a/external/fieldtrip/fileio/private/istrue.m +++ b/external/fieldtrip/fileio/private/istrue.m @@ -1,7 +1,7 @@ function y = istrue(x) -% ISTRUE ensures that a true/false input argument like "yes", "true" -% or "on" is converted into a boolean +% ISTRUE converts an input argument like "yes/no", "true/false" or "on/off" into a +% boolean. If the input is boolean, then it will remain like that. % Copyright (C) 2009-2012, Robert Oostenveld % diff --git a/external/fieldtrip/fileio/private/jaga16_packet.m b/external/fieldtrip/fileio/private/jaga16_packet.m index 6569c48a..21fc58d5 100644 --- a/external/fieldtrip/fileio/private/jaga16_packet.m +++ b/external/fieldtrip/fileio/private/jaga16_packet.m @@ -29,7 +29,7 @@ elseif buf(1)==3 version = 3; else - error('unsupported version of packet'); + ft_error('unsupported version of packet'); end % the packet size is 1396 bytes with timestamp, 1388 without. diff --git a/external/fieldtrip/fileio/private/keyval.m b/external/fieldtrip/fileio/private/keyval.m index b176ce8d..0043c72b 100644 --- a/external/fieldtrip/fileio/private/keyval.m +++ b/external/fieldtrip/fileio/private/keyval.m @@ -44,7 +44,7 @@ end if mod(length(varargin),2) - error('optional input arguments should come in key-value pairs, i.e. there should be an even number'); + ft_error('optional input arguments should come in key-value pairs, i.e. there should be an even number'); end % the 1st, 3rd, etc. contain the keys, the 2nd, 4th, etc. contain the values @@ -58,7 +58,7 @@ end if ~all(valid) - error('optional input arguments should come in key-value pairs, the optional input argument %d is invalid (should be a string)', i); + ft_error('optional input arguments should come in key-value pairs, the optional input argument %d is invalid (should be a string)', i); end hit = find(strcmpi(key, keys)); @@ -69,7 +69,7 @@ % the requested key was found val = vals{hit}; else - error('multiple input arguments with the same name'); + ft_error('multiple input arguments with the same name'); end if nargout>1 diff --git a/external/fieldtrip/fileio/private/labelcmb2indx.m b/external/fieldtrip/fileio/private/labelcmb2indx.m index db7f97a5..8fc4dc2e 100644 --- a/external/fieldtrip/fileio/private/labelcmb2indx.m +++ b/external/fieldtrip/fileio/private/labelcmb2indx.m @@ -1,4 +1,4 @@ -function [indx] = labelcmb2indx(labelcmb, label) +function [indx, label, blockindx, blocklabel] = labelcmb2indx(labelcmb, label) % LABELCMB2INDX computes an array with indices, corresponding to the order % in a list of labels, for an Nx2 list of label combinations @@ -46,6 +46,32 @@ % % $Id$ +% check whether the labelcmb contains any square brackets, indicative of +% blockwise decompositions +if all(~cellfun('isempty',strfind(labelcmb(:),'['))) + tmp = strfind(labelcmb, '['); + tmplabelcmb = labelcmb; + tmpblock = labelcmb; + for k = 1:numel(tmplabelcmb) + tmplabelcmb{k} = labelcmb{k}( 1:(tmp{k}-1)); + tmpblock{k} = labelcmb{k}((tmp{k}+1):(end-1)); + end + blocklabel = cell(0,1); + tmp = tmpblock; + while ~isempty(tmp) + blocklabel{end+1, 1} = tmp{1}; + tmp = tmp(~strcmp(tmp(:,1),blocklabel{end}),:); + end + [indx, label] = labelcmb2indx(tmplabelcmb, unique(tmplabelcmb(:))); + [blockindx, blocklabel] = labelcmb2indx(tmpblock, blocklabel); + blockindx = blockindx(:,1); +% for k = 1:numel(blocklabel) +% nperblock(k,1) = sum(blockindx==k); +% end + return; +end + + if nargin==1, label = unique(labelcmb(:)); end @@ -62,7 +88,7 @@ if nargin==1, %autoindx = find(sel1 & sel2); autoindx = find(sel(:,1) & sel(:,2), 1, 'first'); - if isempty(autoindx), error('the required autocombination is not found in the input'); end + if isempty(autoindx), ft_error('the required autocombination is not found in the input'); end else autoindx = k; end diff --git a/external/fieldtrip/fileio/private/loadama.m b/external/fieldtrip/fileio/private/loadama.m index 373be8b8..dcd3f835 100644 --- a/external/fieldtrip/fileio/private/loadama.m +++ b/external/fieldtrip/fileio/private/loadama.m @@ -32,7 +32,7 @@ version = fread(fid, 1, 'int'); if version~=10 - error(sprintf('%s is either not an inverted A matrix, or one of an old version', filename)); + ft_error(sprintf('%s is either not an inverted A matrix, or one of an old version', filename)); end mode = fread(fid, 1, 'int'); @@ -79,7 +79,7 @@ % read the gradiometers if mode~=0 - error('gradiometers not yet implemented'); + ft_error('gradiometers not yet implemented'); else grad = []; end diff --git a/external/fieldtrip/fileio/private/loadvar.m b/external/fieldtrip/fileio/private/loadvar.m index f9e41813..8d06c471 100644 --- a/external/fieldtrip/fileio/private/loadvar.m +++ b/external/fieldtrip/fileio/private/loadvar.m @@ -19,15 +19,15 @@ % this is probably due to MATLAB filename and MATLAB version issues var = whos('-file', filename); -if length(var)==0 && nargin==1 +if isempty(var) && nargin==1 filecontent = load(filename); % read everything from the file, regardless of how the variables are called varname = fieldnames(filecontent); if length(varname)==1 % the one variable in the file will be returned - value = filecontent.(varname{i}); + value = filecontent.(varname{1}); clear filecontent else - error('cannot read an unspecified variable in case of a file containing multiple variables'); + ft_error('cannot read an unspecified variable in case of a file containing multiple variables'); end elseif length(var)==1 diff --git a/external/fieldtrip/fileio/private/match_str.m b/external/fieldtrip/fileio/private/match_str.m index 440a3818..39eced66 100644 --- a/external/fieldtrip/fileio/private/match_str.m +++ b/external/fieldtrip/fileio/private/match_str.m @@ -1,10 +1,11 @@ function [sel1, sel2] = match_str(a, b, fullout) -% MATCH_STR looks for matching labels in two listst of strings +% MATCH_STR looks for matching labels in two lists of strings % and returns the indices into both the 1st and 2nd list of the matches. % They will be ordered according to the first input argument. % -% [sel1, sel2] = match_str(strlist1, strlist2) +% Use as +% [sel1, sel2] = match_str(strlist1, strlist2) % % The strings can be stored as a char matrix or as an vertical array of % cells, the matching is done for each row. @@ -69,7 +70,7 @@ % According to the original implementation empty numeric elements are % allowed, but are not returned as match. This is different to empty string % elements, which are returned as match. -% See also http://bugzilla.fcdonders.nl/show_bug.cgi?id=1808 +% See also http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=1808 empty_a = cellfun(@isnumeric, a) & cellfun(@isempty, a); empty_b = cellfun(@isnumeric, b) & cellfun(@isempty, b); % the following allows the unique function to operate normally diff --git a/external/fieldtrip/fileio/private/mne2grad.m b/external/fieldtrip/fileio/private/mne2grad.m index 6b82c7b3..2cad2765 100644 --- a/external/fieldtrip/fileio/private/mne2grad.m +++ b/external/fieldtrip/fileio/private/mne2grad.m @@ -7,8 +7,8 @@ % Use as % [grad, elec] = mne2grad(hdr, dewar, coilaccuracy) % where -% dewar = boolean, whether to return it in dewar or head coordinates (default is head coordinates) -% coilaccuracy = empty or a number (default is empty) +% dewar = boolean, whether to return it in dewar or head coordinates (default = false, i.e. head coordinates) +% coilaccuracy = empty or a number (default = []) % % See also CTF2GRAD, BTI2GRAD @@ -82,8 +82,8 @@ orig.chs = fiff_transform_meg_chs(orig.chs,orig.dev_head_t); orig.chs = fiff_transform_eeg_chs(orig.chs,orig.dev_head_t); % EEG channels are normally stored in head coordinates anyway, but what the heck else - warning('No device to head transform available in fif file'); - warning('MEG channels will likely have coordinates in device frame, not head frame'); + ft_warning('No device to head transform available in fif file'); + ft_warning('MEG channels will likely have coordinates in device frame, not head frame'); end else if ~isempty(orig.dev_head_t) @@ -94,8 +94,8 @@ orig.chs = fiff_transform_meg_chs(orig.chs,orig.head_dev_t); % MEG channels are normally stored in dewar coordinates anyway, but what the heck orig.chs = fiff_transform_eeg_chs(orig.chs,orig.head_dev_t); else - warning('No device to head transform available in fif file'); - warning('EEG channels will likely have coordinates in head frame, not device frame'); + ft_warning('No device to head transform available in fif file'); + ft_warning('EEG channels will likely have coordinates in head frame, not device frame'); end end @@ -198,7 +198,7 @@ others = [orig.chs(sel).logno] > 16; grad.chantype(sel(others)) = {'other trigger'}; else - warning('There does not seem to be a suitable trigger channel.'); + ft_warning('There does not seem to be a suitable trigger channel.'); grad.chantype(sel) = {'other trigger'}; end end @@ -260,19 +260,19 @@ % how many Planar gradiometers? nPlaGrad = 0; - for i = 1:orig.nchan; + for i = 1:orig.nchan nPlaGrad = nPlaGrad +(orig.chs(i).coil_type==3012 | orig.chs(i).coil_type==3013 | orig.chs(i).coil_type==3014 | orig.chs(i).coil_type==2) ; end % how many Magnetometers? nMag = 0; - for i = 1:orig.nchan; + for i = 1:orig.nchan nMag = nMag +(orig.chs(i).coil_type==3022 | orig.chs(i).coil_type==3023 | orig.chs(i).coil_type==3024); end % how many Axial gradiometers? nAxGrad = 0; - for i = 1:orig.nchan; + for i = 1:orig.nchan nAxGrad = nAxGrad +(orig.chs(i).coil_type==7001); % babySQUID end @@ -372,7 +372,7 @@ % check we've got all the MEG channels: kChan = kChan-1; if kChan ~= (nPlaGrad + nMag +nAxGrad) - error('Number of MEG channels identified does not match number of channels in grad structure'); + ft_error('Number of MEG channels identified does not match number of channels in grad structure'); end % determine the type of acquisition system @@ -394,7 +394,7 @@ % how many EEG channels? nEEG = 0; -for i = 1:orig.nchan; +for i = 1:orig.nchan nEEG = nEEG +(orig.chs(i).kind==2); end @@ -432,7 +432,7 @@ % check we've got all the EEG channels: if kChan~=(nEEG) - error('Number of EEG channels identified does not match number of channels in elec structure!!!!!'); + ft_error('Number of EEG channels identified does not match number of channels in elec structure!!!!!'); end % multiply by 100 to get cm diff --git a/external/fieldtrip/fileio/private/mxDeserialize.m b/external/fieldtrip/fileio/private/mxDeserialize.m index 696f4ff8..d9b4843f 100644 --- a/external/fieldtrip/fileio/private/mxDeserialize.m +++ b/external/fieldtrip/fileio/private/mxDeserialize.m @@ -31,7 +31,7 @@ argout = mxDeserialize_c(argin); else % use the C++ implementation of the mex file - % see http://bugzilla.fcdonders.nl/show_bug.cgi?id=2452 + % see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2452 argout = mxDeserialize_cpp(argin); end diff --git a/external/fieldtrip/fileio/private/mxSerialize.m b/external/fieldtrip/fileio/private/mxSerialize.m index 78befccb..a2534051 100644 --- a/external/fieldtrip/fileio/private/mxSerialize.m +++ b/external/fieldtrip/fileio/private/mxSerialize.m @@ -31,7 +31,7 @@ argout = mxSerialize_c(argin); else % use the C++ implementation of the mex file - % see http://bugzilla.fcdonders.nl/show_bug.cgi?id=2452 + % see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2452 argout = mxSerialize_cpp(argin); end diff --git a/external/fieldtrip/fileio/private/ndgrid.m b/external/fieldtrip/fileio/private/ndgrid.m index c88a655c..cfc6870f 100644 --- a/external/fieldtrip/fileio/private/ndgrid.m +++ b/external/fieldtrip/fileio/private/ndgrid.m @@ -50,7 +50,7 @@ % $Id$ if nargin==0 - error('MATLAB:ndgrid:NotEnoughInputs', 'Not enough input arguments.'); + ft_error('MATLAB:ndgrid:NotEnoughInputs', 'Not enough input arguments.'); end if nargin==1, varargin = repmat(varargin,[1 max(nargout,2)]); end @@ -117,7 +117,7 @@ varargout{4} = xx(ones1, ones2, ones3, :,ones5); varargout{5} = yy(ones1, ones2, ones3, :,ones5); otherwise - error('this version of ndgrid supports inputs up to 5 dimensions'); + ft_error('this version of ndgrid supports inputs up to 5 dimensions'); %call the ndgrid from elmat %FIXME this has to be done end diff --git a/external/fieldtrip/fileio/private/np_read_splitted_fileinfo.m b/external/fieldtrip/fileio/private/np_read_splitted_fileinfo.m index 9e7c1c3e..aea7636e 100644 --- a/external/fieldtrip/fileio/private/np_read_splitted_fileinfo.m +++ b/external/fieldtrip/fileio/private/np_read_splitted_fileinfo.m @@ -24,59 +24,59 @@ % ------------------------------------------------------------------------- d=dir(filename); if d(1).bytes==0, - error('File size = 0 KB.'); + ft_error('File size = 0 KB.'); end fid=fopen(filename,'r'); if fid==-1, - error(['Unable to open file "' filename '". Error code: ' ferror(fid)]); + ft_error(['Unable to open file "' filename '". Error code: ' ferror(fid)]); end status=fseek(fid,16,'bof'); if status~=0, fclose(fid); - error('Unable to set filepointer to index 16.'); + ft_error('Unable to set filepointer to index 16.'); end [np_info.fp_data,count]=fread(fid,1,'int32'); if count~=1, fclose(fid); - error('Unable to read filepointer for data block.'); + ft_error('Unable to read filepointer for data block.'); end [fp_header,count]=fread(fid,1,'int32'); if count~=1, fclose(fid); - error('Unable to read filepointer for header block.'); + ft_error('Unable to read filepointer for header block.'); end [fp_marker,count]=fread(fid,1,'int32'); if count~=1, fclose(fid); - error('Unable to read filepointer for marker block.'); + ft_error('Unable to read filepointer for marker block.'); end [fp_text,count]=fread(fid,1,'int32'); if count~=1, fclose(fid); - error('Unable to read filepointer for text block.'); + ft_error('Unable to read filepointer for text block.'); end status=fseek(fid,fp_header,'bof'); if status~=0, fclose(fid); - error('Unable to set file to fp_header.'); + ft_error('Unable to set file to fp_header.'); end [np_info.K,count]=fread(fid,1,'short'); % lese Kanalanzahl if count~=1, fclose(fid); - error('Unable to read number of channels.'); + ft_error('Unable to read number of channels.'); end [ignore,count]=fscanf(fid,'%19c',1); if count~=1, fclose(fid); - error('Unable to read duration string.'); + ft_error('Unable to read duration string.'); end % Sampleanzahl ermitteln: % frühere Version: % [np_info.N,count]=fread(fid,1,'int32'); % if count~=1, -% error(['Fehler beim Lesen der Messdauer. Fehlercode: ' ferror(fid)]); +% ft_error(['Fehler beim Lesen der Messdauer. Fehlercode: ' ferror(fid)]); % end % jetzt: Ermittlung aus FilePointern und FileSize!!! d=dir(filename); @@ -90,18 +90,18 @@ % wahrscheinlich keine Daten % if (np_info.fp_data==filesize), - error(['Unable to read data (no data?). fp_text = ' num2str(fp_text) '; fp_marker = ' num2str(fp_marker) '; fp_header = ' num2str(fp_header) ';fp_data = ' num2str(np_info.fp_data) '; filesize = ' num2str(filesize)]); + ft_error(['Unable to read data (no data?). fp_text = ' num2str(fp_text) '; fp_marker = ' num2str(fp_marker) '; fp_header = ' num2str(fp_header) ';fp_data = ' num2str(np_info.fp_data) '; filesize = ' num2str(filesize)]); end np_info.N=(fp_vector(idx+1)-fp_vector(idx))/SIZEOF_FLOAT/np_info.K; status=fseek(fid,fp_header+39,'bof'); if status~=0, fclose(fid); - error('Unable to set filepointer to sampling frquency of 1st channel.'); + ft_error('Unable to set filepointer to sampling frquency of 1st channel.'); end [fa_str,count]=fscanf(fid,'%19c',1); % lese Abtastfrequenz Kanal 1 if count~=1, fclose(fid); - error('Unable to read sampling frquency of 1st channel.'); + ft_error('Unable to read sampling frquency of 1st channel.'); end np_info.fa=str2num(fa_str(2:19)); % Umwandlung: CHAR-Array in double-Zahl @@ -112,7 +112,7 @@ status=fseek(fid,fp_text,'bof'); if status~=0, fclose(fid); - error('Unable to set filepointer to begin of text block.'); + ft_error('Unable to set filepointer to begin of text block.'); end tline=fgetl(fid); % [PatInfo] tline=fgetl(fid); % Name=... @@ -146,12 +146,12 @@ status=fseek(fid,fp_header+35+(i-1)*203+166,'bof'); if status~=0, fclose(fid); - error(['Unable to set filepointer to signal name of channel ' num2str(i) '.']); + ft_error(['Unable to set filepointer to signal name of channel ' num2str(i) '.']); end [h,count]=fscanf(fid,'%8c',1); if count~=1, fclose(fid); - error(['Unable to read channel name for channel ' num2str(i) '.']); + ft_error(['Unable to read channel name for channel ' num2str(i) '.']); end % % wahre Stringlänge bestimmen! @@ -178,12 +178,12 @@ status=fseek(fid,fp_header+35+(i-1)*203+186,'bof'); if status~=0, fclose(fid); - error(['Unable to set filepointer to unit of channel ' num2str(i) '.']); + ft_error(['Unable to set filepointer to unit of channel ' num2str(i) '.']); end [h,count]=fscanf(fid,'%16c',1); if count~=1, fclose(fid); - error(['unable to read unit of channel ' num2str(i) '.']); + ft_error(['unable to read unit of channel ' num2str(i) '.']); end h_unit=h(2:8); % @@ -230,7 +230,7 @@ end fid=fopen([pa filesep fn(1:14) '.EE_'],'r'); if fid==-1, - error('Unable to read setup (marker 70) in *.EE_ file.'); + ft_error('Unable to read setup (marker 70) in *.EE_ file.'); end s=fscanf(fid,'%c',inf); fclose(fid); @@ -251,7 +251,7 @@ % Sekundärmontage fid=fopen([filename(1:length(filename)-1) '_'],'r'); if fid==-1, - error('Unable to read setup (marker 16518) in *.EE_ file.'); + ft_error('Unable to read setup (marker 16518) in *.EE_ file.'); end s=fscanf(fid,'%c',inf); fclose(fid); @@ -312,7 +312,7 @@ % fid=fopen([filename(1:length(filename)-1) '_'],'r'); if fid==-1, - error('Unable to read primary setup in *.EE_ file.'); + ft_error('Unable to read primary setup in *.EE_ file.'); end s=fscanf(fid,'%c',inf); fclose(fid); @@ -358,12 +358,12 @@ end fid=fopen([np_info.pathname filesep np_info.filename],'r'); if fid==-1, - error('Error while opening *.EEG file (read PhysMinMax).'); + ft_error('Error while opening *.EEG file (read PhysMinMax).'); end status=fseek(fid,np_info.fp_data,'bof'); if status~=0, fclose(fid); - error('Unable to set filepointer to begin of data block (read PhysMinMax).'); + ft_error('Unable to set filepointer to begin of data block (read PhysMinMax).'); end SamplesToRead=1000; try @@ -385,5 +385,5 @@ fclose(fid); catch fclose(fid); - error('Error while calculating physical minimum or maximum.'); + ft_error('Error while calculating physical minimum or maximum.'); end diff --git a/external/fieldtrip/fileio/private/np_readdata.m b/external/fieldtrip/fileio/private/np_readdata.m index 690115f3..1c7c87a5 100644 --- a/external/fieldtrip/fileio/private/np_readdata.m +++ b/external/fieldtrip/fileio/private/np_readdata.m @@ -64,7 +64,7 @@ error ('idx_begin is to small.'); end if ((N_start+N-1)>(np_info.N-1)) - error('data_length is to big.'); + ft_error('data_length is to big.'); end end np_data.data=zeros(N,np_info.K); @@ -86,19 +86,19 @@ % ------------------------------------------------------------------------- fid=fopen(filename,'r'); if fid==-1, - error(['Unable to open file "' filename '" . Error code: ' ferror(fid)]); + ft_error(['Unable to open file "' filename '" . Error code: ' ferror(fid)]); end status=fseek(fid,np_info.fp_data+N_start*np_info.K*4,'bof'); % 4 Byte pro Sample if status~=0, fclose(fid); - error('Unable to set filepointer to begin of data block.'); + ft_error('Unable to set filepointer to begin of data block.'); end [np_data.data,count]=fread(fid,[np_info.K N],'float'); % lese Messdaten %if count~=N*np_info.K, % fclose(fid); -% error('Number of read samples unequal to product N*K.'); +% ft_error('Number of read samples unequal to product N*K.'); %end np_data.data=np_data.data'; % transponieren fclose(fid); diff --git a/external/fieldtrip/fileio/private/np_readmarker.m b/external/fieldtrip/fileio/private/np_readmarker.m index a6d0874a..1bb346f2 100644 --- a/external/fieldtrip/fileio/private/np_readmarker.m +++ b/external/fieldtrip/fileio/private/np_readmarker.m @@ -72,21 +72,21 @@ error ('idx_begin is to small.'); end if (N_stop>(np_info.N-1)) - error('data_length is to big.'); + ft_error('data_length is to big.'); end end % Markeranzahl auslesen, Strukturen und cell-Arrays definieren fid=fopen([filename(1:length(filename)-1) '_'],'r'); if fid==-1, - error(['Unable to open file "' [filename(1:length(filename)-1) '_'] '" . Error code: ' ferror(fid)]); + ft_error(['Unable to open file "' [filename(1:length(filename)-1) '_'] '" . Error code: ' ferror(fid)]); end try s=fscanf(fid,'%c',inf); fclose(fid); catch fclose(fid); - error('Error while reading *.EE_ file.'); + ft_error('Error while reading *.EE_ file.'); end Names=strfind(s,'Name'); Anzahl_Marker=length(Names); @@ -230,7 +230,7 @@ % Ergänzung: 16.2.2005 % if length(idx)>1, - error(['Typ ' num2str(MarkerTyp) ' was found ' num2str(length(idx)) ' times in np_marker.markernames.']); + ft_error(['Typ ' num2str(MarkerTyp) ' was found ' num2str(length(idx)) ' times in np_marker.markernames.']); end if ~isempty(idx), % Fall a) ausschließen MarkerName=np_marker.markernames{idx}; diff --git a/external/fieldtrip/fileio/private/pos2dim.m b/external/fieldtrip/fileio/private/pos2dim.m index 6c96f6ff..26622c0a 100644 --- a/external/fieldtrip/fileio/private/pos2dim.m +++ b/external/fieldtrip/fileio/private/pos2dim.m @@ -5,7 +5,7 @@ % % Use as % [dim] = pos2dim(pos) -% where pos is an ordered list of positions +% where pos is an ordered list of positions. % % The output dim is a 3-element vector which correspond to the 3D % volumetric dimensions @@ -15,6 +15,7 @@ % Copyright (C) 2009, Jan-Mathijs Schoffelen if isstruct(pos) + % the input is a FieldTrip data structure pos = pos.pos; end diff --git a/external/fieldtrip/fileio/private/pos2dim3d.m b/external/fieldtrip/fileio/private/pos2dim3d.m index 366654de..757b14f8 100644 --- a/external/fieldtrip/fileio/private/pos2dim3d.m +++ b/external/fieldtrip/fileio/private/pos2dim3d.m @@ -5,10 +5,13 @@ % elements are appended to the output. % % Use as -% [dim] = pos2dim3d(pos, dimold) where pos is an ordered list of positions -% and dimold optionally the original dimensionality of the functional data -% The output dim is a 3+ element vector of which the first three elements -% correspond to the 3D volumetric dimensions +% [dim] = pos2dim3d(pos, dimold) +% where pos is an ordered list of positions and where the (optional) +% dimold is a vector with the original dimensionality of the anatomical +% or functional data. +% +% The output dim is a 1x3 or 1xN vector of which the first three elements +% correspond to the 3D volumetric dimensions. % % See also POS2DIM, POS2TRANSFORM @@ -17,7 +20,7 @@ if nargin==1 && ~isstruct(pos), dimold = zeros(0,2); elseif isstruct(pos), - %the input is a structure + % the input is a FieldTrip data structure dimord = pos.dimord; dimtok = tokenize(dimord, '_'); for i = 1:length(dimtok) @@ -27,10 +30,10 @@ dimold(i,1) = numel(getfield(pos, dimtok{i})); end end - pos = pos.pos; + pos = pos.pos; else if size(pos,1)~=dimold(1), - error('the first element in the second input should be equal to the number of positions'); + ft_error('the first element in the second input should be equal to the number of positions'); end end diff --git a/external/fieldtrip/fileio/private/pos2transform.m b/external/fieldtrip/fileio/private/pos2transform.m index 3030bc97..a15403c4 100644 --- a/external/fieldtrip/fileio/private/pos2transform.m +++ b/external/fieldtrip/fileio/private/pos2transform.m @@ -4,8 +4,8 @@ % of positions. % % Use as -% [transform] = pos2transform(pos, dim) where pos is an ordered list of positions -% and should specify a full 3D volume +% [transform] = pos2transform(pos, dim) +% where pos is an ordered list of positions that should specify a full 3D volume. % % The output transform is a 4x4 homogenous transformation matrix which transforms % from 'voxelspace' into the positions provided in the input diff --git a/external/fieldtrip/fileio/private/quaternion.m b/external/fieldtrip/fileio/private/quaternion.m index ad8d5e06..bd34c4f6 100644 --- a/external/fieldtrip/fileio/private/quaternion.m +++ b/external/fieldtrip/fileio/private/quaternion.m @@ -48,7 +48,7 @@ % $Id$ if numel(q)~=7 - error('incorrect input vector'); + ft_error('incorrect input vector'); end % all of these quaternions are zero-offset in the original equation, but one-offset in the MATLAB vector diff --git a/external/fieldtrip/fileio/private/read_16bit.mexmaci64 b/external/fieldtrip/fileio/private/read_16bit.mexmaci64 index 10b3daca87996a54c859bae20a420b00650d66aa..d0cfa5e66018665d7ef4370a5aad20e28364d4ea 100755 GIT binary patch literal 9184 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 diff --git a/external/fieldtrip/fileio/private/read_16bit.mexw32 b/external/fieldtrip/fileio/private/read_16bit.mexw32 index 5d7307489faf625adf580cd1265bd2c65321a1a7..641231a15080eb3b7188865bea1d850e3362909b 100755 GIT binary patch delta 32 lcmZp$X|S2_fyGzmS>(hoK1}9MH#;#d5(V=&zYvpP2LRqH47~sV delta 32 lcmZp$X|S2_fyMIQr_hOCe3&#BZgyf^Bnswlejz5o4gm9w4i^9b diff --git a/external/fieldtrip/fileio/private/read_16bit.mexw64 b/external/fieldtrip/fileio/private/read_16bit.mexw64 index 6b9a394d28a4406612b6643c45944df06dd14611..8b467aaae45b717bfd76b395a6ba85c7a7ec177d 100755 GIT binary patch delta 33 mcmZp0XmFVDfMx#kr;!t%_%L7OW87@a7$^o7*xVsr!2tjOSq?=2 delta 33 lcmZp0XmFVDfW?RTbLhk;KFn@*44aJ^1I54sn>)lSH~`Wm3y%N* diff --git a/external/fieldtrip/fileio/private/read_24bit.mexmaci64 b/external/fieldtrip/fileio/private/read_24bit.mexmaci64 index 4441dc716113242b23adab321d07e1902ab1e123..f875cdd51869812e226a2f812ec03081e3628c20 100755 GIT binary patch literal 9184 zcmeHNU2IfE6rOFtZfkY7qzNU0xu`V=O=$~iO9XeJ#k+9}g_fTL%4OT$Z8z*+@7~3Q z2W>1oY_QmvXfW}C@Z{g4HbEn{0#Y?fMKMGT5{$5o5=dVpC1E|^+_~G`TWg5%!G}A^ z%sJmVXU?2^W~RM&X3tOGxLd-QqnI(~r0S+B&1dW|QIthgmlZLlC>VC=*g}`PGt3W^#Ma=h79b; zS<|x$e>3sHpVFs>R)38T8lB$~K7d82hGbTJ-3eU_MSF$4)!+BR-wB~Nv4DlX zNvJ5v=nJ7}j}nRoV;mRGN6KaNY!eQE3*r-UlPHSXrv$Y?L^UMV_{N35I?(|bYh}DPxU9kss&>2v-nwKFZi7qS!WVRPzgLQN1@LeV%`guU zi*bIqGk@F}7JeT0Efltqg~{ zBB|P*14IqYJ=m-H9cJ67$dQAsOeQpVN9|s*qPAWP0{cd)Gx2;ve@+VR+YcmkHB!4i zKd#5A51vz|JY!y-5V(yn$_lE`1LJw^VrRh4fSmz519k@f4;k1dr+@SA@NV~R^LDh$ zgMU={(&y!La&&OISTC1{)?T51&Y4Bj_>R2f%-nX+f4afjj--pjn*wsnOR$85RPM|- z`Ihd?*?h~3u!O{SPPhXSMKV}X= zfN+w;Ot~srCisxO0*%W9$;wgV$;l`zDR0}{2kFx$pNdsAg3>9juJsXMyFiMKcfWDoQxIAgQHG4`&II5e>$7l053;c zC{U>|g44r=1@nKd4ASMePS9-k8B^mbioykR>G!W`f3 zobRY49g5@NR^~{#9q#fH=P*soTyn#Db}NgIr>%nS7BnbmT+oAp9uoAZpvMF~A?W*p zjtDv`=$C@dj=+}K8L%^8XTZ*YodG)ob_VPW*cq@hU}wP2fSmz51OIgfDwewUz-Oh0 zF6VmqrMl8Z_snz&zNMcHvwnAlM~S311j6B1H*l4K=}1FYn`6nYu-Y1+i|&;2^r|}O zC9dD7sVdMij-FHX=71i6pw1Mu0yUaw6OhM5?cITJK!ZrmiTGu@IY`?A3QA42Xj*Hc zw}XCHK&CqlSsPut>p=+iR(h0RcQ}^dk@NxKfCj2K08V89QUD26-4`Ro9B@ome?=RU z(QciNhFA@bb2PO-8Pe3AKs>Zx)o^6Q>WkULLOPV0z@6#D!U6tsh3U)X_}N1ZRgQ_G z;AjwqpPdmEx5DC{mbB*YA8=>u0v6{!xMwAp^VML%O&092VA;UtxNN%x2MkO@7zIah z1acU^1Ifoj7JSTtk6ZBD7W|kw2SO6j z5edhkBNflT?JqIRdv4AF=9qSKO^MYc){(h_3YR62SdcTD2;ARqAJXuRL)6?d2HQ%} TL9|Iwu|W)B`^?suwTIbX>Fm0& literal 9320 zcmeHNZEPIH8J>+V@dZNmf*^GS#7iqn5kZb!+K_%CuNJE7rBgm$G_d4(%Z2^fLdwV%(#0>ZH>ir9{__Gi#Bb5Cs2GNsG168%Z~D0L z{k|ye4a$DN_0M}XV|!#17nmno=vfS-FFG8pYw_pDmq^SL*!682M(RK=RqOv{_Iz`g zZ+_oeuUgG83N%N=R4F;u68|F7kZ%vT{#{~z$XCUU8b&Vu-|T79P)WJ~TyGE0D^<7# z;-*tJj9CB99ozc){THb5=9;p^8TnFSr+z-)K)8+ak(MVOzjx#pPaeypcdt8t*Rx+G zu8T6$#QF}Cgr1)?jj@Xa+HMv+d`0{7gs&qx@-=cnVT|548>EZ`7m$hOYg|qhLQB&u zIk3Kt?jpO0=PJruC}XVp`1IzA@sw#9rMQ#Xl*=aaqn$J%vI$b->5BWAjUBJJU)*UJ za7n)qBHzk3m2C_DA=^$Wxp8CX=K79H`tfKf4gK~elZM^dUEgg{_3@9|#xJ$#ZuyL}O0V>!=*OwrPK7>sFdVBK3|BV;cxTkZzog$k(s&pe z|3-cCU?f(tBh~ACjiS&fLE~MnaVOXGrhiR{#gelz_rvNNq9x|Oue+!E-PfvrC!&Ay z+ts(Z{MNj#-uia+b!b(-xr1!Q+>hsD>aCwt%it!a``uU7!*`?Z{%J?$#z(u)>h9@k ziU>Z8?*6%&B@lD}qPy=%>U2M;+=)J0PpVHp3vb93e2sRWjkycQsluvT(e9qs-ILWj zs5&sQK*-r1b3f}|P}|2yg{jBxTc#e1Dl_l5&CEtto=}e|Gqd59Cn`^Q)H-oi)qk&# z&$P^33eT&zoS0YFgg({1Q~g^P_P-W$z3O|Uq)%=;qq}YT_^WLXMt4WQ7kwyd{N|*z zPXV@R=$L!1d%F4@v`LLzt!d6>iA}5Rhe^QL!ASMTsL(5#ICRyK2! z!a7BgUQBqd^10__;3qZC5IOgT=Xp~ZeDM+UGMHC5vrjO80P_-O9u&+gV1C4zdj<0X zmL?DPj5P={9|Cb1? zxmkM%hSv7t+*KS}C+M7+4z2HdBr?Sw(bo1F>13{Gn~cx~AnX+ZbOB(42w)3A*Io~Cu^;B6+*uO8)De-xEendtj+1 zjD5NKcHCX4$Bzl@?=msrr?QBj5$%f}W6PHMFXES*@bM=6+a`Rr31gqG-X6Bz>hVR6 z7q6Wx-a)~sZJ084!4N8h1820j)`2Z3Y(GUPuc3S`WlFus{vDS8wZBFu`uU8JC>K&W zldgf_P@6R_G1^x3?}vz64@R1%n~^IP_mxXb!~GFW+#j)7!({Z=qg;t{4f?CEaoqvQ r6<1qpsD1G&qZYotNct;FR0qffP&=iR%Sezzwe{2Zi2UjcV#)pkNP;e; diff --git a/external/fieldtrip/fileio/private/read_24bit.mexw32 b/external/fieldtrip/fileio/private/read_24bit.mexw32 index 5d59bb6511135e48532e29116cd98785c6713f6a..e9bffc40d198342da522e2cce9bd07d954be1e68 100755 GIT binary patch delta 32 lcmZp$X|S2_fyGniS>(hoK1?wgo1GXJiGul?Ux-Pt0|3}a3|#;K delta 32 lcmZp$X|S2_fyM0Kr_hOCe3$}MHajsc5(V=&zYvpP2LSEv4Z8pU diff --git a/external/fieldtrip/fileio/private/read_24bit.mexw64 b/external/fieldtrip/fileio/private/read_24bit.mexw64 index 174f2dbf7d7212601b822f6e409428eae8aa27a4..e58f4e06ef7048fbc0fb6ecb3d66172c5e4bb2cb 100755 GIT binary patch delta 32 lcmZp0X>ghFfMx#kr;!t%_%In-Z#H6FBnIYhz9Fu`1pxI-4k`cu delta 32 lcmZp0X>ghFfW@2nbLhk;K1_?VHXAW65(D!$-w@Z}0sz@s3~vAc diff --git a/external/fieldtrip/fileio/private/read_4d_hdr.m b/external/fieldtrip/fileio/private/read_4d_hdr.m index 7e20032b..13dca896 100644 --- a/external/fieldtrip/fileio/private/read_4d_hdr.m +++ b/external/fieldtrip/fileio/private/read_4d_hdr.m @@ -38,7 +38,7 @@ fid = fopen(datafile, 'r', 'b'); if fid == -1 - error('Cannot open file %s', datafile); + ft_error('Cannot open file %s', datafile); end fseek(fid, 0, 'eof'); @@ -185,7 +185,7 @@ fseek(fid, nbytes2 - 32, 'cof'); if strcmp(header.process(np).step(ns).hdr.type, 'PDF_Weight_Table'), - warning('reading in weight table: no warranty that this is correct. it seems to work for the Glasgow 248-magnetometer system. if you have some code yourself, and/or would like to test it on your own data, please contact Jan-Mathijs'); + ft_warning('reading in weight table: no warranty that this is correct. it seems to work for the Glasgow 248-magnetometer system. if you have some code yourself, and/or would like to test it on your own data, please contact Jan-Mathijs'); tmpfp = ftell(fid); tmp = fread(fid, 1, 'uint8'); Nchan = fread(fid, 1, 'uint32'); @@ -233,7 +233,7 @@ fid = fopen(configfile, 'r', 'b'); if fid == -1 - error('Cannot open config file'); + ft_error('Cannot open config file'); end header.config_data.version = fread(fid, 1, 'uint16=>uint16'); @@ -499,7 +499,7 @@ case 8%shorted header.config.channel_data(ch).device_data.reserved = fread(fid, 32, 'uchar=>uchar')'; otherwise - error('Unknown device type: %d\n', header.config.channel_data(ch).type); + ft_error('Unknown device type: %d\n', header.config.channel_data(ch).type); end end diff --git a/external/fieldtrip/fileio/private/read_ahdf5_hdr.m b/external/fieldtrip/fileio/private/read_ahdf5_hdr.m index e2e7e155..3b1c04db 100644 --- a/external/fieldtrip/fileio/private/read_ahdf5_hdr.m +++ b/external/fieldtrip/fileio/private/read_ahdf5_hdr.m @@ -2,14 +2,14 @@ %read header if nargin ~= 1 - error('Wrong number of input arguments'); + ft_error('Wrong number of input arguments'); end if ~isempty(datafile), id = h5readatt(datafile, '/', 'id'); if ~strcmp(id, 'AnyWave') - error('This is not the ahf5 format.'); + ft_error('This is not the ahf5 format.'); end ch = h5read(datafile, '/channels'); diff --git a/external/fieldtrip/fileio/private/read_asa.m b/external/fieldtrip/fileio/private/read_asa.m index 7b773870..c9742c9a 100644 --- a/external/fieldtrip/fileio/private/read_asa.m +++ b/external/fieldtrip/fileio/private/read_asa.m @@ -44,7 +44,7 @@ fid = fopen(filename, 'rt'); if fid==-1 - error(sprintf('could not open file %s', filename)); + ft_error(sprintf('could not open file %s', filename)); end if nargin<4 diff --git a/external/fieldtrip/fileio/private/read_asa_bnd.m b/external/fieldtrip/fileio/private/read_asa_bnd.m index f1fed18f..aedb71c8 100644 --- a/external/fieldtrip/fileio/private/read_asa_bnd.m +++ b/external/fieldtrip/fileio/private/read_asa_bnd.m @@ -52,7 +52,7 @@ elseif strcmpi(Unit,'m') pnt = 1000*pnt; else - error(sprintf('Unknown unit of distance for triangulated boundary (%s)', Unit)); + ft_error(sprintf('Unknown unit of distance for triangulated boundary (%s)', Unit)); end bnd.pnt = pnt; diff --git a/external/fieldtrip/fileio/private/read_asa_dip.m b/external/fieldtrip/fileio/private/read_asa_dip.m index d1ea3487..f94ca3c8 100644 --- a/external/fieldtrip/fileio/private/read_asa_dip.m +++ b/external/fieldtrip/fileio/private/read_asa_dip.m @@ -63,7 +63,7 @@ frewind(fid1); if length(time)~=Ntim - error('incorrect timescale'); + ft_error('incorrect timescale'); end while isempty(pos) diff --git a/external/fieldtrip/fileio/private/read_asa_elc.m b/external/fieldtrip/fileio/private/read_asa_elc.m index 8d9ea90f..22978c5d 100644 --- a/external/fieldtrip/fileio/private/read_asa_elc.m +++ b/external/fieldtrip/fileio/private/read_asa_elc.m @@ -45,7 +45,7 @@ elseif strcmpi(Unit,'m') pnt = 1000*pnt; elseif ~isempty(Unit) - error('Unknown unit of distance for electrodes (%s)', Unit); + ft_error('Unknown unit of distance for electrodes (%s)', Unit); end tmp = tokenize(lab{1}); diff --git a/external/fieldtrip/fileio/private/read_asa_mri.m b/external/fieldtrip/fileio/private/read_asa_mri.m index 39424ab2..b4728a5b 100644 --- a/external/fieldtrip/fileio/private/read_asa_mri.m +++ b/external/fieldtrip/fileio/private/read_asa_mri.m @@ -176,7 +176,7 @@ % and in case of VoxelOn..., ASA counts voxels from the corner of the MRI % In both cases, ASA starts counting at [0 0 0], which is C convention % whereas I want to count from the 1st voxel and number that with [1 1 1] -if ~isempty(hdr.posx) & ~isempty(hdr.negy) & ~isempty(hdr.posy) +if ~isempty(hdr.posx) && ~isempty(hdr.negy) && ~isempty(hdr.posy) offset = (dim + [1 1 1])/2; hdr.fiducial.mri.nas = hdr.posx + offset; hdr.fiducial.mri.lpa = hdr.posy + offset; diff --git a/external/fieldtrip/fileio/private/read_asa_msr.m b/external/fieldtrip/fileio/private/read_asa_msr.m index efee0d6e..7efe09eb 100644 --- a/external/fieldtrip/fileio/private/read_asa_msr.m +++ b/external/fieldtrip/fileio/private/read_asa_msr.m @@ -47,7 +47,7 @@ elseif strcmpi(UnitT,'s') time = 1000*time; elseif ~isempty(UnitT) - error(sprintf('Unknown unit of time (%s)', UnitT)); + ft_error(sprintf('Unknown unit of time (%s)', UnitT)); end if strcmpi(UnitM,'uv') @@ -63,7 +63,7 @@ elseif strcmpi(UnitM,'pt') val = 1000*val; elseif ~isempty(UnitM) - error(sprintf('Unknown unit of measurement (%s)', UnitM)); + ft_error(sprintf('Unknown unit of measurement (%s)', UnitM)); end if length(size(lab))==2 diff --git a/external/fieldtrip/fileio/private/read_asa_vol.m b/external/fieldtrip/fileio/private/read_asa_vol.m index 1277494d..4ed2e227 100644 --- a/external/fieldtrip/fileio/private/read_asa_vol.m +++ b/external/fieldtrip/fileio/private/read_asa_vol.m @@ -37,7 +37,7 @@ bnd3 = read_asa(fn, 'Boundary3', '%s'); bnd4 = read_asa(fn, 'Boundary4', '%s'); -if ~isempty(radii) | ~isempty(pos) +if ~isempty(radii) || ~isempty(pos) % this appears to be a spherical volume conductor if strcmpi(UnitP,'mm') radii = 1*radii; @@ -49,7 +49,7 @@ radii = 1000*radii; pos = 1000*pos; else - error(sprintf('Unknown unit of distance for volume (%s)', UnitP)); + ft_error(sprintf('Unknown unit of distance for volume (%s)', UnitP)); end end @@ -60,7 +60,7 @@ elseif strcmpi(UnitC,'s/mm') cond = cond/1000; else - error(sprintf('Unknown unit of conductivity for volume (%s)', UnitC)); + ft_error(sprintf('Unknown unit of conductivity for volume (%s)', UnitC)); end if ~isempty(radii) @@ -84,7 +84,7 @@ vol.bnd(4) = read_asa_bnd(fullfile(path, bnd4)); end if Nbnd>=5 - error('cannot read more than 4 boundaries'); + ft_error('cannot read more than 4 boundaries'); end % if there is a precomputed matrix, read it from an external file @@ -95,7 +95,7 @@ mab_file = read_asa(fullfile(path, mat_file), 'Matrix', '%s'); fid = fopen(fullfile(path, mab_file), 'rb', 'ieee-le'); if fid==-1 - error(sprintf('could not open file %s', mab_file)); + ft_error(sprintf('could not open file %s', mab_file)); else vol.mat = fread(fid, [nr nc], 'float32'); fclose(fid); diff --git a/external/fieldtrip/fileio/private/read_besa_avr.m b/external/fieldtrip/fileio/private/read_besa_avr.m index 20534492..6d433f92 100644 --- a/external/fieldtrip/fileio/private/read_besa_avr.m +++ b/external/fieldtrip/fileio/private/read_besa_avr.m @@ -88,7 +88,7 @@ end if ~ok - error('Could not interpret the header information.'); + ft_error('Could not interpret the header information.'); end % rewind to the beginning of the file, skip the header line @@ -117,7 +117,7 @@ lbl = strrep(lbl ,'EEG ', ''); % remove the channel type avr.label = lbl; else - warning('Could not create channels labels.'); + ft_warning('Could not create channels labels.'); end end diff --git a/external/fieldtrip/fileio/private/read_besa_besa.m b/external/fieldtrip/fileio/private/read_besa_besa.m index be266889..59e67681 100644 --- a/external/fieldtrip/fileio/private/read_besa_besa.m +++ b/external/fieldtrip/fileio/private/read_besa_besa.m @@ -1,9 +1,8 @@ - function [data] = read_besa_besa(filename, header, begsample, endsample, chanindx) -%% Reads BESA .besa format files + +% READ_BESA_BESA reads data and header information from a BESA file % See formatting document here % -% % Use as % [header] = read_besa_besa(filename); % where @@ -15,12 +14,12 @@ % header.nSamplesPre number of pre-trigger samples in each trial % header.nTrials number of trials % header.label cell-array with labels of each channel -% header.orig detailled EDF header information +% header.orig detailed BESA header information % % Use as % [header] = read_besa_besa(filename, [], chanindx); % where -% filename name of the datafile, including the .edf extension +% filename name of the datafile, including the .besa extension % chanindx index of channels to read (optional, default is all) % Note that since % This returns a header structure with the following elements @@ -30,24 +29,38 @@ % header.nSamplesPre number of pre-trigger samples in each trial % header.nTrials number of trials % header.label cell-array with labels of each channel -% header.orig detailled EDF header information +% header.orig detailed BESA header information % % Or use as % [dat] = read_besa_besa(filename, header, begsample, endsample, chanindx); % where -% filename name of the datafile, including the .edf extension +% filename name of the datafile, including the .besa extension % header header structure, see above % begsample index of the first sample to read % endsample index of the last sample to read % chanindx index of channels to read (optional, default is all) % This returns a Nchans X Nsamples data matrix -% -% -% 2016 - Kristopher Anderson, Knight Lab, Helen Wills Neuroscience Institute, University of California, Berkeley +% Copyright (C) 2015-2017, Kristopher Anderson & Arjen Stolk +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ -% For debugging %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% TODO -warning on;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% TODO switch nargin case 1 @@ -57,12 +70,9 @@ case 3 chanindx=begsample; case 4 - error('ReadBesaMatlab:ErrorInput','Number of input arguments should be 1,2,3, or 5'); + ft_error('ReadBesaMatlab:ErrorInput','Number of input arguments should be 1,2,3, or 5'); end - - - needhdr = (nargin==1)||(nargin==3); needevt = (nargin==2); % Not implemented yet %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% TODO needdat = (nargin==5); @@ -79,14 +89,23 @@ data.orig.chansel = chanindx; % header.orig.chansel is used for reading channels from data data.nChans = numel(chanindx); data.label = data.label(chanindx); - data.orig.channel_info.orig_n_channels = data.orig.channel_info.n_channels; - data.orig.channel_info.n_channels = numel(chanindx); - data.orig.channel_info.orig_lsbs = data.orig.channel_info.lsbs; data.orig.channel_info.lsbs = data.orig.channel_info.lsbs(chanindx); - data.orig.channel_info.orig_channel_labels = data.orig.channel_info.channel_labels; data.orig.channel_info.channel_labels = data.orig.channel_info.channel_labels(chanindx); - data.orig.channel_info.orig_channel_states = data.orig.channel_info.channel_states; data.orig.channel_info.channel_states = data.orig.channel_info.channel_states(chanindx); + if isfield(data.orig.channel_info, 'channel_units') % test data did not have this field + data.chanunit = data.orig.channel_info.channel_units; + else + data.chanunit = repmat({'unknown'}, size(data.orig.channel_info.channel_states)); % unknown + end + data.chantype = repmat({'unknown'}, size(data.orig.channel_info.channel_states)); % start with unknown + data.chantype([data.orig.channel_info.channel_states(:).BSA_CHANTYPE_TRIGGER]==1) = {'trigger'}; % test data did not have any of the below set to 1 + data.chantype([data.orig.channel_info.channel_states(:).BSA_CHANTYPE_CORTICALGRID]==1) = {'ecog'}; + data.chantype([data.orig.channel_info.channel_states(:).BSA_CHANTYPE_INTRACRANIAL]==1) = {'ieeg'}; + data.chantype([data.orig.channel_info.channel_states(:).BSA_CHANTYPE_SCALPELECTRODE]==1) = {'eeg'}; + data.chantype([data.orig.channel_info.channel_states(:).BSA_CHANTYPE_MAGNETOMETER]==1) = {'megmag'}; + data.chantype([data.orig.channel_info.channel_states(:).BSA_CHANTYPE_AXIAL_GRADIOMETER]==1) = {'megaxial'}; + data.chantype([data.orig.channel_info.channel_states(:).BSA_CHANTYPE_PLANAR_GRADIOMETER]==1) = {'megplanar'}; + data.chantype([data.orig.channel_info.channel_states(:).BSA_CHANTYPE_MEGREFERENCE]==1) = {'megref'}; return end @@ -164,7 +183,7 @@ % Check for necessary values if(~isfield(header.orig.channel_info,'n_channels')) fclose(fid); - error('ReadBesaMatlab:ErrorNoNChannels','header.orig.channel_info.n_channels does not exist. This is needed for reading data blocks'); + ft_error('ReadBesaMatlab:ErrorNoNChannels','header.orig.channel_info.n_channels does not exist. This is needed for reading data blocks'); end if(~isfield(header.orig.channel_info,'lsbs')) % No least significant bit values found, so setting them all to 1.0 @@ -223,7 +242,7 @@ % Skip to start of BDAT section if(fseek(fid,double(bdat_offset),'bof') == -1) % double() because Windows can't seek to uint64 fclose(fid); - error('ReadBesaMatlab:ErrorFseek','fseek to %d failed [BDAT]',bdat_offset); + ft_error('ReadBesaMatlab:ErrorFseek','fseek to %d failed [BDAT]',bdat_offset); end % Read BDAT tag and offset @@ -233,7 +252,7 @@ if(file_length < (ftell(fid)+ofst_BDAT)) expected_length = ftell(fid)+ofst_BDAT; fclose(fid); - error('ReadBesaMatlab:ErrorFileTooShortForDataBlock','Data block expected file at least %d bytes long but file is %d bytes long',expected_length,file_length); + ft_error('ReadBesaMatlab:ErrorFileTooShortForDataBlock','Data block expected file at least %d bytes long but file is %d bytes long',expected_length,file_length); end % Determine type of data in this block @@ -377,7 +396,7 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) otherwise current_loc = ftell(fid); fclose(fid); - error('ReadBesaMatlab:ErrorBDATReadPrefixValueUnknownScheme','Unknown scheme CH:%d prefix_val:%d File offset:%d',channel_n,prefix_val,current_loc); + ft_error('ReadBesaMatlab:ErrorBDATReadPrefixValueUnknownScheme','Unknown scheme CH:%d prefix_val:%d File offset:%d',channel_n,prefix_val,current_loc); end end @@ -389,7 +408,7 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) % Check that expected amout of data was read if((data_block_offset+double(data_block_length)) ~= ftell(fid)) - warning('ReadBesaMatlab:WarningDidNotReadExactBlockLength','%d bytes off. Read %d bytes from data block. Should have read %d bytes', ... + ft_warning('ReadBesaMatlab:WarningDidNotReadExactBlockLength','%d bytes off. Read %d bytes from data block. Should have read %d bytes', ... (ftell(fid)-data_block_offset)-double(data_block_length),ftell(fid)-data_block_offset,double(data_block_length)); end @@ -434,7 +453,7 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) expected_samples = numel(outbuffer((last_outbuffer_idx+1):end)); received_samples = numel(firstscheme_lookuptable(inbuffer+1)); fclose(fid); - error('ReadBesaMatlab:ErrorUnexpectedNSamplesFromPreCompression','Expected %d samples, but got %d samples. [first scheme, no ABs]', ... + ft_error('ReadBesaMatlab:ErrorUnexpectedNSamplesFromPreCompression','Expected %d samples, but got %d samples. [first scheme, no ABs]', ... expected_samples,received_samples); else rethrow(ME); @@ -458,7 +477,7 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) expected_samples = numel(outbuffer((last_outbuffer_idx+1):(last_outbuffer_idx+2*(ab_idx-last_ab_idx-1)))); received_samples = numel(firstscheme_lookuptable(inbuffer((last_ab_idx+1):(ab_idx-1))+1,:)); fclose(fid); - error('ReadBesaMatlab:ErrorUnexpectedNSamplesFromPreCompression','Expected %d samples, but got %d samples. [first scheme, middle of buffer]', ... + ft_error('ReadBesaMatlab:ErrorUnexpectedNSamplesFromPreCompression','Expected %d samples, but got %d samples. [first scheme, middle of buffer]', ... expected_samples,received_samples); else rethrow(ME); @@ -493,7 +512,7 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) else % not an alowed announcing byte value fclose(fid); - error('ReadBesaMatlab:ErrorABOutOfRange','Announcing byte out of range: %d',inbuffer(ab_idx)); + ft_error('ReadBesaMatlab:ErrorABOutOfRange','Announcing byte out of range: %d',inbuffer(ab_idx)); end % Go to next AB @@ -512,7 +531,7 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) expected_samples = numel(outbuffer((last_outbuffer_idx+1):end)); received_samples = numel(firstscheme_lookuptable(inbuffer((last_ab_idx+1):end)+1,:)); fclose(fid); - error('ReadBesaMatlab:ErrorUnexpectedNSamplesFromPreCompression','Expected %d samples, but got %d samples. [first scheme, end of buffer]', ... + ft_error('ReadBesaMatlab:ErrorUnexpectedNSamplesFromPreCompression','Expected %d samples, but got %d samples. [first scheme, end of buffer]', ... expected_samples,received_samples); else rethrow(ME); @@ -556,7 +575,7 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) expected_samples = numel(outbuffer((last_outbuffer_idx+1):end)); received_samples = numel(secondscheme_lookup(inbuffer+1,meshgrid_vals)); fclose(fid); - error('ReadBesaMatlab:ErrorUnexpectedNSamplesFromPreCompression','Expected %d samples, but got %d samples. [second scheme, no ABs]', ... + ft_error('ReadBesaMatlab:ErrorUnexpectedNSamplesFromPreCompression','Expected %d samples, but got %d samples. [second scheme, no ABs]', ... expected_samples,received_samples); else rethrow(ME); @@ -598,7 +617,7 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) else % not an allowed announcing byte value fclose(fid); - error('ReadBesaMatlab:ErrorABOutOfRange','Announcing byte out of range [second scheme]: %d',inbuffer(ab_idx)); + ft_error('ReadBesaMatlab:ErrorABOutOfRange','Announcing byte out of range [second scheme]: %d',inbuffer(ab_idx)); end % Go to next AB @@ -617,7 +636,7 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) expected_samples = numel(outbuffer((last_outbuffer_idx+1):end)); received_samples = numel(secondscheme_lookup(inbuffer((last_ab_idx+1):end)+1,meshgrid_vals)); fclose(fid); - error('ReadBesaMatlab:ErrorUnexpectedNSamplesFromPreCompression','Expected %d samples, but got %d samples. [second scheme, end of buffer]', ... + ft_error('ReadBesaMatlab:ErrorUnexpectedNSamplesFromPreCompression','Expected %d samples, but got %d samples. [second scheme, end of buffer]', ... expected_samples,received_samples); else rethrow(ME); @@ -688,7 +707,7 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) expected_samples = numel(outbuffer((last_outbuffer_idx+1):end)); received_samples = numel(thirdscheme_lookup(inbuffer+1,meshgrid_vals)); fclose(fid); - error('ReadBesaMatlab:ErrorUnexpectedNSamplesFromPreCompression','Expected %d samples, but got %d samples. [third scheme, no ABs]', ... + ft_error('ReadBesaMatlab:ErrorUnexpectedNSamplesFromPreCompression','Expected %d samples, but got %d samples. [third scheme, no ABs]', ... expected_samples,received_samples); else rethrow(ME); @@ -730,7 +749,7 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) else % not an allowed announcing byte value fclose(fid); - error('ReadBesaMatlab:ErrorABOutOfRange','Announcing byte out of range [third scheme]: %d',inbuffer(ab_idx)); + ft_error('ReadBesaMatlab:ErrorABOutOfRange','Announcing byte out of range [third scheme]: %d',inbuffer(ab_idx)); end % Go to next AB @@ -749,7 +768,7 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) expected_samples = numel(outbuffer((last_outbuffer_idx+1):end)); received_samples = numel(thirdscheme_lookup(inbuffer((last_ab_idx+1):end)+1,meshgrid_vals)); fclose(fid); - error('ReadBesaMatlab:ErrorUnexpectedNSamplesFromPreCompression','Expected %d samples, but got %d samples. [third scheme, end of buffer]', ... + ft_error('ReadBesaMatlab:ErrorUnexpectedNSamplesFromPreCompression','Expected %d samples, but got %d samples. [third scheme, end of buffer]', ... expected_samples,received_samples); else rethrow(ME); @@ -819,35 +838,15 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) if ~strcmp(expected_tag,out_tag) curr_offset = ftell(fid); fclose(fid); - error('ReadBesaMatlab:ErrorTagMismatch','Expecting [%s] but read [%s] at offset %d',expected_tag,out_tag,curr_offset); + ft_error('ReadBesaMatlab:ErrorTagMismatch','Expecting [%s] but read [%s] at offset %d',expected_tag,out_tag,curr_offset); end end % Read offset value following tag out_offset = fread(fid,1,'*uint32'); - - - - function [header] = read_besa_besa_header(fname) -%% Reads BESA .besa format header information and skips data -% See formatting document here -% -% [alldata,file_info,channel_info,tags,events] = readbesa(fname) -% -% inputs: -% fname [string] - path to .besa file -% -% outputs: -% header [structure] - Header information -% -% -% -% 2016 - Kristopher Anderson, Knight Lab, Helen Wills Neuroscience Institute, University of California, Berkeley - -% For debugging %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% TODO -warning on;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% TODO +% READ_BESA_BESA_HEADER reads header information from a BESA fileheader and skips data %% Open file [fid,msg] = fopen(fname,'r'); @@ -879,15 +878,15 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) BCAL_offset = fread(fid,1,'*int64'); otherwise % Unrecognzed tag. Try to skip forward by offset - warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); + ft_warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); if((ftell(fid)+current_length) <= file_length) if(fseek(fid,current_length,'cof') == -1) fclose(fid); - error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in header block [BCF1]))',current_length); + ft_error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in header block [BCF1]))',current_length); end else fclose(fid); - error('ReadBesaMatlab:ErrorSkippingForwardAfterUnexpectedTag','Offset after unexpected [%d] tag points to beyond eof [%d]',current_length,file_length); + ft_error('ReadBesaMatlab:ErrorSkippingForwardAfterUnexpectedTag','Offset after unexpected [%d] tag points to beyond eof [%d]',current_length,file_length); end end @@ -896,15 +895,15 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) % Check for necessary header data if ~exist('BFMI_offset','var') fclose(fid); - error('ReadBesaMatlab:ErrorNoHeaderBFMI','No BFMI block found in header'); + ft_error('ReadBesaMatlab:ErrorNoHeaderBFMI','No BFMI block found in header'); end if ~exist('BTAG_offset','var') fclose(fid); - error('ReadBesaMatlab:ErrorNoHeaderBTAG','No BTAG block found in header'); + ft_error('ReadBesaMatlab:ErrorNoHeaderBTAG','No BTAG block found in header'); end if ~exist('BCAL_offset','var') fclose(fid); - error('ReadBesaMatlab:ErrorNoHeaderBCAL','No BCAL block found in header'); + ft_error('ReadBesaMatlab:ErrorNoHeaderBCAL','No BCAL block found in header'); end %% 'tag list' blocks @@ -921,7 +920,7 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) % This does not take into account length of final block but might still be useful if(file_length <= header.orig.tags.tags.position(end)) fclose(fid); - error('ReadBesaMatlab:ErrorFileTooShort','Expected file at least %d bytes long but file is %d bytes long',header.orig.tags.tags(end).position,file_length); + ft_error('ReadBesaMatlab:ErrorFileTooShort','Expected file at least %d bytes long but file is %d bytes long',header.orig.tags.tags(end).position,file_length); end %% 'file main info' blocks @@ -945,7 +944,7 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) % NEED TO IMPLEMENT OVERWRITES %%%%%%%%%%%%%%%%%%%%%%%%%%% TODO if ~isfield(header.orig.channel_info,'n_channels') - error('ReadBesaMatlab:ErrorNoHeaderNChannels','Missing number of channels in header [BCAL:CHNR]'); + ft_error('ReadBesaMatlab:ErrorNoHeaderNChannels','Missing number of channels in header [BCAL:CHNR]'); end % Combine info from channel_info.coord_data and channel_info.channel_states to get actual coordinate data @@ -1011,13 +1010,13 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) if isfield(header.orig.file_info,'s_rate') header.Fs = header.orig.file_info.s_rate; else - warning('ReadBesaMatlab:WarningMissingHeaderInfo','Missing sample rate in header'); + ft_warning('ReadBesaMatlab:WarningMissingHeaderInfo','Missing sample rate in header'); header.Fs = []; end if isfield(header.orig.file_info,'n_samples') header.nSamples = header.orig.file_info.n_samples; else - warning('ReadBesaMatlab:WarningMissingHeaderInfo','Missing number of samples in header'); + ft_warning('ReadBesaMatlab:WarningMissingHeaderInfo','Missing number of samples in header'); header.nSamples = []; end @@ -1028,7 +1027,7 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) if isfield(header.orig.channel_info,'channel_labels') header.label = header.orig.channel_info.channel_labels; else - warning('ReadBesaMatlab:WarningMissingHeaderInfo','Missing channel labels in header.orig. Creating default channel names'); + ft_warning('ReadBesaMatlab:WarningMissingHeaderInfo','Missing channel labels in header.orig. Creating default channel names'); for channel_n = 1:header.nChans header.label{channel_n} = sprintf('chan%03d', channel_n); end @@ -1057,7 +1056,7 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) % Skip to start of BTAG section if(fseek(fid,tags.next_BTAG_ofst,'bof') == -1) fclose(fid); - error('ReadBesaMatlab:ErrorFseek','fseek to %d failed [BTAG]',tags.next_BTAG_ofst); + ft_error('ReadBesaMatlab:ErrorFseek','fseek to %d failed [BTAG]',tags.next_BTAG_ofst); end tags.offsets(end+1) = tags.next_BTAG_ofst; @@ -1079,15 +1078,15 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) tags.tags.n_samples(tags.n_tags) = double(fread(fid,1,'*uint32')); otherwise % Unrecognzed tag. Try to skip forward by offset - warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); + ft_warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); if((ftell(fid)+current_length) <= file_length) if(fseek(fid,current_length,'cof') == -1) fclose(fid); - error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [BTAG]))',current_length); + ft_error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [BTAG]))',current_length); end else fclose(fid); - error('ReadBesaMatlab:ErrorSkippingForwardAfterUnexpectedTag','Offset after unexpected [%d] tag points to beyond eof [%d]',current_length,file_length); + ft_error('ReadBesaMatlab:ErrorSkippingForwardAfterUnexpectedTag','Offset after unexpected [%d] tag points to beyond eof [%d]',current_length,file_length); end end end @@ -1095,7 +1094,7 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) % Check that expected amout of file was read expected_length = double(tag_block_length) + 8; % 8 for tag and offset if((tags.offsets(end)+expected_length) ~= ftell(fid)) - warning('ReadBesaMatlab:WarningDidNotReadExactBlockLength','%d bytes off. Read %d bytes from tag block. Should have read %d bytes', ... + ft_warning('ReadBesaMatlab:WarningDidNotReadExactBlockLength','%d bytes off. Read %d bytes from tag block. Should have read %d bytes', ... (ftell(fid)-tags.offsets(end))-expected_length,ftell(fid)-tags.offsets(end),expected_length); end @@ -1111,7 +1110,7 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) % Skip to start of BFMI section if(fseek(fid,file_info.next_BFMI_ofst,'bof') == -1) fclose(fid); - error('ReadBesaMatlab:ErrorFseek','fseek to %d failed [BFMI]',file_info.next_BFMI_ofst); + ft_error('ReadBesaMatlab:ErrorFseek','fseek to %d failed [BFMI]',file_info.next_BFMI_ofst); end file_info.offsets(end+1) = file_info.next_BFMI_ofst; @@ -1167,15 +1166,15 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) file_info.institution.phone_number = read_chars(fid,current_length); otherwise % Unrecognzed tag. Try to skip forward by offset - warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); + ft_warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); if((ftell(fid)+current_length) <= file_length) if(fseek(fid,current_length,'cof') == -1) fclose(fid); - error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [BFMI:FINA]))',current_length); + ft_error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [BFMI:FINA]))',current_length); end else fclose(fid); - error('ReadBesaMatlab:ErrorSkippingForwardAfterUnexpectedTag','Offset after unexpected [%d] tag points to beyond eof [%d]',current_length,file_length); + ft_error('ReadBesaMatlab:ErrorSkippingForwardAfterUnexpectedTag','Offset after unexpected [%d] tag points to beyond eof [%d]',current_length,file_length); end end end @@ -1241,15 +1240,15 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) file_info.staff(end).function = read_chars(fid,current_length); otherwise % Unrecognzed tag. Try to skip forward by offset - warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); + ft_warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); if((ftell(fid)+current_length) <= file_length) if(fseek(fid,current_length,'cof') == -1) fclose(fid); - error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [BFMI:RSTA]))',current_length); + ft_error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [BFMI:RSTA]))',current_length); end else fclose(fid); - error('ReadBesaMatlab:ErrorSkippingForwardAfterUnexpectedTag','Offset after unexpected [%d] tag points to beyond eof [%d]',current_length,file_length); + ft_error('ReadBesaMatlab:ErrorSkippingForwardAfterUnexpectedTag','Offset after unexpected [%d] tag points to beyond eof [%d]',current_length,file_length); end end end @@ -1313,15 +1312,15 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) file_info.subject.address.phone_number = read_chars(fid,current_length); otherwise % Unrecognzed tag. Try to skip forward by offset - warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); + ft_warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); if((ftell(fid)+current_length) <= file_length) if(fseek(fid,current_length,'cof') == -1) fclose(fid); - error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [BFMI:PAAD]))',current_length); + ft_error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [BFMI:PAAD]))',current_length); end else fclose(fid); - error('ReadBesaMatlab:ErrorSkippingForwardAfterUnexpectedTag','Offset after unexpected [%d] tag points to beyond eof [%d]',current_length,file_length); + ft_error('ReadBesaMatlab:ErrorSkippingForwardAfterUnexpectedTag','Offset after unexpected [%d] tag points to beyond eof [%d]',current_length,file_length); end end end @@ -1346,15 +1345,15 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) file_info.additional_info.inf2 = read_chars(fid,current_length); otherwise % Unrecognzed tag. Try to skip forward by offset - warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); + ft_warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); if((ftell(fid)+current_length) <= file_length) if(fseek(fid,current_length,'cof') == -1) fclose(fid); - error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [BFMI]))',current_length); + ft_error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [BFMI]))',current_length); end else fclose(fid); - error('ReadBesaMatlab:ErrorSkippingForwardAfterUnexpectedTag','Offset after unexpected [%d] tag points to beyond eof [%d]',current_length,file_length); + ft_error('ReadBesaMatlab:ErrorSkippingForwardAfterUnexpectedTag','Offset after unexpected [%d] tag points to beyond eof [%d]',current_length,file_length); end end end @@ -1362,7 +1361,7 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) % Check that expected amout of file was read expected_length = double(fileinfo_block_length) + 8; % 8 for tag and offset if((file_info.offsets(end)+expected_length) ~= ftell(fid)) - warning('ReadBesaMatlab:WarningDidNotReadExactBlockLength','%d bytes off. Read %d bytes from file info block. Should have read %d bytes', ... + ft_warning('ReadBesaMatlab:WarningDidNotReadExactBlockLength','%d bytes off. Read %d bytes from file info block. Should have read %d bytes', ... (ftell(fid)-file_info.offsets(end))-expected_length,ftell(fid)-file_info.offsets(end),expected_length); end @@ -1378,7 +1377,7 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) % Skip to start of BCAL section if(fseek(fid,channel_info.next_BCAL_ofst,'bof') == -1) fclose(fid); - error('ReadBesaMatlab:ErrorFseek','fseek to %d failed [BCAL]',channel_info.next_BCAL_ofst); + ft_error('ReadBesaMatlab:ErrorFseek','fseek to %d failed [BCAL]',channel_info.next_BCAL_ofst); end channel_info.offsets(end+1) = channel_info.next_BCAL_ofst; @@ -1522,12 +1521,12 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) channel_info.filter_info(channel_n).pass_freq = fread(fid,1,'*single'); channel_info.filter_info(channel_n).pass_width = fread(fid,1,'*single'); if(ftell(fid) ~= filter_object_offset+filter_object_size) - warning('ReadBesaMatlab:WarningFilterInfoObject','Did not read expected number bytes in filter object [BCAL:CHFI]. Filter information may be incorrect'); + ft_warning('ReadBesaMatlab:WarningFilterInfoObject','Did not read expected number bytes in filter object [BCAL:CHFI]. Filter information may be incorrect'); end end % Check that expected amout of file was read and move to correct position if not if(ftell(fid) ~= offset_end_chfi) - warning('ReadBesaMatlab:WarningFilterInfoBlock','Did not read expected number of bytes in filter info block [BCAL:CHFI]. Filter information may be incorrect. Skipping to next block'); + ft_warning('ReadBesaMatlab:WarningFilterInfoBlock','Did not read expected number of bytes in filter info block [BCAL:CHFI]. Filter information may be incorrect. Skipping to next block'); fseek(fid,offset_end_chfi+1,'bof'); end % Somewhat complicated structure, no test data %%%%%%%%%%%%%%%%%% TODO @@ -1542,31 +1541,31 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) % BESA CTF component. Internal use only if(fseek(fid,current_length,'cof') == -1) fclose(fid); - error('ReadBesaMatlab:ErrorFseek','fseek to %d failed [BCAL:%s]',current_length,current_tag); + ft_error('ReadBesaMatlab:ErrorFseek','fseek to %d failed [BCAL:%s]',current_length,current_tag); end case 'COMH' % BESA head transformation. Internal use only if(fseek(fid,current_length,'cof') == -1) fclose(fid); - error('ReadBesaMatlab:ErrorFseek','fseek to %d failed [BCAL:%s]',current_length,current_tag); + ft_error('ReadBesaMatlab:ErrorFseek','fseek to %d failed [BCAL:%s]',current_length,current_tag); end case 'CHSC' % BESA spatial components. Internal use only if(fseek(fid,current_length,'cof') == -1) fclose(fid); - error('ReadBesaMatlab:ErrorFseek','fseek to %d failed [BCAL:%s]',current_length,current_tag); + ft_error('ReadBesaMatlab:ErrorFseek','fseek to %d failed [BCAL:%s]',current_length,current_tag); end otherwise % Unrecognzed tag. Try to skip forward by offset - warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); + ft_warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); if((ftell(fid)+current_length) <= file_length) if(fseek(fid,current_length,'cof') == -1) fclose(fid); - error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag [BCAL]))',current_length); + ft_error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag [BCAL]))',current_length); end else fclose(fid); - error('ReadBesaMatlab:ErrorSkippingForwardAfterUnexpectedTag','Offset after unexpected [%d] tag points to beyond eof [%d]',current_length,file_length); + ft_error('ReadBesaMatlab:ErrorSkippingForwardAfterUnexpectedTag','Offset after unexpected [%d] tag points to beyond eof [%d]',current_length,file_length); end end end @@ -1574,7 +1573,7 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) % Check that expected amout of file was read expected_length = double(channel_block_length) + 8; % 8 for tag and offset if((channel_info.offsets(end)+expected_length) ~= ftell(fid)) - warning('ReadBesaMatlab:WarningDidNotReadExactBlockLength','%d bytes off. Read %d bytes from channel block. Should have read %d bytes', ... + ft_warning('ReadBesaMatlab:WarningDidNotReadExactBlockLength','%d bytes off. Read %d bytes from channel block. Should have read %d bytes', ... (ftell(fid)-channel_info.offsets(end))-expected_length,ftell(fid)-channel_info.offsets(end),expected_length); end @@ -1593,7 +1592,7 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) % Skip to start of BEVT section if(fseek(fid,BEVT_offset,'bof') == -1) fclose(fid); - error('ReadBesaMatlab:ErrorFseek','fseek to %d failed [BEVT]',BEVT_offset); + ft_error('ReadBesaMatlab:ErrorFseek','fseek to %d failed [BEVT]',BEVT_offset); end % Read BEVT tag and offset @@ -1616,15 +1615,15 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) events.version = double(fread(fid,1,'*uint32')); otherwise % Unrecognzed tag. Try to skip forward by offset - warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); + ft_warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); if((ftell(fid)+current_length) <= file_length) if(fseek(fid,current_length,'cof') == -1) fclose(fid); - error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [BEVT:HEAD]))',current_length); + ft_error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [BEVT:HEAD]))',current_length); end else fclose(fid); - error('ReadBesaMatlab:ErrorSkippingForwardAfterUnexpectedTag','Offset after unexpected [%d] tag points to beyond eof [%d]',current_length,file_length); + ft_error('ReadBesaMatlab:ErrorSkippingForwardAfterUnexpectedTag','Offset after unexpected [%d] tag points to beyond eof [%d]',current_length,file_length); end end end @@ -1638,7 +1637,7 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) % Check that expected amout of file was read expected_length = double(event_block_length) + 8; % 8 for tag and offset if((BEVT_offset+expected_length) ~= ftell(fid)) - warning('ReadBesaMatlab:WarningDidNotReadExactBlockLength','%d bytes off. Read %d bytes from event block. Should have read %d bytes', ... + ft_warning('ReadBesaMatlab:WarningDidNotReadExactBlockLength','%d bytes off. Read %d bytes from event block. Should have read %d bytes', ... (ftell(fid)-BEVT_offset)-expected_length,ftell(fid)-BEVT_offset,expected_length); end @@ -1671,14 +1670,14 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) % used by BESA internally if(fseek(fid,event_length,'cof') == -1) fclose(fid); - error('ReadBesaMatlab:ErrorFseek','fseek to %d failed [LIST:MPS]',event_length); + ft_error('ReadBesaMatlab:ErrorFseek','fseek to %d failed [LIST:MPS]',event_length); end case 'MPSC' % Classified multiple pattern search event tag % used by BESA internally if(fseek(fid,event_length,'cof') == -1) fclose(fid); - error('ReadBesaMatlab:ErrorFseek','fseek to %d failed [LIST:MPSC]',event_length); + ft_error('ReadBesaMatlab:ErrorFseek','fseek to %d failed [LIST:MPSC]',event_length); end case 'PATT' % Pattern event tag @@ -1700,10 +1699,10 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) event_obj = read_event_tag_imp(fid,ftell(fid),event_length,event_obj); otherwise % Unrecognzed tag. Try to skip forward by offset - warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',event_tag,ftell(fid)); + ft_warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',event_tag,ftell(fid)); if(fseek(fid,event_length,'cof') == -1) fclose(fid); - error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [LIST]))',event_length); + ft_error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [LIST]))',event_length); end end @@ -1752,10 +1751,10 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) event_obj.state.EVT_STATE_DELETED = logical(bitand(event_obj.state.value,uint32(hex2dec('01000000')),'uint32')); otherwise % Unrecognzed tag. Try to skip forward by offset - warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); + ft_warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); if(fseek(fid,current_length,'cof') == -1) fclose(fid); - error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [BEVT:BASE]))',current_length); + ft_error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [BEVT:BASE]))',current_length); end end end @@ -1773,10 +1772,10 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) event_obj = read_event_tag_base(fid,ftell(fid),current_length,event_obj); otherwise % Unrecognzed tag. Try to skip forward by offset - warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); + ft_warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); if(fseek(fid,current_length,'cof') == -1) fclose(fid); - error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [BEVT:COMM]))',current_length); + ft_error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [BEVT:COMM]))',current_length); end end end @@ -1791,10 +1790,10 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) event_obj = read_event_tag_base(fid,ftell(fid),current_length,event_obj); otherwise % Unrecognzed tag. Try to skip forward by offset - warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); + ft_warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); if(fseek(fid,current_length,'cof') == -1) fclose(fid); - error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [BEVT:MARK]))',current_length); + ft_error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [BEVT:MARK]))',current_length); end end end @@ -1809,10 +1808,10 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) event_obj = read_event_tag_comm(fid,ftell(fid),current_length,event_obj); otherwise % Unrecognzed tag. Try to skip forward by offset - warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); + ft_warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); if(fseek(fid,current_length,'cof') == -1) fclose(fid); - error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [BEVT:GENE]))',current_length); + ft_error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [BEVT:GENE]))',current_length); end end end @@ -1845,10 +1844,10 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) event_obj = read_event_tag_comm(fid,ftell(fid),current_length,event_obj); otherwise % Unrecognzed tag. Try to skip forward by offset - warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); + ft_warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); if(fseek(fid,current_length,'cof') == -1) fclose(fid); - error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [BEVT:SEGM]))',current_length); + ft_error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [BEVT:SEGM]))',current_length); end end end @@ -1869,10 +1868,10 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) event_obj = read_event_tag_comm(fid,ftell(fid),current_length,event_obj); otherwise % Unrecognzed tag. Try to skip forward by offset - warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); + ft_warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); if(fseek(fid,current_length,'cof') == -1) fclose(fid); - error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [BEVT:ASGM]))',current_length); + ft_error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [BEVT:ASGM]))',current_length); end end end @@ -1887,10 +1886,10 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) event_obj = read_event_tag_base(fid,ftell(fid),current_length,event_obj); otherwise % Unrecognzed tag. Try to skip forward by offset - warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); + ft_warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); if(fseek(fid,current_length,'cof') == -1) fclose(fid); - error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [BEVT:PATT]))',current_length); + ft_error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [BEVT:PATT]))',current_length); end end end @@ -1911,10 +1910,10 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) event_obj = read_event_tag_comm(fid,ftell(fid),current_length,event_obj); otherwise % Unrecognzed tag. Try to skip forward by offset - warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); + ft_warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); if(fseek(fid,current_length,'cof') == -1) fclose(fid); - error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [BEVT:TRIG]))',current_length); + ft_error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [BEVT:TRIG]))',current_length); end end end @@ -1946,12 +1945,12 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) case 'MPS ' if(fseek(fid,event_length,'cof') == -1) fclose(fid); - error('ReadBesaMatlab:ErrorFseek','fseek to %d failed [LIST:MPS]',event_length); + ft_error('ReadBesaMatlab:ErrorFseek','fseek to %d failed [LIST:MPS]',event_length); end case 'MPSC' if(fseek(fid,event_length,'cof') == -1) fclose(fid); - error('ReadBesaMatlab:ErrorFseek','fseek to %d failed [LIST:MPSC]',event_length); + ft_error('ReadBesaMatlab:ErrorFseek','fseek to %d failed [LIST:MPSC]',event_length); end case 'PATT' event_obj.partner_event = read_event_tag_patt(fid,ftell(fid),event_length,event_obj); @@ -1967,20 +1966,20 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) event_obj.partner_event = read_event_tag_imp(fid,ftell(fid),event_length,event_obj); otherwise % Unrecognzed tag. Try to skip forward by offset - warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] in PAIR:PART at offset %d',event_tag,ftell(fid)); + ft_warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] in PAIR:PART at offset %d',event_tag,ftell(fid)); if(fseek(fid,event_length,'cof') == -1) fclose(fid); - error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [BEVT:PAIR:PART]))',event_length); + ft_error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [BEVT:PAIR:PART]))',event_length); end end case 'COMM' event_obj = read_event_tag_comm(fid,ftell(fid),current_length,event_obj); otherwise % Unrecognzed tag. Try to skip forward by offset - warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); + ft_warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); if(fseek(fid,current_length,'cof') == -1) fclose(fid); - error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [BEVT:PAIR]))',current_length); + ft_error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [BEVT:PAIR]))',current_length); end end end @@ -1995,10 +1994,10 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) event_obj = read_event_tag_pair(fid,ftell(fid),current_length,event_obj); otherwise % Unrecognzed tag. Try to skip forward by offset - warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); + ft_warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); if(fseek(fid,current_length,'cof') == -1) fclose(fid); - error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [BEVT:ARTI]))',current_length); + ft_error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [BEVT:ARTI]))',current_length); end end end @@ -2013,10 +2012,10 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) event_obj = read_event_tag_pair(fid,ftell(fid),current_length,event_obj); otherwise % Unrecognzed tag. Try to skip forward by offset - warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); + ft_warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); if(fseek(fid,current_length,'cof') == -1) fclose(fid); - error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [BEVT:EPOC]))',current_length); + ft_error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [BEVT:EPOC]))',current_length); end end end @@ -2056,10 +2055,10 @@ case num2str([CONST_FLOAT CONST_UNCOMPRESSED]) event_obj = read_event_tag_base(fid,ftell(fid),current_length,event_obj); otherwise % Unrecognzed tag. Try to skip forward by offset - warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); + ft_warning('ReadBesaMatlab:WarningUnexpectedTag','Read unexpected tag [%s] at offset %d',current_tag,ftell(fid)); if(fseek(fid,current_length,'cof') == -1) fclose(fid); - error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [BEVT:IMP]))',current_length); + ft_error('ReadBesaMatlab:ErrorFseek','fseek to %d failed (after unexpected tag in [BEVT:IMP]))',current_length); end end end diff --git a/external/fieldtrip/fileio/private/read_besa_sfp.m b/external/fieldtrip/fileio/private/read_besa_sfp.m index b40a4562..f40ad3d8 100644 --- a/external/fieldtrip/fileio/private/read_besa_sfp.m +++ b/external/fieldtrip/fileio/private/read_besa_sfp.m @@ -37,4 +37,4 @@ lab = lab(i1); pos = pos(i1,:); end - \ No newline at end of file + diff --git a/external/fieldtrip/fileio/private/read_biff.m b/external/fieldtrip/fileio/private/read_biff.m index 1d78a10e..f5483cbb 100644 --- a/external/fieldtrip/fileio/private/read_biff.m +++ b/external/fieldtrip/fileio/private/read_biff.m @@ -5,12 +5,12 @@ % This is a attemt for a reference implementation to read the BIFF % file format as defined by the Clinical Neurophysiology department of % the University Medical Centre, Nijmegen. -% +% % read all data and information % [data] = read_biff(filename) % or read a selected top-level chunk % [chunk] = read_biff(filename, chunkID) -% +% % known top-level chunk id's are % data : measured data (matrix) % dati : information on data (struct) @@ -19,7 +19,7 @@ % evnt : event markers (struct) % Copyright (C) 2000, Robert Oostenveld -% +% % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. % @@ -42,8 +42,6 @@ this = []; fid = fopen(filename, 'r'); -fseek(fid,0,'eof'); -eof = ftell(fid); fseek(fid,0,'bof'); [id, siz] = chunk_header(fid); @@ -52,17 +50,17 @@ case 'SEMG' child = subtree(BIFF, id); this = read_biff_chunk(fid, id, siz, child); - + case 'LIST' fprintf('skipping unimplemented chunk id="%s" size=%4d\n', id, siz); - + case 'CAT ' fprintf('skipping unimplemented chunk id="%s" size=%4d\n', id, siz); - + otherwise fprintf('skipping unrecognized chunk id="%s" size=%4d\n', id, siz); fseek(fid, siz, 'cof'); - + end % switch fclose(fid); % close file @@ -78,87 +76,84 @@ fprintf('skipping empty chunk id="%s" size=%4d\n', id, siz); assert(~feof(fid)); fseek(fid, siz, 'cof'); - + elseif isempty(chunk) % this is an unrecognized chunk fprintf('skipping unrecognized chunk id="%s" size=%4d\n', id, siz); assert(~feof(fid)); fseek(fid, siz, 'cof'); - + else eoc = ftell(fid) + siz; name = char(chunk.desc(2)); type = char(chunk.desc(3)); - - fprintf('reading chunk id= "%s" size=%4d name="%s"\n', id, siz, name); - - switch type - case 'group' - - while ~feof(fid) & ftell(fid). +% +% $Id$ + +% define output +elec.label = {}; % N x 1 cell array +elec.elecpos = []; % N x 3 matrix + +% conditional variables +WaitForPos = 0; +WaitForDescript = 0; +WaitForDim = 0; + +% open and read ascii-file line by line +fileline = 0; +fid = fopen(mgridfile,'r'); % open ascii-file +while fileline >= 0 % read line by line + + fileline = fgets(fid); % read a line + if fileline > 0 + + % grid number + if ~isempty(findstr(fileline,'# Electrode Grid ')) + GridNr = sscanf(fileline(findstr(fileline, 'Grid '):end),'Grid %i'); + WaitForDescript = 1; + WaitForDim = 1; + end + + % grid description + if ~isempty(findstr(fileline,'#Description')) && WaitForDescript + nextfileline = fgets(fid); + GridDescript = sscanf(nextfileline,'%s'); + WaitForDescript = 0; + end + + % grid dimension + if ~isempty(findstr(fileline,'#Dimensions')) && WaitForDim + nextfileline = fgets(fid); + GridDim = sscanf(nextfileline,'%i %i')'; % row & column + WaitForDim = 0; + end + + % electrode number + if ~isempty(findstr(fileline,'# Electrode ')) + type = sscanf(fileline(findstr(fileline,'Electrode '):end),'Electrode %s'); + if ~strcmp(type, 'Grid') + ElecNr = sscanf(fileline(findstr(fileline,'Electrode '):end),'Electrode %i %i')'; + WaitForPos = 1; + end + end + + % electrode position + if ~isempty(findstr(fileline,'#Position')) && WaitForPos + nextfileline = fgets(fid); + ElecPos = sscanf(nextfileline,'%f %f %f')'; % x, y, and z + WaitForPos = 0; + end + + % electrode present + if ~isempty(findstr(fileline,'#Electrode Present')) + nextfileline = fgets(fid); + ElecPres = logical(sscanf(nextfileline,'%f'))'; % 1 = present; 0 = not present + if ~ElecPres + ElecPos = NaN(1,3); + end + end + + % store + if ~isempty(findstr(fileline,'#Value')) + elec.label{end+1,1} = [GridDescript num2str(GridDim(2) - ElecNr(2) + GridDim(2)*ElecNr(1))]; + elec.elecpos(end+1,:) = ElecPos; + end + + end % if fileline +end % end of while loop +fclose(fid); + +% assume a unipolar montage, where the reference is implicit and the electrode positions are identical to the channel positions +elec.chanpos = elec.elecpos; +elec.tra = eye(size(elec.elecpos,1)); + +% for now it remains unclear what units and coordinate system this is expressed, see https://github.com/fieldtrip/fieldtrip/pull/342 +% elec.coordsys = ERROR +% elec.unit = ERROR diff --git a/external/fieldtrip/fileio/private/read_biosemi_bdf.m b/external/fieldtrip/fileio/private/read_biosemi_bdf.m index 6a39356c..9b979dc8 100644 --- a/external/fieldtrip/fileio/private/read_biosemi_bdf.m +++ b/external/fieldtrip/fileio/private/read_biosemi_bdf.m @@ -27,7 +27,7 @@ % chanindx index of channels to read (optional, default is all) % This returns a Nchans X Nsamples data matrix -% Copyright (C) 2006, Robert Oostenveld +% Copyright (C) 2006-2017, Robert Oostenveld % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -153,10 +153,21 @@ tmp = find(EDF.Cal < 0); EDF.Cal(tmp) = ones(size(tmp)); EDF.Off(tmp) = zeros(size(tmp)); + + % the following adresses https://github.com/fieldtrip/fieldtrip/pull/395 + tmp = find(strcmpi(cellstr(EDF.Label), 'STATUS')); + if EDF.Cal(tmp)~=1 + timeout = 60*15; % do not show it for the next 15 minutes + ft_warning('FieldTrip:BDFCalibration', 'calibration for status channel appears incorrect, setting it to 1', timeout); + EDF.Cal(tmp) = 1; + end + if EDF.Off(tmp)~=0 + timeout = 60*15; % do not show it for the next 15 minutes + ft_warning('FieldTrip:BDFOffset', 'offset for status channel appears incorrect, setting it to 0', timeout); + EDF.Off(tmp) = 0; + end EDF.Calib=[EDF.Off';(diag(EDF.Cal))]; - %EDF.Calib=sparse(diag([1; EDF.Cal])); - %EDF.Calib(1,2:EDF.NS+1)=EDF.Off'; EDF.SampleRate = EDF.SPR / EDF.Dur; @@ -198,7 +209,7 @@ % convert the header to Fieldtrip-style %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% if any(EDF.SampleRate~=EDF.SampleRate(1)) - error('channels with different sampling rate not supported'); + ft_error('channels with different sampling rate not supported'); end hdr.Fs = EDF.SampleRate(1); hdr.nChans = EDF.NS; @@ -254,14 +265,11 @@ endsample = endsample - (begepoch-1)*epochlength; % correct for the number of bytes that were skipped dat = dat(:, begsample:endsample); - % Calibrate the data - calib = diag(EDF.Cal(chanindx)); - if length(chanindx)>1 - % using a sparse matrix speeds up the multiplication - dat = sparse(calib) * dat; - else - % in case of one channel the sparse multiplication would result in a sparse array - dat = calib * dat; + % convert from digital to physical values and apply the offset + calib = EDF.Cal(chanindx); + offset = EDF.Off(chanindx); + for i=1:numel(calib) + dat(i,:) = calib(i)*dat(i,:) + offset(i); end end @@ -279,12 +287,12 @@ fp = fopen(filename,'r','ieee-le'); status = fseek(fp, offset, 'bof'); if status - error(['failed seeking ' filename]); + ft_error(['failed seeking ' filename]); end [buf,num] = fread(fp,numwords,'bit24=>double'); fclose(fp); if (num1 && any(diff(biosig.SampleRate)) - error('channels with different sampling rates are not supported'); + ft_error('channels with different sampling rates are not supported'); else hdr.Fs = biosig.SampleRate(1); end if length(biosig.SPR)>1 && any(diff(biosig.SPR)) - error('channels with different number of samples are not supported'); + ft_error('channels with different number of samples are not supported'); else hdr.nSamples = biosig.SPR(1); end diff --git a/external/fieldtrip/fileio/private/read_brainvision_eeg.m b/external/fieldtrip/fileio/private/read_brainvision_eeg.m index d56bc69c..93df7b6e 100644 --- a/external/fieldtrip/fileio/private/read_brainvision_eeg.m +++ b/external/fieldtrip/fileio/private/read_brainvision_eeg.m @@ -167,7 +167,7 @@ fclose(fid); else - error('unsupported sub-fileformat'); + ft_error('unsupported sub-fileformat'); end if ~isempty(chanindx) diff --git a/external/fieldtrip/fileio/private/read_brainvision_vhdr.m b/external/fieldtrip/fileio/private/read_brainvision_vhdr.m index 5b78fda7..7f305c05 100644 --- a/external/fieldtrip/fileio/private/read_brainvision_vhdr.m +++ b/external/fieldtrip/fileio/private/read_brainvision_vhdr.m @@ -47,7 +47,7 @@ if ~isempty(resolution) hdr.resolution(i) = resolution; else - warning('unknown resolution (i.e. recording units) for channel %d in %s', i, filename); + ft_warning('unknown resolution (i.e. recording units) for channel %d in %s', i, filename); hdr.resolution(i) = 1; end end @@ -68,7 +68,7 @@ % but that might be on another location than the present working directory info = dir(datafile); if isempty(info) - error('cannot determine the location of the data file %s', hdr.DataFile); + ft_error('cannot determine the location of the data file %s', hdr.DataFile); end switch lower(hdr.BinaryFormat) case 'int_16'; @@ -110,7 +110,7 @@ end if isinf(hdr.nSamples) - warning('cannot determine number of samples for this sub-fileformat'); + ft_warning('cannot determine number of samples for this sub-fileformat'); end % the number of trials is unkown, assume continuous data diff --git a/external/fieldtrip/fileio/private/read_brainvision_vmrk.m b/external/fieldtrip/fileio/private/read_brainvision_vmrk.m index d7daec18..617b4dcc 100644 --- a/external/fieldtrip/fileio/private/read_brainvision_vmrk.m +++ b/external/fieldtrip/fileio/private/read_brainvision_vmrk.m @@ -42,7 +42,7 @@ fid=fopen(filename,'rt'); if fid==-1, - error('cannot open marker file') + ft_error('cannot open marker file') end line=1; diff --git a/external/fieldtrip/fileio/private/read_bti_ascii.m b/external/fieldtrip/fileio/private/read_bti_ascii.m index a4237e80..7ce8d4cf 100644 --- a/external/fieldtrip/fileio/private/read_bti_ascii.m +++ b/external/fieldtrip/fileio/private/read_bti_ascii.m @@ -32,14 +32,14 @@ fid = fopen(filename, 'r'); if fid==-1 - error(sprintf('could not open file %s', filename)); + ft_error(sprintf('could not open file %s', filename)); end line = ''; while ischar(line) - line = cleanline(fgetl(fid)) + line = cleanline(fgetl(fid)); - if isempty(line) | line==-1 | isempty(findstr(line, ':')) + if isempty(line) || line==-1 || isempty(findstr(line, ':')) continue end @@ -65,7 +65,7 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function line = cleanline(line) -if isempty(line) | line==-1 +if isempty(line) || line==-1 return end comment = findstr(line, '//'); diff --git a/external/fieldtrip/fileio/private/read_bti_hs.m b/external/fieldtrip/fileio/private/read_bti_hs.m index 17d802a1..05f542cb 100644 --- a/external/fieldtrip/fileio/private/read_bti_hs.m +++ b/external/fieldtrip/fileio/private/read_bti_hs.m @@ -1,4 +1,4 @@ -function [output, firstIndexPoint] = read_4d_hs( filename, outfile) +function [output, firstIndexPoint] = read_bti_hs( filename, outfile) %read_hs_file Reads in BTI-Headshape files % filename: file with the headshape informations diff --git a/external/fieldtrip/fileio/private/read_bti_m4d.m b/external/fieldtrip/fileio/private/read_bti_m4d.m index 4ade29ea..1987adbf 100644 --- a/external/fieldtrip/fileio/private/read_bti_m4d.m +++ b/external/fieldtrip/fileio/private/read_bti_m4d.m @@ -33,7 +33,7 @@ fid = fopen(filename, 'r'); if fid==-1 - error(sprintf('could not open file %s', filename)); + ft_error(sprintf('could not open file %s', filename)); end % start with an empty header structure @@ -83,7 +83,7 @@ val = line((sep+1):end); elseif length(sep)<1 % this is not what I would expect - error('unexpected content in m4d file'); + ft_error('unexpected content in m4d file'); end if ~isempty(strfind(line, 'Begin')) && (~isempty(strfind(line, 'Meg_Position_Information')) || ~isempty(strfind(line, 'Ref_Position_Information'))) @@ -130,7 +130,7 @@ msi.grad.coilpos = [msi.grad.coilpos; num(:,1:3)]; msi.grad.coilori = [msi.grad.coilori; num(:,4:6)]; else - error('unknown gradiometer design') + ft_error('unknown gradiometer design') end end diff --git a/external/fieldtrip/fileio/private/read_bucn_nirshdr.m b/external/fieldtrip/fileio/private/read_bucn_nirshdr.m index 55af46d4..aafb1f24 100644 --- a/external/fieldtrip/fileio/private/read_bucn_nirshdr.m +++ b/external/fieldtrip/fileio/private/read_bucn_nirshdr.m @@ -49,6 +49,13 @@ nchan = numel(label); Fs = str2num(strtok(strtok(label{1},'#Time.'),'Hz')); +% test whether the channel labels are non-numeric +labelnumber = cellfun(@str2num, label, 'UniformOutput', false); +labelstring = cellfun(@isempty, labelnumber, 'UniformOutput', true); +if ~any(labelstring) + ft_error('channel labels were not found in the first line of the file'); +end + % read the rest dat = textscan(fid, '%f'); fclose(fid); diff --git a/external/fieldtrip/fileio/private/read_buffer_offline_events.m b/external/fieldtrip/fileio/private/read_buffer_offline_events.m index e8e60182..94b4b8fb 100644 --- a/external/fieldtrip/fileio/private/read_buffer_offline_events.m +++ b/external/fieldtrip/fileio/private/read_buffer_offline_events.m @@ -69,7 +69,7 @@ value_size = wordsize{value_type+1}*value_numel; if type_size + value_size > bufsize - warning('Invalid event definition - skipping remaining contents'); + ft_warning('Invalid event definition - skipping remaining contents'); break; end diff --git a/external/fieldtrip/fileio/private/read_buffer_offline_header.m b/external/fieldtrip/fileio/private/read_buffer_offline_header.m index de88161e..c6fca82e 100644 --- a/external/fieldtrip/fileio/private/read_buffer_offline_header.m +++ b/external/fieldtrip/fileio/private/read_buffer_offline_header.m @@ -51,7 +51,7 @@ txt=[]; finfo=dir([headerfile '.txt']); if ( isempty(finfo) || finfo.bytes==0 ) - warning(sprintf('Could not open text header file : %s',headerfile)); + ft_warning(sprintf('Could not open text header file : %s',headerfile)); else txt.nSamples=0; FA = fopen([headerfile '.txt'], 'r'); @@ -90,7 +90,7 @@ elseif strcmp(val,'little') txt.orig.endianness='ieee-le'; else - error('Invalid value for key ''endian''.'); + ft_error('Invalid value for key ''endian''.'); end end continue; @@ -103,7 +103,7 @@ txt.label{ind} = name; nameFlag = 2; else - error('Invalid channel name definition - broken header file?'); + ft_error('Invalid channel name definition - broken header file?'); end end end @@ -114,7 +114,7 @@ bin=[]; finfo=dir(headerfile); if ( isempty(finfo) || finfo.bytes==0 ) - warning(sprintf('Couldnt open binary header file : %s',headerfile)); + ft_warning(sprintf('Couldnt open binary header file : %s',headerfile)); hdr = copyfields(txt, hdr, fieldnames(txt)); % ensure that the predefined stuff still exists else if ( ~isfield(hdr.orig,'endianness') ) @@ -129,13 +129,13 @@ hdr.bufsize = fread(F,1,'uint32'); if isfield(txt,'nChans') && ~isequal(hdr.nChans,txt.nChans) - error('Number of channels in binary header does not match ASCII definition'); + ft_error('Number of channels in binary header does not match ASCII definition'); end if isfield(txt,'nChans') && ~isequal(hdr.nSamples,txt.nSamples) - warning('Number of samples in binary header does not match ASCII definition'); + ft_warning('Number of samples in binary header does not match ASCII definition'); end if isfield(txt,'nEvents') && ~isequal(hdr.nEvents,txt.nEvents) - error('Number of events in binary header does not match ASCII definition'); + ft_error('Number of events in binary header does not match ASCII definition'); end if isempty(hdr.data_type) hdr.data_type = strmatch(txt.orig.data_type,type)-1; @@ -144,7 +144,7 @@ hdr.orig.data_type = type{hdr.data_type+1}; hdr.orig.wordsize = wordsize{hdr.data_type+1}; %else - % error('Data type in binary header does not match ASCII definition'); + % ft_error('Data type in binary header does not match ASCII definition'); %end % TODO: add chunk handling @@ -164,7 +164,7 @@ if typeAndSize(2) == 8*hdr.nChans hdr.resolutions = fread(F, [hdr.nChans, 1], 'double'); else - warning('Invalid size of RESOLUTIONS chunk - skipping'); + ft_warning('Invalid size of RESOLUTIONS chunk - skipping'); dummy = fread(F, typeAndSize(2), 'uint8=>uint8'); end case 4 % FT_CHUNK_ASCII_KEYVAL @@ -175,7 +175,7 @@ if typeAndSize(2) == 348 hdr.nifti_1 = decode_nifti1(hdr.orig.nifti_1); else - warning('Invalid size of NIFTI_1 chunk - skipping'); + ft_warning('Invalid size of NIFTI_1 chunk - skipping'); end case 6 % FT_CHUNK_SIEMENS_AP = 6 hdr.orig.siemensap = fread(F, typeAndSize(2), 'uint8=>uint8'); @@ -211,7 +211,7 @@ n = fileSize / hdr.orig.wordsize / hdr.nChans; hdr.nSamples = floor(n); if hdr.nSamples ~= n - warning('Size of ''samples'' is not a multiple of the size of one sample'); + ft_warning('Size of ''samples'' is not a multiple of the size of one sample'); end end diff --git a/external/fieldtrip/fileio/private/read_ced_son.m b/external/fieldtrip/fileio/private/read_ced_son.m index c4cde9a6..8f970f0a 100644 --- a/external/fieldtrip/fileio/private/read_ced_son.m +++ b/external/fieldtrip/fileio/private/read_ced_son.m @@ -94,7 +94,7 @@ end [st,libinfo] = ns_GetLibraryInfo; if st, - error(['Could not get NeuroShare library info, please use the NS_SETLIBRARY function.']); + ft_error(['Could not get NeuroShare library info, please use the NS_SETLIBRARY function.']); else, disp(['Loading file ' datafile ' using NeuroShare library v',... num2str(libinfo.LibVersionMaj),'.',num2str(libinfo.LibVersionMin),' ...']); @@ -104,7 +104,7 @@ [st,fhandle] = ns_OpenFile(datafile); if st, [st,mesg] = ns_GetLastErrorMsg; - error(mesg); + ft_error(mesg); end; try, @@ -113,7 +113,7 @@ if st, [st,mesg] = ns_GetLastErrorMsg; ns_CloseFile(fhandle); - error(mesg); + ft_error(mesg); end; % Build catalogue of entities @@ -165,11 +165,11 @@ out.header(cnt).units = ainfo.Units; out.header(cnt).mode = 'continuous'; elseif strcmpi(MODE,'triggered'), - warning(['Triggered channel mode not implemented yet']); + ft_warning(['Triggered channel mode not implemented yet']); out = []; return else, - error(['Unknown channel mode for channel ',num2str(channr)]); + ft_error(['Unknown channel mode for channel ',num2str(channr)]); end; end; out.header = orderfields(out.header); @@ -220,7 +220,7 @@ pars.channels = analoglist; else, % renumber requested channels to entityIDs if length(pars.channels)>length(analoglist), - error(['Requested more analog channels than present in datafile']); + ft_error(['Requested more analog channels than present in datafile']); else, pars.channels = analoglist(pars.channels); end; @@ -261,14 +261,14 @@ % get the same number of samples as in the target channel endsample = begsample + itemcount-1; [st,contcount,chandata] = ns_GetAnalogData(fhandle,channr, begsample,itemcount); - if contcount~=itemcount, warning(['Discontinuity in data']); end; + if contcount~=itemcount, ft_warning(['Discontinuity in data']); end; % make a time scale [st,begtime] = ns_GetTimeByIndex(fhandle,channr,begsample); [st,endtime] = ns_GetTimeByIndex(fhandle,channr,endsample); sourcestep = out.header([out.header.sonentityid]==channr).samplerate; - if sourcestep~=targetstep, warning(['Source and target channels have time steps of different size']); end; + if sourcestep~=targetstep, ft_warning(['Source and target channels have time steps of different size']); end; chantime = [begtime:1/sourcestep:endtime]; out.data{cnt} = chandata(:)'; @@ -291,6 +291,6 @@ [st,mesg] = ns_GetLastErrorMsg; disp(mesg); end; - error(lasterr); + ft_error(lasterr); end; diff --git a/external/fieldtrip/fileio/private/read_combined_ds.m b/external/fieldtrip/fileio/private/read_combined_ds.m index dcc3c2b4..045c7ca2 100644 --- a/external/fieldtrip/fileio/private/read_combined_ds.m +++ b/external/fieldtrip/fileio/private/read_combined_ds.m @@ -85,7 +85,7 @@ end if ~any(sel) - error('no supported files were found'); + ft_error('no supported files were found'); end fname = fname(sel); @@ -98,44 +98,44 @@ end if any([filehdr.nChans]~=1) - error('more than one channel per file not supported'); + ft_error('more than one channel per file not supported'); else hdr.nChans = sum([filehdr.nChans]); end if length(unique([filehdr.label]))~=nfiles - error('not all channels have a unique name'); + ft_error('not all channels have a unique name'); else hdr.label = [filehdr.label]'; end if any(diff([filehdr.Fs])) - error('different sampling frequenties per file not supported'); + ft_error('different sampling frequenties per file not supported'); else hdr.Fs = filehdr(1).Fs; end if any(diff([filehdr.nSamples])) - error('different nSamples per file not supported'); + ft_error('different nSamples per file not supported'); else hdr.nSamples = filehdr(1).nSamples; end if any(diff([filehdr.nSamplesPre])) - error('different nSamplesPre per file not supported'); + ft_error('different nSamplesPre per file not supported'); else hdr.nSamplesPre = filehdr(1).nSamplesPre; end if any(diff([filehdr.nTrials])) - error('different nTrials per file not supported'); + ft_error('different nTrials per file not supported'); else hdr.nTrials = filehdr(1).nTrials; end if isfield(filehdr, 'TimeStampPerSample') if any(diff([filehdr.TimeStampPerSample])) - error('different TimeStampPerSample per file not supported'); + ft_error('different TimeStampPerSample per file not supported'); else hdr.TimeStampPerSample = filehdr(1).TimeStampPerSample; end @@ -143,7 +143,7 @@ if isfield(filehdr, 'FirstTimeStamp') if any(diff([filehdr.FirstTimeStamp])) - error('different FirstTimeStamp per file not supported'); + ft_error('different FirstTimeStamp per file not supported'); else hdr.FirstTimeStamp = filehdr(1).FirstTimeStamp; end diff --git a/external/fieldtrip/fileio/private/read_ctf_ascii.m b/external/fieldtrip/fileio/private/read_ctf_ascii.m index ebb1d24b..9e71cf2f 100644 --- a/external/fieldtrip/fileio/private/read_ctf_ascii.m +++ b/external/fieldtrip/fileio/private/read_ctf_ascii.m @@ -40,7 +40,7 @@ fid = fopen(filename, 'r'); if fid==-1 - error(sprintf('could not open file %s', filename)); + ft_error(sprintf('could not open file %s', filename)); end line = ''; @@ -61,7 +61,7 @@ item = strtrim(item); % turn warnings off - ws = warning('off'); + ws = ft_warning('off'); % the item name should be a real string, otherwise I cannot put it into the structure if strcmp(sprintf('%d', str2num(deblank(item))), deblank(item)) @@ -79,7 +79,7 @@ end % revert to previous warning state - warning(ws); + ft_warning(ws); end subline = cleanline(fgetl(fid)); % read the first item end diff --git a/external/fieldtrip/fileio/private/read_ctf_cls.m b/external/fieldtrip/fileio/private/read_ctf_cls.m index 8de11f39..40b63771 100644 --- a/external/fieldtrip/fileio/private/read_ctf_cls.m +++ b/external/fieldtrip/fileio/private/read_ctf_cls.m @@ -44,7 +44,7 @@ S1 =fscanf(fid,'%s',1); if readList - if ~isempty(S1) & ~isempty(str2num(S1(2:end))) + if ~isempty(S1) && ~isempty(str2num(S1(2:end))) k = k + 1; condTmp = [condTmp 1+str2num(S1(2:end))]; else @@ -60,7 +60,7 @@ condLabels(nCondition) = {S1} ; end - if strcmp(S1,'NUMBER') & strcmp(S2,'TRIAL') + if strcmp(S1,'NUMBER') && strcmp(S2,'TRIAL') if ~isempty(S1) readList = 1; k = 0; diff --git a/external/fieldtrip/fileio/private/read_ctf_coef.m b/external/fieldtrip/fileio/private/read_ctf_coef.m index 2e2d6cfd..f60049a4 100644 --- a/external/fieldtrip/fileio/private/read_ctf_coef.m +++ b/external/fieldtrip/fileio/private/read_ctf_coef.m @@ -30,7 +30,7 @@ % $Id$ if nargin~=0 - error('this function does not accept input parameters') + ft_error('this function does not accept input parameters') end % start with an empty coefficient list diff --git a/external/fieldtrip/fileio/private/read_ctf_dat.m b/external/fieldtrip/fileio/private/read_ctf_dat.m index d28786e8..ad3ecdc2 100644 --- a/external/fieldtrip/fileio/private/read_ctf_dat.m +++ b/external/fieldtrip/fileio/private/read_ctf_dat.m @@ -32,7 +32,7 @@ fid = fopen(filename, 'r'); if fid==-1 - error(sprintf('could not open file %s', filename)); + ft_error(sprintf('could not open file %s', filename)); end % read the sample number @@ -56,7 +56,7 @@ chan = 0; while (1) line = fgetl(fid); - if ~isempty(line) & line==-1 + if ~isempty(line) && line==-1 % reached end of file break end diff --git a/external/fieldtrip/fileio/private/read_ctf_hc.m b/external/fieldtrip/fileio/private/read_ctf_hc.m index 61ab60de..ccb0d10c 100644 --- a/external/fieldtrip/fileio/private/read_ctf_hc.m +++ b/external/fieldtrip/fileio/private/read_ctf_hc.m @@ -67,7 +67,7 @@ fid = fopen(filename, 'r'); if fid==-1 - error(sprintf('could not open file %s', filename)); + ft_error('could not open file %s', filename); end fseek(fid, 0, 'bof'); @@ -81,23 +81,23 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% while ~strcmp(line, 'standard nasion coil position relative to dewar (cm):') line = fgetl(fid); - if ~ischar(line) & line==-1, error('premature end of file'), end + if ~ischar(line) && line==-1, ft_error('premature end of file'), end end line = fgetl(fid); [t, r] = strtok(line, '='); hc.standard.nas(1) = str2num(r(2:end)); line = fgetl(fid); [t, r] = strtok(line, '='); hc.standard.nas(2) = str2num(r(2:end)); line = fgetl(fid); [t, r] = strtok(line, '='); hc.standard.nas(3) = str2num(r(2:end)); % NOTE THAT THERE IS AN TYPING ERROR IN SOME CTF FILES WHICH I HAVE TO REPRODUCE HERE (staNdard) -while ~(strcmp(line, 'stadard left ear coil position relative to dewar (cm):') | ... +while ~(strcmp(line, 'stadard left ear coil position relative to dewar (cm):') || ... strcmp(line, 'standard left ear coil position relative to dewar (cm):')) line = fgetl(fid); - if ~ischar(line) & line==-1, error('premature end of file'), end + if ~ischar(line) && line==-1, ft_error('premature end of file'), end end line = fgetl(fid); [t, r] = strtok(line, '='); hc.standard.lpa(1) = str2num(r(2:end)); line = fgetl(fid); [t, r] = strtok(line, '='); hc.standard.lpa(2) = str2num(r(2:end)); line = fgetl(fid); [t, r] = strtok(line, '='); hc.standard.lpa(3) = str2num(r(2:end)); while ~strcmp(line, 'standard right ear coil position relative to dewar (cm):') line = fgetl(fid); - if ~ischar(line) & line==-1, error('premature end of file'), end + if ~ischar(line) && line==-1, ft_error('premature end of file'), end end line = fgetl(fid); [t, r] = strtok(line, '='); hc.standard.rpa(1) = str2num(r(2:end)); line = fgetl(fid); [t, r] = strtok(line, '='); hc.standard.rpa(2) = str2num(r(2:end)); @@ -111,21 +111,21 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% while ~strcmp(line, 'measured nasion coil position relative to dewar (cm):') line = fgetl(fid); - if ~ischar(line) & line==-1, error('premature end of file'), end + if ~ischar(line) && line==-1, ft_error('premature end of file'), end end line = fgetl(fid); [t, r] = strtok(line, '='); hc.dewar.nas(1) = str2num(r(2:end)); line = fgetl(fid); [t, r] = strtok(line, '='); hc.dewar.nas(2) = str2num(r(2:end)); line = fgetl(fid); [t, r] = strtok(line, '='); hc.dewar.nas(3) = str2num(r(2:end)); while ~strcmp(line, 'measured left ear coil position relative to dewar (cm):') line = fgetl(fid); - if ~ischar(line) & line==-1, error('premature end of file'), end + if ~ischar(line) && line==-1, ft_error('premature end of file'), end end line = fgetl(fid); [t, r] = strtok(line, '='); hc.dewar.lpa(1) = str2num(r(2:end)); line = fgetl(fid); [t, r] = strtok(line, '='); hc.dewar.lpa(2) = str2num(r(2:end)); line = fgetl(fid); [t, r] = strtok(line, '='); hc.dewar.lpa(3) = str2num(r(2:end)); while ~strcmp(line, 'measured right ear coil position relative to dewar (cm):') line = fgetl(fid); - if ~ischar(line) & line==-1, error('premature end of file'), end + if ~ischar(line) && line==-1, ft_error('premature end of file'), end end line = fgetl(fid); [t, r] = strtok(line, '='); hc.dewar.rpa(1) = str2num(r(2:end)); line = fgetl(fid); [t, r] = strtok(line, '='); hc.dewar.rpa(2) = str2num(r(2:end)); @@ -139,21 +139,21 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% while ~strcmp(line, 'measured nasion coil position relative to head (cm):') line = fgetl(fid); - if ~ischar(line) & line==-1, error('premature end of file'), end + if ~ischar(line) && line==-1, ft_error('premature end of file'), end end line = fgetl(fid); [t, r] = strtok(line, '='); hc.head.nas(1) = str2num(r(2:end)); line = fgetl(fid); [t, r] = strtok(line, '='); hc.head.nas(2) = str2num(r(2:end)); line = fgetl(fid); [t, r] = strtok(line, '='); hc.head.nas(3) = str2num(r(2:end)); while ~strcmp(line, 'measured left ear coil position relative to head (cm):') line = fgetl(fid); - if ~ischar(line) & line==-1, error('premature end of file'), end + if ~ischar(line) && line==-1, ft_error('premature end of file'), end end line = fgetl(fid); [t, r] = strtok(line, '='); hc.head.lpa(1) = str2num(r(2:end)); line = fgetl(fid); [t, r] = strtok(line, '='); hc.head.lpa(2) = str2num(r(2:end)); line = fgetl(fid); [t, r] = strtok(line, '='); hc.head.lpa(3) = str2num(r(2:end)); while ~strcmp(line, 'measured right ear coil position relative to head (cm):') line = fgetl(fid); - if ~ischar(line) & line==-1, error('premature end of file'), end + if ~ischar(line) && line==-1, ft_error('premature end of file'), end end line = fgetl(fid); [t, r] = strtok(line, '='); hc.head.rpa(1) = str2num(r(2:end)); line = fgetl(fid); [t, r] = strtok(line, '='); hc.head.rpa(2) = str2num(r(2:end)); diff --git a/external/fieldtrip/fileio/private/read_ctf_hdm.m b/external/fieldtrip/fileio/private/read_ctf_hdm.m index e8039af0..a109a502 100644 --- a/external/fieldtrip/fileio/private/read_ctf_hdm.m +++ b/external/fieldtrip/fileio/private/read_ctf_hdm.m @@ -50,7 +50,7 @@ vol.o(2) = ascii.MEG_Sphere.ORIGIN_Y; vol.o(3) = ascii.MEG_Sphere.ORIGIN_Z; else - error('no headmodel information found'); + ft_error('no headmodel information found'); end % add the fiducials, these are in raw MRI coordinates diff --git a/external/fieldtrip/fileio/private/read_ctf_meg4.m b/external/fieldtrip/fileio/private/read_ctf_meg4.m index 9c547541..f4ba39b1 100644 --- a/external/fieldtrip/fileio/private/read_ctf_meg4.m +++ b/external/fieldtrip/fileio/private/read_ctf_meg4.m @@ -52,23 +52,23 @@ ntrl = hdr.nTrials; nchn = hdr.nChans; -if begsample<1, error('cannot read before the start of the data'); end -if endsample>nsmp*ntrl*nchn, error('cannot read beyond the end of the data'); end -if begsample>endsample, error('cannot read a negative number of samples'); end +if begsample<1, ft_error('cannot read before the start of the data'); end +if endsample>nsmp*ntrl*nchn, ft_error('cannot read beyond the end of the data'); end +if begsample>endsample, ft_error('cannot read a negative number of samples'); end if nargin<5, chanindx = 1:nchn; end -if isempty(chanindx), error('no channels were specified for reading CTF data'); end +if isempty(chanindx), ft_error('no channels were specified for reading CTF data'); end %open the .meg4 file fid = fopen(fname,'r','ieee-be'); if fid == -1, - error('could not open datafile'); + ft_error('could not open datafile'); end %check whether it is a known format CTFformat=char(fread(fid, 8, 'uint8'))'; % This function was written for MEG41RS, but also seems to work for some other formats if ~strcmp(CTFformat(1,1:7),'MEG41CP') && ~strcmp(CTFformat(1,1:7),'MEG4CPT') - warning('meg4 format (%s) is not supported for file %s, trying anyway...', CTFformat(1,1:7), fname); + ft_warning('meg4 format (%s) is not supported for file %s, trying anyway...', CTFformat(1,1:7), fname); end %determine size of .meg4 file diff --git a/external/fieldtrip/fileio/private/read_ctf_mri.m b/external/fieldtrip/fileio/private/read_ctf_mri.m index 37ed7034..412ff6c1 100644 --- a/external/fieldtrip/fileio/private/read_ctf_mri.m +++ b/external/fieldtrip/fileio/private/read_ctf_mri.m @@ -32,14 +32,14 @@ fid = fopen(filename, 'rb', 'ieee-be', 'ISO-8859-1'); if fid<=0 - error(sprintf('could not open MRI file: %s\n', filename)); + ft_error(sprintf('could not open MRI file: %s\n', filename)); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % READ THE IMAGE HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -ws = warning('off'); +ws = ft_warning('off'); % general header information hdr.identifierString = fread(fid,[1 32],'uint8=>char'); % CTF_MRI_FORMAT VER 2.2 @@ -128,7 +128,7 @@ precision = '*uint16'; end else - error('unknown datasize (%d) in CTF mri file.', hdr.dataSize); + ft_error('unknown datasize (%d) in CTF mri file.', hdr.dataSize); end mri = fread(fid, hdr.imageSize.^3, precision); mri = reshape(mri, [hdr.imageSize hdr.imageSize hdr.imageSize]); diff --git a/external/fieldtrip/fileio/private/read_ctf_mri4.m b/external/fieldtrip/fileio/private/read_ctf_mri4.m index 6ddbe43d..0f1995c4 100644 --- a/external/fieldtrip/fileio/private/read_ctf_mri4.m +++ b/external/fieldtrip/fileio/private/read_ctf_mri4.m @@ -29,13 +29,13 @@ fid = fopen(filename,'rb', 'ieee-be'); if fid<=0 - error(sprintf('could not open MRI file: %s\n', filename)); + ft_error(sprintf('could not open MRI file: %s\n', filename)); end [cpersist] = read_cpersist(fid); % turn warnings off -ws = warning('off'); +ws = ft_warning('off'); % general header information hdr.identifierString = get_value(cpersist, '_CTFMRI_VERSION'); % CTF_MRI_FORMAT VER 4.1 @@ -118,7 +118,7 @@ elseif(hdr.dataSize == 2) slicedata = uint16(fread(fid, [256 256], 'uint16')); else - error('Unknown datasize in CTF MRI file'); + ft_error('Unknown datasize in CTF MRI file'); end; mri(:, :, slice) = slicedata; @@ -217,8 +217,8 @@ function [value] = get_value(cpersist, key) idx = find(strcmp({cpersist.key}, key)); - if(numel(idx) < 1), error('Specified key does not exist.'); end; - if(numel(idx) > 1), error('Specified key is not unique.'); end; + if(numel(idx) < 1), ft_error('Specified key does not exist.'); end; + if(numel(idx) > 1), ft_error('Specified key is not unique.'); end; value = cpersist(idx).value; end @@ -232,7 +232,7 @@ function [cpersist] = read_cpersist(fid) magic = char(fread(fid, 4, 'char'))'; - if(~strcmp(magic, 'WS1_')), error('Invalid CPersist header'); end; + if(~strcmp(magic, 'WS1_')), ft_error('Invalid CPersist header'); end; cpersist = struct('key', {}, 'value', {}); @@ -279,7 +279,7 @@ vsize = fread(fid, 1, 'int32'); value = char(fread(fid, vsize, 'char'))'; otherwise - error(['Unsupported valuetype (' num2str(vtype) ') found in CPersist object']); + ft_error(['Unsupported valuetype (' num2str(vtype) ') found in CPersist object']); end end diff --git a/external/fieldtrip/fileio/private/read_ctf_res4.m b/external/fieldtrip/fileio/private/read_ctf_res4.m index bc783931..8c31e647 100644 --- a/external/fieldtrip/fileio/private/read_ctf_res4.m +++ b/external/fieldtrip/fileio/private/read_ctf_res4.m @@ -46,14 +46,14 @@ % Check if header file exist if fid == -1 errMsg = strcat('Could not open header file:',fname); - error(errMsg); + ft_error(errMsg); end % First 8 bytes contain filetype, check is fileformat is correct. % This function was written for MEG41RS, but also seems to work for some other formats CTFformat=char(fread(fid,8,'uint8'))'; if ~strcmp(CTFformat(1,1:7),'MEG41RS') && ~strcmp(CTFformat(1,1:7),'MEG42RS') && ~strcmp(CTFformat(1,1:7),'MEG3RES') - warning('res4 format (%s) is not supported for file %s, trying anyway...', CTFformat(1,1:7), fname); + ft_warning('res4 format (%s) is not supported for file %s, trying anyway...', CTFformat(1,1:7), fname); end % Read the initial parameters diff --git a/external/fieldtrip/fileio/private/read_ctf_sens.m b/external/fieldtrip/fileio/private/read_ctf_sens.m index dc1d62d9..15f9ea8e 100644 --- a/external/fieldtrip/fileio/private/read_ctf_sens.m +++ b/external/fieldtrip/fileio/private/read_ctf_sens.m @@ -32,7 +32,7 @@ fid = fopen(filename, 'r'); if fid==-1 - error(sprintf('could not open file %s', filename)); + ft_error(sprintf('could not open file %s', filename)); end % skip the first line @@ -42,7 +42,7 @@ chan = 0; while (1) line = fgetl(fid); - if ~isempty(line) & line==-1 + if ~isempty(line) && line==-1 % reached end of file break end diff --git a/external/fieldtrip/fileio/private/read_ctf_shape.m b/external/fieldtrip/fileio/private/read_ctf_shape.m index d361608d..86fa1ace 100644 --- a/external/fieldtrip/fileio/private/read_ctf_shape.m +++ b/external/fieldtrip/fileio/private/read_ctf_shape.m @@ -30,7 +30,7 @@ shape = read_ctf_ascii([filename '_info']); if ~strcmp(shape.MRI_Info.COORDINATES, 'HEAD') - warning('points on head shape are NOT in headcoordinates') + ft_warning('points on head shape are NOT in headcoordinates') end fid = fopen(filename, 'rt'); diff --git a/external/fieldtrip/fileio/private/read_ctf_shm.m b/external/fieldtrip/fileio/private/read_ctf_shm.m index eb1705f0..8c9e658d 100644 --- a/external/fieldtrip/fileio/private/read_ctf_shm.m +++ b/external/fieldtrip/fileio/private/read_ctf_shm.m @@ -1,4 +1,4 @@ -function [varargout] = funname(varargin) +function [varargout] = read_ctf_shm(varargin) % READ_CTF_SHM reads metainformation or selected blocks of data from % shared memory. This function can be used for real-time processing of @@ -42,7 +42,7 @@ try % try to compile the mex file on the fly - warning('trying to compile MEX file from %s', mexsrc); + ft_warning('trying to compile MEX file from %s', mexsrc); cd(mexdir); mex(mexsrc); cd(pwdir); @@ -51,7 +51,7 @@ catch % compilation failed disp(lasterr); - error('could not locate MEX file for %s', mexname); + ft_error('could not locate MEX file for %s', mexname); cd(pwdir); success = false; end diff --git a/external/fieldtrip/fileio/private/read_ctf_svl.m b/external/fieldtrip/fileio/private/read_ctf_svl.m index 8a6ebfa8..7bb72fc2 100644 --- a/external/fieldtrip/fileio/private/read_ctf_svl.m +++ b/external/fieldtrip/fileio/private/read_ctf_svl.m @@ -7,7 +7,7 @@ fid = fopen(filename, 'rb', 'ieee-be', 'ISO-8859-1'); if fid <= 0 - error('Could not open SAM file: %s\n', filename); + ft_error('Could not open SAM file: %s\n', filename); end @@ -19,7 +19,7 @@ hdr.numChans = fread(fid, 1, 'int32'); hdr.numWeights = fread(fid, 1, 'int32'); % 0 for static image. if(hdr.numWeights ~= 0) - warning('hdr.numWeights ~= 0'); + ft_warning('hdr.numWeights ~= 0'); end fread(fid,1,'int32'); % Padding to next 8 byte boundary. diff --git a/external/fieldtrip/fileio/private/read_curry.m b/external/fieldtrip/fileio/private/read_curry.m index b81002d0..7cb4e95b 100644 --- a/external/fieldtrip/fileio/private/read_curry.m +++ b/external/fieldtrip/fileio/private/read_curry.m @@ -32,7 +32,7 @@ fid = fopen(filename, 'rt'); if fid<0 - error(sprintf('could not open file: %s', filename)); + ft_error(sprintf('could not open file: %s', filename)); end s = []; @@ -55,7 +55,7 @@ % read the next line line = fgetl(fid); % process the data in the line - if strcmp(blocktype, 'START') & ~isempty(strfind(line, '=')) + if strcmp(blocktype, 'START') && ~isempty(strfind(line, '=')) % the line looks like "lhs = rhs" [lhs, rhs] = strtok(line, '='); lhs = strtrim(lhs); @@ -74,8 +74,8 @@ % FIXME end - if isnumeric(line) | feof(fid) - error('unexpected end of file'); + if isnumeric(line) || feof(fid) + ft_error('unexpected end of file'); end end % while ~END diff --git a/external/fieldtrip/fileio/private/read_deymed_ini.m b/external/fieldtrip/fileio/private/read_deymed_ini.m index 36791019..16f37797 100644 --- a/external/fieldtrip/fileio/private/read_deymed_ini.m +++ b/external/fieldtrip/fileio/private/read_deymed_ini.m @@ -48,7 +48,7 @@ dummy = fread(fid, [1, 1], 'int8'); % this is 4 in the example file if dummy~=4 - warning('deviant header format detected'); + ft_warning('deviant header format detected'); end % A numerical comparison between a deymed dat file and a BESA-exported edf version of the diff --git a/external/fieldtrip/fileio/private/read_edf.m b/external/fieldtrip/fileio/private/read_edf.m index 82bb33f0..c208e9dc 100644 --- a/external/fieldtrip/fileio/private/read_edf.m +++ b/external/fieldtrip/fileio/private/read_edf.m @@ -1,43 +1,26 @@ function [dat] = read_edf(filename, hdr, begsample, endsample, chanindx) -% READ_EDF reads specified samples from an EDF continous datafile -% It neglects all trial boundaries as if the data was acquired in -% non-continous mode. -% Note that since FieldTrip only accommodates a single sampling rate in a -% given dataset whereas edf allows specification of a sampling rate for -% each channel, if there are heterogenous sampling rates then this function -% will automatically choose a subset. If the last such channel is -% different from the rest, the assumption will be made that it is the -% annotation channel and the rest will be selected. If that is not the -% case, then the largest subset of channels with a consistent sampling rate -% will be chosen. To avoid this automatic selection process, the user may -% specify their own choice of channels using chanindx. In this case, the -% automatic selection will only occur if the user selected channels -% still have heterogenous sampling rates. In this case the automatic -% selection will occur amongst the user specified channels. While reading -% the header the resulting channel selection decision will be stored in -% hdr.orig.chansel and the contents of this field will override chanindx -% during data reading. +% READ_EDF reads specified samples from an EDF datafile. It neglects all trial or +% data block boundaries as if the data was acquired in non-continous mode. % -% Use as -% [hdr] = read_edf(filename); -% where -% filename name of the datafile, including the .edf extension -% This returns a header structure with the following elements -% hdr.Fs sampling frequency -% hdr.nChans number of channels -% hdr.nSamples number of samples per trial -% hdr.nSamplesPre number of pre-trigger samples in each trial -% hdr.nTrials number of trials -% hdr.label cell-array with labels of each channel -% hdr.orig detailled EDF header information +% Note that since FieldTrip only accommodates a single sampling rate in a given +% dataset, whereas EDF allows specification of a sampling rate for each channel. If +% there are heterogenous sampling rates then this function will automatically choose +% a subset. If the last such channel is different from the rest, the assumption will +% be made that it is the annotation channel and the rest will be selected. If that +% is not the case, then the largest subset of channels with a consistent sampling +% rate will be chosen. To avoid this automatic selection process, the user may +% specify their own choice of channels using chanindx. In this case, the automatic +% selection will only occur if the user selected channels still have heterogenous +% sampling rates. In this case the automatic selection will occur amongst the user +% specified channels. While reading the header the resulting channel selection +% decision will be stored in hdr.orig.chansel and the contents of this field will +% override chanindx during data reading. % % Use as -% [hdr] = read_edf(filename, [], chanindx); +% [hdr] = read_edf(filename) % where % filename name of the datafile, including the .edf extension -% chanindx index of channels to read (optional, default is all) -% Note that since % This returns a header structure with the following elements % hdr.Fs sampling frequency % hdr.nChans number of channels @@ -48,7 +31,7 @@ % hdr.orig detailled EDF header information % % Or use as -% [dat] = read_edf(filename, hdr, begsample, endsample, chanindx); +% [dat] = read_edf(filename, hdr, begsample, endsample, chanindx) % where % filename name of the datafile, including the .edf extension % hdr header structure, see above @@ -58,13 +41,13 @@ % This returns a Nchans X Nsamples data matrix % % Or use as -% [evt] = read_edf(filename, hdr); +% [evt] = read_edf(filename, hdr) % where % filename name of the datafile, including the .edf extension % hdr header structure, see above % This returns an Nsamples data vector of just the annotation channel -% Copyright (C) 2006, Robert Oostenveld +% Copyright (C) 2006, Robert Oostenveld and others % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -85,14 +68,14 @@ % $Id$ switch nargin - case 1 - chanindx=[]; - case 2 - chanindx=[]; - case 3 - chanindx=begsample; - case 4 -end; + case 1 + chanindx=[]; + case 2 + chanindx=[]; + case 3 + chanindx=begsample; + case 4 +end needhdr = (nargin==1)||(nargin==3); needevt = (nargin==2); @@ -103,24 +86,24 @@ % read the header, this code is from EEGLAB's openbdf %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% FILENAME = filename; - + % defines Seperator for Subdirectories SLASH='/'; BSLASH=char(92); - + cname=computer; - if cname(1:2)=='PC' SLASH=BSLASH; end; - + if cname(1:2)=='PC' SLASH=BSLASH; end + fid=fopen(FILENAME,'r','ieee-le'); if fid<0 fprintf(2,['Error LOADEDF: File ' FILENAME ' not found\n']); return; - end; - + end + EDF.FILE.FID=fid; EDF.FILE.OPEN = 1; EDF.FileName = FILENAME; - + PPos=min([max(find(FILENAME=='.')) length(FILENAME)+1]); SPos=max([0 find((FILENAME=='/') | (FILENAME==BSLASH))]); EDF.FILE.Ext = FILENAME(PPos+1:length(FILENAME)); @@ -129,44 +112,44 @@ EDF.FILE.Path = pwd; else EDF.FILE.Path = FILENAME(1:SPos-1); - end; + end EDF.FileName = [EDF.FILE.Path SLASH EDF.FILE.Name '.' EDF.FILE.Ext]; - - H1=char(fread(EDF.FILE.FID,256,'char')'); % + + H1=char(fread(EDF.FILE.FID,256,'char')'); EDF.VERSION=H1(1:8); % 8 Byte Versionsnummer - %if 0 fprintf(2,'LOADEDF: WARNING Version EDF Format %i',ver); end; + %if 0 fprintf(2,'LOADEDF: WARNING Version EDF Format %i',ver); end EDF.PID = deblank(H1(9:88)); % 80 Byte local patient identification EDF.RID = deblank(H1(89:168)); % 80 Byte local recording identification %EDF.H.StartDate = H1(169:176); % 8 Byte %EDF.H.StartTime = H1(177:184); % 8 Byte EDF.T0=[str2num(H1(168+[7 8])) str2num(H1(168+[4 5])) str2num(H1(168+[1 2])) str2num(H1(168+[9 10])) str2num(H1(168+[12 13])) str2num(H1(168+[15 16])) ]; - + % Y2K compatibility until year 2090 if EDF.VERSION(1)=='0' if EDF.T0(1) < 91 EDF.T0(1)=2000+EDF.T0(1); else EDF.T0(1)=1900+EDF.T0(1); - end; - else ; + end + else % in a future version, this is hopefully not needed - end; - + end + EDF.HeadLen = str2num(H1(185:192)); % 8 Byte Length of Header % reserved = H1(193:236); % 44 Byte EDF.NRec = str2num(H1(237:244)); % 8 Byte # of data records - EDF.Dur = str2num(H1(245:252)); % 8 Byte # duration of data record in sec - EDF.NS = str2num(H1(253:256)); % 8 Byte # of signals - - EDF.Label = char(fread(EDF.FILE.FID,[16,EDF.NS],'char')'); + EDF.Dur = str2num(H1(245:252)); % 8 Byte # duration of data record in sec + EDF.NS = str2num(H1(253:256)); % 8 Byte # of signals + + EDF.Label = char(fread(EDF.FILE.FID,[16,EDF.NS],'char')'); EDF.Transducer = char(fread(EDF.FILE.FID,[80,EDF.NS],'char')'); - EDF.PhysDim = char(fread(EDF.FILE.FID,[8,EDF.NS],'char')'); - + EDF.PhysDim = char(fread(EDF.FILE.FID,[ 8,EDF.NS],'char')'); + EDF.PhysMin= str2num(char(fread(EDF.FILE.FID,[8,EDF.NS],'char')')); EDF.PhysMax= str2num(char(fread(EDF.FILE.FID,[8,EDF.NS],'char')')); EDF.DigMin = str2num(char(fread(EDF.FILE.FID,[8,EDF.NS],'char')')); EDF.DigMax = str2num(char(fread(EDF.FILE.FID,[8,EDF.NS],'char')')); - + % check validity of DigMin and DigMax if (length(EDF.DigMin) ~= EDF.NS) fprintf(2,'Warning OPENEDF: Failing Digital Minimum\n'); @@ -193,24 +176,23 @@ EDF.PhysMin = EDF.DigMin; EDF.PhysMax = EDF.DigMax; end - EDF.PreFilt= char(fread(EDF.FILE.FID,[80,EDF.NS],'char')'); % - tmp = fread(EDF.FILE.FID,[8,EDF.NS],'char')'; % samples per data record - EDF.SPR = str2num(char(tmp)); % samples per data record - + EDF.PreFilt= char(fread(EDF.FILE.FID,[80,EDF.NS],'char')'); + EDF.SPR = str2num(char(fread(EDF.FILE.FID,[8,EDF.NS],'char')')); % samples per data record + fseek(EDF.FILE.FID,32*EDF.NS,0); - + EDF.Cal = (EDF.PhysMax-EDF.PhysMin)./(EDF.DigMax-EDF.DigMin); EDF.Off = EDF.PhysMin - EDF.Cal .* EDF.DigMin; tmp = find(EDF.Cal < 0); EDF.Cal(tmp) = ones(size(tmp)); EDF.Off(tmp) = zeros(size(tmp)); - + EDF.Calib=[EDF.Off';(diag(EDF.Cal))]; %EDF.Calib=sparse(diag([1; EDF.Cal])); %EDF.Calib(1,2:EDF.NS+1)=EDF.Off'; - + EDF.SampleRate = EDF.SPR / EDF.Dur; - + EDF.FILE.POS = ftell(EDF.FILE.FID); if EDF.NRec == -1 % unknown record size, determine correct NRec fseek(EDF.FILE.FID, 0, 'eof'); @@ -218,15 +200,15 @@ EDF.NRec = floor((endpos - EDF.FILE.POS) / (sum(EDF.SPR) * 2)); fseek(EDF.FILE.FID, EDF.FILE.POS, 'bof'); H1(237:244)=sprintf('%-8i',EDF.NRec); % write number of records - end; - + end + EDF.Chan_Select=(EDF.SPR==max(EDF.SPR)); for k=1:EDF.NS if EDF.Chan_Select(k) EDF.ChanTyp(k)='N'; else EDF.ChanTyp(k)=' '; - end; + end if findstr(upper(EDF.Label(k,:)),'ECG') EDF.ChanTyp(k)='C'; elseif findstr(upper(EDF.Label(k,:)),'EKG') @@ -237,24 +219,24 @@ EDF.ChanTyp(k)='O'; elseif findstr(upper(EDF.Label(k,:)),'EMG') EDF.ChanTyp(k)='M'; - end; - end; - + end + end + if isempty(chanindx) - chanindx=[1:EDF.NS]; - end; - + chanindx=1:EDF.NS; + end + EDF.AS.spb = sum(EDF.SPR); % Samples per Block bi=[0;cumsum(EDF.SPR)]; - + idx=[];idx2=[]; - for k=1:EDF.NS, + for k=1:EDF.NS idx2=[idx2, (k-1)*max(EDF.SPR)+(1:EDF.SPR(k))]; - end; + end maxspr=max(EDF.SPR); idx3=zeros(EDF.NS*maxspr,1); - for k=1:EDF.NS, idx3(maxspr*(k-1)+(1:maxspr))=bi(k)+ceil((1:maxspr)'/maxspr*EDF.SPR(k));end; - + for k=1:EDF.NS, idx3(maxspr*(k-1)+(1:maxspr))=bi(k)+ceil((1:maxspr)'/maxspr*EDF.SPR(k));end + %EDF.AS.bi=bi; EDF.AS.IDX2=idx2; %EDF.AS.IDX3=idx3; @@ -265,25 +247,28 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % convert the header to Fieldtrip-style %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - if all(EDF.SampleRate(chanindx)==EDF.SampleRate(chanindx(1))) - chansel=chanindx; - hdr.Fs = EDF.SampleRate(chanindx(1)); + if all(EDF.SampleRate(chanindx)==EDF.SampleRate(chanindx(1))) + chansel=chanindx; + hdr.Fs = EDF.SampleRate(chanindx(1)); hdr.nChans = length(chansel); - hdr.label = cellstr(EDF.Label); - hdr.label = hdr.label(chansel); + hdr.label = cellstr(EDF.Label(chansel,:)); % it is continuous data, therefore append all records in one trial - hdr.nSamples = EDF.NRec * EDF.SPR(chansel(1)); + hdr.nSamples = EDF.NRec * EDF.SPR(chansel(1)); hdr.nSamplesPre = 0; hdr.nTrials = 1; + hdr.chanunit = cellstr(EDF.PhysDim(chansel,:)); + hdr.chantype = repmat({'unknown'}, size(hdr.chanunit)); % start with unknown + hdr.chantype(strcmp(hdr.chanunit, 'uV')) = {'eeg'}; % it might also be EOG, ECG, EMG, etc + hdr.chantype(strcmp(hdr.chanunit, 'Boolean')) = {'trigger'}; hdr.orig = EDF; % this will be used on subsequent reading of data - if length(chansel) ~= EDF.NS - hdr.orig.chansel = chansel; + if length(chansel) ~= EDF.NS + hdr.orig.chansel = chansel; else - hdr.orig.chansel = 1:hdr.nChans; - end; + hdr.orig.chansel = 1:hdr.nChans; + end hdr.orig.annotation = find(strcmp(cellstr(hdr.orig.Label), 'EDF Annotations')); - + elseif all(EDF.SampleRate(1:end-1)==EDF.SampleRate(1)) % only the last channel has a deviant sampling frequency % this is the case for EGI recorded datasets that have been converted @@ -292,21 +277,21 @@ % continue with the subset of channels that has a consistent sampling frequency hdr.Fs = EDF.SampleRate(chansel(1)); hdr.nChans = length(chansel); - warning('Skipping "%s" as continuous data channel because of inconsistent sampling frequency (%g Hz)', deblank(EDF.Label(end,:)), EDF.SampleRate(end)); - hdr.label = cellstr(EDF.Label); - hdr.label = hdr.label(chansel); + ft_warning('Skipping "%s" as continuous data channel because of inconsistent sampling frequency (%g Hz)', deblank(EDF.Label(end,:)), EDF.SampleRate(end)); + hdr.label = cellstr(EDF.Label(chansel,:)); % it is continuous data, therefore append all records in one trial hdr.nSamples = EDF.NRec * EDF.SPR(chansel(1)); hdr.nSamplesPre = 0; hdr.nTrials = 1; hdr.orig = EDF; % this will be used on subsequent reading of data - hdr.orig.chansel = chansel; + hdr.orig.chansel = chansel; hdr.orig.annotation = find(strcmp(cellstr(hdr.orig.Label), 'EDF Annotations')); - + else % select the sampling rate that results in the most channels [a, b, c] = unique(EDF.SampleRate); + chancount = nan(size(a)); for i=1:length(a) chancount(i) = sum(c==i); end @@ -326,85 +311,79 @@ % this will be used on subsequent reading of data hdr.orig.chansel = chansel; hdr.orig.annotation = find(strcmp(cellstr(hdr.orig.Label), 'EDF Annotations')); - - warning('channels with different sampling rate not supported, using a subselection of %d channels at %f Hz', length(hdr.label), hdr.Fs); + + ft_warning('channels with different sampling rate not supported, selecting subset of %d channels at %f Hz', length(hdr.label), hdr.Fs); end - + % return the header dat = hdr; - + elseif needdat || needevt %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % read the data %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % retrieve the original header EDF = hdr.orig; - - % There can be an optional chansel field containing a list of predefined - % channels. These channels are in that case also the only ones represented in - % the FieldTrip header, which means that teh other channels are simply not - % visible to the naive user. This field can be present because the user - % specified an explicit channel selection in FT_READ_HEADER or because the - % read_edf function had to automatically choose a subset to cope with - % heterogenous sampling rates or even both. In any case, at this point in the - % file reading process the contents of the chansel field has the proper - % specification for channel selection, taking into account both the user channel - % selection as well as any correction that might have been made due to + + % There can be an optional chansel field containing a list of predefined channels. + % These channels are in that case also the only ones represented in the FieldTrip + % header, which means that teh other channels are simply not visible to the naive + % user. This field can be present because the user specified an explicit channel + % selection in FT_READ_HEADER or because the read_edf function had to automatically + % choose a subset to cope with heterogenous sampling rates or even both. In any + % case, at this point in the file reading process the contents of the chansel field + % has the proper specification for channel selection, taking into account both the + % user channel selection as well as any correction that might have been made due to % heterogenous sampling rates. if ~isempty(chanindx) && ~isfield(EDF, 'chansel') % a subset of channels should been selected from the full list of channels in the file chanindx = chanindx; % keep as it is - chanSel = true; + useChanindx = true; elseif ~isempty(chanindx) && isfield(EDF, 'chansel') % a subset of channels should been selected from the predefined list chanindx = EDF.chansel(chanindx); - chanSel = true; + useChanindx = true; elseif isempty(chanindx) && isfield(EDF, 'chansel') % all channels from the predefined list should be selected chanindx = EDF.chansel(chanindx); - chanSel = true; + useChanindx = true; elseif isempty(chanindx) && ~isfield(EDF, 'chansel') % simply select all channels that are present in the file chanindx = 1:EDF.NS; - chanSel = false; - else - % the code should not end up here - error('these were all four possible options') + useChanindx = false; end if needevt % read the annotation channel, not the data channels chanindx = EDF.annotation; begsample = 1; - endsample = EDF.SPR(end)*EDF.NRec; + endsample = EDF.SPR(EDF.annotation)*EDF.NRec; end - if chanSel + if useChanindx epochlength = EDF.SPR(chanindx(1)); % in samples for the selected channel blocksize = sum(EDF.SPR); % in samples for all channels chanoffset = EDF.SPR; chanoffset = round(cumsum([0; chanoffset(1:end-1)])); - % get the selection from the subset of channels - nchans = length(chanindx); - else + nchans = length(chanindx); % get the selection from the subset of channels + else epochlength = EDF.SPR(1); % in samples for a single channel blocksize = sum(EDF.SPR); % in samples for all channels - % use all channels - nchans = EDF.NS; + nchans = EDF.NS; % use all channels end % determine the trial containing the begin and end sample begepoch = floor((begsample-1)/epochlength) + 1; endepoch = floor((endsample-1)/epochlength) + 1; nepochs = endepoch - begepoch + 1; - + % allocate memory to hold the data dat = zeros(length(chanindx),nepochs*epochlength); % read and concatenate all required data epochs for i=begepoch:endepoch - if chanSel + if useChanindx % only a subset of channels with consistent sampling frequency is read offset = EDF.HeadLen + (i-1)*blocksize*2; % in bytes % read the complete data block @@ -413,7 +392,7 @@ % cut out the part that corresponds with a single channel dat(j,((i-begepoch)*epochlength+1):((i-begepoch+1)*epochlength)) = buf((1:epochlength) + chanoffset(chanindx(j))); end - + elseif length(chanindx)==1 % this is more efficient if only one channel has to be read, e.g. the status channel offset = EDF.HeadLen + (i-1)*blocksize*2; % in bytes @@ -421,7 +400,7 @@ % read the data for a single channel buf = readLowLevel(filename, offset, epochlength); % see below in subfunction dat(:,((i-begepoch)*epochlength+1):((i-begepoch+1)*epochlength)) = buf; - + else % read the data from all channels, subsequently select the desired channels offset = EDF.HeadLen + (i-1)*blocksize*2; % in bytes @@ -431,14 +410,14 @@ dat(:,((i-begepoch)*epochlength+1):((i-begepoch+1)*epochlength)) = buf(:,chanindx)'; end end - + % select the desired samples begsample = begsample - (begepoch-1)*epochlength; % correct for the number of bytes that were skipped endsample = endsample - (begepoch-1)*epochlength; % correct for the number of bytes that were skipped dat = dat(:, begsample:endsample); - + % Calibrate the data - if chanSel + if useChanindx calib = diag(EDF.Cal(chanindx)); end if length(chanindx)>1 @@ -462,14 +441,12 @@ fp = fopen(filename,'r','ieee-le'); status = fseek(fp, offset, 'bof'); if status - error(['failed seeking ' filename]); + ft_error(['failed seeking ' filename]); end [buf,num] = fread(fp,numwords,'bit16=>double'); fclose(fp); if (num= first_trigger)) + if ((trigger(1,tr) <= m) && (trigger(1,tr) >= first_trigger)) NoTrig=NoTrig+1; end end diff --git a/external/fieldtrip/fileio/private/read_micromed_trc.m b/external/fieldtrip/fileio/private/read_micromed_trc.m index c20cf8f0..cdc2306f 100644 --- a/external/fieldtrip/fileio/private/read_micromed_trc.m +++ b/external/fieldtrip/fileio/private/read_micromed_trc.m @@ -9,7 +9,7 @@ % ---------------- Opening File------------------ fid=fopen(filename,'rb'); if fid==-1 - error('Can''t open *.trc file') + ft_error('Can''t open *.trc file') end %------------------reading patient & recording info---------- @@ -59,7 +59,7 @@ fseek(fid,175,-1); header.Header_Type=fread(fid,1,'char'); if header.Header_Type ~= 4 - error('*.trc file is not Micromed System98 Header type 4') + ft_error('*.trc file is not Micromed System98 Header type 4') end fseek(fid,138,-1); @@ -142,7 +142,7 @@ datend = ftell(fid); header.Num_Samples = (datend-datbeg)/(header.Bytes*header.Num_Chan); if rem(header.Num_Samples, 1)~=0 - warning('rounding off the number of samples'); + ft_warning('rounding off the number of samples'); header.Num_Samples = floor(header.Num_Samples); end % output the header diff --git a/external/fieldtrip/fileio/private/read_mpi_dap.m b/external/fieldtrip/fileio/private/read_mpi_dap.m index 4147b5fc..22eacbee 100644 --- a/external/fieldtrip/fileio/private/read_mpi_dap.m +++ b/external/fieldtrip/fileio/private/read_mpi_dap.m @@ -71,7 +71,7 @@ analog{w,s,j} = analog{w,s,j} * 2.5/2048; end else - error('unknown analog mode'); + ft_error('unknown analog mode'); end end @@ -177,5 +177,5 @@ dummy = fread(fid, 1, 'int16'); % 14-15 dummy = fread(fid, 1, 'int16'); % 16-17 otherwise - error(sprintf('unsupported format for header (%d)', hdr.headertype)); + ft_error(sprintf('unsupported format for header (%d)', hdr.headertype)); end diff --git a/external/fieldtrip/fileio/private/read_nervus_data.m b/external/fieldtrip/fileio/private/read_nervus_data.m index 307bd88d..c1645116 100644 --- a/external/fieldtrip/fileio/private/read_nervus_data.m +++ b/external/fieldtrip/fileio/private/read_nervus_data.m @@ -38,7 +38,7 @@ if nargin == 0 - error('Missing argument'); + ft_error('Missing argument'); elseif nargin == 1 segment = 1; range = [1 nrvHdr.Segments(1).duration*max(nrvHdr.Segments(1).samplingRate)]; @@ -111,7 +111,7 @@ end if lastSection > lastSectionForSegment - error('Index out of range for current section: %i > %i, on channel: %i', ... + ft_error('Index out of range for current section: %i > %i, on channel: %i', ... range(2), cSectionLengths(lastSectionForSegment+1), chIdx(i)); end diff --git a/external/fieldtrip/fileio/private/read_nervus_header.m b/external/fieldtrip/fileio/private/read_nervus_header.m index d6b27a0f..6b406815 100644 --- a/external/fieldtrip/fileio/private/read_nervus_header.m +++ b/external/fieldtrip/fileio/private/read_nervus_header.m @@ -36,7 +36,7 @@ % ---------------- Opening File------------------ h = fopen(filename,'rb','ieee-le'); if h==-1 - error('Can''t open Nervus EEG file') + ft_error('Can''t open Nervus EEG file') end nrvHdr = struct(); @@ -54,10 +54,11 @@ nrvHdr.PatientInfo = read_nervus_header_patient(h, nrvHdr.StaticPackets, nrvHdr.MainIndex); nrvHdr.SigInfo = read_nervus_header_SignalInfo(h, nrvHdr.StaticPackets, nrvHdr.MainIndex, ITEMNAMESIZE, LABELSIZE, UNITSIZE); nrvHdr.ChannelInfo = read_nervus_header_ChannelInfo(h, nrvHdr.StaticPackets, nrvHdr.MainIndex, ITEMNAMESIZE, LABELSIZE); -nrvHdr.TSInfo = read_nervus_header_TSInfo(h, nrvHdr.DynamicPackets, nrvHdr.MainIndex, ITEMNAMESIZE, TSLABELSIZE, LABELSIZE); +nrvHdr.TSInfo = read_nervus_header_TSInfo(nrvHdr.DynamicPackets, TSLABELSIZE, LABELSIZE); nrvHdr.Segments = read_nervus_header_Segments(h, nrvHdr.StaticPackets, nrvHdr.MainIndex, nrvHdr.TSInfo); nrvHdr.Events = read_nervus_header_events(h, nrvHdr.StaticPackets, nrvHdr.MainIndex); nrvHdr.MontageInfo = read_nervus_header_montage(h, nrvHdr.StaticPackets, nrvHdr.MainIndex); +nrvHdr.MontageInfo2 = read_nervus_header_dynamic_montages(nrvHdr.DynamicPackets); reference = unique(nrvHdr.Segments(1).refName(cellfun(@length, [nrvHdr.Segments(1).refName])>0)); if strcmp(reference, 'REF') @@ -477,20 +478,37 @@ end end -function [TSInfo] = read_nervus_header_TSInfo(h, DynamicPackets, Index, ITEMNAMESIZE, TSLABELSIZE, LABELSIZE) +function [TSInfo] = read_nervus_header_TSInfo(DynamicPackets, TSLABELSIZE, LABELSIZE) tsPackets = DynamicPackets(strcmp({DynamicPackets.IDStr},'TSGUID')); +if isempty(tsPackets) + ft_error(['No TSINFO found']); +end + +tsPacket = tsPackets(1); +TSInfo = read_nervus_header_one_TSInfo(tsPacket, TSLABELSIZE, LABELSIZE); + if length(tsPackets) > 1 - warning(['Multiple TSinfo packets detected; using first instance ' ... - ' ac for all segments. See documentation for info.']); -elseif isempty(tsPackets) - warning(['No TSINFO found']); -else - tsPacket = tsPackets(1); - + allEqual = 1; + for i = 2: size(tsPackets,2) + nextTsPacket = tsPackets(i); + nextTSInfo = read_nervus_header_one_TSInfo(nextTsPacket, TSLABELSIZE, LABELSIZE); + areEqual = compareTsInfoPackets(TSInfo, nextTSInfo); + if (areEqual == 0) + allEqual = 0; + break; + end + end + if (allEqual == 0) + ft_error('Multiple TSInfo packets found and they are not the same.'); + end +end +end + +function [TSInfo] = read_nervus_header_one_TSInfo(tsPacket, TSLABELSIZE, LABELSIZE) TSInfo = struct(); elems = typecast(tsPacket.data(753:756),'uint32'); - alloc = typecast(tsPacket.data(757:760),'uint32'); + %alloc = typecast(tsPacket.data(757:760),'uint32'); offset = 761; for i = 1:elems @@ -518,7 +536,58 @@ offset = offset + 552; %disp([num2str(i) ' : ' TSInfo(i).label ' : ' TSInfo(i).activeSensor ' : ' TSInfo(i).refSensor ' : ' num2str(TSInfo(i).samplingRate)]); end + end + +function areEqual = compareTsInfoPackets(TSInfo1, TSInfo2) + areEqual = 1; + if (size(TSInfo1,2) ~= size(TSInfo2,2)) + areEqual = 0; + else + for i = 1:size(TSInfo1,2) + if (~strcmp(TSInfo1(i).label,TSInfo2(i).label)) + areEqual = 0; + break; + end + if (~strcmp(TSInfo1(i).activeSensor,TSInfo2(i).activeSensor)) + areEqual = 0; + break; + end + if (~strcmp(TSInfo1(i).refSensor,TSInfo2(i).refSensor)) + areEqual = 0; + break; + end + if (TSInfo1(i).lowcut ~= TSInfo2(i).lowcut) + areEqual = 0; + break; + end + if (TSInfo1(i).hiCut ~= TSInfo2(i).hiCut) + areEqual = 0; + break; + end + if (TSInfo1(i).samplingRate ~= TSInfo2(i).samplingRate) + areEqual = 0; + break; + end + if (TSInfo1(i).resolution ~= TSInfo2(i).resolution) + areEqual = 0; + break; + end + if (TSInfo1(i).specialMark ~= TSInfo2(i).specialMark) + areEqual = 0; + break; + end + if (TSInfo1(i).notch ~= TSInfo2(i).notch) + areEqual = 0; + break; + end + if (TSInfo1(i).eeg_offset ~= TSInfo2(i).eeg_offset) + areEqual = 0; + break; + end + end + end + end function [segments] = read_nervus_header_Segments(h, StaticPackets, Index, TSInfo) @@ -679,3 +748,50 @@ end end + +function [montages] = read_nervus_header_dynamic_montages(DynamicPackets) +%% Get montages from the dynamic packets - Jan Brogger - September 2016 + +montagePackets = DynamicPackets(strcmp({DynamicPackets.IDStr},'DERIVATIONGUID')); +montages = struct(); +for numMontage = 1:size(montagePackets,2) + montagePacket = montagePackets(numMontage); + + guidmixed = montagePacket.data(1:16); + guidnonmixed = [guidmixed(04), guidmixed(03), guidmixed(02), guidmixed(01), ... + guidmixed(06), guidmixed(05), guidmixed(08), guidmixed(07), ... + guidmixed(09), guidmixed(10), guidmixed(11), guidmixed(12), ... + guidmixed(13), guidmixed(15), guidmixed(15), guidmixed(16)]; + montages(numMontage).guid1 = num2str(guidnonmixed,'%02X'); + + montages(numMontage).packetSize = typecast(montagePacket.data(17:24),'uint64'); + + guidmixed2 = montagePacket.data(25:40); + guidnonmixed2 = [guidmixed2(04), guidmixed2(03), guidmixed2(02), guidmixed2(01), ... + guidmixed2(06), guidmixed2(05), guidmixed2(08), guidmixed2(07), ... + guidmixed2(09), guidmixed2(10), guidmixed2(11), guidmixed2(12), ... + guidmixed2(13), guidmixed2(15), guidmixed2(15), guidmixed2(16)]; + montages(numMontage).guid2 = num2str(guidnonmixed2,'%02X'); + + montages(numMontage).itemName = deblank(cast(montagePacket.data(41:104),'char')'); + montages(numMontage).elements = typecast(montagePacket.data(745:748),'uint32'); + montages(numMontage).alloc = typecast(montagePacket.data(749:752),'uint32'); + + offset = 753; + for i=1:montages(numMontage).elements + montages(numMontage).channel(i).name = deblank(cast(montagePacket.data(offset:(offset+127)),'char')'); + offset = offset + 128; + montages(numMontage).channel(i).active = deblank(cast(montagePacket.data(offset:(offset+63)),'char')'); + offset = offset + 64; + montages(numMontage).channel(i).reference = deblank(cast(montagePacket.data(offset:(offset+63)),'char')'); + offset = offset + 64; + montages(numMontage).channel(i).isDerived = montagePacket.data(offset); + offset = offset + 1; + montages(numMontage).channel(i).isSpecial = montagePacket.data(offset); + offset = offset + 1; + offset = offset + 256; + offset = offset + 6; + end +end + +end diff --git a/external/fieldtrip/fileio/private/read_neuralynx_bin.m b/external/fieldtrip/fileio/private/read_neuralynx_bin.m index 1626b79f..ae8c7b6b 100644 --- a/external/fieldtrip/fileio/private/read_neuralynx_bin.m +++ b/external/fieldtrip/fileio/private/read_neuralynx_bin.m @@ -88,7 +88,7 @@ format = 'float64'; samplesize = 8; else - warning('could not detect sample format, assuming file format subtype 1 with ''int32'''); + ft_warning('could not detect sample format, assuming file format subtype 1 with ''int32'''); subtype = 1; % the file format is version 1 format = 'int32'; samplesize = 4; @@ -113,14 +113,14 @@ [p, f, x1] = fileparts(filename); [p, f, x2] = fileparts(f); if isempty(x2) - warning('could not determine channel label'); + ft_warning('could not determine channel label'); label = 'unknown'; else label = x2(2:end); end clear p f x1 x2 otherwise - error('unknown file format subtype'); + ft_error('unknown file format subtype'); end % determine the downscale factor, i.e. the number of bits that the integer representation has to be shifted back to the left @@ -131,12 +131,12 @@ downscale = 0; case 2 % these might contain a multiplication factor but that factor cannot be retrieved from the file - warning('downscale factor is unknown for ''%s'', assuming that no downscaling was applied', filename); + ft_warning('downscale factor is unknown for ''%s'', assuming that no downscaling was applied', filename); downscale = 0; case 3 downscale = double(magic(8)); otherwise - error('unknown file format subtype'); + ft_error('unknown file format subtype'); end [p1, f1, x1] = fileparts(filename); @@ -191,7 +191,7 @@ dat = dat.*(2^downscale); end if length(dat)<(endsample-begsample+1) - error('could not read the requested data'); + ft_error('could not read the requested data'); end end % needdat @@ -203,7 +203,7 @@ function [siz] = filesize(filename) l = dir(filename); if l.isdir - error(sprintf('"%s" is not a file', filename)); + ft_error(sprintf('"%s" is not a file', filename)); end siz = l.bytes; diff --git a/external/fieldtrip/fileio/private/read_neuralynx_dma.m b/external/fieldtrip/fileio/private/read_neuralynx_dma.m index a8e75386..5085d2c2 100644 --- a/external/fieldtrip/fileio/private/read_neuralynx_dma.m +++ b/external/fieldtrip/fileio/private/read_neuralynx_dma.m @@ -120,7 +120,7 @@ fclose(fid); if ~nboards - error('could not determine the number of boards and channels'); + ft_error('could not determine the number of boards and channels'); end % deal with ascii and numeric input for the channel selection @@ -168,7 +168,7 @@ case 'all' chanindx = 1:blocksize; otherwise - error('unknown value in channel'); + ft_error('unknown value in channel'); end elseif nargin<4 channel = 'all'; @@ -233,11 +233,11 @@ fclose(fid); % check that the junk at the beginning was correctly detected if (beg_stx~=2048) - error('problem with STX at the begin of the file'); + ft_error('problem with STX at the begin of the file'); end % check that the file is truely continuous, i.e. no gaps with junk in between if (end_stx~=2048) - error('problem with STX at the end of the file'); + ft_error('problem with STX at the end of the file'); end % combine the two uint32 words into a uint64 hdr.FirstTimeStamp = timestamp_neuralynx(beg_tsl, beg_tsh); @@ -257,7 +257,7 @@ dat = fread(fid, [blocksize (endsample-begsample+1)], 'int32=>int32'); fclose(fid); if size(dat,2)<(endsample-begsample+1) - error('could not read all samples'); + ft_error('could not read all samples'); end if ~strcmp(channel, 'all') % select the subset of desired channels @@ -273,7 +273,7 @@ % Note that the last block with 274*4 bytes can sometimes be incomplete, which is relevant when endsample=inf dat = fread(fid, [1 (endsample-begsample+1)], 'int32=>int32', (nboards*32+18-1)*4); if size(dat,2)<(endsample-begsample+1) - error('could not read all samples'); + ft_error('could not read all samples'); end fclose(fid); end diff --git a/external/fieldtrip/fileio/private/read_neuralynx_ds.m b/external/fieldtrip/fileio/private/read_neuralynx_ds.m index d44ec3ed..f97801c2 100644 --- a/external/fieldtrip/fileio/private/read_neuralynx_ds.m +++ b/external/fieldtrip/fileio/private/read_neuralynx_ds.m @@ -74,7 +74,7 @@ ftype_nts = find(ftype==3); if length(fname)==0 - error('the dataset directory contains no supported files'); + ft_error('the dataset directory contains no supported files'); end for i=1:length(fname) @@ -87,7 +87,7 @@ case 3 orig(i) = read_neuralynx_nts(fname{i}, 0, 0); otherwise - error('unsupported'); + ft_error('unsupported'); end end @@ -124,9 +124,9 @@ case 2 recordsize = 32; % each record contains 32 samples case 3 - error('this has not been implemented yet'); + ft_error('this has not been implemented yet'); otherwise - error('unsupported'); + ft_error('unsupported'); end % ensure that the last timestamp refers to the last sample TimeStampPerSample(i) = double(LastTimeStamp(i)-FirstTimeStamp(i))/((NRecords(i)-1)*recordsize); % this should be in double precision, since it can be fractional @@ -134,7 +134,7 @@ end % for length(orig) if any(SamplingFrequency~=SamplingFrequency(1)) - warning('not all channels have the same sampling rate'); + ft_warning('not all channels have the same sampling rate'); end if ~isempty(ftype_ncs) @@ -142,18 +142,18 @@ % there seems to be a matlab bug (observed in Matlab75 on windows) which causes this uint64 comparison to fail if there are exactly 8 files % therefore check once more after converting them to double if any(double(FirstTimeStamp(ftype_ncs))~=double(FirstTimeStamp(ftype_ncs(1)))) - error('not all continuous channels start at the same time'); + ft_error('not all continuous channels start at the same time'); end end if any(LastTimeStamp(ftype_ncs)~=LastTimeStamp(ftype_ncs(1))) % there seems to be a matlab bug (observed in Matlab75 on windows) which causes this uint64 comparison to fail if there are exactly 8 files % therefore check once more after converting them to double if any(double(LastTimeStamp(ftype_ncs))~=double(LastTimeStamp(ftype_ncs(1)))) - warning('not all continuous channels end at the same time'); + ft_warning('not all continuous channels end at the same time'); end end if any(NRecords(ftype_ncs)~=NRecords(ftype_ncs(1))) - warning('not all continuous channels have the same number of records'); + ft_warning('not all continuous channels have the same number of records'); end end % if ftype_ncs diff --git a/external/fieldtrip/fileio/private/read_neuralynx_ncs.m b/external/fieldtrip/fileio/private/read_neuralynx_ncs.m index ef9b72fa..60b962b6 100644 --- a/external/fieldtrip/fileio/private/read_neuralynx_ncs.m +++ b/external/fieldtrip/fileio/private/read_neuralynx_ncs.m @@ -58,7 +58,7 @@ end % if ~isMexv6 && ~mexWarning -% warning('Reading Neuralynx CSC files is faster if you install the MATLAB importer mex files, see http://neuralynx.com/research_software/file_converters_and_utilities/'); +% ft_warning('Reading Neuralynx CSC files is faster if you install the MATLAB importer mex files, see http://neuralynx.com/research_software/file_converters_and_utilities/'); % mexWarning = true; % end @@ -111,7 +111,7 @@ % set to the correct position status = fseek(fid, headersize + (k-1)*recordsize, 'bof'); if status~=0 - error('cannot jump to the requested record'); + ft_error('cannot jump to the requested record'); end % read a single continuous data record @@ -133,7 +133,7 @@ % explain the jump (which is always > one block) Fs = mode(double(SampFreq)); if abs(Fs/hdr.SamplingFrequency-1)>0.01 - warning('the sampling frequency as read out from the header equals %2.2f and differs from the mode sampling frequency as read out from the data %2.2f\n', ... + ft_warning('the sampling frequency as read out from the header equals %2.2f and differs from the mode sampling frequency as read out from the data %2.2f\n', ... hdr.SamplingFrequency, Fs); % check which one was correct @@ -141,7 +141,7 @@ fsEst = 1e6./mode(d); indx = nearest([Fs hdr.SamplingFrequency], fsEst); if indx==1 - warning('correcting the header frequency from %2.2f to %2.2f', hdr.SamplingFrequency, Fs); + ft_warning('correcting the header frequency from %2.2f to %2.2f', hdr.SamplingFrequency, Fs); hdr.SamplingFrequency = Fs; end end @@ -165,7 +165,7 @@ ts_range_predicted = (NRecords-1)*512*gapCorrectedTimeStampPerSample; ts_range_observed = double(tsE-ts1); if abs(ts_range_predicted-ts_range_observed)>minJump - warning('discontinuous recording, predicted number of timestamps and observed number of timestamps differ by %2.2f \n Please consult the wiki on http://www.fieldtriptoolbox.org/getting_started/neuralynx?&#discontinuous_recordings',... + ft_warning('discontinuous recording, predicted number of timestamps and observed number of timestamps differ by %2.2f \n Please consult the wiki on http://www.fieldtriptoolbox.org/getting_started/neuralynx?&#discontinuous_recordings',... abs(ts_range_predicted-ts_range_observed) ); end @@ -177,9 +177,9 @@ if begrecord==0 && endrecord==0 % only read the header elseif begrecord<1 - error('cannot read before the first record'); + ft_error('cannot read before the first record'); elseif begrecord>NRecords - error('cannot read beyond the last record') + ft_error('cannot read beyond the last record') elseif endrecord>NRecords endrecord = NRecords; end @@ -188,20 +188,20 @@ % leave numrecord information here for proper synchronisation numrecord = (endrecord-begrecord+1); if isMexv6 - % warning('Reading with neuralynx_v6 mex files'); + % ft_warning('Reading with neuralynx_v6 mex files'); [TimeStamp, ChanNumber, SampFreq, NumValidSamp, Samp] = Nlx2MatCSC(filename, READ_ALL, HEADER_NO, EXTRACT_RECORD_RANGE, [begrecord, endrecord]); TimeStamp = uint64(TimeStamp); % to match signature of ft_read_... output elseif isMexv3 - % warning('Reading with neuralynx_v3 mex files'); + % ft_warning('Reading with neuralynx_v3 mex files'); % note that the indexing in the mex file is 0-offset (C++ style) rather than 1-offset (MATLAB style) [TimeStamp, ChanNumber, SampFreq, NumValidSamp, Samp] = Nlx2MatCSC_v3(filename, READ_ALL, HEADER_NO, EXTRACT_RECORD_RANGE, [begrecord-1, endrecord-1]); TimeStamp = uint64(TimeStamp); % to match signature of ft_read_... output else - % warning('Reading with native MATLAB code'); + % ft_warning('Reading with native MATLAB code'); % rewind to the first record to be read status = fseek(fid, headersize + (begrecord-1)*recordsize, 'bof'); if status~=0 - error('cannot jump to the requested record'); + ft_error('cannot jump to the requested record'); end TimeStamp = zeros(1,numrecord,'uint64'); diff --git a/external/fieldtrip/fileio/private/read_neuralynx_nev.m b/external/fieldtrip/fileio/private/read_neuralynx_nev.m index 05953e46..fc5ddaa0 100644 --- a/external/fieldtrip/fileio/private/read_neuralynx_nev.m +++ b/external/fieldtrip/fileio/private/read_neuralynx_nev.m @@ -94,7 +94,7 @@ if implementation==1 if ~isempty(flt_maxnumber) - warning('filtering on maximum number not yet implemneted'); + ft_warning('filtering on maximum number not yet implemneted'); end % this is the slow way of reading it % it also does not allow filtering @@ -115,7 +115,7 @@ if implementation==2 if ~isempty(flt_maxnumber) - warning('filtering on maximum number not yet implemneted'); + ft_warning('filtering on maximum number not yet implemneted'); end % this is a faster way of reading it and it is still using the automatic type conversion from Matlab fp = offset; @@ -152,7 +152,7 @@ flt_maxnumber = inf; end if fseek(fid, offset, 'bof')~=0 - error(ferror(fid)); + ft_error(ferror(fid)); end buf = fread(fid, (flt_maxnumber-flt_minnumber+1)*184, 'uint8=>uint8'); [PktStart, PktId , PktDataSize , TimeStamp , EventId , TTLValue , CRC , Dummy , Extra1 , Extra2 , Extra3 , Extra4 , Extra5 , Extra6 , Extra7 , Extra8 , EventString] = ... diff --git a/external/fieldtrip/fileio/private/read_neuralynx_nse.m b/external/fieldtrip/fileio/private/read_neuralynx_nse.m index bbaf2c79..70075f81 100644 --- a/external/fieldtrip/fileio/private/read_neuralynx_nse.m +++ b/external/fieldtrip/fileio/private/read_neuralynx_nse.m @@ -63,9 +63,9 @@ if begrecord==0 && endrecord==0 % only read the header elseif begrecord<1 - error('cannot read before the first record'); + ft_error('cannot read before the first record'); elseif begrecord>NRecords - error('cannot read beyond the last record') + ft_error('cannot read beyond the last record') elseif endrecord>NRecords endrecord = NRecords; end diff --git a/external/fieldtrip/fileio/private/read_neuralynx_nst.m b/external/fieldtrip/fileio/private/read_neuralynx_nst.m index 8cb2e889..3f9b4a48 100644 --- a/external/fieldtrip/fileio/private/read_neuralynx_nst.m +++ b/external/fieldtrip/fileio/private/read_neuralynx_nst.m @@ -62,9 +62,9 @@ if begrecord==0 && endrecord==0 % only read the header elseif begrecord<1 - error('cannot read before the first record'); + ft_error('cannot read before the first record'); elseif begrecord>NRecords - error('cannot read beyond the last record') + ft_error('cannot read beyond the last record') elseif endrecord>NRecords endrecord = NRecords; end @@ -84,7 +84,7 @@ % rewind to the first record to be read status = fseek(fid, headersize + (begrecord-1)*recordsize, 'bof'); if status~=0 - error('cannot jump to the requested record'); + ft_error('cannot jump to the requested record'); end numrecord = (endrecord-begrecord+1); diff --git a/external/fieldtrip/fileio/private/read_neuralynx_nts.m b/external/fieldtrip/fileio/private/read_neuralynx_nts.m index 6e21d171..6c23b9a6 100644 --- a/external/fieldtrip/fileio/private/read_neuralynx_nts.m +++ b/external/fieldtrip/fileio/private/read_neuralynx_nts.m @@ -46,9 +46,9 @@ if begrecord==0 && endrecord==0 % only read the header elseif begrecord<1 - error('cannot read before the first record'); + ft_error('cannot read before the first record'); elseif begrecord>NRecords - error('cannot read beyond the last record') + ft_error('cannot read beyond the last record') elseif endrecord>NRecords endrecord = NRecords; end diff --git a/external/fieldtrip/fileio/private/read_neuralynx_ntt.m b/external/fieldtrip/fileio/private/read_neuralynx_ntt.m index 2566f7a5..863563f3 100644 --- a/external/fieldtrip/fileio/private/read_neuralynx_ntt.m +++ b/external/fieldtrip/fileio/private/read_neuralynx_ntt.m @@ -73,9 +73,9 @@ if begrecord==0 && endrecord==0 % only read the header elseif begrecord<1 - error('cannot read before the first record'); + ft_error('cannot read before the first record'); elseif begrecord>NRecords - error('cannot read beyond the last record') + ft_error('cannot read beyond the last record') elseif endrecord>NRecords endrecord = NRecords; end @@ -84,7 +84,7 @@ % rewind to the first record to be read status = fseek(fid, headersize + (begrecord-1)*recordsize, 'bof'); if status~=0 - error('cannot jump to the requested record'); + ft_error('cannot jump to the requested record'); end numrecord = (endrecord-begrecord+1); diff --git a/external/fieldtrip/fileio/private/read_neuralynx_sdma.m b/external/fieldtrip/fileio/private/read_neuralynx_sdma.m index 4bfaa70b..6a127672 100644 --- a/external/fieldtrip/fileio/private/read_neuralynx_sdma.m +++ b/external/fieldtrip/fileio/private/read_neuralynx_sdma.m @@ -43,7 +43,7 @@ needdat = (nargin>=2); if ~isdir(dataset) - error('dataset should be a directory'); + ft_error('dataset should be a directory'); end % determine the content of the dataset directory @@ -406,7 +406,7 @@ % determine the number of samples for each channel nsamples = cell2mat({orig.nSamples}); if any(nsamples~=nsamples(1)) - error('different number of samples over channels are not supported'); + ft_error('different number of samples over channels are not supported'); else hdr.nSamples = nsamples(1); end @@ -414,9 +414,9 @@ % determine the sampling frequency for each channel fsample = cell2mat({orig.Fs}); if any(diff(fsample)) - error('different sampling rates over channels are not supported'); + ft_error('different sampling rates over channels are not supported'); elseif any(fsample~=hdr.Fs) - error('inconsistent sampling rates'); + ft_error('inconsistent sampling rates'); end % determine the first and last timestamp, by reading them from the timestamp channels diff --git a/external/fieldtrip/fileio/private/read_neuralynx_ttl.m b/external/fieldtrip/fileio/private/read_neuralynx_ttl.m index 1e067d3a..45939823 100644 --- a/external/fieldtrip/fileio/private/read_neuralynx_ttl.m +++ b/external/fieldtrip/fileio/private/read_neuralynx_ttl.m @@ -45,7 +45,7 @@ fseek(fid, begsample-1, 'cof'); % skip to the beginning of the interesting data dat = fread(fid, endsample-begsample+1, 'uint32=>uint32')'; if length(dat)<(endsample-begsample+1) - error('could not read the requested data'); + ft_error('could not read the requested data'); end fclose(fid); diff --git a/external/fieldtrip/fileio/private/read_neuromag_hc.m b/external/fieldtrip/fileio/private/read_neuromag_hc.m index d82935d6..70c87524 100644 --- a/external/fieldtrip/fileio/private/read_neuromag_hc.m +++ b/external/fieldtrip/fileio/private/read_neuromag_hc.m @@ -57,7 +57,7 @@ % 1 is device, i.e. dewar % 4 is fiducial system, i.e. head coordinates if hdr.orig.dig(i).coord_frame~=4 - warning(['Digitiser point (' num2str(i) ') not stored in head coordinates!']); + ft_warning(['Digitiser point (' num2str(i) ') not stored in head coordinates!']); end switch hdr.orig.dig(i).kind % constants defined in MNE - see p.215 of MNE manual @@ -72,7 +72,7 @@ case 3 % RPA hc.head.label{posN} = 'RPA'; otherwise - error('Unidentified cardinal point in file'); + ft_error('Unidentified cardinal point in file'); end posN = posN + 1; @@ -92,7 +92,7 @@ posN = posN + 1; otherwise - warning('Unidentified digitiser point in file!'); + ft_warning('Unidentified digitiser point in file!'); end end @@ -112,7 +112,7 @@ hdr.orig.dig(k).coord_frame = 1; end else - warning('No device to head transform available in fif file'); + ft_warning('No device to head transform available in fif file'); return end @@ -123,7 +123,7 @@ % 1 is device, i.e. dewar % 4 is fiducial system, i.e. head coordinates if hdr.orig.dig(i).coord_frame~=1 - warning(['Digitiser point (' num2str(i) ') not stored in head coordinates!']); + ft_warning(['Digitiser point (' num2str(i) ') not stored in head coordinates!']); end switch hdr.orig.dig(i).kind % constants defined in MNE - see p.215 of MNE manual @@ -138,7 +138,7 @@ case 3 % RPA hc.dewar.label{posN} = 'RPA'; otherwise - error('Unidentified cardinal point in file'); + ft_error('Unidentified cardinal point in file'); end posN = posN + 1; @@ -158,7 +158,7 @@ posN = posN + 1; otherwise - warning('Unidentified digitiser point in file!'); + ft_warning('Unidentified digitiser point in file!'); end end diff --git a/external/fieldtrip/fileio/private/read_neuroshare.m b/external/fieldtrip/fileio/private/read_neuroshare.m index 506e6320..69b70f80 100644 --- a/external/fieldtrip/fileio/private/read_neuroshare.m +++ b/external/fieldtrip/fileio/private/read_neuroshare.m @@ -116,7 +116,7 @@ % give warning if unkown entities are found if ~isempty(list.unknown) - warning(['There are ' num2str(length(list.unknown)) ' unknown entities found, these will be ignored.']); + ft_warning(['There are ' num2str(length(list.unknown)) ' unknown entities found, these will be ignored.']); end % retrieve event information @@ -172,7 +172,7 @@ end end elseif strcmp(readevent, 'yes') && isempty(list.event) - warning('no events were found in the data') + ft_warning('no events were found in the data') end @@ -202,7 +202,7 @@ [feedback analog.contcount analog.data] = ns_GetAnalogData(fileID, chanindx, begsample, itemcount); if feedback~=0, [feedback err] = ns_GetLastErrorMsg; disp(err), end elseif strcmp(readanalog, 'yes') && isempty(list.analog) - warning('no analog events were found in the data') + ft_warning('no analog events were found in the data') end @@ -214,7 +214,7 @@ [feedback segment.timestamp segment.data segment.samplecount segment.unitID] = ns_GetSegmentData(fileID, list.segment, 1:max([hdr.entityinfo(list.segment).ItemCount])); if feedback~=0, [feedback err] = ns_GetLastErrorMsg; disp(err), end elseif strcmp(readspike, 'yes') && isempty(list.segment) - warning('no spike waveforms were found in the data') + ft_warning('no spike waveforms were found in the data') end % retrieve neural events [ spike timestamps ] @@ -225,7 +225,7 @@ if feedback~=0, [feedback err] = ns_GetLastErrorMsg; disp(err), end end elseif strcmp(readspike, 'yes') && isempty(list.neural) - warning('no spike timestamps were found in the data') + ft_warning('no spike timestamps were found in the data') end diff --git a/external/fieldtrip/fileio/private/read_nex_data.m b/external/fieldtrip/fileio/private/read_nex_data.m index b4bfeb2e..f6a01372 100644 --- a/external/fieldtrip/fileio/private/read_nex_data.m +++ b/external/fieldtrip/fileio/private/read_nex_data.m @@ -70,7 +70,7 @@ % this just reads the indices of LFP starts ind = fread(fid,hdr.varheader(sgn(sgnlop)).cnt,'int32'); if length(ind)>1 - error('multiple A/D segments are not supported'); + ft_error('multiple A/D segments are not supported'); end % convert from timestamps to samples, expressed in the sampling frequency of the AD channels @@ -81,9 +81,9 @@ ch_endsample = endsample - tim; if (ch_begsample<1) - error(sprintf('cannot read before the begin of the recorded data (channel %d)', sgn(sgnlop))); + ft_error(sprintf('cannot read before the begin of the recorded data (channel %d)', sgn(sgnlop))); elseif (ch_endsample>hdr.varheader(sgn(sgnlop)).numsmp) - error(sprintf('cannot read beyond the end of the recorded data (channel %d)', sgn(sgnlop))); + ft_error(sprintf('cannot read beyond the end of the recorded data (channel %d)', sgn(sgnlop))); end % seek to the beginning of the interesting data, correct for the A/D card initialisation delay @@ -94,7 +94,7 @@ dat(sgnlop,:) = dum(:)' * hdr.varheader(sgn(sgnlop)).adtomv; else - % warning('unsupported data format for channel %s', hdr.label{sgn(sgnlop)}); + % ft_warning('unsupported data format for channel %s', hdr.label{sgn(sgnlop)}); end end diff --git a/external/fieldtrip/fileio/private/read_nex_event.m b/external/fieldtrip/fileio/private/read_nex_event.m index d01b15d9..7ffd7827 100644 --- a/external/fieldtrip/fileio/private/read_nex_event.m +++ b/external/fieldtrip/fileio/private/read_nex_event.m @@ -44,7 +44,7 @@ hdr = read_nex_header(filename); adindx = find(cell2mat({hdr.varheader.typ})==5); if isempty(adindx) % this would otherwise produce an error - warning('No continuous variables found - using hdr.filheader.frequency'); + ft_warning('No continuous variables found - using hdr.filheader.frequency'); smpfrq = hdr.filheader.frequency; else smpfrq = hdr.varheader(adindx(1)).wfrequency; @@ -59,17 +59,26 @@ for mrkn = 1:numel(mrkvarnum) status = fseek(fid,hdr.varheader(mrkvarnum(mrkn)).offset,'bof'); - if status < 0; error('error with fseek'); end + if status < 0; ft_error('error with fseek'); end % read the time of the triggers dum = fread(fid,hdr.varheader(mrkvarnum(mrkn)).cnt,'int32'); + + % skip importing this marker if empty + if isempty(dum) + ft_warning(['skipping marker ' deblank(hdr.varheader(mrkvarnum(mrkn)).nam) ... + ' because no timestamps were found']) + continue + end + + % convert timestamp to sample number timestamp = dum; dum = dum ./(hdr.filheader.frequency./smpfrq); mrk.tim = round(dum); % read the value of the triggers status = fseek(fid,64,'cof'); - if status < 0; error('error with fseek'); end + if status < 0; ft_error('error with fseek'); end dum = fread(fid, [hdr.varheader(mrkvarnum(mrkn)).mrklen, ... hdr.varheader(mrkvarnum(mrkn)).cnt], 'uchar'); mrk.val = str2num(char(dum(1:5,:)')); %#ok non-scalar @@ -97,11 +106,19 @@ for int = 1:numel(intvarnum) status = fseek(fid,hdr.varheader(intvarnum(int)).offset,'bof'); - if status < 0; error('error with fseek'); end + if status < 0; ft_error('error with fseek'); end % read the time of the triggers dum1 = fread(fid,hdr.varheader(intvarnum(int)).cnt,'int32'); dum2 = fread(fid,hdr.varheader(intvarnum(int)).cnt,'int32'); + + % skip importing this interval if empty + if isempty(dum1) && isempty(dum2) + ft_warning(['skipping interval ' deblank(hdr.varheader(intvarnum(int)).nam) ... + ' because no timestamps were found']) + continue + end + timestamp = dum1; dum1 = dum1 ./(hdr.filheader.frequency./smpfrq); dum2 = dum2 ./(hdr.filheader.frequency./smpfrq); @@ -131,10 +148,19 @@ for ev = 1:numel(evtvarnum) status = fseek(fid,hdr.varheader(evtvarnum(ev)).offset,'bof'); - if status < 0; error('error with fseek'); end + if status < 0; ft_error('error with fseek'); end % read the time of the triggers dum = fread(fid,hdr.varheader(evtvarnum(ev)).cnt,'int32'); + + % skip importing this event if empty + if isempty(dum) + ft_warning(['skipping event ' deblank(hdr.varheader(evtvarnum(ev)).nam) ... + ' because no timestamps were found']) + continue + end + + % convert timestamp to sample number timestamp = dum; dum = dum ./(hdr.filheader.frequency./smpfrq); evt.tim = round(dum); @@ -159,4 +185,4 @@ end status = fclose(fid); -if status < 0; error('error with fclose'); end +if status < 0; ft_error('error with fclose'); end diff --git a/external/fieldtrip/fileio/private/read_nifti2_hdr.m b/external/fieldtrip/fileio/private/read_nifti2_hdr.m index de580177..fb4ac727 100644 --- a/external/fieldtrip/fileio/private/read_nifti2_hdr.m +++ b/external/fieldtrip/fileio/private/read_nifti2_hdr.m @@ -53,14 +53,14 @@ if hdr.sizeof_hdr~=348 && hdr.sizeof_hdr~=540 fclose(fid); - error('cannot open %s as nifti file, hdr size = %d, should be 348 or 540\n', filename, hdr.sizeof_hdr); + ft_error('cannot open %s as nifti file, hdr size = %d, should be 348 or 540\n', filename, hdr.sizeof_hdr); else % the file is now open with the appropriate little or big-endianness end if hdr.sizeof_hdr==348 % the remainder of the code is for nifti-2 files - error('%s seems to be a nifti-1 file', filename) + ft_error('%s seems to be a nifti-1 file', filename) end hdr.magic = fread(fid, [1 8 ], 'int8=>int8' ); % 4 `n', '+', `2', `\0','\r','\n','\032','\n' or (0x6E,0x2B,0x32,0x00,0x0D,0x0A,0x1A,0x0A) @@ -70,7 +70,7 @@ if hdr.dim(1)<1 || hdr.dim(1)>7 % see http://nifti.nimh.nih.gov/nifti-1/documentation/nifti1fields/nifti1fields_pages/dim.html - error('inconsistent endianness in the header'); + ft_error('inconsistent endianness in the header'); end hdr.intent_p1 = fread(fid, [1 1 ], 'double=>double' ); % 80 0 diff --git a/external/fieldtrip/fileio/private/read_nihonkohden_hdr.m b/external/fieldtrip/fileio/private/read_nihonkohden_hdr.m index d9d0f0cd..eb16bb16 100644 --- a/external/fieldtrip/fileio/private/read_nihonkohden_hdr.m +++ b/external/fieldtrip/fileio/private/read_nihonkohden_hdr.m @@ -101,4 +101,4 @@ clear dat; % close input file -fclose(fid); \ No newline at end of file +fclose(fid); diff --git a/external/fieldtrip/fileio/private/read_nmc_archive_k_data.m b/external/fieldtrip/fileio/private/read_nmc_archive_k_data.m index f0d7d689..39c7570e 100644 --- a/external/fieldtrip/fileio/private/read_nmc_archive_k_data.m +++ b/external/fieldtrip/fileio/private/read_nmc_archive_k_data.m @@ -44,7 +44,7 @@ % Getting data-directory out of data-filename and check datadir = datafile(1:(findstr(datafile, 'eeg.noreref')+11)); if exist(datadir,'dir') ~= 7 - error('no proper data-directory provided, please check your paths'); + ft_error('no proper data-directory provided, please check your paths'); end % Getting session name + path out of data-filename diff --git a/external/fieldtrip/fileio/private/read_nmc_archive_k_event.m b/external/fieldtrip/fileio/private/read_nmc_archive_k_event.m index d32ff2c8..ae570547 100644 --- a/external/fieldtrip/fileio/private/read_nmc_archive_k_event.m +++ b/external/fieldtrip/fileio/private/read_nmc_archive_k_event.m @@ -37,7 +37,7 @@ % Checking events-file: if exist(eventfile,'file') ~= 2 - error('no events.mat file found in specified directory'); + ft_error('no events.mat file found in specified directory'); end % Load event-file as events_old @@ -94,5 +94,5 @@ % Send warning if no events are found for current session if isempty(event) - warning(['no events found for session: ' sessionname ' of subject: ' subjname]) + ft_warning(['no events found for session: ' sessionname ' of subject: ' subjname]) end diff --git a/external/fieldtrip/fileio/private/read_nmc_archive_k_hdr.m b/external/fieldtrip/fileio/private/read_nmc_archive_k_hdr.m index 5c7b3407..8c9db12a 100644 --- a/external/fieldtrip/fileio/private/read_nmc_archive_k_hdr.m +++ b/external/fieldtrip/fileio/private/read_nmc_archive_k_hdr.m @@ -37,7 +37,7 @@ % Checking paramfile if exist(paramfile,'file') ~= 2 - error('specified newparams.txt file not found'); + ft_error('specified newparams.txt file not found'); end % Reading samplingrate and channelnumber from paramfile @@ -74,7 +74,7 @@ channelnum = list(end); missingchan = setdiff(1:list(end),list); catch - error('error in newparams.txt, certain variables not present for subject') + ft_error('error in newparams.txt, certain variables not present for subject') end end end % while @@ -91,7 +91,7 @@ if strcmp(param,'dataformat') dataformat = value(3:end-1); if ~strcmp(dataformat, 'short') && ~strcmp(dataformat, 'int16') - error('dataformat from newparams.txt not recognized') + ft_error('dataformat from newparams.txt not recognized') end end if ~isempty(dataformat) @@ -106,7 +106,7 @@ if strcmp(dataformat, 'short') || strcmp(dataformat, 'int16') nBytes = 2; else - error('dataformat from newparams.txt not recognized') + ft_error('dataformat from newparams.txt not recognized') end % Get missing channel numbers from paramfile if not read in from above @@ -161,7 +161,7 @@ elseif strcmp(paramfile(end-10:end),'.params.txt') datafile = [paramfile(1:end-11) channelext]; else - error(['could not properly parse param-file: ' paramfile]) + ft_error(['could not properly parse param-file: ' paramfile]) end datafid = fopen(datafile,'r','l'); fseek(datafid,0,'eof'); diff --git a/external/fieldtrip/fileio/private/read_ns_avg.m b/external/fieldtrip/fileio/private/read_ns_avg.m index 521163e3..09942bf4 100644 --- a/external/fieldtrip/fileio/private/read_ns_avg.m +++ b/external/fieldtrip/fileio/private/read_ns_avg.m @@ -51,7 +51,7 @@ % open the file and seek towards the place where the raw data is fid = fopen(filename,'r','ieee-le'); if fid<0 - error(['cannot open ', filename]); + ft_error(['cannot open ', filename]); else fseek(fid, 900, 'cof'); % skip general header fseek(fid, 75*avg.nchan, 'cof'); % skip channel headers diff --git a/external/fieldtrip/fileio/private/read_ns_eeg.m b/external/fieldtrip/fileio/private/read_ns_eeg.m index 3b371b8b..6008f940 100644 --- a/external/fieldtrip/fileio/private/read_ns_eeg.m +++ b/external/fieldtrip/fileio/private/read_ns_eeg.m @@ -51,7 +51,7 @@ % open the file and seek towards the place where the raw data is fid = fopen(filename,'r','ieee-le'); if fid<0 - error(['cannot open ', filename]); + ft_error(['cannot open ', filename]); end % the default is to read all epochs @@ -74,7 +74,7 @@ epoch_size = eeg.nchan*eeg.npnt*4 + 13; elseif floor(sample_size)>4 % although this is not to be expected, it might be due to a very large "footer" compared to the data size - % Olga Sysoeva reported that this extention to the datatype detection fixed it for her (see http://bugzilla.fcdonders.nl/show_bug.cgi?id=547) + % Olga Sysoeva reported that this extention to the datatype detection fixed it for her (see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=547) datatype ='int32'; epoch_size = eeg.nchan*eeg.npnt*4 + 13; end @@ -88,7 +88,7 @@ fseek(fid, 75*eeg.nchan, 'cof'); % skip channel headers status = fseek(fid, (epoch(i)-1)*epoch_size, 'cof'); % skip first epochs if status~=0 - error('seek error while reading epoch data'); + ft_error('seek error while reading epoch data'); end % fprintf('reading epoch %d at offset %d\n', epoch(i), ftell(fid)); @@ -104,7 +104,7 @@ % read raw signal raw = fread(fid, eeg.nchan*eeg.npnt, datatype); if length(raw)~=eeg.nchan*eeg.npnt - error('fread error while reading epoch data'); + ft_error('fread error while reading epoch data'); end data(i,:,:) = reshape(raw, [eeg.nchan, eeg.npnt]); diff --git a/external/fieldtrip/fileio/private/read_ns_hdr.m b/external/fieldtrip/fileio/private/read_ns_hdr.m index 3f22b6dc..689ada48 100644 --- a/external/fieldtrip/fileio/private/read_ns_hdr.m +++ b/external/fieldtrip/fileio/private/read_ns_hdr.m @@ -37,7 +37,7 @@ fid = fopen(filename,'r','ieee-le'); if fid<0, - error(['cannot open ', filename]); + ft_error(['cannot open ', filename]); end; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -310,7 +310,7 @@ % data in frequency domain else % probably old datafile, assume the data to be in time domain - warning('assuming the data to be in time domain (domain was %d)', hdr.domain); + ft_warning('assuming the data to be in time domain (domain was %d)', hdr.domain); hdr.domain=0; end diff --git a/external/fieldtrip/fileio/private/read_off.m b/external/fieldtrip/fileio/private/read_off.m index e327a80c..189cd84a 100644 --- a/external/fieldtrip/fileio/private/read_off.m +++ b/external/fieldtrip/fileio/private/read_off.m @@ -33,7 +33,7 @@ [s, count] = fscanf(fid, '%s\n', 1); if ~strcmp(s,'OFF') msg = sprintf('wrong file type %s', s); - error(msg); + ft_error(msg); end % read the number of vertex points and triangles @@ -51,7 +51,7 @@ fclose(fid); else - error('unable to open file'); + ft_error('unable to open file'); end diff --git a/external/fieldtrip/fileio/private/read_plexon_ddt.m b/external/fieldtrip/fileio/private/read_plexon_ddt.m index 89cb0657..b1771586 100644 --- a/external/fieldtrip/fileio/private/read_plexon_ddt.m +++ b/external/fieldtrip/fileio/private/read_plexon_ddt.m @@ -92,7 +92,7 @@ dat.MaxMagnitudeMV = fread(fid, 1, 'short'); dat.Padding = fread(fid, 189, 'char'); else - error('unsupported version of ddt file'); + ft_error('unsupported version of ddt file'); end % determine the number of samples by looking at the length of the datafile diff --git a/external/fieldtrip/fileio/private/read_plexon_ds.m b/external/fieldtrip/fileio/private/read_plexon_ds.m index 15732bd0..218fb7e4 100644 --- a/external/fieldtrip/fileio/private/read_plexon_ds.m +++ b/external/fieldtrip/fileio/private/read_plexon_ds.m @@ -59,9 +59,9 @@ ftype = ftype(ftype>0); if isempty(fname) - error('the directory contains no supported files'); + ft_error('the directory contains no supported files'); elseif any(ftype~=1) - error('only nex files are supported in a plexon dataset directory'); + ft_error('only nex files are supported in a plexon dataset directory'); end for i=1:length(fname) @@ -70,17 +70,17 @@ case 1 orig(i) = read_plexon_nex(fname{i}); case 'plexon_plx' - error('plx files are not supported in plexon dataset directory'); + ft_error('plx files are not supported in plexon dataset directory'); case 'plexon_ddt' - error('ddt files are not supported in plexon dataset directory'); + ft_error('ddt files are not supported in plexon dataset directory'); otherwise - error('unsupported file in plexon dataset directory'); + ft_error('unsupported file in plexon dataset directory'); end end for i=1:length(fname) if length(orig(i).VarHeader)>1 - error('multiple channels in a single NEX file not supported'); + ft_error('multiple channels in a single NEX file not supported'); else % combine the information from the different files in a single header label{i} = deblank(orig(i).VarHeader.Name); @@ -95,27 +95,27 @@ end if any(Type~=5) - error('not all channels contain continuous data'); + ft_error('not all channels contain continuous data'); end if any(WFrequency~=WFrequency(1)) - warning('not all channels have the same sampling rate'); + ft_warning('not all channels have the same sampling rate'); end if any(Frequency~=Frequency(1)) - warning('not all channels have the same timestamp rate'); + ft_warning('not all channels have the same timestamp rate'); end if any(Beg~=Beg(1)) - warning('not all channels start at the same time'); + ft_warning('not all channels start at the same time'); end if any(End~=End(1)) - warning('not all channels end at the same time'); + ft_warning('not all channels end at the same time'); end if any(NPointsWave~=NPointsWave(1)) - warning('not all channels have the same number of samples'); + ft_warning('not all channels have the same number of samples'); end % construct the header that applies to all channels combined @@ -164,11 +164,11 @@ nex = read_plexon_nex(thisfile, 'header', hdr.orig(thischan), 'channel', 1, 'begsample', begsample, 'endsample', endsample); % always read the first and only channel dat(i,:) = nex.dat; case 'plexon_plx' - error('plx files are not supported in plexon dataset directory'); + ft_error('plx files are not supported in plexon dataset directory'); case 'plexon_ddt' - error('ddt files are not supported in plexon dataset directory'); + ft_error('ddt files are not supported in plexon dataset directory'); otherwise - error('unsupported file in plexon dataset directory'); + ft_error('unsupported file in plexon dataset directory'); end end end diff --git a/external/fieldtrip/fileio/private/read_plexon_nex.m b/external/fieldtrip/fileio/private/read_plexon_nex.m index 19230413..5ac1e1e5 100644 --- a/external/fieldtrip/fileio/private/read_plexon_nex.m +++ b/external/fieldtrip/fileio/private/read_plexon_nex.m @@ -67,7 +67,7 @@ % sizeof(NexVarHeader) = 208 hdr.FileHeader = NexFileHeader(fid); if hdr.FileHeader.NumVars<1 - error('no channels present in file'); + ft_error('no channels present in file'); end hdr.VarHeader = NexVarHeader(fid, hdr.FileHeader.NumVars); end @@ -102,14 +102,14 @@ case 4 % Population vector - error('population vectors are not supported'); + ft_error('population vectors are not supported'); case 5 % Continuously recorded variables buf.ts = fread(fid, [1 vh.Count], 'int32=>int32'); buf.indx = fread(fid, [1 vh.Count], 'int32=>int32'); if vh.Count>1 && (begsample~=1 || endsample~=inf) - error('reading selected samples from multiple AD segments is not supported'); + ft_error('reading selected samples from multiple AD segments is not supported'); end if ~tsonly numsample = min(endsample - begsample + 1, vh.NPointsWave); @@ -130,7 +130,7 @@ end otherwise - error('incorrect channel type'); + ft_error('incorrect channel type'); end % switch channel type % return the data of this channel diff --git a/external/fieldtrip/fileio/private/read_plexon_plx.m b/external/fieldtrip/fileio/private/read_plexon_plx.m index 22411f8d..2d4b1189 100644 --- a/external/fieldtrip/fileio/private/read_plexon_plx.m +++ b/external/fieldtrip/fileio/private/read_plexon_plx.m @@ -152,7 +152,7 @@ sel = find(sel); if isempty(sel) - warning('spike channel %d contains no data', ChannelIndex(i)); + ft_warning('spike channel %d contains no data', ChannelIndex(i)); varargin{end+1} = []; continue; end @@ -162,7 +162,7 @@ % check whether the number of samples per block makes sense if any(num~=num(1)) - error('spike channel blocks with diffent number of samples'); + ft_error('spike channel blocks with diffent number of samples'); end % allocate memory to hold the data @@ -214,8 +214,8 @@ sel = find(sel); if isempty(sel) - error(sprintf('Continuous channel %d contains no data', SlowChannelIndex(i))); - % warning('Continuous channel %d contains no data', SlowChannelIndex(i)); + ft_error(sprintf('Continuous channel %d contains no data', SlowChannelIndex(i))); + % ft_warning('Continuous channel %d contains no data', SlowChannelIndex(i)); % varargin{end+1} = []; % continue; end @@ -274,7 +274,7 @@ % all information is already contained in the DataBlockHeader, i.e. there is nothing to read if isempty(sel) - warning('event channel %d contains no data', EventIndex(i)); + ft_warning('event channel %d contains no data', EventIndex(i)); end event.TimeStamp = ts(sel); event.Channel = chan(sel); diff --git a/external/fieldtrip/fileio/private/read_ply.m b/external/fieldtrip/fileio/private/read_ply.m index b28fbdc7..ea36fa73 100644 --- a/external/fieldtrip/fileio/private/read_ply.m +++ b/external/fieldtrip/fileio/private/read_ply.m @@ -25,13 +25,13 @@ line = readline(fid); if ~strcmp(line, 'ply') fclose(fid); - error('unexpected header line'); + ft_error('unexpected header line'); end line = readline(fid); if ~strncmp(line, 'format', 6) fclose(fid); - error('unexpected header line'); + ft_error('unexpected header line'); else format = line(8:end); end @@ -39,7 +39,7 @@ if ~strncmp(line, 'element vertex', 14) fclose(fid); - error('unexpected header line'); + ft_error('unexpected header line'); else nvert = str2double(line(16:end)); end @@ -55,7 +55,7 @@ if ~strncmp(line, 'element face', 12) fclose(fid); - error('unexpected header line'); + ft_error('unexpected header line'); else nface = str2double(line(14:end)); end @@ -68,7 +68,7 @@ % it would not be very difficult to enhance the reader here with another % representation of the faces, i.e. something else than "uchar int" fclose(fid); - error('unexpected header line'); + ft_error('unexpected header line'); end line = readline(fid); @@ -178,11 +178,11 @@ fclose(fid); otherwise - error('unsupported format'); + ft_error('unsupported format'); end % switch else - error('unable to open file'); + ft_error('unable to open file'); end % each polygon can have a different number of elements diff --git a/external/fieldtrip/fileio/private/read_polhemus_fil.m b/external/fieldtrip/fileio/private/read_polhemus_fil.m index c0b29743..9f0cfe4f 100644 --- a/external/fieldtrip/fileio/private/read_polhemus_fil.m +++ b/external/fieldtrip/fileio/private/read_polhemus_fil.m @@ -70,10 +70,10 @@ if strcmp(file{nl},'NZ') NZ = [NZ ; str2num(file{nl+1}) str2num(file{nl+2}) str2num(file{nl+3}) ]; nl = nl + 4; - elseif strcmp(file{nl},'LE') | strcmp(file{nl},'OG') + elseif strcmp(file{nl},'LE') || strcmp(file{nl},'OG') LE = [LE ; str2num(file{nl+1}) str2num(file{nl+2}) str2num(file{nl+3}) ]; nl = nl + 4; - elseif strcmp(file{nl},'RE') | strcmp(file{nl},'OD') + elseif strcmp(file{nl},'RE') || strcmp(file{nl},'OD') RE = [RE ; str2num(file{nl+1}) str2num(file{nl+2}) str2num(file{nl+3}) ]; nl = nl + 4; elseif isempty(str2num(file{nl})) % Add possible other named points diff --git a/external/fieldtrip/fileio/private/read_sbin_data.m b/external/fieldtrip/fileio/private/read_sbin_data.m index 9fe707db..a1d1b38d 100644 --- a/external/fieldtrip/fileio/private/read_sbin_data.m +++ b/external/fieldtrip/fileio/private/read_sbin_data.m @@ -38,7 +38,7 @@ fh=fopen([filename],'r'); if fh==-1 - error('wrong filename') + ft_error('wrong filename') end version = fread(fh,1,'int32'); @@ -59,7 +59,7 @@ end; version = swapbytes(uint32(version)); %hdr.orig.header_array is already byte-swapped else - error('ERROR: This is not a simple binary file. Note that NetStation does not successfully directly convert EGIS files to simple binary format.\n'); + ft_error('ERROR: This is not a simple binary file. Note that NetStation does not successfully directly convert EGIS files to simple binary format.\n'); end; if bitand(version,1) == 0 @@ -90,20 +90,20 @@ if unsegmented status = fseek(fh, 36+Nevent*4, 'bof'); %skip over header if status==-1 - error('Failure to skip over header of simple binary file.') + ft_error('Failure to skip over header of simple binary file.') end; status = fseek(fh, ((begtrial-1)*(hdr.nChans+Nevent)*dataLength), 'cof'); %skip previous trials if status==-1 - error('Failure to skip over previous trials of simple binary file.') + ft_error('Failure to skip over previous trials of simple binary file.') end; if (hdr.orig.header_array(14))==0 && (hdr.orig.header_array(15) > 1) %epoch-marked simple binary file format status = fseek(fh, 30, 'bof'); %skip over header if status==-1 - error('Failure to skip over header of simple binary file.') + ft_error('Failure to skip over header of simple binary file.') end; status = fseek(fh, ((begtrial-1)*(hdr.nChans+Nevent)*dataLength), 'cof'); %skip previous trials if status==-1 - error('Failure to skip over previous trials of simple binary file.') + ft_error('Failure to skip over previous trials of simple binary file.') end; NSamples = fread(fh,1,'int32',endian); NEvent = fread(fh,1,'int16',endian); @@ -137,17 +137,17 @@ nSamples = endtrial-begtrial+1; %interpret begtrial and endtrial as sample indices [trialData count] = fread(fh, [hdr.nChans+Nevent, nSamples],dataType,endian); if count < ((hdr.nChans+Nevent) * nSamples) - error('Failure to read all samples of simple binary file.') + ft_error('Failure to read all samples of simple binary file.') end; end; else status = fseek(fh, 40+length(hdr.orig.CatLengths)+sum(hdr.orig.CatLengths)+Nevent*4, 'bof'); %skip over header if status==-1 - error('Failure to skip over header of simple binary file.') + ft_error('Failure to skip over header of simple binary file.') end; status = fseek(fh, (begtrial-1)*trialLength, 'cof'); %skip over initial segments if status==-1 - error('Failure to skip over previous trials of simple binary file.') + ft_error('Failure to skip over previous trials of simple binary file.') end; trialData=zeros(hdr.nChans,hdr.nSamples,endtrial-begtrial+1); @@ -155,12 +155,12 @@ for segment=1:(endtrial-begtrial+1) status = fseek(fh, 6, 'cof'); %skip over segment info if status==-1 - error('Failure to skip over segment info of simple binary file.') + ft_error('Failure to skip over segment info of simple binary file.') end; [temp count] = fread(fh, [(hdr.nChans+Nevent), hdr.nSamples],dataType,endian); if count < ((hdr.nChans+Nevent) * hdr.nSamples) - error('Failure to read all samples of simple binary file.') + ft_error('Failure to read all samples of simple binary file.') end; trialData(:,:,segment) = temp(1:hdr.nChans,:); end @@ -168,5 +168,5 @@ trialData=trialData(chanindx, :,:); status = fclose(fh); if status==-1 - error('Failure to close simple binary file.') + ft_error('Failure to close simple binary file.') end; diff --git a/external/fieldtrip/fileio/private/read_sbin_events.m b/external/fieldtrip/fileio/private/read_sbin_events.m index 8467528d..5dd4528c 100644 --- a/external/fieldtrip/fileio/private/read_sbin_events.m +++ b/external/fieldtrip/fileio/private/read_sbin_events.m @@ -40,7 +40,7 @@ fid=fopen([filename],'r'); if fid==-1 - error('wrong filename') + ft_error('wrong filename') end version = fread(fid,1,'int32'); @@ -52,29 +52,29 @@ endian = 'ieee-be'; elseif cEndian == 'L' endian = 'ieee-le'; - end; + end elseif (version > 6) && ~bitand(version,6) if cEndian == 'B' endian = 'ieee-le'; elseif cEndian == 'L' endian = 'ieee-be'; - end; + end version = swapbytes(uint32(version)); else - error('ERROR: This is not a simple binary file. Note that NetStation does not successfully directly convert EGIS files to simple binary format.\n'); -end; + ft_error('ERROR: This is not a simple binary file. Note that NetStation does not successfully directly convert EGIS files to simple binary format.\n'); +end if bitand(version,1) == 0 %error('ERROR: This is an unsegmented file, which is not supported.\n'); unsegmented = 1; else unsegmented = 0; -end; +end precision = bitand(version,6); if precision == 0 - error('File precision is not defined.'); -end; + ft_error('File precision is not defined.'); +end % read header... year = fread(fid,1,'int16',endian); @@ -89,7 +89,7 @@ Gain = fread(fid,1,'int16',endian); Bits = fread(fid,1,'int16',endian); Range = fread(fid,1,'int16',endian); -if unsegmented, +if unsegmented NumCategors = 0; NSegments = 1; NSamples = fread(fid,1,'int32',endian); @@ -131,7 +131,7 @@ segHdr = zeros(NSegments,2); if unsegmented - eventData = logical(zeros(NEvent,NSegments*NSamples)); + eventData = false(NEvent,NSegments*NSamples); switch precision case 2 dataType = 'int16'; diff --git a/external/fieldtrip/fileio/private/read_sbin_header.m b/external/fieldtrip/fileio/private/read_sbin_header.m index 589fa4e3..c6862fa2 100644 --- a/external/fieldtrip/fileio/private/read_sbin_header.m +++ b/external/fieldtrip/fileio/private/read_sbin_header.m @@ -41,12 +41,12 @@ fid=fopen([filename],'r'); if fid==-1 - error('wrong filename') + ft_error('wrong filename') end version = fread(fid,1,'int32'); if isempty(version) - error('ERROR: This is not a simple binary file. Note that NetStation does not successfully directly convert EGIS files to simple binary format.'); + ft_error('ERROR: This is not a simple binary file. Note that NetStation does not successfully directly convert EGIS files to simple binary format.'); end; %check byteorder @@ -65,7 +65,7 @@ end; version = swapbytes(uint32(version)); else - error('ERROR: This is not a simple binary file. Note that NetStation does not successfully directly convert EGIS files to simple binary format.'); + ft_error('ERROR: This is not a simple binary file. Note that NetStation does not successfully directly convert EGIS files to simple binary format.'); end; if bitand(version,1) == 0 @@ -76,7 +76,7 @@ precision = bitand(version,6); if precision == 0 - error('File precision is not defined.'); + ft_error('File precision is not defined.'); end; % read header... diff --git a/external/fieldtrip/fileio/private/read_shm_data.m b/external/fieldtrip/fileio/private/read_shm_data.m index 3ac9040a..56c3d8be 100644 --- a/external/fieldtrip/fileio/private/read_shm_data.m +++ b/external/fieldtrip/fileio/private/read_shm_data.m @@ -93,7 +93,7 @@ end % if any(isnan(dat(:))) -% warning('data has been padded with NaNs'); +% ft_warning('data has been padded with NaNs'); % fprintf('trials present = %d - %d\n', min(trlNum), max(trlNum)); % fprintf('trials requested = %d - %d\n', begtrial, endtrial); % end diff --git a/external/fieldtrip/fileio/private/read_shm_header.m b/external/fieldtrip/fileio/private/read_shm_header.m index 3e18d9a8..a184b652 100644 --- a/external/fieldtrip/fileio/private/read_shm_header.m +++ b/external/fieldtrip/fileio/private/read_shm_header.m @@ -39,7 +39,7 @@ % get the name of the headerfile from shared memory sel = find(msgType==0); if isempty(sel) - error('could not determine header file location from shared memory'); + ft_error('could not determine header file location from shared memory'); end buf = read_ctf_shm(sel); % this includes the headerfile as string, and the trigger information from AcqBuffer str = char(typecast(buf(1:256), 'uint8')); % assume that the filename will not exceed 256 characters in length @@ -65,7 +65,7 @@ % do online detection of triggers inside AcqBuffer trgchan = find(origSensType(:)'==11); if length(trgchan)>10 - error('online detection of triggers in AcqBuffer only works with up to 10 trigger channels'); + ft_error('online detection of triggers in AcqBuffer only works with up to 10 trigger channels'); end % specify the channel count and the trigger channels in the setup buffer buf(28160-9011) = hdr.nChans; % tell the number of actual channels @@ -79,7 +79,7 @@ % write the updated setup packet, this should cause AcqBuffer to do online trigger detection write_ctf_shm(sel, 0, 0, 0, 0, 0, buf); else - warning('no setup in shared memory, could not enable trigger detection'); + ft_warning('no setup in shared memory, could not enable trigger detection'); end else diff --git a/external/fieldtrip/fileio/private/read_spike6mat_data.m b/external/fieldtrip/fileio/private/read_spike6mat_data.m index 06df6909..fb7d3dc7 100644 --- a/external/fieldtrip/fileio/private/read_spike6mat_data.m +++ b/external/fieldtrip/fileio/private/read_spike6mat_data.m @@ -40,7 +40,7 @@ try vars = struct2cell(load(filename)); catch - error('File not found or wrong format.'); + ft_error('File not found or wrong format.'); end if isempty(chanindx) diff --git a/external/fieldtrip/fileio/private/read_spike6mat_header.m b/external/fieldtrip/fileio/private/read_spike6mat_header.m index d4d39112..1ee48508 100644 --- a/external/fieldtrip/fileio/private/read_spike6mat_header.m +++ b/external/fieldtrip/fileio/private/read_spike6mat_header.m @@ -22,7 +22,7 @@ try vars = struct2cell(load(filename)); catch - error('File not found or wrong format.'); + ft_error('File not found or wrong format.'); end header = []; @@ -42,7 +42,7 @@ end if length(unique(fsample))>1 || length(unique(onsets))>1 || length(unique(lengths))>1 - error('Only files with identical channel parameters are supported'); + ft_error('Only files with identical channel parameters are supported'); end header.Fs = unique(fsample); diff --git a/external/fieldtrip/fileio/private/read_spmeeg_event.m b/external/fieldtrip/fileio/private/read_spmeeg_event.m index 48a967a9..28d170a9 100644 --- a/external/fieldtrip/fileio/private/read_spmeeg_event.m +++ b/external/fieldtrip/fileio/private/read_spmeeg_event.m @@ -73,6 +73,6 @@ end else - error('Cannot recognize an SPM EEG header format'); + ft_error('Cannot recognize an SPM EEG header format'); end diff --git a/external/fieldtrip/fileio/private/read_spmeeg_header.m b/external/fieldtrip/fileio/private/read_spmeeg_header.m index 99f91a32..5064e410 100644 --- a/external/fieldtrip/fileio/private/read_spmeeg_header.m +++ b/external/fieldtrip/fileio/private/read_spmeeg_header.m @@ -23,7 +23,7 @@ D = load(filename, 'D'); D = D.D; catch - error('File not found or wrong format.'); + ft_error('File not found or wrong format.'); end header = []; @@ -62,7 +62,7 @@ end else - error('Cannot recognize an SPM EEG header format'); + ft_error('Cannot recognize an SPM EEG header format'); end header.orig = D; diff --git a/external/fieldtrip/fileio/private/read_tdt_sev.m b/external/fieldtrip/fileio/private/read_tdt_sev.m index 9d1d31c7..501b0445 100644 --- a/external/fieldtrip/fileio/private/read_tdt_sev.m +++ b/external/fieldtrip/fileio/private/read_tdt_sev.m @@ -35,9 +35,9 @@ fmt = 'double'; wsize = 8; case 5 - error('don''t know what a DFORM_QWORD is'); + ft_error('don''t know what a DFORM_QWORD is'); otherwise - error('unknown dtype'); + ft_error('unknown dtype'); end fseek(fid, begsample*wsize, 'cof'); diff --git a/external/fieldtrip/fileio/private/read_tdt_tev.m b/external/fieldtrip/fileio/private/read_tdt_tev.m index 063db636..f5eaece6 100644 --- a/external/fieldtrip/fileio/private/read_tdt_tev.m +++ b/external/fieldtrip/fileio/private/read_tdt_tev.m @@ -76,9 +76,9 @@ case 4 fmt = 'double'; case 5 - error('don''t know what a DFORM_QWORD is'); + ft_error('don''t know what a DFORM_QWORD is'); otherwise - error('unknown tsq.type'); + ft_error('unknown tsq.type'); end % switch siz = double(tsq(i).size)-10; % in words fseek(fidsev(index), tsq(i).offset, 'bof'); @@ -101,9 +101,9 @@ case 4 fmt = 'double'; case 5 - error('don''t know what a DFORM_QWORD is'); + ft_error('don''t know what a DFORM_QWORD is'); otherwise - error('unknown tsq.type'); + ft_error('unknown tsq.type'); end % switch siz = double(tsq(i).size)-10; % in words fseek(fidnev, tsq(i).offset, 'bof'); diff --git a/external/fieldtrip/fileio/private/read_tmsi_poly5.m b/external/fieldtrip/fileio/private/read_tmsi_poly5.m index 15bdc85c..edb3df20 100644 --- a/external/fieldtrip/fileio/private/read_tmsi_poly5.m +++ b/external/fieldtrip/fileio/private/read_tmsi_poly5.m @@ -1,4 +1,4 @@ -function [out] = read_tmri_poly5(filename, varargin) +function [out] = read_tmsi_poly5(filename, varargin) % READ_TMSI_POLY5 % diff --git a/external/fieldtrip/fileio/private/read_trigger.m b/external/fieldtrip/fileio/private/read_trigger.m index 9d10f310..3daefdb4 100644 --- a/external/fieldtrip/fileio/private/read_trigger.m +++ b/external/fieldtrip/fileio/private/read_trigger.m @@ -63,7 +63,11 @@ end % read the trigger channel as raw data, can safely assume that it is continuous -dat = ft_read_data(filename, 'header', hdr, 'dataformat', dataformat, 'begsample', begsample, 'endsample', endsample, 'chanindx', chanindx, 'checkboundary', 0); +if ~isempty(chanindx) + dat = ft_read_data(filename, 'header', hdr, 'dataformat', dataformat, 'begsample', begsample, 'endsample', endsample, 'chanindx', chanindx, 'checkboundary', 0); +else + dat = zeros(0, endsample-begsample+1); +end % start with an empty event structure event = []; @@ -78,13 +82,19 @@ if denoise for i=1:length(chanindx) if (sum(diff(find(diff(dat(i,:))~=0)) == 1)/length(dat(i,:))) > 0.8 - warning(['trigger channel ' hdr.label{chanindx(i)} ' looks like noise and will be ignored']); + ft_warning(['trigger channel ' hdr.label{chanindx(i)} ' looks like noise and will be ignored']); dat(i,:) = 0; end end end if fixbiosemi + if ft_platform_supports('int32_logical_operations') + % convert to 32-bit integer representation and only preserve the lowest 24 bits + dat = bitand(int32(dat), 2^24-1); + % apparently the 24 bits are still shifted by one byte + dat = bitshift(dat,-8); + else % find indices of negative numbers signbit = find(dat < 0); % change type to double (otherwise bitcmp will fail) @@ -97,6 +107,7 @@ dat(signbit) = dat(signbit)+(2^(24-1)); % typecast the data to ensure that the status channel is represented in 32 bits dat = uint32(dat); + end byte1 = 2^8 - 1; byte2 = 2^16 - 1 - byte1; @@ -246,6 +257,6 @@ end end otherwise - error('incorrect specification of ''detectflank'''); + ft_error('incorrect specification of ''detectflank'''); end end diff --git a/external/fieldtrip/fileio/private/read_vtk.m b/external/fieldtrip/fileio/private/read_vtk.m index 3c76ca91..565bf389 100644 --- a/external/fieldtrip/fileio/private/read_vtk.m +++ b/external/fieldtrip/fileio/private/read_vtk.m @@ -44,5 +44,5 @@ fclose(fid); else - error('unable to open file'); + ft_error('unable to open file'); end diff --git a/external/fieldtrip/fileio/private/read_yokogawa_data.m b/external/fieldtrip/fileio/private/read_yokogawa_data.m index 57851a0f..e7a03a70 100644 --- a/external/fieldtrip/fileio/private/read_yokogawa_data.m +++ b/external/fieldtrip/fileio/private/read_yokogawa_data.m @@ -35,7 +35,7 @@ % $Id$ if ~ft_hastoolbox('yokogawa') - error('cannot determine whether Yokogawa toolbox is present'); + ft_error('cannot determine whether Yokogawa toolbox is present'); end % hdr = read_yokogawa_header(filename); @@ -77,9 +77,9 @@ begtrial = ceil(begsample/hdr.sample_count); endtrial = ceil(endsample/hdr.sample_count); if begtrial<1 - error('cannot read before the begin of the file'); + ft_error('cannot read before the begin of the file'); elseif endtrial>hdr.actual_epoch_count - error('cannot read beyond the end of the file'); + ft_error('cannot read beyond the end of the file'); end epoch_count = endtrial-begtrial+1; start_epoch = begtrial-1; @@ -89,7 +89,7 @@ channum = dat(:,1); dat = dat(:,2:end); if size(dat,2)~=epoch_count*hdr.sample_count - error('could not read all epochs'); + ft_error('could not read all epochs'); end rawbegsample = begsample - (begtrial-1)*hdr.sample_count; rawendsample = endsample - (begtrial-1)*hdr.sample_count; @@ -98,15 +98,15 @@ dat = dat(:,rawbegsample:rawendsample); otherwise - error('unknown data type'); + ft_error('unknown data type'); end fclose(fid); if size(dat,1)~=hdr.channel_count - error('could not read all channels'); + ft_error('could not read all channels'); elseif size(dat,2)~=(endsample-begsample+1) - error('could not read all samples'); + ft_error('could not read all samples'); end % Count of AxialGradioMeter diff --git a/external/fieldtrip/fileio/private/read_yokogawa_data_new.m b/external/fieldtrip/fileio/private/read_yokogawa_data_new.m index f51d4126..5a60cc91 100644 --- a/external/fieldtrip/fileio/private/read_yokogawa_data_new.m +++ b/external/fieldtrip/fileio/private/read_yokogawa_data_new.m @@ -33,7 +33,7 @@ % $Id$ if ~ft_hastoolbox('yokogawa_meg_reader') - error('cannot determine whether Yokogawa toolbox is present'); + ft_error('cannot determine whether Yokogawa toolbox is present'); end % hdr = read_yokogawa_header(filename); @@ -68,16 +68,16 @@ begtrial = ceil(begsample/hdr.sample_count); endtrial = ceil(endsample/hdr.sample_count); if begtrial<1 - error('cannot read before the begin of the file'); + ft_error('cannot read before the begin of the file'); elseif endtrial>hdr.actual_epoch_count - error('cannot read beyond the end of the file'); + ft_error('cannot read beyond the end of the file'); end epoch_count = endtrial-begtrial+1; start_epoch = begtrial-1; % read all the neccessary trials that contain the desired samples dat = getYkgwData(filename, start_epoch, epoch_count); if size(dat,2)~=epoch_count*hdr.sample_count - error('could not read all epochs'); + ft_error('could not read all epochs'); end rawbegsample = begsample - (begtrial-1)*hdr.sample_count; rawendsample = endsample - (begtrial-1)*hdr.sample_count; @@ -86,14 +86,14 @@ dat = dat(:,rawbegsample:rawendsample); otherwise - error('unknown data type'); + ft_error('unknown data type'); end if size(dat,1)~=hdr.channel_count - error('could not read all channels'); + ft_error('could not read all channels'); elseif size(dat,2)~=(endsample-begsample+1) - error('could not read all samples'); + ft_error('could not read all samples'); end % select only the desired channels diff --git a/external/fieldtrip/fileio/private/read_yokogawa_event.m b/external/fieldtrip/fileio/private/read_yokogawa_event.m index c0f42132..4095c372 100644 --- a/external/fieldtrip/fileio/private/read_yokogawa_event.m +++ b/external/fieldtrip/fileio/private/read_yokogawa_event.m @@ -123,7 +123,7 @@ end else - error('cannot determine, whether Yokogawa toolbox is present'); + ft_error('cannot determine, whether Yokogawa toolbox is present'); end % read the trigger channels and detect the flanks @@ -134,7 +134,7 @@ end if isempty(event) - warning('no triggers were detected, please specify the "trigindx" option'); + ft_warning('no triggers were detected, please specify the "trigindx" option'); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/external/fieldtrip/fileio/private/read_yokogawa_header.m b/external/fieldtrip/fileio/private/read_yokogawa_header.m index 13b3f3f4..78d986e6 100644 --- a/external/fieldtrip/fileio/private/read_yokogawa_header.m +++ b/external/fieldtrip/fileio/private/read_yokogawa_header.m @@ -52,7 +52,7 @@ % fopen iee-le if ~ft_hastoolbox('yokogawa') - error('cannot determine whether Yokogawa toolbox is present'); + ft_error('cannot determine whether Yokogawa toolbox is present'); end handles = definehandles; @@ -77,7 +77,7 @@ switch acq_type case handles.AcqTypeContinuousRaw [sample_rate, sample_count] = GetMeg160ContinuousAcqCondM(fid); - if isempty(sample_rate) | isempty(sample_count) + if isempty(sample_rate) || isempty(sample_count) fclose(fid); return; end @@ -86,20 +86,20 @@ case handles.AcqTypeEvokedAve [sample_rate, sample_count, pretrigger_length, averaged_count] = GetMeg160EvokedAcqCondM( fid ); - if isempty(sample_rate) | isempty(sample_count) | isempty(pretrigger_length) | isempty(averaged_count) + if isempty(sample_rate) || isempty(sample_count) || isempty(pretrigger_length) || isempty(averaged_count) fclose(fid); return; end case handles.AcqTypeEvokedRaw [sample_rate, sample_count, pretrigger_length, actual_epoch_count] = GetMeg160EvokedAcqCondM( fid ); - if isempty(sample_rate) | isempty(sample_count) | isempty(pretrigger_length) | isempty(actual_epoch_count) + if isempty(sample_rate) || isempty(sample_count) || isempty(pretrigger_length) || isempty(actual_epoch_count) fclose(fid); return; end otherwise - error('unknown data type'); + ft_error('unknown data type'); end % these are always present @@ -141,7 +141,7 @@ hdr.nSamplesPre = orig.pretrigger_length; hdr.nTrials = orig.actual_epoch_count; otherwise - error('unknown acquisition type'); + ft_error('unknown acquisition type'); end % construct a cell-array with labels of each channel diff --git a/external/fieldtrip/fileio/private/read_yokogawa_header_new.m b/external/fieldtrip/fileio/private/read_yokogawa_header_new.m index 2e479749..95f57704 100644 --- a/external/fieldtrip/fileio/private/read_yokogawa_header_new.m +++ b/external/fieldtrip/fileio/private/read_yokogawa_header_new.m @@ -44,7 +44,7 @@ % fopen iee-le if ~ft_hastoolbox('yokogawa_meg_reader') - error('cannot determine whether Yokogawa toolbox is present'); + ft_error('cannot determine whether Yokogawa toolbox is present'); end handles = definehandles; @@ -74,8 +74,8 @@ case handles.AcqTypeContinuousRaw sample_rate = acq_cond.sample_rate; sample_count = acq_cond.sample_count; - if isempty(sample_rate) | isempty(sample_count) - error('invalid sample rate or sample count in ', filename); + if isempty(sample_rate) || isempty(sample_count) + ft_error('invalid sample rate or sample count in ', filename); return; end pretrigger_length = 0; @@ -86,12 +86,12 @@ sample_count = acq_cond.frame_length; pretrigger_length = acq_cond.pretrigger_length; averaged_count = acq_cond.average_count; - if isempty(sample_rate) | isempty(sample_count) | isempty(pretrigger_length) | isempty(averaged_count) - error('invalid sample rate or sample count or pretrigger length or average count in ', filename); + if isempty(sample_rate) || isempty(sample_count) || isempty(pretrigger_length) || isempty(averaged_count) + ft_error('invalid sample rate or sample count or pretrigger length or average count in ', filename); return; end if acq_cond.multi_trigger.enable - error('multi trigger mode not supported for ', filename); + ft_error('multi trigger mode not supported for ', filename); return; end case handles.AcqTypeEvokedRaw @@ -99,17 +99,17 @@ sample_count = acq_cond.frame_length; pretrigger_length = acq_cond.pretrigger_length; actual_epoch_count = acq_cond.average_count; - if isempty(sample_rate) | isempty(sample_count) | isempty(pretrigger_length) | isempty(actual_epoch_count) - error('invalid sample rate or sample count or pretrigger length or epoch count in ', filename); + if isempty(sample_rate) || isempty(sample_count) || isempty(pretrigger_length) || isempty(actual_epoch_count) + ft_error('invalid sample rate or sample count or pretrigger length or epoch count in ', filename); return; end if acq_cond.multi_trigger.enable - error('multi trigger mode not supported for ', filename); + ft_error('multi trigger mode not supported for ', filename); return; end otherwise - error('unknown data type'); + ft_error('unknown data type'); end clear('acq_cond'); % remove structure as local variables are collected in the end @@ -149,7 +149,7 @@ hdr.nSamplesPre = orig.pretrigger_length; hdr.nTrials = orig.actual_epoch_count; otherwise - error('unknown acquisition type'); + ft_error('unknown acquisition type'); end % construct a cell-array with labels of each channel diff --git a/external/fieldtrip/fileio/private/readbdf.m b/external/fieldtrip/fileio/private/readbdf.m index cc590985..4f6e701e 100644 --- a/external/fieldtrip/fileio/private/readbdf.m +++ b/external/fieldtrip/fileio/private/readbdf.m @@ -67,7 +67,7 @@ try, S(EDF.AS.IDX2)=s; catch, - error('File is incomplete (try reading begining of file)'); + ft_error('File is incomplete (try reading begining of file)'); end; %%%%% Test on Over- (Under-) Flow diff --git a/external/fieldtrip/fileio/private/readmarkerfile.m b/external/fieldtrip/fileio/private/readmarkerfile.m index 420aaed3..1c9f0989 100644 --- a/external/fieldtrip/fileio/private/readmarkerfile.m +++ b/external/fieldtrip/fileio/private/readmarkerfile.m @@ -12,7 +12,7 @@ name = fullfile(folder, 'MarkerFile.mrk'); if ~exist(name, 'file') - error('%s not found', name); + ft_error('%s not found', name); end f = fopen(name, 'rt'); @@ -40,7 +40,7 @@ for i = 1:length(nsamples) if nsamples(i) == 0 - warning('marker %s in %s has zero samples', names{i}, folder); + ft_warning('marker %s in %s has zero samples', names{i}, folder); end end diff --git a/external/fieldtrip/fileio/private/refine.m b/external/fieldtrip/fileio/private/refine.m index 993499c3..92548ba5 100755 --- a/external/fieldtrip/fileio/private/refine.m +++ b/external/fieldtrip/fileio/private/refine.m @@ -181,6 +181,6 @@ [trir, pntr] = reducepatch(tri, pnt, varargin{1}); otherwise - error(['unsupported method: ' method]); + ft_error(['unsupported method: ' method]); end diff --git a/external/fieldtrip/fileio/private/rotate.m b/external/fieldtrip/fileio/private/rotate.m index d6b05256..2512a5a8 100644 --- a/external/fieldtrip/fileio/private/rotate.m +++ b/external/fieldtrip/fileio/private/rotate.m @@ -49,7 +49,7 @@ % $Id$ if numel(f)~=3 - error('incorrect input vector'); + ft_error('incorrect input vector'); end % convert degrees to radians diff --git a/external/fieldtrip/fileio/private/solid_angle.m b/external/fieldtrip/fileio/private/solid_angle.m index c984e803..47e65c67 100644 --- a/external/fieldtrip/fileio/private/solid_angle.m +++ b/external/fieldtrip/fileio/private/solid_angle.m @@ -1,4 +1,4 @@ -function [varargout] = funname(varargin) +function [varargout] = solid_angle(varargin) % SOLID_ANGLE of a planar triangle as seen from the origin % @@ -33,7 +33,6 @@ % You should have received a copy of the GNU General Public License % along with FieldTrip. If not, see . % -% $Id$ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % The first section contains the plain MATLAB implementation. The mex file @@ -79,7 +78,7 @@ % w = 2 * atan2 (nom, den); % return % else -% error('invalid input'); +% ft_error('invalid input'); % end % compile the missing mex file on the fly @@ -93,7 +92,7 @@ try % try to compile the mex file on the fly - warning('trying to compile MEX file from %s', mexsrc); + ft_warning('trying to compile MEX file from %s', mexsrc); cd(mexdir); if ispc @@ -111,7 +110,7 @@ catch % compilation failed disp(lasterr); - error('could not locate MEX file for %s', mexname); + ft_error('could not locate MEX file for %s', mexname); cd(pwdir); success = false; end diff --git a/external/fieldtrip/fileio/private/solid_angle.mexa64 b/external/fieldtrip/fileio/private/solid_angle.mexa64 index d94d91903daba7af06c027953cbd8f5bc78e29f4..a09e02e630aae3124abc1c336d5d1a1d3a101109 100755 GIT binary patch delta 1247 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 diff --git a/external/fieldtrip/fileio/private/solid_angle.mexw32 b/external/fieldtrip/fileio/private/solid_angle.mexw32 index dda325cac0d7aa134388ff413a50572953861617..6ffabebf93b9126092295ed7c1f25ba324aa865b 100755 GIT binary patch delta 32 lcmZp0XmFVDgQZ30S>(h&K1{byZT4c+5(o1)S4ecQ0|4tG4PXEO delta 32 kcmZp0XmFVDgC*eKr_hOie3*LMHhVE@iG%r@D3 - Va.dim = dim(1:3); - Va.n = dim(4:end); - else - Va.dim = dim; - Va.n = 1; - end - Va.pinfo = [1 0 0]'; - %Va.dt = [typ 1]; % this is not necessary because assigned in spm_create_vol - - Va = spm_create_vol(Va); - Va = spm_write_vol(Va,data); - case {'spm12'} - N = nifti; - N.mat = transform; - N.mat_intent = 'Aligned'; - N.dat = file_array(filename, dim, 'FLOAT32-LE'); - create(N); - switch length(N.dat.dim) - case 2 - N.dat(:,:) = data; - case 3 - N.dat(:,:,:) = data; - case 4 - N.dat(:,:,:, :) = data; - otherwise - error('Invalid output dimensions'); - end - - Va = spm_vol(N.dat.fname); - otherwise - error('unsupported version of spm requested'); + case 'spm2' + %see spm_vol + Va = []; + Va.mat = transform; + Va.fname = filename; + Va.dim = [dim typ]; + Va.n = 1; + Va.pinfo = [1 0 0]'; + Va.private.hdr.dime.datatype = typ; + Va = spm_create_vol(Va); + Va = spm_write_vol(Va,data); + + case 'spm8' + Va = []; + Va.mat = transform; + Va.fname = filename; + if numel(dim)>3 + Va.dim = dim(1:3); + Va.n = dim(4:end); + else + Va.dim = dim; + Va.n = 1; + end + Va.pinfo = [1 0 0]'; + %Va.dt = [typ 1]; % this is not necessary because assigned in spm_create_vol + Va = spm_create_vol(Va); + Va = spm_write_vol(Va,data); + + case 'spm12' + N = nifti; + N.mat = transform; + N.mat_intent = 'Aligned'; + N.dat = file_array(filename, dim, 'FLOAT32-LE'); + create(N); + switch length(N.dat.dim) + case 2 + N.dat(:,:) = data; + case 3 + N.dat(:,:,:) = data; + case 4 + N.dat(:,:,:, :) = data; + otherwise + ft_error('Invalid output dimensions'); + end + Va = spm_vol(N.dat.fname); + + otherwise + ft_error('unsupported SPM version requested'); end - diff --git a/external/fieldtrip/fileio/private/write_bioimage_mgrid.m b/external/fieldtrip/fileio/private/write_bioimage_mgrid.m new file mode 100644 index 00000000..cc09f8ba --- /dev/null +++ b/external/fieldtrip/fileio/private/write_bioimage_mgrid.m @@ -0,0 +1,298 @@ +function write_bioimage_mgrid(filename, elec) + +% -------------------------------------------------------- +% WRITE_BIOIMAGE_MGRID writes BioImage Suite .mgrid files from a FieldTrip +% elec datatype structure +% +% Use as: +% write_bioimage_mgrid(filename, elec) +% where filename has an .mgrid file extension and elec has both a label +% and an elecpos field +% +% To view the mgrid file in BioImage Suite, ensure that the orientation of +% the scan (e.g., RAS) corresponds with the orientation of the electrode +% positions (in head coordinates) of elec +% +% Copyright (C) 2017, Arjen Stolk & Sandon Griffin +% -------------------------------------------------------- + + +% extract info from label field +for e = 1:numel(elec.label) % electrode loop + ElecStrs{e,1} = regexprep(elec.label{e}, '\d+(?:_(?=\d))?', ''); % without electrode numbers + ElecNrs(e) = str2double(regexp(elec.label{e},'-?\d+\.?\d*|-?\d*\.?\d+', 'match')); % without electrode strings + tmp = strfind(elec.label{e}, num2str(ElecNrs(e))); % the position of the first number within the label + ElecNumPos(e) = tmp:tmp+numel(ElecNrs(e))-1; % the positions of the numbers within the label +end +GridDescript = unique(ElecStrs); +ngrids = numel(GridDescript); +for g = 1:ngrids % grid loop + Grid2Elec{g} = match_str(ElecStrs, GridDescript{g}); % assign electrodes to grids +end + +% Check to make sure there are no electrodes missing and if some appear to +% be missing, add electrodes with NaN's for the position in order to have +% the numbers of the electrodes in the mgrid file match the numbers in the +% elec file +for g = 1:ngrids % grid loop + if max(ElecNrs(Grid2Elec{g})) ~= numel(Grid2Elec{g}) % if there is an electrode in the grid that appears to be missing + for e = 1:max(ElecNrs(Grid2Elec{g})) + tmp = find(ElecNrs(Grid2Elec{g}) == e); + if isempty(tmp) + warning('Electrode %s%d appears to be missing, so a filler electrode with no location will be added in its place', char(unique(ElecStrs(Grid2Elec{g}))), e); + n_elecs = numel(elec.label); % number of electrodes currently described in elec file + ElecStrs{n_elecs+1} = char(unique(ElecStrs(Grid2Elec{g}))); + ElecNrs(n_elecs+1) = e; + elec.label{n_elecs+1} = [char(unique(ElecStrs(Grid2Elec{g}))), num2str(e)]; + elec.elecpos(n_elecs+1, :) = [NaN NaN NaN]; + end + end + end +end + +% Update Grid2Elec +for g = 1:ngrids % grid loop + Grid2Elec{g} = match_str(ElecStrs, GridDescript{g}); % assign electrodes to grids +end + +% open and write ascii-file line by line +fid = fopen(filename, 'wt'); % open ascii-file + +% file header +fprintf(fid, '#vtkpxElectrodeMultiGridSource File\n'); +fprintf(fid, '#Description\n'); +fprintf(fid, 'patient\n'); +fprintf(fid, '#Comment\n'); +fprintf(fid, 'no additional comment\n'); +fprintf(fid, '#Number of Grids\n'); +fprintf(fid, [' ' num2str(ngrids) '\n']); + +for g = 1:ngrids % grid loop + + % grid info + fprintf(fid, '#- - - - - - - - - - - - - - - - - - -\n'); + fprintf(fid, ['# Electrode Grid ' num2str(ngrids-1) '\n']); % mgrid count starts at 0 + fprintf(fid, '- - - - - - - - - - - - - - - - - - -\n'); + fprintf(fid, '#vtkpxElectrodeGridSource File v2\n'); + fprintf(fid, '#Description\n'); + fprintf(fid, [GridDescript{g} '\n']); + fprintf(fid, '#Dimensions\n'); + + % determine grid dimensions + if isequal(numel(Grid2Elec{g}), 256) + GridDim(1) = 16; GridDim(2) = 16; + elseif isequal(numel(Grid2Elec{g}), 64) + GridDim(1) = 8; GridDim(2) = 8; + elseif isequal(numel(Grid2Elec{g}), 48) + e6 = elec.elecpos(match_str(elec.label, [GridDescript{g} num2str(6)]),:); + e7 = elec.elecpos(match_str(elec.label, [GridDescript{g} num2str(7)]),:); + e8 = elec.elecpos(match_str(elec.label, [GridDescript{g} num2str(8)]),:); + e9 = elec.elecpos(match_str(elec.label, [GridDescript{g} num2str(9)]),:); + d6to7 = sqrt(sum((e6-e7).^2)); % distance of elec 6 to 7 + d8to9 = sqrt(sum((e8-e9).^2)); % distance of elec 8 to 9 + if d8to9 >= d6to7 % break between e8 and e9 + GridDim(1) = 6; GridDim(2) = 8; + elseif d6to7 > d8to9 % break between e6 and e7 + GridDim(1) = 8; GridDim(2) = 6; + end + elseif isequal(numel(Grid2Elec{g}), 32) + e4 = elec.elecpos(match_str(elec.label, [GridDescript{g} num2str(4)]),:); + e5 = elec.elecpos(match_str(elec.label, [GridDescript{g} num2str(5)]),:); + e8 = elec.elecpos(match_str(elec.label, [GridDescript{g} num2str(8)]),:); + e9 = elec.elecpos(match_str(elec.label, [GridDescript{g} num2str(9)]),:); + d4to5 = sqrt(sum((e4-e5).^2)); % distance of elec 4 to 5 + d8to9 = sqrt(sum((e8-e9).^2)); % distance of elec 8 to 9 + if d8to9 >= d4to5 % break between e8 and e9 + GridDim(1) = 4; GridDim(2) = 8; + elseif d4to5 > d8to9 % break between e4 and e5 + GridDim(1) = 8; GridDim(2) = 4; + end + elseif isequal(numel(Grid2Elec{g}), 24) + e4 = elec.elecpos(match_str(elec.label, [GridDescript{g} num2str(4)]),:); + e5 = elec.elecpos(match_str(elec.label, [GridDescript{g} num2str(5)]),:); + e6 = elec.elecpos(match_str(elec.label, [GridDescript{g} num2str(6)]),:); + e7 = elec.elecpos(match_str(elec.label, [GridDescript{g} num2str(7)]),:); + d4to5 = sqrt(sum((e4-e5).^2)); % distance of elec 4 to 5 + d6to7 = sqrt(sum((e6-e7).^2)); % distance of elec 6 to 7 + if d6to7 >= d4to5 % break between e6 and e7 + GridDim(1) = 4; GridDim(2) = 6; + elseif d4to5 > d6to7 % break between e4 and e5 + GridDim(1) = 6; GridDim(2) = 4; + end + elseif isequal(numel(Grid2Elec{g}), 20) + e4 = elec.elecpos(match_str(elec.label, [GridDescript{g} num2str(4)]),:); + e5 = elec.elecpos(match_str(elec.label, [GridDescript{g} num2str(5)]),:); + d4to5 = sqrt(sum((e4-e5).^2)); % distance of elec 4 to 5 + d5to6 = sqrt(sum((e5-e6).^2)); % distance of elec 5 to 6 + if d5to6 >= d4to5 % break between e5 and e6 + GridDim(1) = 4; GridDim(2) = 5; + elseif d4to5 > d5to6 % break between e4 and e5 + GridDim(1) = 5; GridDim(2) = 4; + end + elseif isequal(numel(Grid2Elec{g}), 16) + e4 = elec.elecpos(match_str(elec.label, [GridDescript{g} num2str(4)]),:); + e5 = elec.elecpos(match_str(elec.label, [GridDescript{g} num2str(5)]),:); + e8 = elec.elecpos(match_str(elec.label, [GridDescript{g} num2str(8)]),:); + e9 = elec.elecpos(match_str(elec.label, [GridDescript{g} num2str(9)]),:); + d4to5 = sqrt(sum((e4-e5).^2)); % distance of elec 4 to 5 + d8to9 = sqrt(sum((e8-e9).^2)); % distance of elec 8 to 9 + d4to8 = sqrt(sum((e4-e8).^2)); % distance of elec 4 to 8 + if d8to9 > 2*d4to5 % break between e8 and e9 + GridDim(1) = 2; GridDim(2) = 8; + elseif d4to5 > 2*d4to8 % break between e4 and e5 + GridDim(1) = 4; GridDim(2) = 4; + else + GridDim(1) = 1; GridDim(2) = 16; + end + elseif isequal(numel(Grid2Elec{g}), 12) + e4 = elec.elecpos(match_str(elec.label, [GridDescript{g} num2str(4)]),:); + e5 = elec.elecpos(match_str(elec.label, [GridDescript{g} num2str(5)]),:); + e6 = elec.elecpos(match_str(elec.label, [GridDescript{g} num2str(6)]),:); + e7 = elec.elecpos(match_str(elec.label, [GridDescript{g} num2str(7)]),:); + d4to5 = sqrt(sum((e4-e5).^2)); % distance of elec 5 to 6 + d5to6 = sqrt(sum((e5-e6).^2)); % distance of elec 5 to 6 + d6to7 = sqrt(sum((e6-e7).^2)); % distance of elec 6 to 7 + if d4to5 > 2*d5to6 % break between e4 and e5 + GridDim(1) = 3; GridDim(2) = 4; % 4x3 unsuppported + elseif d6to7 > 2*d5to6 % break between e6 and e7 + GridDim(1) = 2; GridDim(2) = 6; + else + GridDim(1) = 1; GridDim(2) = 12; + end + elseif isequal(numel(Grid2Elec{g}), 8) + e3 = elec.elecpos(match_str(elec.label, [GridDescript{g} num2str(3)]),:); + e4 = elec.elecpos(match_str(elec.label, [GridDescript{g} num2str(4)]),:); + e5 = elec.elecpos(match_str(elec.label, [GridDescript{g} num2str(5)]),:); + d3to4 = sqrt(sum((e3-e4).^2)); % distance of elec 3 to 4 + d4to5 = sqrt(sum((e4-e5).^2)); % distance of elec 4 to 5 + if d4to5 > 2*d3to4 % break between e4 and e5 + GridDim(1) = 2; GridDim(2) = 4; + else + GridDim(1) = 1; GridDim(2) = 8; + end + else + GridDim(1) = 1; GridDim(2) = numel(Grid2Elec{g}); + % ft_error('At least one of the electrode tracts or grids has dimensions that are not supported by write_bioimage_mgrid. If electrodes are missing from a grid, enter NaN(1,3) for electrode position'); + end + fprintf('assuming %s has %d x %d dimensions\n', GridDescript{g}, GridDim(1), GridDim(2)); % feedback of the grid dimensions + + fprintf(fid, [' ' num2str(GridDim(1)) ' ' num2str(GridDim(2)) '\n']); + fprintf(fid, '#Electrode Spacing\n'); + fprintf(fid, ' 10.0000 10.0000\n'); + fprintf(fid, '#Electrode Type\n'); + fprintf(fid, '0\n'); + fprintf(fid, '#Radius\n'); + fprintf(fid, '2.000000\n'); + fprintf(fid, '#Thickeness\n'); + fprintf(fid, '0.050000\n'); + fprintf(fid, '#Color\n'); + fprintf(fid, [num2str(rand) ' ' num2str(rand) ' ' num2str(rand) '\n']); + + % mgrid electrode numbering: + % When BIS reads an mgrid file, electrodes within a set of contacts (i.e., grid, depth, or + % strip) are implicitly assigned a number based on the order they are + % printed in the mgrid file. The first electrode printed in the mgrid + % file corresponds with the electrode in the top left of the mgrid GUI. + % Subsequent electrodes are assigned numbers moving to the right and + % then down in mgrid file. + % + % for instance in an 4x5 grid, the electrodes will appear in the + % following orientation in the BiImage Suite GUI + % + % #5 #10 #15 #20 + % #4 #9 #14 #19 + % #3 #8 #13 #18 + % #2 #7 #12 #17 + % #1 #6 #11 #16 + + % In this example, electrodes must be printed in the electrode file in the following + % order: 5 10 15 20 4 9 14 19 3 8... + + mgrid_print_order = []; + for nrows = 0:GridDim(2)-1 + nextrow = GridDim(2)-nrows:GridDim(2):numel(Grid2Elec{g})-nrows; + mgrid_print_order = [mgrid_print_order nextrow]; + end + + for m = mgrid_print_order + + e = match_str(elec.label,[GridDescript{g} num2str(m)]); + + % electrode info + fprintf(fid, '#- - - - - - - - - - - - - - - - - - -\n'); + + % indexing electrode positions within a grid/depth in BIS: + % mgrid gui indexes the rows and columns starting from the top left (0,0) + % and increasing down and to the right. These indexes are explicitly + % used to identify the electrodes in the mgrid file + % + % for instance in an 4x5 grid, the electrodes indexes will appear in the + % mgrid GUI as follows + % + % (0,0) (1,0) (2,0) (3,0) + % (0,1) (1,1) (2,1) (3,1) + % (0,2) (1,2) (2,2) (3,2) + % (0,3) (1,3) (2,3) (3,3) + % (0,4) (1,4) (2,4) (3,4) + % + % In this example, the first electrode to be written in the mgrid file + % will be 'Electrode 0 0' which corresponds to electrode #5 of the grid + + if GridDim(1) == 1 % if the electrode is part of a depth or strip + ElecNr(1) = 0; + ElecNr(2) = GridDim(2)-m; + else % if the electrode is part of a grid + r = rem(m,GridDim(2)); + if r == 0 + ElecNr(1) = (m/GridDim(2)) - 1; + ElecNr(2) = 0; + else + ElecNr(1) = floor(m/GridDim(2)); + ElecNr(2) = GridDim(2) - r; + end + end + fprintf(fid, ['# Electrode ' num2str(ElecNr(1)) ' ' num2str(ElecNr(2)) '\n']); + fprintf(fid, '- - - - - - - - - - - - - - - - - - -\n'); + fprintf(fid, '#vtkpxElectrodeSource2 File\n'); + fprintf(fid, '#Position\n'); + fprintf(fid, [' ' num2str(elec.elecpos(e,1)) ' ' ... + num2str(elec.elecpos(e,2)) ' ' num2str(elec.elecpos(e,3)) '\n']); + fprintf(fid, '#Normal\n'); + fprintf(fid, ' 1.0000 0.0000 0.0000\n'); + fprintf(fid, '#Motor Function\n'); + fprintf(fid, '0\n'); + fprintf(fid, '#Sensory Function\n'); + fprintf(fid, '0\n'); + fprintf(fid, '#Visual Function\n'); + fprintf(fid, '0\n'); + fprintf(fid, '#Language Function\n'); + fprintf(fid, '0\n'); + fprintf(fid, '#Auditory Function\n'); + fprintf(fid, '0\n'); + fprintf(fid, '#User1 Function\n'); + fprintf(fid, '0\n'); + fprintf(fid, '#User2 Function\n'); + fprintf(fid, '0\n'); + fprintf(fid, '#Seizure Onset\n'); + fprintf(fid, '0\n'); + fprintf(fid, '#Spikes Present\n'); + fprintf(fid, '0\n'); + fprintf(fid, '#Electrode Present\n'); + if any(isnan(elec.elecpos(e,:))) % check if electrode is present + fprintf(fid, '0\n'); % 0 = not present + else + fprintf(fid, '1\n'); % 1 = present + end + fprintf(fid, '#Electrode Type\n'); + fprintf(fid, '0\n'); + fprintf(fid, '#Radius\n'); + fprintf(fid, '2.000000\n'); + fprintf(fid, '#Thickeness\n'); + fprintf(fid, '0.050000\n'); + fprintf(fid, '#Values\n'); + fprintf(fid, '1\n'); + fprintf(fid, '0.000000\n'); + + end % end of elec loop +end % end of grid loop +fclose(fid); diff --git a/external/fieldtrip/fileio/private/write_brainvision_eeg.m b/external/fieldtrip/fileio/private/write_brainvision_eeg.m index 4e8e6567..e099be5d 100644 --- a/external/fieldtrip/fileio/private/write_brainvision_eeg.m +++ b/external/fieldtrip/fileio/private/write_brainvision_eeg.m @@ -43,7 +43,7 @@ function write_brainvision_eeg(filename, hdr, dat, event) end if hdr.nChans~=nchan - error('number of channels in in header does not match with the data'); + ft_error('number of channels in in header does not match with the data'); end % this is the only supported data format @@ -67,7 +67,7 @@ function write_brainvision_eeg(filename, hdr, dat, event) % open the data file and write the binary data fid = fopen(datafile, 'wb', 'ieee-le'); if length(size(dat))>2 - warning('writing segmented data as if it were continuous'); + ft_warning('writing segmented data as if it were continuous'); for i=1:ntrl fwrite(fid, squeeze(dat(i,:,:)), 'float32'); end diff --git a/external/fieldtrip/fileio/private/write_ctf_shm.m b/external/fieldtrip/fileio/private/write_ctf_shm.m index dcf6387d..29b3ef54 100644 --- a/external/fieldtrip/fileio/private/write_ctf_shm.m +++ b/external/fieldtrip/fileio/private/write_ctf_shm.m @@ -1,4 +1,4 @@ -function [varargout] = funname(varargin) +function [varargout] = write_ctf_shm(varargin) % WRITE_CTF_SHM writes metainformation and data as a packet to shared memory. % This function can be used for real-time processing of data while it is @@ -39,7 +39,7 @@ try % try to compile the mex file on the fly - warning('trying to compile MEX file from %s', mexsrc); + ft_warning('trying to compile MEX file from %s', mexsrc); cd(mexdir); mex(mexsrc); cd(pwdir); @@ -48,7 +48,7 @@ catch % compilation failed disp(lasterr); - error('could not locate MEX file for %s', mexname); + ft_error('could not locate MEX file for %s', mexname); cd(pwdir); success = false; end diff --git a/external/fieldtrip/fileio/private/write_edf.m b/external/fieldtrip/fileio/private/write_edf.m index 4da162b7..f1a3ecb1 100644 --- a/external/fieldtrip/fileio/private/write_edf.m +++ b/external/fieldtrip/fileio/private/write_edf.m @@ -60,21 +60,32 @@ function write_edf(filename, hdr, data) error 'Cannot write complex-valued data.'; end +scale = max(abs(data), [], 2); +scale(scale==0) = 1; % prevent division-by-zero +scale = 32767 ./ scale; + +for i=1:size(data,1) + data(i,:) = data(i,:) * scale(i); +end + +data = int16(data); + +% the min and max should be integers maxV = max(data, [], 2); minV = min(data, [], 2); -if ~strcmp(class(data),'int16') - warning('Warning: data type is not int16, saving to EDF might introduce round-off errors.'); - if max(maxV) > 32767 | min(minV) < -32768 - error('Data cannot be represented as signed 16-bit integers'); - end - data = int16(data); -end +% if ~isa(data,'int16') +% ft_warning('Warning: data type is not int16, saving to EDF might introduce round-off errors.'); +% if max(maxV) > 32767 | min(minV) < -32768 +% ft_error('Data cannot be represented as signed 16-bit integers'); +% end +% data = int16(data); +% end digMin = sprintf('%-8i', minV); digMax = sprintf('%-8i', maxV); -physMin = digMin; -physMax = digMax; +physMin = sprintf('%-8g', double(minV) ./ scale); +physMax = sprintf('%-8g', double(maxV) ./ scale); fid = fopen(filename, 'wb', 'ieee-le'); % first write fixed part diff --git a/external/fieldtrip/fileio/private/write_neuralynx_ncs.m b/external/fieldtrip/fileio/private/write_neuralynx_ncs.m index bb94c172..f3f28eb3 100644 --- a/external/fieldtrip/fileio/private/write_neuralynx_ncs.m +++ b/external/fieldtrip/fileio/private/write_neuralynx_ncs.m @@ -30,7 +30,7 @@ function write_neuralynx_ncs(filename, ncs) % $Id$ if ~isa(ncs.TimeStamp, 'uint64') - error('timestamps should be uint64'); + ft_error('timestamps should be uint64'); end % convert the data from uV into V @@ -63,7 +63,7 @@ function write_neuralynx_ncs(filename, ncs) case 'double' buf = [buf sprintf('-%s\t%s\r\n', f{i}, num2str(v))]; otherwise - error('unknown class in writing header'); + ft_error('unknown class in writing header'); end end diff --git a/external/fieldtrip/fileio/private/write_neuralynx_nts.m b/external/fieldtrip/fileio/private/write_neuralynx_nts.m index 43a75a25..8642c208 100644 --- a/external/fieldtrip/fileio/private/write_neuralynx_nts.m +++ b/external/fieldtrip/fileio/private/write_neuralynx_nts.m @@ -28,7 +28,7 @@ function write_neuralynx_nts(filename, nts) % $Id$ if ~isa(nts.TimeStamp, 'uint64') - error('timestamps should be uint64'); + ft_error('timestamps should be uint64'); end fid = fopen(filename, 'wb', 'ieee-le'); @@ -47,7 +47,7 @@ function write_neuralynx_nts(filename, nts) case 'double' buf = [buf sprintf('-%s\t%g\r\n', f{i}, v)]; otherwise - error('unknown class in writing header'); + ft_error('unknown class in writing header'); end end diff --git a/external/fieldtrip/fileio/private/write_plexon_nex.m b/external/fieldtrip/fileio/private/write_plexon_nex.m index 8bc01453..a133410a 100644 --- a/external/fieldtrip/fileio/private/write_plexon_nex.m +++ b/external/fieldtrip/fileio/private/write_plexon_nex.m @@ -54,7 +54,7 @@ function write_plexon_nex(filename, nex) nsamples = size(dat,2); nwaves = 1; % only one continuous datasegment is supported if length(hdr.VarHeader)~=nchans - error('incorrect number of channels'); + ft_error('incorrect number of channels'); end % convert the data from floating point into int16 values % each channel gets its own optimal calibration factor @@ -85,7 +85,7 @@ function write_plexon_nex(filename, nex) nsamples = size(dat,1); nwaves = size(dat,2); if length(hdr.VarHeader)~=nchans - error('incorrect number of channels'); + ft_error('incorrect number of channels'); end % convert the data from floating point into int16 values ADMaxValue = double(intmax('int16')); @@ -106,7 +106,7 @@ function write_plexon_nex(filename, nex) ADtoMV = 1/MVtoAD; otherwise - error('unsupported data type') + ft_error('unsupported data type') end % switch type % determine the first and last timestamp @@ -197,7 +197,7 @@ function write_plexon_nex(filename, nex) fwrite(fid, ts , 'int32'); % timestamps, one for each spike fwrite(fid, dat , 'int16'); % waveforms, one for each spike otherwise - error('unsupported data type'); + ft_error('unsupported data type'); end % switch end % of the nested function diff --git a/external/fieldtrip/fileio/private/write_ply.m b/external/fieldtrip/fileio/private/write_ply.m index f456c3de..f75a1aea 100644 --- a/external/fieldtrip/fileio/private/write_ply.m +++ b/external/fieldtrip/fileio/private/write_ply.m @@ -26,7 +26,7 @@ function write_ply(fn, pnt, tri, format) if size(tri,2)==4 % describe the sides of the tetraheders as polygon surface elements - % see http://bugzilla.fcdonders.nl/show_bug.cgi?id=1836 + % see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=1836 tri = [ tri(:,[3 2 1]) tri(:,[2 4 1]) @@ -35,7 +35,7 @@ function write_ply(fn, pnt, tri, format) ]; elseif size(tri,2)==8 % describe the sides of the hexaheders as polygon surface elements - % see http://bugzilla.fcdonders.nl/show_bug.cgi?id=1836 + % see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=1836 tri = [ tri(:,[4 3 2 1]) tri(:,[1 2 6 5]) @@ -102,7 +102,7 @@ function write_ply(fn, pnt, tri, format) case 9 fprintf(fid, '9\t%d\t%d\t%d\t%d\n', tri'); otherwise - error('unsupported size for polygons (%d)', num); + ft_error('unsupported size for polygons (%d)', num); end % case else fwrite(fid, pnt', 'single'); % float @@ -116,5 +116,5 @@ function write_ply(fn, pnt, tri, format) fclose(fid); else - error('unable to open file'); + ft_error('unable to open file'); end diff --git a/external/fieldtrip/fileio/private/write_serial_event.m b/external/fieldtrip/fileio/private/write_serial_event.m index b2785730..8870f3bc 100644 --- a/external/fieldtrip/fileio/private/write_serial_event.m +++ b/external/fieldtrip/fileio/private/write_serial_event.m @@ -60,7 +60,7 @@ function write_serial_event(filename, event) fprintf(s,'%s',msg); end else - error('could not write event to serial port'); + ft_error('could not write event to serial port'); end %% this is the old code @@ -105,5 +105,5 @@ function write_serial_event(filename, event) % if isa(s,'serial') && strcmp(s.Status,'open') % fwrite(s,char(event.value)); % else -% error('could not write event to serial port'); +% ft_error('could not write event to serial port'); % end diff --git a/external/fieldtrip/fileio/private/write_vtk.m b/external/fieldtrip/fileio/private/write_vtk.m index 0c00a600..21773bb9 100644 --- a/external/fieldtrip/fileio/private/write_vtk.m +++ b/external/fieldtrip/fileio/private/write_vtk.m @@ -50,5 +50,5 @@ function write_vtk(fn, pnt, tri) fclose(fid); else - error('unable to open file'); + ft_error('unable to open file'); end diff --git a/external/fieldtrip/fileio/private/xml2struct.m b/external/fieldtrip/fileio/private/xml2struct.m index b6b0f8ac..31bfff5d 100644 --- a/external/fieldtrip/fileio/private/xml2struct.m +++ b/external/fieldtrip/fileio/private/xml2struct.m @@ -38,7 +38,7 @@ % Written by W. Falkena, ASTI, TUDelft, 21-08-2010 % Attribute parsing speed increased by 40% by A. Wanner, 14-6-2011 % 2011/12/14 giopia: changes in the main function to make more similar to xml2struct of the XML4MAT toolbox, bc it's used by fieldtrip -% 2012/04/04 roboos: added the original license clause, see also http://bugzilla.fcdonders.nl/show_bug.cgi?id=645#c11 +% 2012/04/04 roboos: added the original license clause, see also http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=645#c11 % 2012/04/04 roboos: don't print the filename that is being read %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -85,7 +85,7 @@ end if (exist(file,'file') == 0) - error(['The file ' file ' could not be found']); + ft_error(['The file ' file ' could not be found']); end end %fprintf('xml2struct reading %s\n', file); % gp 11/12/15 diff --git a/external/fieldtrip/fileio/private/yokogawa2grad.m b/external/fieldtrip/fileio/private/yokogawa2grad.m index 5f402e9e..6ac6f028 100644 --- a/external/fieldtrip/fileio/private/yokogawa2grad.m +++ b/external/fieldtrip/fileio/private/yokogawa2grad.m @@ -28,7 +28,7 @@ % $Id$ if ~ft_hastoolbox('yokogawa') - error('cannot determine whether Yokogawa toolbox is present'); + ft_error('cannot determine whether Yokogawa toolbox is present'); end if isfield(hdr, 'label') diff --git a/external/fieldtrip/fileio/private/yokogawa2grad_new.m b/external/fieldtrip/fileio/private/yokogawa2grad_new.m index 6b0e4dd7..5025361c 100644 --- a/external/fieldtrip/fileio/private/yokogawa2grad_new.m +++ b/external/fieldtrip/fileio/private/yokogawa2grad_new.m @@ -31,7 +31,7 @@ % The following line is only a safety measure: No function of the toolbox % is actually called in this routine. if ~ft_hastoolbox('yokogawa_meg_reader') - error('cannot determine whether Yokogawa toolbox is present'); + ft_error('cannot determine whether Yokogawa toolbox is present'); end if isfield(hdr, 'label') diff --git a/external/fieldtrip/fileio/private/yokogawa2vol.m b/external/fieldtrip/fileio/private/yokogawa2vol.m index fbb876fd..5d972ba4 100644 --- a/external/fieldtrip/fileio/private/yokogawa2vol.m +++ b/external/fieldtrip/fileio/private/yokogawa2vol.m @@ -36,5 +36,5 @@ vol.r = hdr.mri_info.r; vol.o = [hdr.mri_info.cx hdr.mri_info.cy hdr.mri_info.cz]; else - error('unsupported volume conductor model'); + ft_error('unsupported volume conductor model'); end diff --git a/external/fieldtrip/forward/ft_apply_montage.m b/external/fieldtrip/forward/ft_apply_montage.m index 2b5e73ee..5262952b 100644 --- a/external/fieldtrip/forward/ft_apply_montage.m +++ b/external/fieldtrip/forward/ft_apply_montage.m @@ -18,7 +18,7 @@ % montage.labelnew = Mx1 cell-array % % As an example, a bipolar montage could look like this -% bipolar.labelold = {'1', '2', '3', '4'} +% bipolar.labelold = {'1', '2', '3', '4'} % bipolar.labelnew = {'1-2', '2-3', '3-4'} % bipolar.tra = [ % +1 -1 0 0 @@ -75,8 +75,8 @@ end % use "old/new" instead of "org/new" -montage = fixmontage(montage); -input = fixmontage(input); % the input might also be a montage +montage = fixoldorg(montage); +input = fixoldorg(input); % the input might be a montage or a sensor array % get optional input arguments keepunused = ft_getopt(varargin, 'keepunused', 'no'); @@ -99,7 +99,7 @@ if ~isfield(montage, 'chantypeold') montage.chantypeold = repmat({'unknown'}, size(montage.labelold)); if isfield(input, 'chantype') && ~istrue(inverse) - warning('copying input chantype to montage'); + ft_warning('copying input chantype to montage'); [sel1, sel2] = match_str(montage.labelold, input.label); montage.chantypeold(sel1) = input.chantype(sel2); end @@ -108,7 +108,7 @@ if ~isfield(montage, 'chantypenew') montage.chantypenew = repmat({'unknown'}, size(montage.labelnew)); if isfield(input, 'chantype') && istrue(inverse) - warning('copying input chantype to montage'); + ft_warning('copying input chantype to montage'); [sel1, sel2] = match_str(montage.labelnew, input.label); montage.chantypenew(sel1) = input.chantype(sel2); end @@ -117,7 +117,7 @@ if ~isfield(montage, 'chanunitold') montage.chanunitold = repmat({'unknown'}, size(montage.labelold)); if isfield(input, 'chanunit') && ~istrue(inverse) - warning('copying input chanunit to montage'); + ft_warning('copying input chanunit to montage'); [sel1, sel2] = match_str(montage.labelold, input.label); montage.chanunitold(sel1) = input.chanunit(sel2); end @@ -126,7 +126,7 @@ if ~isfield(montage, 'chanunitnew') montage.chanunitnew = repmat({'unknown'}, size(montage.labelnew)); if isfield(input, 'chanunit') && istrue(inverse) - warning('copying input chanunit to montage'); + ft_warning('copying input chanunit to montage'); [sel1, sel2] = match_str(montage.labelnew, input.label); montage.chanunitnew(sel1) = input.chanunit(sel2); end @@ -162,19 +162,19 @@ % check the consistency of the montage if ~iscell(montage.labelold) || ~iscell(montage.labelnew) - error('montage labels need to be specified in cell-arrays'); + ft_error('montage labels need to be specified in cell-arrays'); end % check the consistency of the montage if ~all(isfield(montage, {'tra', 'labelold', 'labelnew'})) - error('the second input argument does not correspond to a montage'); + ft_error('the second input argument does not correspond to a montage'); end % check the consistency of the montage if size(montage.tra,1)~=length(montage.labelnew) - error('the number of channels in the montage is inconsistent'); + ft_error('the number of channels in the montage is inconsistent'); elseif size(montage.tra,2)~=length(montage.labelold) - error('the number of channels in the montage is inconsistent'); + ft_error('the number of channels in the montage is inconsistent'); end % use a default unit transfer from sensors to channels if not otherwise specified @@ -212,15 +212,14 @@ end % select and keep the columns that are non-empty, i.e. remove the empty columns -selcol = find(~all(montage.tra==0, 1)); -montage.tra = montage.tra(:,selcol); -montage.labelold = montage.labelold(selcol); +selcol = find(~all(montage.tra==0, 1)); +montage.tra = montage.tra(:,selcol); +montage.labelold = montage.labelold(selcol); montage.chantypeold = montage.chantypeold(selcol); montage.chanunitold = montage.chanunitold(selcol); clear selcol -% select and remove the columns corresponding to channels that are not present in the -% original data +% select and remove the columns corresponding to channels that are not present in the original data remove = setdiff(montage.labelold, intersect(montage.labelold, inputlabel)); selcol = match_str(montage.labelold, remove); % we cannot just remove the colums, all rows that depend on it should also be removed @@ -259,15 +258,15 @@ % use an anonymous function to test for the presence of NaNs in the input data hasnan = @(x) any(isnan(x(:))); if any(cellfun(hasnan, data_unused.trial)) - error('FieldTrip:NaNsinInputData', ['Your input data contains NaNs in channels that are unused '... + ft_error('FieldTrip:NaNsinInputData', ['Your input data contains NaNs in channels that are unused '... 'in the supplied montage. This would result in undesired NaNs in the '... 'output data. Please remove these channels from the input data (using '... 'ft_selectdata) before attempting to apply the montage.']); end end + if istrue(keepunused) - % add the channels that are not rereferenced to the input and output of the - % montage + % add the channels that are not rereferenced to the input and output of the montage montage.tra((m+(1:k)),(n+(1:k))) = eye(k); montage.labelold = cat(1, montage.labelold(:), addlabel(:)); montage.labelnew = cat(1, montage.labelnew(:), addlabel(:)); @@ -288,15 +287,15 @@ m = size(montage.tra,1); n = size(montage.tra,2); if length(unique(montage.labelnew))~=m - error('not all output channels of the montage are unique'); + ft_error('not all output channels of the montage are unique'); end if length(unique(montage.labelold))~=n - error('not all input channels of the montage are unique'); + ft_error('not all input channels of the montage are unique'); end % determine whether all channels that have to be rereferenced are available if length(intersect(inputlabel, montage.labelold))~=length(montage.labelold) - error('not all channels that are required in the montage are available in the data'); + ft_error('not all channels that are required in the montage are available in the data'); end % reorder the columns of the montage matrix @@ -331,9 +330,9 @@ end if isfield(input, 'chantype') && ~isequal(input.chantype, montage.chantypeold) - error('inconsistent chantype in data and montage'); + ft_error('inconsistent chantype in data and montage'); elseif isfield(input, 'chantypenew') && ~isequal(input.chantypenew, montage.chantypeold) - error('inconsistent chantype in data and montage'); + ft_error('inconsistent chantype in data and montage'); end if isfield(input, 'labelold') && isfield(input, 'labelnew') @@ -374,11 +373,13 @@ sens.tra = montage.tra * sens.tra; end - % The montage operates on the coil weights in sens.tra, but the output channels - % can be different. If possible, we want to keep the original channel positions - % and orientations. + % The montage operates on the coil weights in sens.tra, but the output channels can be different. + % If possible, we want to keep the original channel positions and orientations. [sel1, sel2] = match_str(montage.labelnew, inputlabel); - keepchans = length(sel1)==length(montage.labelnew); + keepchans = isequal(sel1(:)', 1:numel(montage.labelnew)); + + posweight = abs(montage.tra); + posweight = diag(1./sum(posweight,2)) * posweight; if isfield(sens, 'chanpos') if keepchans @@ -386,9 +387,14 @@ else if ~isfield(sens, 'chanposold') % add a chanposold only if it is not there yet - sens.chanposold = sens.chanpos; + sens.chanposold = sens.chanpos; + % also keep the old label, type and unit for reference + sens.labelold = inputlabel; + sens.chantypeold = inputchantype; + sens.chanunitold = inputchanunit; end - sens.chanpos = nan(numel(montage.labelnew),3); + % compute the channel positions as a weighted sum of the original ones + sens.chanpos = posweight * sens.chanpos; end end @@ -399,7 +405,8 @@ if ~isfield(sens, 'chanoriold') sens.chanoriold = sens.chanori; end - sens.chanori = nan(numel(montage.labelnew),3); + % compute the channel orientations as a weighted sum of the original ones + sens.chanori = posweight * sens.chanori; end end @@ -407,20 +414,6 @@ sens.chantype = montage.chantypenew; sens.chanunit = montage.chanunitnew; - % keep the - % original label, - % type and unit - % for reference - if ~isfield(sens, 'labelold') - sens.labelold = inputlabel; - end - if ~isfield(sens, 'chantypeold') - sens.chantypeold = inputchantype; - end - if ~isfield(sens, 'chanunitold') - sens.chanunitold = inputchanunit; - end - % keep track of the order of the balancing and which one is the current one if istrue(inverse) if isfield(sens, 'balance')% && isfield(sens.balance, 'previous') @@ -434,14 +427,14 @@ sens.balance.current = 'none'; end end - elseif ~istrue(inverse) && ~isempty(bname) - if isfield(sens, 'balance'), + elseif ~istrue(inverse) && ~isempty(bname) + if isfield(sens, 'balance') % check whether a balancing montage with name bname already exist, % and if so, how many mnt = fieldnames(sens.balance); sel = strmatch(bname, mnt); - if numel(sel)==0, + if numel(sel)==0 % bname can stay the same elseif numel(sel)==1 % the original should be renamed to 'bname1' and the new one should @@ -477,8 +470,8 @@ input = sens; clear sens - case 'raw'; - % apply the montage to the raw data that was preprocessed using fieldtrip + case 'raw' + % apply the montage to the raw data that was preprocessed using FieldTrip data = input; clear input @@ -533,7 +526,7 @@ end freq.fourierspctrm = output; % replace the original Fourier spectrum else - error('unsupported dimord in frequency data (%s)', freq.dimord); + ft_error('unsupported dimord in frequency data (%s)', freq.dimord); end freq.label = montage.labelnew; @@ -545,7 +538,7 @@ clear freq otherwise - error('unrecognized input'); + ft_error('unrecognized input'); end % switch inputtype % only retain the chantype and/or chanunit if they were present in the input @@ -563,30 +556,9 @@ y = false(1,n); y(x) = true; -function nowarning(varargin) -return - -function s = removefields(s, fn) -for i=1:length(fn) - if isfield(s, fn{i}) - s = rmfield(s, fn{i}); - end -end - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% HELPER FUNCTION use "old/new" instead of "org/new" +% HELPER FUNCTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -function montage = fixmontage(montage) -if isfield(montage, 'labelorg') - montage.labelold = montage.labelorg; - montage = rmfield(montage, 'labelorg'); -end -if isfield(montage, 'chantypeorg') - montage.chantypeold = montage.chantypeorg; - montage = rmfield(montage, 'chantypeorg'); -end -if isfield(montage, 'chanunitorg') - montage.chanunitold = montage.chanunitorg; - montage = rmfield(montage, 'chanunitorg'); -end +function nowarning(varargin) +return diff --git a/external/fieldtrip/forward/ft_average_sens.m b/external/fieldtrip/forward/ft_average_sens.m index e6829a34..bda90bda 100644 --- a/external/fieldtrip/forward/ft_average_sens.m +++ b/external/fieldtrip/forward/ft_average_sens.m @@ -100,7 +100,7 @@ for i=1:nsens if ~isequal(sens(i).label(:), sens(1).label(:)) - error('all sensor arrays should have the same sensors for averaging'); + ft_error('all sensor arrays should have the same sensors for averaging'); end % add them to the sum, to compute the mean location of each ref sensor @@ -146,7 +146,7 @@ asens = csens; else - error('unsupported sensor type'); + ft_error('unsupported sensor type'); end if toplot @@ -183,7 +183,7 @@ end if ~isequal(fiducials(i).fid.label, fiducials(1).fid.label) - error('all fiducials should have the same labels for averaging'); + ft_error('all fiducials should have the same labels for averaging'); end tra1 = ft_headcoordinates(sens(i).chanpos(ind1, :), sens(i).chanpos(ind2, :), sens(i).chanpos(ind3, :)); @@ -199,7 +199,7 @@ cfiducials.fid.pos = fidpos; afiducials = ft_transform_headshape(inv(tra), cfiducials); - afiducials = ft_convert_units(afiducials); + afiducials = ft_determine_units(afiducials); % remove redundant headshape points (3 cm precision) tolerance = 3; @@ -219,5 +219,5 @@ afiducials.pos = afiducials.pos(ind, :); otherwise - error('there should be either one set of fiducials or a set per sensor array'); + ft_error('there should be either one set of fiducials or a set per sensor array'); end % switch nfid diff --git a/external/fieldtrip/forward/ft_compute_leadfield.m b/external/fieldtrip/forward/ft_compute_leadfield.m index 0acb58d2..3b9c1703 100644 --- a/external/fieldtrip/forward/ft_compute_leadfield.m +++ b/external/fieldtrip/forward/ft_compute_leadfield.m @@ -104,10 +104,10 @@ dipoleunit = ft_getopt(varargin, 'dipoleunit'); % this is something like nA*m if any(strcmp(varargin(1:2:end), 'unit')) - error('the ''unit'' option is not supported any more, please use ''chanunit'''); + ft_error('the ''unit'' option is not supported any more, please use ''chanunit'''); end if any(strcmp(varargin(1:2:end), 'units')) - error('the ''units'' option is not supported any more, please use ''chanunit'''); + ft_error('the ''units'' option is not supported any more, please use ''chanunit'''); end if ~isstruct(sens) && size(sens, 2)==3 @@ -144,15 +144,15 @@ end if isfield(headmodel, 'unit') && isfield(sens, 'unit') && ~strcmp(headmodel.unit, sens.unit) - error('inconsistency in the units of the volume conductor and the sensor array'); + ft_error('inconsistency in the units of the volume conductor and the sensor array'); end if ismeg && iseeg % this is something that could be implemented relatively easily - error('simultaneous EEG and MEG not supported'); + ft_error('simultaneous EEG and MEG not supported'); elseif ~ismeg && ~iseeg - error('the input does not look like EEG, nor like MEG'); + ft_error('the input does not look like EEG, nor like MEG'); elseif ismeg switch ft_voltype(headmodel) @@ -195,11 +195,11 @@ ncoils = length(sens.coilpos); if size(headmodel.r, 1)~=ncoils - error('number of spheres is not equal to the number of coils') + ft_error('number of spheres is not equal to the number of coils') end if size(headmodel.o, 1)~=ncoils - error('number of spheres is not equal to the number of coils'); + ft_error('number of spheres is not equal to the number of coils'); end lf = zeros(ncoils, 3*Ndipoles); @@ -278,14 +278,14 @@ %if isfield(headmodel, 'mat') lf = s2mm+h2mm*(headmodel.mat*dsm); %else - % error('No system matrix is present, BEM head model not calculated yet') + % ft_error('No system matrix is present, BEM head model not calculated yet') %end if isfield(sens, 'tra') % compute the leadfield for each gradiometer (linear combination of coils) lf = sens.tra * lf; end else - warning('No system matrix is present, Calling the Nemo Lab pipeline') + ft_warning('No system matrix is present, Calling the Nemo Lab pipeline') lf = leadfield_openmeeg(dippos, headmodel, sens); end @@ -338,7 +338,7 @@ end otherwise - error('unsupported volume conductor model for MEG'); + ft_error('unsupported volume conductor model for MEG'); end % switch voltype for MEG elseif iseeg @@ -403,7 +403,7 @@ Nspheres = length(headmodel.cond); if length(headmodel.r)~=Nspheres - error('the number of spheres in the volume conductor model is ambiguous'); + ft_error('the number of spheres in the volume conductor model is ambiguous'); end if isfield(headmodel, 'o') @@ -428,7 +428,7 @@ headmodel.cond = [headmodel.cond(1) headmodel.cond(2) headmodel.cond(3) headmodel.cond(4)]; funnam = 'eeg_leadfield4'; otherwise - error('more than 4 concentric spheres are not supported') + ft_error('more than 4 concentric spheres are not supported') end lf = zeros(size(sens.elecpos, 1), 3*Ndipoles); @@ -506,7 +506,7 @@ sens.tra = speye(length(headmodel.filename)); otherwise - error('unsupported volume conductor model for EEG'); + ft_error('unsupported volume conductor model for EEG'); end % switch voltype for EEG diff --git a/external/fieldtrip/forward/ft_convert_units.m b/external/fieldtrip/forward/ft_convert_units.m index e81f9502..47279027 100644 --- a/external/fieldtrip/forward/ft_convert_units.m +++ b/external/fieldtrip/forward/ft_convert_units.m @@ -19,7 +19,7 @@ % are specified, this function will only determine the native geometrical % units of the object. % -% See also FT_ESTIMATE_UNITS, FT_READ_VOL, FT_READ_SENS +% See also FT_DETERMINE_UNITS, FT_CONVERT_COORDSYS, FT_DETERMINE_COODSYS % Copyright (C) 2005-2016, Robert Oostenveld % @@ -46,16 +46,28 @@ % 2) determine the requested scaling factor to obtain the output units % 3) try to apply the scaling to the known geometrical elements in the input object +% ensure the correct number of input and output arguments +% narginchk(2,inf); % see below +% nargoutchk(0,1); + +% the "target" input argument has been made required in Aug 2017 +% prior to that it was also possible to use this function to estimate units +% the backward compatibility support can be removed in Aug 2018 +if nargin<2 + ft_warning('calling this function only to determine units is deprecated, please use FT_DETERMINE_COORDSYS instead'); + obj = ft_determine_units(obj); + return +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% parse input options feedback = ft_getopt(varargin, 'feedback', false); if isstruct(obj) && numel(obj)>1 % deal with a structure array for i=1:numel(obj) - if nargin>1 - tmp(i) = ft_convert_units(obj(i), target, varargin{:}); - else - tmp(i) = ft_convert_units(obj(i)); - end + tmp(i) = ft_convert_units(obj(i), target, varargin{:}); end obj = tmp; return @@ -69,119 +81,29 @@ end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% determine the unit-of-dimension of the input object +% determine the units of the input object %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -if isfield(obj, 'unit') && ~isempty(obj.unit) - % use the units specified in the object - unit = obj.unit; - -elseif isfield(obj, 'bnd') && isfield(obj.bnd, 'unit') - - unit = unique({obj.bnd.unit}); - if ~all(strcmp(unit, unit{1})) - error('inconsistent units in the individual boundaries'); - else - unit = unit{1}; - end - - % keep one representation of the units rather than keeping it with each boundary - % the units will be reassigned further down - obj.bnd = rmfield(obj.bnd, 'unit'); - -else - % try to determine the units by looking at the size of the object - if isfield(obj, 'chanpos') && ~isempty(obj.chanpos) - siz = norm(idrange(obj.chanpos)); - unit = ft_estimate_units(siz); - - elseif isfield(obj, 'elecpos') && ~isempty(obj.elecpos) - siz = norm(idrange(obj.elecpos)); - unit = ft_estimate_units(siz); - - elseif isfield(obj, 'coilpos') && ~isempty(obj.coilpos) - siz = norm(idrange(obj.coilpos)); - unit = ft_estimate_units(siz); - - elseif isfield(obj, 'pnt') && ~isempty(obj.pnt) - siz = norm(idrange(obj.pnt)); - unit = ft_estimate_units(siz); - - elseif isfield(obj, 'pos') && ~isempty(obj.pos) - siz = norm(idrange(obj.pos)); - unit = ft_estimate_units(siz); - - elseif isfield(obj, 'transform') && ~isempty(obj.transform) - % construct the corner points of the volume in voxel and in head coordinates - [pos_voxel, pos_head] = cornerpoints(obj.dim, obj.transform); - siz = norm(idrange(pos_head)); - unit = ft_estimate_units(siz); - - elseif isfield(obj, 'fid') && isfield(obj.fid, 'pnt') && ~isempty(obj.fid.pnt) - siz = norm(idrange(obj.fid.pnt)); - unit = ft_estimate_units(siz); - - elseif isfield(obj, 'fid') && isfield(obj.fid, 'pos') && ~isempty(obj.fid.pos) - siz = norm(idrange(obj.fid.pos)); - unit = ft_estimate_units(siz); - - elseif ft_voltype(obj, 'infinite') - % this is an infinite medium volume conductor, which does not care about units - unit = 'm'; - - elseif ft_voltype(obj,'singlesphere') - siz = obj.r; - unit = ft_estimate_units(siz); - - elseif ft_voltype(obj,'localspheres') - siz = median(obj.r); - unit = ft_estimate_units(siz); - - elseif ft_voltype(obj,'concentricspheres') - siz = max(obj.r); - unit = ft_estimate_units(siz); - - elseif isfield(obj, 'bnd') && isstruct(obj.bnd) && isfield(obj.bnd(1), 'pnt') && ~isempty(obj.bnd(1).pnt) - siz = norm(idrange(obj.bnd(1).pnt)); - unit = ft_estimate_units(siz); - - elseif isfield(obj, 'bnd') && isstruct(obj.bnd) && isfield(obj.bnd(1), 'pos') && ~isempty(obj.bnd(1).pos) - siz = norm(idrange(obj.bnd(1).pos)); - unit = ft_estimate_units(siz); - - elseif isfield(obj, 'nas') && isfield(obj, 'lpa') && isfield(obj, 'rpa') - pnt = [obj.nas; obj.lpa; obj.rpa]; - siz = norm(idrange(pnt)); - unit = ft_estimate_units(siz); - - else - error('cannot determine geometrical units'); - - end % recognized type of volume conduction model or sensor array -end % determine input units - -if nargin<2 || isempty(target) - % just remember the units in the output and return - obj.unit = unit; - return -elseif strcmp(unit, target) - % no conversion is needed - obj.unit = unit; - return -end +obj = ft_determine_units(obj); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % compute the scaling factor from the input units to the desired ones %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -scale = ft_scalingfactor(unit, target); + +if isequal(obj.unit, target) + % there is nothing to do + return +end if istrue(feedback) % give some information about the conversion - fprintf('converting units from ''%s'' to ''%s''\n', unit, target) + fprintf('converting units from ''%s'' to ''%s''\n', obj.unit, target) end + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % apply the scaling factor %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +scale = ft_scalingfactor(obj.unit, target); % volume conductor model if isfield(obj, 'r'), obj.r = scale * obj.r; end @@ -225,7 +147,7 @@ elseif strcmp(obj.chanunit{i}, 'unknown') % assume that it is T or V, don't do anything else - error('unexpected units %s', obj.chanunit{i}); + ft_error('unexpected units %s', obj.chanunit{i}); end end % for end % if @@ -243,12 +165,12 @@ if isfield(obj, 'zgrid') && ~ischar(obj.zgrid), obj.zgrid = scale * obj.zgrid; end % anatomical MRI or functional volume -if isfield(obj, 'transform'), +if isfield(obj, 'transform') H = diag([scale scale scale 1]); obj.transform = H * obj.transform; end -if isfield(obj, 'transformorig'), +if isfield(obj, 'transformorig') H = diag([scale scale scale 1]); obj.transformorig = H * obj.transformorig; end @@ -266,15 +188,3 @@ % remember the unit obj.unit = target; - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% IDRANGE interdecile range for more robust range estimation -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -function r = idrange(x) -keeprow=true(size(x,1),1); -for l=1:size(x,2) - keeprow = keeprow & isfinite(x(:,l)); -end -sx = sort(x(keeprow,:), 1); -ii = round(interp1([0, 1], [1, size(x(keeprow,:), 1)], [.1, .9])); % indices for 10 & 90 percentile -r = diff(sx(ii, :)); diff --git a/external/fieldtrip/forward/ft_determine_units.m b/external/fieldtrip/forward/ft_determine_units.m new file mode 100644 index 00000000..8c5864a3 --- /dev/null +++ b/external/fieldtrip/forward/ft_determine_units.m @@ -0,0 +1,171 @@ +function [obj] = ft_determine_units(obj) + +% FT_DETERMINE_UNITS tries to determine the units of a geometrical object by +% looking at its size and by relating this to the approximate size of the +% human head according to the following table: +% from 0.050 to 0.500 -> meter +% from 0.500 to 5.000 -> decimeter +% from 5.000 to 50.000 -> centimeter +% from 50.000 to 500.000 -> millimeter +% +% Use as +% dataout = ft_determine_units(datain) +% where the input obj structure can be +% - an anatomical MRI +% - an electrode or gradiometer definition +% - a volume conduction model of the head +% or most other FieldTrip structures that represent geometrical information. +% +% See also FT_CONVERT_UNITS, FT_DETERMINE_COODSYS, FT_CONVERT_COORDSYS + +% Copyright (C) 2005-2017, Robert Oostenveld +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +% ensure the correct number of input and output arguments +% narginchk(1,1); +% nargoutchk(0,1); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +if isstruct(obj) && numel(obj)>1 + % deal with a structure array + for i=1:numel(obj) + tmp(i) = ft_determine_units(obj(i)); + end + obj = tmp; + return +elseif iscell(obj) && numel(obj)>1 + % deal with a cell array + % this might represent combined EEG, ECoG and/or MEG + for i=1:numel(obj) + obj{i} = ft_determine_units(obj{i}); + end + return +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +if isfield(obj, 'unit') && ~isempty(obj.unit) + % use the units specified in the object + unit = obj.unit; + +elseif isfield(obj, 'bnd') && isfield(obj.bnd, 'unit') + + unit = unique({obj.bnd.unit}); + if ~all(strcmp(unit, unit{1})) + ft_error('inconsistent units in the individual boundaries'); + else + unit = unit{1}; + end + + % keep one representation of the units rather than keeping it with each boundary + % the units will be reassigned further down + obj.bnd = rmfield(obj.bnd, 'unit'); + +else + % try to determine the units by looking at the size of the object + if isfield(obj, 'chanpos') && ~isempty(obj.chanpos) + siz = norm(idrange(obj.chanpos)); + unit = ft_estimate_units(siz); + + elseif isfield(obj, 'elecpos') && ~isempty(obj.elecpos) + siz = norm(idrange(obj.elecpos)); + unit = ft_estimate_units(siz); + + elseif isfield(obj, 'coilpos') && ~isempty(obj.coilpos) + siz = norm(idrange(obj.coilpos)); + unit = ft_estimate_units(siz); + + elseif isfield(obj, 'pnt') && ~isempty(cat(1, obj.pnt)) + % the obj can be a struct.array, hence the concatenation + siz = norm(idrange(cat(1, obj.pnt))); + unit = ft_estimate_units(siz); + + elseif isfield(obj, 'pos') && ~isempty(cat(1, obj.pos)) + % the obj can be a struct.array, hence the concatenation + siz = norm(idrange(cat(1, obj.pos))); + unit = ft_estimate_units(siz); + + elseif isfield(obj, 'transform') && ~isempty(obj.transform) + % construct the corner points of the volume in voxel and in head coordinates + [pos_voxel, pos_head] = cornerpoints(obj.dim, obj.transform); + siz = norm(idrange(pos_head)); + unit = ft_estimate_units(siz); + + elseif isfield(obj, 'fid') && isfield(obj.fid, 'pnt') && ~isempty(obj.fid.pnt) + siz = norm(idrange(obj.fid.pnt)); + unit = ft_estimate_units(siz); + + elseif isfield(obj, 'fid') && isfield(obj.fid, 'pos') && ~isempty(obj.fid.pos) + siz = norm(idrange(obj.fid.pos)); + unit = ft_estimate_units(siz); + + elseif ft_voltype(obj, 'infinite') + % this is an infinite medium volume conductor, which does not care about units + unit = 'm'; + + elseif ft_voltype(obj,'singlesphere') + siz = obj.r; + unit = ft_estimate_units(siz); + + elseif ft_voltype(obj,'localspheres') + siz = median(obj.r); + unit = ft_estimate_units(siz); + + elseif ft_voltype(obj,'concentricspheres') + siz = max(obj.r); + unit = ft_estimate_units(siz); + + elseif isfield(obj, 'bnd') && isstruct(obj.bnd) && isfield(obj.bnd(1), 'pnt') && ~isempty(obj.bnd(1).pnt) + siz = norm(idrange(obj.bnd(1).pnt)); + unit = ft_estimate_units(siz); + + elseif isfield(obj, 'bnd') && isstruct(obj.bnd) && isfield(obj.bnd(1), 'pos') && ~isempty(obj.bnd(1).pos) + siz = norm(idrange(obj.bnd(1).pos)); + unit = ft_estimate_units(siz); + + elseif isfield(obj, 'nas') && isfield(obj, 'lpa') && isfield(obj, 'rpa') + pnt = [obj.nas; obj.lpa; obj.rpa]; + siz = norm(idrange(pnt)); + unit = ft_estimate_units(siz); + + else + ft_error('cannot determine geometrical units'); + + end % recognized type of volume conduction model or sensor array +end % determine input units + +% add the units to the output object +for i=1:numel(obj) + % obj can be a struct-array, hence the loop + obj(i).unit = unit; +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% IDRANGE interdecile range for more robust range estimation +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function r = idrange(x) +keeprow=true(size(x,1),1); +for l=1:size(x,2) + keeprow = keeprow & isfinite(x(:,l)); +end +sx = sort(x(keeprow,:), 1); +ii = round(interp1([0, 1], [1, size(x(keeprow,:), 1)], [.1, .9])); % indices for 10 & 90 percentile +r = diff(sx(ii, :)); diff --git a/external/fieldtrip/forward/ft_estimate_units.m b/external/fieldtrip/forward/ft_estimate_units.m index ce0b457f..d44dc8ae 100644 --- a/external/fieldtrip/forward/ft_estimate_units.m +++ b/external/fieldtrip/forward/ft_estimate_units.m @@ -46,14 +46,14 @@ if indx>length(unit) indx = length(unit); - warning('assuming that the units are "%s"', unit{indx}); + ft_warning('assuming that the units are "%s"', unit{indx}); elseif indx<1 indx = 1; - warning('assuming that the units are "%s"', unit{indx}); + ft_warning('assuming that the units are "%s"', unit{indx}); elseif abs((est-floor(est)) - 0.5)<0.1 % the size estimate falls within the expected range, but is not very decisive % for example round(1.49) results in meter, but round(1.51) results in decimeter - warning('the estimated units are not very decisive, assuming that the units are "%s"', unit{indx}); + ft_warning('the estimated units are not very decisive, assuming that the units are "%s"', unit{indx}); end unit = unit{indx}; diff --git a/external/fieldtrip/forward/ft_headmodel_bemcp.m b/external/fieldtrip/forward/ft_headmodel_bemcp.m index d5f91805..59d299a3 100644 --- a/external/fieldtrip/forward/ft_headmodel_bemcp.m +++ b/external/fieldtrip/forward/ft_headmodel_bemcp.m @@ -60,7 +60,7 @@ numboundaries = length(headmodel.bnd); if numboundaries~=3 - error('this only works for three surfaces'); + ft_error('this only works for three surfaces'); end % determine the desired nesting of the compartments @@ -76,13 +76,13 @@ end if isempty(conductivity) - warning('No conductivity is declared, assuming standard values') + ft_warning('No conductivity is declared, assuming standard values') % brain/skull/skin conductivity = [1 1/80 1] * 0.33; headmodel.cond = conductivity; else if numel(conductivity)~=numboundaries - error('a conductivity value should be specified for each compartment'); + ft_error('a conductivity value should be specified for each compartment'); end headmodel.cond = conductivity(order); end @@ -92,10 +92,10 @@ % do some sanity checks if headmodel.skin_surface~=3 - error('the third surface should be the skin'); + ft_error('the third surface should be the skin'); end % if headmodel.source~=1 -% error('the first surface should be the inside of the skull'); +% ft_error('the first surface should be the inside of the skull'); % end % Build Triangle 4th point diff --git a/external/fieldtrip/forward/ft_headmodel_concentricspheres.m b/external/fieldtrip/forward/ft_headmodel_concentricspheres.m index 865730e4..c7e39907 100644 --- a/external/fieldtrip/forward/ft_headmodel_concentricspheres.m +++ b/external/fieldtrip/forward/ft_headmodel_concentricspheres.m @@ -51,7 +51,7 @@ if any(strcmp(varargin(1:2:end), 'unit')) || any(strcmp(varargin(1:2:end), 'units')) % the geometrical units should be specified in the input mesh - error('the ''unit'' option is not supported any more'); + ft_error('the ''unit'' option is not supported any more'); end if isnumeric(mesh) && size(mesh,2)==3 @@ -67,14 +67,14 @@ mesh = fixpos(mesh); if ~isstruct(mesh) || ~isfield(mesh, 'pos') - error('the input mesh should be a set of points or a single triangulated surface') + ft_error('the input mesh should be a set of points or a single triangulated surface') end % start with an empty volume conductor headmodel = []; % ensure that the mesh has units, estimate them if needed -mesh = ft_convert_units(mesh); +mesh = ft_determine_units(mesh); % copy the geometrical units into the volume conductor headmodel.unit = mesh(1).unit; @@ -120,7 +120,7 @@ elseif length(headmodel.r)==4 headmodel.cond = [0.3300 1 0.0042 0.3300]; % brain, csf, skull, skin else - error('conductivity values should be specified for each tissue type'); + ft_error('conductivity values should be specified for each tissue type'); end else % the conductivity as specified by the user should be in the same order as the geometries diff --git a/external/fieldtrip/forward/ft_headmodel_dipoli.m b/external/fieldtrip/forward/ft_headmodel_dipoli.m index c1c46495..9e8d26d5 100644 --- a/external/fieldtrip/forward/ft_headmodel_dipoli.m +++ b/external/fieldtrip/forward/ft_headmodel_dipoli.m @@ -53,13 +53,13 @@ % % feed in the correct geometry. % % % % if ~all(surface_closed(headmodel.bnd)) -% % error('...'); +% % ft_error('...'); % % end % % if any(surface_intersection(headmodel.bnd)) -% % error('...'); +% % ft_error('...'); % % end % % if any(surface_selfintersection(headmodel.bnd)) -% % error('...'); +% % ft_error('...'); % % end % % % The following checks should always be done. @@ -102,7 +102,7 @@ end if isempty(conductivity) - warning('No conductivity is declared, Assuming standard values\n') + ft_warning('No conductivity is declared, Assuming standard values\n') if numboundaries == 1 conductivity = 1; elseif numboundaries == 3 @@ -113,12 +113,12 @@ % skin / outer skull / inner skull / brain conductivity = [1 1/80 1 1] * 0.33; else - error('Conductivity values are required!') + ft_error('Conductivity values are required!') end headmodel.cond = conductivity; else if numel(conductivity)~=numboundaries - error('a conductivity value should be specified for each compartment'); + ft_error('a conductivity value should be specified for each compartment'); end headmodel.cond = conductivity(order); end @@ -144,7 +144,7 @@ % linux computer dipoli = [dipoli '.glnx86']; otherwise - error('there is no dipoli executable for your platform'); + ft_error('there is no dipoli executable for your platform'); end fprintf('using the executable "%s"\n', dipoli); @@ -208,7 +208,7 @@ end catch - error('an error ocurred while running the dipoli executable - please look at the screen output'); + ft_error('an error ocurred while running the dipoli executable - please look at the screen output'); end % delete the temporary files @@ -237,10 +237,10 @@ if w<0 && (abs(w)-4*pi)<1000*eps % FIXME: this method is rigorous only for star shaped surfaces - warning('your normals are outwards oriented\n') + ft_warning('your normals are outwards oriented\n') ok = 0; elseif w>0 && (abs(w)-4*pi)<1000*eps - % warning('your normals are inwards oriented\n') + % ft_warning('your normals are inwards oriented\n') ok = 1; else fprintf('attention: your surface probably is irregular!') diff --git a/external/fieldtrip/forward/ft_headmodel_fns.m b/external/fieldtrip/forward/ft_headmodel_fns.m index bd86d195..821d7636 100644 --- a/external/fieldtrip/forward/ft_headmodel_fns.m +++ b/external/fieldtrip/forward/ft_headmodel_fns.m @@ -61,17 +61,17 @@ tolerance = ft_getopt(varargin, 'tolerance', 1e-8); if isempty(sens) - error('A set of sensors is required') + ft_error('A set of sensors is required') end if ispc - error('FNS only works on Linux and OS X') + ft_error('FNS only works on Linux and OS X') end % check the consistency between tissue values and the segmentation vecval = ismember(tissueval,unique(seg(:))); if any(vecval)==0 - warning('Some of the tissue values are not in the segmentation') + ft_warning('Some of the tissue values are not in the segmentation') end % create the files to be written diff --git a/external/fieldtrip/forward/ft_headmodel_halfspace.m b/external/fieldtrip/forward/ft_headmodel_halfspace.m index 41f4d556..2d03d1b9 100644 --- a/external/fieldtrip/forward/ft_headmodel_halfspace.m +++ b/external/fieldtrip/forward/ft_headmodel_halfspace.m @@ -43,7 +43,7 @@ cond = ft_getopt(varargin, 'conductivity'); if isempty(cond) - warning('Conductivity was not specified, using 1'); + ft_warning('Conductivity was not specified, using 1'); cond = 1; end @@ -55,7 +55,7 @@ elseif size(mesh,2)==3 pos = mesh; else - error('incorrect specification of the geometry'); + ft_error('incorrect specification of the geometry'); end % fit a plane to the points @@ -78,7 +78,7 @@ elseif strcmpi(model,'monopole') headmodel.type = 'halfspace_monopole'; else - error('unknow method') + ft_error('unknow method') end function [N,P] = fit_plane(X) diff --git a/external/fieldtrip/forward/ft_headmodel_interpolate.m b/external/fieldtrip/forward/ft_headmodel_interpolate.m index 59d28151..e5d8682d 100644 --- a/external/fieldtrip/forward/ft_headmodel_interpolate.m +++ b/external/fieldtrip/forward/ft_headmodel_interpolate.m @@ -131,7 +131,7 @@ grid.leadfield = cell(dim); % ensure that it has geometrical units (probably mm) - grid = ft_convert_units(grid); + grid = ft_determine_units(grid); % Read leadfield, all channels, all locations, 3 orientations [lftdim, lft] = readBESAlft(lftfile); @@ -163,7 +163,7 @@ nchan = length(sens.label); if size(grid.leadfield{insideindx(1)},1)~=nchan - error('the number of channels does not match'); + ft_error('the number of channels does not match'); end headmodel = []; @@ -180,7 +180,7 @@ headmodel.unit = grid.unit; else % estimate the units - headmodel = ft_convert_units(headmodel); + headmodel = ft_determine_units(headmodel); end % these go in the same directory as the other nii files, they will be removed after use @@ -279,24 +279,24 @@ n4 = length(sens.label); % desired channels % this is the montage for getting the the desired channels from the desired electrode positions - make4from3.labelorg = cell(n3,1); + make4from3.labelold = cell(n3,1); make4from3.labelnew = sens.label; make4from3.tra = sens.tra; for i=1:n3 - make4from3.labelorg{i} = sprintf('3to4_%d', i); + make4from3.labelold{i} = sprintf('3to4_%d', i); end % this is the montage for getting the computed channels from the computed electrode positions - make1from2.labelorg = cell(n2,1); + make1from2.labelold = cell(n2,1); make1from2.labelnew = inputvol.sens.label; make1from2.tra = inputvol.sens.tra; for i=1:n2 - make1from2.labelorg{i} = sprintf('2to1_%d', i); + make1from2.labelold{i} = sprintf('2to1_%d', i); end % this is the montage that maps the computed electrode positions to the desired positions - make3from2.labelorg = make1from2.labelorg; % the computed electrodes - make3from2.labelnew = make4from3.labelorg; % the desired electrodes + make3from2.labelold = make1from2.labelold; % the computed electrodes + make3from2.labelnew = make4from3.labelold; % the desired electrodes make3from2.tra = tra; % the following should be read as a sequence of left-hand multiplications @@ -305,7 +305,7 @@ % or as make4from3 * make3from2 * inv(make1from2) make4from1.tra = make4from3.tra * make3from2.tra / make1from2.tra; - make4from1.labelorg = make1from2.labelnew; + make4from1.labelold = make1from2.labelnew; make4from1.labelnew = make4from3.labelnew; sens = ft_apply_montage(inputvol.sens, make4from1, 'keepunused', 'no'); diff --git a/external/fieldtrip/forward/ft_headmodel_localspheres.m b/external/fieldtrip/forward/ft_headmodel_localspheres.m index e00713a3..3bed7ba4 100644 --- a/external/fieldtrip/forward/ft_headmodel_localspheres.m +++ b/external/fieldtrip/forward/ft_headmodel_localspheres.m @@ -44,13 +44,12 @@ % $Id$ % get the additional inputs and set the defaults -unit = ft_getopt(varargin, 'unit'); feedback = ft_getopt(varargin, 'feedback', true); singlesphere = ft_getopt(varargin, 'singlesphere', 'no'); if any(strcmp(varargin(1:2:end), 'unit')) || any(strcmp(varargin(1:2:end), 'units')) % the geometrical units should be specified in the input mesh - error('the ''unit'' option is not supported any more'); + ft_error('the ''unit'' option is not supported any more'); end % convert from 'yes'/'no' string into boolean value @@ -69,20 +68,21 @@ mesh = fixpos(mesh); if ~isstruct(mesh) || ~isfield(mesh, 'pos') - error('the input mesh should be a set of points or a single triangulated surface') + ft_error('the input mesh should be a set of points or a single triangulated surface') end if isstruct(mesh) && numel(mesh)>1 - error('There must be only 1 mesh given as input'); + ft_error('There must be only 1 mesh given as input'); end % start with an empty volume conductor headmodel = []; % ensure that the mesh has units, estimate them if needed -mesh = ft_convert_units(mesh); +mesh = ft_determine_units(mesh); -% ensure that it has consistent units +% ensure that it has a consistent representation and consistent units +grad = ft_datatype_sens(grad); grad = ft_convert_units(grad, mesh.unit); % copy the geometrical units into the volume conductor @@ -134,40 +134,34 @@ headmodel.o = zeros(Nchan,3); % origin of every sphere headmodel.label = cell(Nchan,1); % corresponding gradiometer channel label for every sphere +allpos = grad.chanpos; +allori = grad.chanori; +if any(~isfinite(allpos(:))) + % probably the data has been backprojected from a component structure, + % use chanposold, if possible + if isfield(grad, 'chanposold') + allpos = grad.chanposold; + allori = grad.chanoriold; + else + ft_error('cannot extract channel position information from sensor description'); + end +end + for chan=1:Nchan - coilsel = find(grad.tra(chan,:)~=0); - allpos = grad.coilpos(coilsel, :); % position of all coils belonging to this channel - allori = grad.coilori(coilsel, :); % orientation of all coils belonging to this channel - + thispos = allpos(chan,:); + thisori = allori(chan,:); + if istrue(feedback) cla - plot3(grad.coilpos(:,1), grad.coilpos(:,2), grad.coilpos(:,3), 'b.'); % all coils - plot3( allpos(:,1), allpos(:,2), allpos(:,3), 'r*'); % this channel in red + plot3( allpos(:,1), allpos(:,2), allpos(:,3), 'b.'); % all channels + plot3(thispos(:,1), thispos(:,2), thispos(:,3), 'r*'); % this channel in red end - % determine the average position and orientation of this channel - thispos = mean(allpos,1); - [u, s, v] = svd(allori); - thisori = v(:,1)'; if dot(thispos,thisori)<0 % the orientation should be outwards pointing thisori = -thisori; end - - % compute the distance from every coil along this channels orientation - dist = zeros(size(coilsel)); - for i=1:length(coilsel) - dist(i) = dot((allpos(i,:)-thispos), thisori); - end - - [m, i] = min(dist); - % check whether the minimum difference is larger than a typical distance - if abs(m)>(baseline/4) - % replace the position of this channel by the coil that is the closest to the head (axial gradiometer) - % except when the center of the channel is approximately just as good (planar gradiometer) - thispos = allpos(i,:); - end - + % find the headshape points that are close to this channel dist = sqrt(sum((mesh-repmat(thispos,Nshape,1)).^2, 2)); shapesel = find(dist&1 > /dev/null\n']); - fprintf(efid,['om_minverser ./' hmfile ' ./' hminvfile ' 2>&1 > /dev/null\n']); + fprintf(efid,[prefix 'om_assemble -HM ./' geomfile ' ./' condfile ' ./' hmfile ' 2>&1 > /dev/null\n']); + fprintf(efid,[prefix 'om_minverser ./' hmfile ' ./' hminvfile ' 2>&1 > /dev/null\n']); else - fprintf(efid,['om_assemble -HM ./' geomfile ' ./' condfile ' ./' hmfile '\n']); - fprintf(efid,['om_minverser ./' hmfile ' ./' hminvfile '\n']); + fprintf(efid,[prefix 'om_assemble -HM ./' geomfile ' ./' condfile ' ./' hmfile '\n']); + fprintf(efid,[prefix 'om_minverser ./' hmfile ' ./' hminvfile '\n']); end fclose(efid); @@ -169,20 +168,20 @@ try % execute OpenMEEG and read the resulting file if ispc - dos([exefile]); + dos(exefile); else version = om_getgccversion; if version>3 dos(['./' exefile]); else - error('non suitable GCC compiler version (must be superior to gcc3)'); + ft_error('non suitable GCC compiler version (must be superior to gcc3)'); end end headmodel.mat = om_load_sym(hminvfile,'binary'); cleaner(headmodel,bndfile,condfile,geomfile,hmfile,hminvfile,exefile) cd(tmpfolder) catch - warning('an error ocurred while running OpenMEEG'); + ft_warning('an error ocurred while running OpenMEEG'); disp(lasterr); cleaner(headmodel,bndfile,condfile,geomfile,hmfile,hminvfile,exefile) cd(tmpfolder) @@ -221,11 +220,11 @@ function cleaner(headmodel,bndfile,condfile,geomfile,hmfile,hminvfile,exefile) if w<0 && (abs(w)-4*pi)<1000*eps ok = 0; - warning('your normals are outwards oriented\n') + ft_warning('your normals are outwards oriented\n') elseif w>0 && (abs(w)-4*pi)<1000*eps ok = 1; -% warning('your normals are inwards oriented') +% ft_warning('your normals are inwards oriented') else - error('your surface probably is irregular\n') + ft_error('your surface probably is irregular\n') ok = 0; end diff --git a/external/fieldtrip/forward/ft_headmodel_simbio.m b/external/fieldtrip/forward/ft_headmodel_simbio.m index 8fdbfffc..eb8b4366 100644 --- a/external/fieldtrip/forward/ft_headmodel_simbio.m +++ b/external/fieldtrip/forward/ft_headmodel_simbio.m @@ -48,7 +48,7 @@ if isfield(mesh,'pos') headmodel.pos = mesh.pos; else - error('Vertex field is required!') + ft_error('Vertex field is required!') end if isfield(mesh,'tet') @@ -56,23 +56,23 @@ elseif isfield(mesh,'hex') headmodel.hex = mesh.hex; else - error('Connectivity information is required!') + ft_error('Connectivity information is required!') end if isfield(mesh,'tissue') headmodel.tissue = mesh.tissue; else - error('No element indices declared!') + ft_error('No element indices declared!') end if isempty(conductivity) - error('No conductivity information!') + ft_error('No conductivity information!') end if length(conductivity) >= length(unique(headmodel.tissue)) headmodel.cond = conductivity; else - error('Wrong conductivity information!') + ft_error('Wrong conductivity information!') end if ~isfield(mesh,'tissuelabel') diff --git a/external/fieldtrip/forward/ft_headmodel_singleshell.m b/external/fieldtrip/forward/ft_headmodel_singleshell.m index d376629c..e9bb8441 100644 --- a/external/fieldtrip/forward/ft_headmodel_singleshell.m +++ b/external/fieldtrip/forward/ft_headmodel_singleshell.m @@ -53,7 +53,7 @@ mesh = fixpos(mesh); if ~isstruct(mesh) || ~isfield(mesh, 'pos') - error('the input mesh should be a set of points or a single triangulated surface') + ft_error('the input mesh should be a set of points or a single triangulated surface') end % represent the mesh in a headmodel strucure @@ -61,7 +61,5 @@ headmodel = []; headmodel.bnd = mesh; headmodel.type = 'singleshell'; -if ~isfield(headmodel, 'unit') - headmodel = ft_convert_units(headmodel); -end +headmodel = ft_determine_units(headmodel); diff --git a/external/fieldtrip/forward/ft_headmodel_singlesphere.m b/external/fieldtrip/forward/ft_headmodel_singlesphere.m index 584d2563..48468457 100644 --- a/external/fieldtrip/forward/ft_headmodel_singlesphere.m +++ b/external/fieldtrip/forward/ft_headmodel_singlesphere.m @@ -43,7 +43,7 @@ if any(strcmp(varargin(1:2:end), 'unit')) || any(strcmp(varargin(1:2:end), 'units')) % the geometrical units should be specified in the input mesh - error('the ''unit'' option is not supported any more'); + ft_error('the ''unit'' option is not supported any more'); end if isnumeric(mesh) && size(mesh,2)==3 @@ -59,22 +59,22 @@ mesh = fixpos(mesh); if ~isstruct(mesh) || ~isfield(mesh, 'pos') - error('the input mesh should be a set of points or a single triangulated surface') + ft_error('the input mesh should be a set of points or a single triangulated surface') end if numel(conductivity)~=1 - error('the conductivity should be a single number') + ft_error('the conductivity should be a single number') end if numel(mesh)~=1 - error('fitting a single sphere requires a single mesh') + ft_error('fitting a single sphere requires a single mesh') end % start with an empty volume conductor headmodel = []; % ensure that the mesh has units, estimate them if needed -mesh = ft_convert_units(mesh); +mesh = ft_determine_units(mesh); % copy the geometrical units into the volume conductor headmodel.unit = mesh.unit; diff --git a/external/fieldtrip/forward/ft_headmodel_slab.m b/external/fieldtrip/forward/ft_headmodel_slab.m index e08c52b3..d1651e39 100644 --- a/external/fieldtrip/forward/ft_headmodel_slab.m +++ b/external/fieldtrip/forward/ft_headmodel_slab.m @@ -44,7 +44,7 @@ cond = ft_getopt(varargin, 'conductivity'); if isempty(cond) - warning('Conductivity was not specified, using 1'); + ft_warning('Conductivity was not specified, using 1'); cond = 1; end @@ -62,7 +62,7 @@ pos1 = mesh1; pos2 = mesh2; else - error('incorrect specification of the geometry'); + ft_error('incorrect specification of the geometry'); end % fit a plane to the points @@ -91,7 +91,7 @@ if strcmpi(model,'monopole') headmodel.type = 'slab_monopole'; else - error('unknow method') + ft_error('unknow method') end function [N,P] = fit_plane(X) diff --git a/external/fieldtrip/forward/ft_inside_vol.m b/external/fieldtrip/forward/ft_inside_vol.m index 7cefd4cd..8e1f06bf 100644 --- a/external/fieldtrip/forward/ft_inside_vol.m +++ b/external/fieldtrip/forward/ft_inside_vol.m @@ -17,7 +17,7 @@ % grad = structure with gradiometer information, used for localspheres % headshape = structure with headshape, used for old CTF localspheres strategy -% Copyright (C) 2003-2013, Robert Oostenveld +% Copyright (C) 2003-2016, Robert Oostenveld % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -97,7 +97,7 @@ case {'halfspace', 'halfspace_monopole'} inside = false(1,size(dippos,1)); - for i = 1:size(dippos,1); + for i = 1:size(dippos,1) pol = dippos(i,:); % condition of dipoles/monopoles falling in the non conductive halfspace inside(i) = acos(dot(headmodel.ori,(pol-headmodel.pos)./norm(pol-headmodel.pos))) >= pi/2; @@ -105,7 +105,7 @@ case 'slab_monopole' inside = false(1,size(dippos,1)); - for i=1:size(dippos,1); + for i=1:size(dippos,1) pol = dippos(i,:); % condition of dipoles/monopoles falling in the non conductive halfspace % Attention: voxels on the boundary are automatically considered outside the strip @@ -120,54 +120,93 @@ inside = bounding_mesh(dippos, pos, tri); case {'simbio'} - - brain = false(size(headmodel.tissue)); - brain = brain | headmodel.tissue == find(strcmp(headmodel.tissuelabel, 'gray')); - brain = brain | headmodel.tissue == find(strcmp(headmodel.tissuelabel, 'white')); - brain = brain | headmodel.tissue == find(strcmp(headmodel.tissuelabel, 'csf')); - - minbrain = min(headmodel.pos(headmodel.hex(brain(:)), :), [], 1); - maxbrain = max(headmodel.pos(headmodel.hex(brain(:)), :), [], 1); - - mindippos = min(dippos, [], 1); - maxdippos = max(dippos, [], 1); - - % combine the two bounding boxes - minbox = max([minbrain; mindippos], [], 1); - maxbox = min([maxbrain; maxdippos], [], 1); - - % prune the mesh to the bounding box - discard1 = true(size(headmodel.hex,1),1); - discard2 = true(size(headmodel.hex,1),1); - for i=1:8 - discard1 = discard1 & any(bsxfun(@minus, headmodel.pos(headmodel.hex(:,i),:), minbox)<0,2); - discard2 = discard2 & any(bsxfun(@minus, headmodel.pos(headmodel.hex(:,i),:), maxbox)>0,2); + % this is a model with hexaheders or tetraheders + if isfield(headmodel, 'tet') + % the subsequent code works both for tetraheders or hexaheders, but assumes the volume elements to be called "hex" + headmodel.hex = headmodel.tet; + headmodel = rmfield(headmodel, 'tet'); end - discard = discard1 | discard2; - - fprintf('pruning mesh from %d to %d elements (%d%%)\n', length(discard), sum(discard), round(100*sum(discard)/length(discard))); - headmodel.hex = headmodel.hex(~discard,:); - headmodel.tissue = headmodel.tissue(~discard); + % determine the size of the relevant elements + numhex = size(headmodel.hex,1); + numpos = size(headmodel.pos,1); + numdip = size(dippos,1); - % determine the center of each volume element - elementpos = zeros(size(headmodel.hex,1),3); - for i=1:8 - elementpos = elementpos + headmodel.pos(headmodel.hex(:,i),:); + % FIXME we have to rethink which tissue types should be flagged as inside + tissue = intersect({'gray', 'white', 'csf', 'brain'}, headmodel.tissuelabel); + + % determine all hexaheders that are labeled as brain + insidehex = false(size(headmodel.tissue)); + for i=1:numel(tissue) + fprintf('selecting dipole positions inside the ''%s'' tissue\n', tissue{i}); + insidehex = insidehex | (headmodel.tissue == find(strcmp(headmodel.tissuelabel, tissue{i}))); end - elementpos = elementpos/8; + % prune the mesh, i.e. only retain hexaheders labeled as brain + fprintf('pruning headmodel volume elements from %d to %d (%d%%)\n', numhex, sum(insidehex), round(100*sum(insidehex)/numhex)); + headmodel.hex = headmodel.hex(insidehex,:); + headmodel.tissue = headmodel.tissue(insidehex); + numhex = sum(insidehex); + clear insidehex + + % determine all vertices that are part of a hexaheder + insidepos = false(numpos,1); + insidepos(headmodel.hex) = true; + + % prune the mesh, i.e. only retain vertices that are part of a hexaheder + fprintf('pruning headmodel vertices from %d to %d (%d%%)\n', numpos, sum(insidepos), round(100*sum(insidepos)/numpos)); + headmodel.pos = headmodel.pos(insidepos,:); + numpos = sum(insidepos); + renumber = zeros(size(insidepos)); + renumber(insidepos) = 1:numpos; % determine the mapping from original to pruned vertex indices + headmodel.hex = renumber(headmodel.hex); % renumber the vertex indices + clear insidepos renumber + + % construct a sparse matrix with the mapping between all hexaheders and vertices + i = repmat(transpose(1:numhex), 1, 8); + j = headmodel.hex; + s = ones(size(i)); + hex2pos = sparse(i(:),j(:),s(:),numhex,numpos); + + % determine the bounding box + minpos = min(headmodel.pos,[],1); + maxpos = max(headmodel.pos,[],1); + insidedip = all(bsxfun(@ge, dippos, minpos),2) & all(bsxfun(@le, dippos, maxpos),2); + fprintf('pruning dipole positions from %d to %d (%d%%)\n', numdip, sum(insidedip), round(100*sum(insidedip)/numdip)); + insidedip = find( insidedip); + dippos = dippos(insidedip,:); + + % find the nearest vertex for each of the dipoles + dsearchn(headmodel.pos, dippos(1,:)); % call it once to precompile stopwatch = tic; - k = dsearchn(elementpos, dippos(1,:)); + dsearchn(headmodel.pos, dippos(1,:)); % call it once to estimate the time t = toc(stopwatch); - fprintf('determining inside points, this takes about %d seconds\n', round(size(dippos,1)*t)); - k = dsearchn(elementpos, dippos); - - % select the source positions that are inside the brain - inside = brain(k); + fprintf('determining inside points, this takes about %d seconds\n', round(numdip*t)); + posindx = dsearchn(headmodel.pos, dippos); + + % The following code is only guaranteed to work with convex elements. Regular + % hexahedra and tetrahedra are convex, and the adapted hexahedra we can use with + % SIMBIO have to be convex as well. + + inside = false(1, numdip); + % for each dipole determine whether it is inside one of the neighbouring hexaheders + % this will be the case for all vertices that are inside the middle, but not at the edges + for i=1:numel(insidedip) + hexindx = find(hex2pos(:,posindx(i))); + for j=1:numel(hexindx) + posx = headmodel.pos(headmodel.hex(hexindx(j),:),1); + posy = headmodel.pos(headmodel.hex(hexindx(j),:),2); + posz = headmodel.pos(headmodel.hex(hexindx(j),:),3); + pos = [posx posy posz]; + if isequal(convhull(pos), convhull([pos; dippos(i,:)])) + inside(insidedip(i)) = true; + break % out of the for-loop + end % if + end % for each hexaheder + end % for each of the dipole positions otherwise - error('unrecognized volume conductor model'); + ft_error('unrecognized volume conductor model'); end % ensure that it is a boolean column vector diff --git a/external/fieldtrip/forward/ft_prepare_vol_sens.m b/external/fieldtrip/forward/ft_prepare_vol_sens.m index ea8f1c32..3976a994 100644 --- a/external/fieldtrip/forward/ft_prepare_vol_sens.m +++ b/external/fieldtrip/forward/ft_prepare_vol_sens.m @@ -115,15 +115,15 @@ headmodel.type = ft_voltype(headmodel); if isfield(headmodel, 'unit') && isfield(sens, 'unit') && ~strcmp(headmodel.unit, sens.unit) - error('inconsistency in the units of the volume conductor and the sensor array'); + ft_error('inconsistency in the units of the volume conductor and the sensor array'); end if ismeg && iseeg % this is something that could be implemented relatively easily - error('simultaneous EEG and MEG not yet supported'); + ft_error('simultaneous EEG and MEG not yet supported'); elseif ~ismeg && ~iseeg - error('the input does not look like EEG, nor like MEG'); + ft_error('the input does not look like EEG, nor like MEG'); elseif ismeg @@ -132,7 +132,7 @@ Nchans = length(sens.label); Ncoils = size(sens.coilpos,1); if Nchans~=Ncoils - error('inconsistent number of channels and coils'); + ft_error('inconsistent number of channels and coils'); end sens.tra = eye(Nchans, Ncoils); end @@ -193,7 +193,7 @@ elseif size(headmodel.r,1)==size(sens.coilpos,1) && isfield(headmodel, 'label') if ~isequal(headmodel.label(:), sens.label(:)) % if only the order is different, it would be possible to reorder them - error('the coils in the volume conduction model do not correspond to the sensor array'); + ft_error('the coils in the volume conduction model do not correspond to the sensor array'); else % the coil-specific spheres in the volume conductor should not have a label % because the label is already specified for the coils in the @@ -221,7 +221,7 @@ % and use the globally fitted single sphere for those missing = setdiff(sens.label, headmodel.label); if ~isempty(missing) - warning('using the global fitted single sphere for %d channels that do not have a local sphere', length(missing)); + ft_warning('using the global fitted single sphere for %d channels that do not have a local sphere', length(missing)); end for i=1:length(missing) headmodel.label(end+1) = missing(i); @@ -295,15 +295,15 @@ end case 'openmeeg' - if isfield(headmodel,'mat') & ~isempty(headmodel.mat) - warning('MEG with openmeeg only supported with NEMO lab pipeline. Please omit the mat matrix from the headmodel structure.'); + if isfield(headmodel,'mat') && ~isempty(headmodel.mat) + ft_warning('MEG with openmeeg only supported with NEMO lab pipeline. Please omit the mat matrix from the headmodel structure.'); end case 'simbio' - error('MEG not yet supported with simbio'); + ft_error('MEG not yet supported with simbio'); otherwise - error('unsupported volume conductor model for MEG'); + ft_error('unsupported volume conductor model for MEG'); end elseif iseeg @@ -318,8 +318,8 @@ Nchans = length(sens.label); sens.label = sens.label(selsens); - try, sens.chantype = sens.chantype(selsens); end; - try, sens.chanunit = sens.chanunit(selsens); end; + try, sens.chantype = sens.chantype(selsens); end + try, sens.chanunit = sens.chanunit(selsens); end if isfield(sens, 'tra') % first only modify the linear combination of electrodes into channels @@ -353,7 +353,7 @@ if is_in_empty dPplane = abs(dot(headmodel.ori, headmodel.pos-P, 2)); if dPplane>md - error('Some electrodes are too distant from the plane: consider repositioning them') + ft_error('Some electrodes are too distant from the plane: consider repositioning them') else % project point on plane Ppr = pointproj(P,[headmodel.pos headmodel.ori]); @@ -382,7 +382,7 @@ dPplane1 = abs(dot(headmodel.ori1, headmodel.pos1-P, 2)); dPplane2 = abs(dot(headmodel.ori2, headmodel.pos2-P, 2)); if dPplane1>md && dPplane2>md - error('Some electrodes are too distant from the planes: consider repositioning them') + ft_error('Some electrodes are too distant from the planes: consider repositioning them') elseif dPplane2>dPplane1 % project point on nearest plane Ppr = pointproj(P,[headmodel.pos1 headmodel.ori1]); @@ -408,7 +408,7 @@ end distance = sqrt(sum(pos.^2,2)); % to the center of the sphere if any((abs(distance-radius)/radius)>0.005) - warning('electrodes do not lie on skin surface -> using radial projection') + ft_warning('electrodes do not lie on skin surface -> using radial projection') end pos = pos * radius ./ [distance distance distance]; if isfield(headmodel, 'o') @@ -539,7 +539,7 @@ end otherwise - error('unsupported volume conductor model for EEG'); + ft_error('unsupported volume conductor model for EEG'); end % FIXME this needs careful thought to ensure that the average referencing which is now done here and there, and that the linear interpolation in case of BEM are all dealt with consistently @@ -560,7 +560,7 @@ if isfield(sens, 'tra') if issparse(sens.tra) && size(sens.tra, 1)==1 % this multiplication would result in a sparse leadfield, which is not what we want - % the effect can be demonstrated as sparse(1)*rand(1,10), see also http://bugzilla.fcdonders.nl/show_bug.cgi?id=1169#c7 + % the effect can be demonstrated as sparse(1)*rand(1,10), see also http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=1169#c7 sens.tra = full(sens.tra); elseif ~issparse(sens.tra) && size(sens.tra, 1)>1 % the multiplication of the "sensor" leadfield (electrode or coil) with the tra matrix to get the "channel" leadfield diff --git a/external/fieldtrip/forward/ft_senslabel.m b/external/fieldtrip/forward/ft_senslabel.m index 4ab57989..85e062af 100644 --- a/external/fieldtrip/forward/ft_senslabel.m +++ b/external/fieldtrip/forward/ft_senslabel.m @@ -87,7 +87,7 @@ output = ft_getopt(varargin, 'output', 'normal'); % 'normal' or 'planarcombined' if ~exist(type, 'var') - error('the requested sensor type "%s" is not supported', type); + ft_error('the requested sensor type "%s" is not supported', type); elseif isempty(eval(type)) % assign the list of channels only once, keep it as persistent variable @@ -3673,7 +3673,7 @@ label = ft_senslabel(type); otherwise - error('the requested sensor type "%s" is not supported', type); + ft_error('the requested sensor type "%s" is not supported', type); end % switch @@ -3700,6 +3700,6 @@ label = [planar(:,1:2) combined]; % magnetometers are in the 3rd column for neuromag306 otherwise - error('unsupported output "%s"', output); + ft_error('unsupported output "%s"', output); end diff --git a/external/fieldtrip/forward/ft_senstype.m b/external/fieldtrip/forward/ft_senstype.m index 1d91722d..b6753338 100644 --- a/external/fieldtrip/forward/ft_senstype.m +++ b/external/fieldtrip/forward/ft_senstype.m @@ -43,18 +43,27 @@ % 'biosemi64' % 'biosemi128' % 'biosemi256' +% 'ant128' % 'neuralynx' % 'plexon' % 'artinis' -% 'ext1020' this includes eeg1020, eeg1010 and eeg1005 -% 'eeg' this was called 'electrode' in older versions -% 'meg' this was called 'magnetometer' in older versions % 'nirs' +% 'meg' +% 'eeg' +% 'ieeg' +% 'seeg' +% 'ecog' +% 'eeg1020' +% 'eeg1010' +% 'eeg1005' +% 'ext1020' in case it is a small subset of eeg1020, eeg1010 or eeg1005 % % The optional input argument for the desired type can be any of the above, or any of % the following generic classes of acquisition systems % 'eeg' +% 'ieeg' % 'ext1020' +% 'ant' % 'biosemi' % 'egi' % 'meg' @@ -81,7 +90,7 @@ % % See also FT_SENSLABEL, FT_CHANTYPE, FT_READ_SENS, FT_COMPUTE_LEADFIELD, FT_DATATYPE_SENS -% Copyright (C) 2007-2016, Robert Oostenveld +% Copyright (C) 2007-2017, Robert Oostenveld % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -146,7 +155,8 @@ iselec = (isa(input, 'struct') && isfield(input, 'label') && isfield(input, 'elecpos')) || iselec; % new style isnirs = isa(input, 'struct') && isfield(input, 'label') && isfield(input, 'transceiver'); islabel = isa(input, 'cell') && ~isempty(input) && isa(input{1}, 'char'); -haslabel = isa(input, 'struct') && isfield(input, 'label'); +haslabel = isa(input, 'struct') && isfield(input, 'label'); +haschantype = isa(input, 'struct') && isfield(input, 'chantype'); if ~(isdata || isheader || isgrad || iselec || isnirs || islabel || haslabel) && isfield(input, 'hdr') input = input.hdr; @@ -211,8 +221,8 @@ elseif haslabel % it does not resemble anything that we had expected at this location, but it does have channel labels % the channel labels can be used to determine the type of sensor array - sens.label = input.label; - islabel = true; + sens = keepfields(input, {'label' 'chantype'}); + islabel = true; else sens = []; @@ -265,21 +275,18 @@ % start with unknown, then try to determine the proper type by looking at the labels type = 'unknown'; - if isgrad && isfield(sens, 'type') - type = sens.type; - - elseif isgrad + if isgrad % this looks like MEG + % revert the component balancing that was previously applied if isfield(sens, 'balance') && strcmp(sens.balance.current, 'comp') sens = undobalancing(sens); end - % determine the type of magnetometer/gradiometer system based on the channel names alone + % determine the particular type of acquisition system based on the channel names alone % this uses a recursive call to the "islabel" section further down type = ft_senstype(sens.label); - %sens_temp.type = type; - if strcmp(type, 'unknown') %|| ~ft_senstype(sens_temp,'meg') + if strcmp(type, 'unknown') % although we don't know the type, we do know that it is MEG type = 'meg'; end @@ -287,24 +294,33 @@ elseif iselec % this looks like EEG - % determine the type of eeg/acquisition system based on the channel names alone + % determine the particular type of acquisition system based on the channel names alone % this uses a recursive call to the "islabel" section further down type = ft_senstype(sens.label); - %sens_temp.type = type; - if strcmp(type, 'unknown') %|| ~ft_senstype(sens_temp,'eeg') - % although we don't know the type, we do know that it is EEG - type = 'eeg'; + if strcmp(type, 'unknown') + % although we don't know the type, we do know that it is EEG, IEEG, SEEG, or ECOG + if haschantype && all(strcmp(sens.chantype, 'eeg')) + type = 'eeg'; + elseif haschantype && all(strcmp(sens.chantype, 'seeg')) + type = 'seeg'; + elseif haschantype && all(strcmp(sens.chantype, 'ecog')) + type = 'ecog'; + elseif haschantype && all(ismember(sens.chantype, {'ieeg' 'seeg' 'ecog'})) + type = 'ieeg'; + else + % fall back to the most generic description + type = 'eeg'; + end end elseif isnirs % this looks like NIRS - % determine the type of eeg/acquisition system based on the channel names alone + % determine the particular type of acquisition system based on the channel names alone % this uses a recursive call to the "islabel" section further down type = ft_senstype(sens.label); - %sens_temp.type = type; - if strcmp(type, 'unknown') %|| ~ft_senstype(sens_temp,'eeg') - % although we don't know the type, we do know that it is EEG + if strcmp(type, 'unknown') + % although we don't know the type, we do know that it is NIRS type = 'nirs'; end @@ -382,7 +398,7 @@ elseif (mean(ismember(ft_senslabel('egi32'), sens.label)) > 0.8) type = 'egi32'; - % the following check on the fraction of channels in the user's data rather than on the fraction of channels in the predefined set + % the following check looks at the fraction of channels in the user's data rather than the fraction in the predefined set elseif (mean(ismember(sens.label, ft_senslabel('eeg1020'))) > 0.8) type = 'eeg1020'; elseif (mean(ismember(sens.label, ft_senslabel('eeg1010'))) > 0.8) @@ -390,12 +406,14 @@ elseif (mean(ismember(sens.label, ft_senslabel('eeg1005'))) > 0.8) type = 'eeg1005'; - elseif (sum(ismember(sens.label, ft_senslabel('eeg1005'))) > 10) % Otherwise it's not even worth recognizing + % the following check looks at the fraction of channels in the user's data rather than the fraction in the predefined set + % there is a minumum number of channels, otherwise it is not worth recognizing + elseif (sum(ismember(sens.label, ft_senslabel('eeg1005'))) > 10) type = 'ext1020'; % this will also cover small subsets of eeg1020, eeg1010 and eeg1005 - elseif any(ismember(ft_senslabel('btiref'), sens.label)) - type = 'bti'; % it might be 148 or 248 channels - elseif any(ismember(ft_senslabel('ctfref'), sens.label)) - type = 'ctf'; % it might be 151 or 275 channels + elseif (sum(ismember(ft_senslabel('btiref'), sens.label)) > 10) + type = 'bti'; % 23 in the reference set, it might be 148 or 248 channels + elseif (sum(ismember(ft_senslabel('ctfref'), sens.label)) > 10) + type = 'ctf'; % 29 in the reference set, it might be 151 or 275 channels end end % look at label, ori and/or pos @@ -432,26 +450,30 @@ if ~isempty(desired) % return a boolean flag switch desired + case {'eeg'} + type = any(strcmp(type, {'eeg' 'ieeg' 'seeg' 'ecog' 'ant128' 'biosemi64' 'biosemi128' 'biosemi256' 'egi32' 'egi64' 'egi128' 'egi256' 'ext1020' 'eeg1005' 'eeg1010' 'eeg1020'})); case 'ext1020' - type = any(strcmp(type, {'eeg1005' 'eeg1010' 'eeg1020' 'ext1020'})); - case {'eeg' 'electrode'} - type = any(strcmp(type, {'eeg' 'electrode' 'ant128' 'biosemi64' 'biosemi128' 'biosemi256' 'egi32' 'egi64' 'egi128' 'egi256' 'eeg1005' 'eeg1010' 'eeg1020' 'ext1020'})); + type = any(strcmp(type, {'ext1020' 'eeg1005' 'eeg1010' 'eeg1020'})); + case {'ieeg'} + type = any(strcmp(type, {'ieeg' 'seeg' 'ecog'})); + case 'ant' + type = any(strcmp(type, {'ant' 'ant128'})); case 'biosemi' - type = any(strcmp(type, {'biosemi64' 'biosemi128' 'biosemi256'})); + type = any(strcmp(type, {'biosemi' 'biosemi64' 'biosemi128' 'biosemi256'})); case 'egi' - type = any(strcmp(type, {'egi32' 'egi64' 'egi128' 'egi256'})); + type = any(strcmp(type, {'egi' 'egi32' 'egi64' 'egi128' 'egi256'})); case 'meg' - type = any(strcmp(type, {'meg' 'magnetometer' 'ctf' 'bti' 'ctf64' 'ctf151' 'ctf275' 'ctf151_planar' 'ctf275_planar' 'neuromag122' 'neuromag306' 'neuromag306_combined' 'bti148' 'bti148_planar' 'bti248' 'bti248_planar' 'bti248grad' 'bti248grad_planar' 'yokogawa9' 'yokogawa160' 'yokogawa160_planar' 'yokogawa64' 'yokogawa64_planar' 'yokogawa440' 'itab' 'itab28' 'itab153' 'itab153_planar'})); + type = any(strcmp(type, {'meg' 'ctf' 'ctf64' 'ctf151' 'ctf275' 'ctf151_planar' 'ctf275_planar' 'neuromag' 'neuromag122' 'neuromag306' 'neuromag306_combined' 'bti' 'bti148' 'bti148_planar' 'bti248' 'bti248_planar' 'bti248grad' 'bti248grad_planar' 'yokogawa' 'yokogawa9' 'yokogawa160' 'yokogawa160_planar' 'yokogawa64' 'yokogawa64_planar' 'yokogawa440' 'itab' 'itab28' 'itab153' 'itab153_planar' 'babysquid' 'babysquid74' 'artenis123' 'magview'})); case 'ctf' type = any(strcmp(type, {'ctf' 'ctf64' 'ctf151' 'ctf275' 'ctf151_planar' 'ctf275_planar'})); case 'bti' type = any(strcmp(type, {'bti' 'bti148' 'bti148_planar' 'bti248' 'bti248_planar' 'bti248grad' 'bti248grad_planar'})); case 'neuromag' - type = any(strcmp(type, {'neuromag122' 'neuromag306'})); + type = any(strcmp(type, {'neuromag' 'neuromag122' 'neuromag306'})); case 'babysquid' - type = any(strcmp(type, {'babysquid74' 'artenis123' 'magview'})); + type = any(strcmp(type, {'babysquid' 'babysquid74' 'artenis123' 'magview'})); case 'yokogawa' - type = any(strcmp(type, {'yokogawa160' 'yokogawa160_planar' 'yokogawa64' 'yokogawa64_planar' 'yokogawa440'})); + type = any(strcmp(type, {'yokogawa' 'yokogawa160' 'yokogawa160_planar' 'yokogawa64' 'yokogawa64_planar' 'yokogawa440'})); case 'itab' type = any(strcmp(type, {'itab' 'itab28' 'itab153' 'itab153_planar'})); case 'meg_axial' diff --git a/external/fieldtrip/forward/ft_sourcedepth.m b/external/fieldtrip/forward/ft_sourcedepth.m index 8eb17ab3..254c76ef 100644 --- a/external/fieldtrip/forward/ft_sourcedepth.m +++ b/external/fieldtrip/forward/ft_sourcedepth.m @@ -87,6 +87,6 @@ % unsupported volume conductor model otherwise - error('upsupported volume conductor model'); + ft_error('upsupported volume conductor model'); end diff --git a/external/fieldtrip/forward/ft_transform_headshape.m b/external/fieldtrip/forward/ft_transform_headshape.m index 84bcc361..00331234 100644 --- a/external/fieldtrip/forward/ft_transform_headshape.m +++ b/external/fieldtrip/forward/ft_transform_headshape.m @@ -6,7 +6,7 @@ % Use as % shape = ft_transform_headshape(transform, shape) % -% See also FT_READ_HEADSHAPE +% See also FT_READ_HEADSHAPE, FT_TRANSFORM_GEOMETRY % Copyright (C) 2008, Robert Oostenveld % diff --git a/external/fieldtrip/forward/ft_transform_sens.m b/external/fieldtrip/forward/ft_transform_sens.m index 9a311652..f8037617 100644 --- a/external/fieldtrip/forward/ft_transform_sens.m +++ b/external/fieldtrip/forward/ft_transform_sens.m @@ -8,7 +8,7 @@ % Use as % sens = ft_transform_sens(transform, sens) % -% See also FT_READ_SENS, FT_PREPARE_VOL_SENS, FT_COMPUTE_LEADFIELD +% See also FT_READ_SENS, FT_PREPARE_VOL_SENS, FT_COMPUTE_LEADFIELD, FT_TRANSFORM_GEOMETRY % Copyright (C) 2008-2011, Robert Oostenveld % diff --git a/external/fieldtrip/forward/ft_transform_vol.m b/external/fieldtrip/forward/ft_transform_vol.m index 00481738..e52e5ea6 100644 --- a/external/fieldtrip/forward/ft_transform_vol.m +++ b/external/fieldtrip/forward/ft_transform_vol.m @@ -8,7 +8,7 @@ % Use as % headmodel = ft_transform_vol(transform, headmodel) % -% See also FT_READ_VOL, FT_PREPARE_VOL_SENS, FT_COMPUTE_LEADFIELD +% See also FT_READ_VOL, FT_PREPARE_VOL_SENS, FT_COMPUTE_LEADFIELD, FT_TRANSFORM_GEOMETRY % Copyright (C) 2008, Robert Oostenveld % diff --git a/external/fieldtrip/forward/private/bounding_mesh.m b/external/fieldtrip/forward/private/bounding_mesh.m index e0e2bb95..22b9c25c 100644 --- a/external/fieldtrip/forward/private/bounding_mesh.m +++ b/external/fieldtrip/forward/private/bounding_mesh.m @@ -30,12 +30,11 @@ % You should have received a copy of the GNU General Public License % along with FieldTrip. If not, see . % -% $Id$ % this can be used for printing detailled user feedback fb = false; -% this is a work-around for http://bugzilla.fcdonders.nl/show_bug.cgi?id=2369 +% this is a work-around for http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2369 pos = double(pos); pnt = double(pnt); tri = double(tri); diff --git a/external/fieldtrip/forward/private/channelposition.m b/external/fieldtrip/forward/private/channelposition.m index 25f8db11..1eecb56a 100644 --- a/external/fieldtrip/forward/private/channelposition.m +++ b/external/fieldtrip/forward/private/channelposition.m @@ -110,7 +110,7 @@ dist(selrest,sum(~isinf(dist(selmode,:)))>0) = inf; numcoils = sum(isfinite(dist),2); if niter>500 - error('Failed to extract the positions of the channels. This is most likely due to the balancing matrix being rank deficient. Please replace data.grad with the original grad-structure obtained after reading the header.'); + ft_error('Failed to extract the positions of the channels. This is most likely due to the balancing matrix being rank deficient. Please replace data.grad with the original grad-structure obtained after reading the header.'); end end else @@ -332,5 +332,5 @@ % do a sanity check on the number of positions nchan = numel(sens.label); if length(lab)~=nchan || size(pnt,1)~=nchan || size(ori,1)~=nchan - warning('the positions were not determined for all channels'); + ft_warning('the positions were not determined for all channels'); end diff --git a/external/fieldtrip/forward/private/defaultId.m b/external/fieldtrip/forward/private/defaultId.m new file mode 100644 index 00000000..f4e1ee99 --- /dev/null +++ b/external/fieldtrip/forward/private/defaultId.m @@ -0,0 +1,57 @@ +function id = defaultId + +% DEFAULTID returns a string that can serve as warning or error identifier, +% for example 'FieldTip:ft_read_header:line345'. +% +% See also WARNING, ERROR, FT_NOTICE, FT_INFO, FT_DEBUG + +% Copyright (C) 2017, Robert Oostenveld +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +stack = dbstack('-completenames'); + +% remove the functions that pertain to the notification system itself +keep = true(size(stack)); +keep(strcmp({stack.name}, 'defaultId')) = false; % this function itself +keep(strcmp({stack.name}, 'ft_notification')) = false; % this one is doing the work underneath ft_error/ft_warning/ft_notice/etc. +keep(strcmp({stack.name}, 'ft_error')) = false; +keep(strcmp({stack.name}, 'ft_warning')) = false; +keep(strcmp({stack.name}, 'ft_notice')) = false; +keep(strcmp({stack.name}, 'ft_info')) = false; +keep(strcmp({stack.name}, 'ft_debug')) = false; +stack = stack(keep); + +% remove the non-FieldTrip functions from the path, these should not be part of the default message identifier +keep = true(size(stack)); +[v, p] = ft_version; +for i=1:numel(stack) + keep(i) = strncmp(p, stack(i).file, length(p)); +end +stack = stack(keep); + +if ~isempty(stack) + % it is called from within a function + stack = flipud(stack); + name = {stack.name}; + id = ['FieldTrip' sprintf(':%s', name{:}) ':line' num2str(stack(end).line)]; +else + % it is called from the command line + id = 'FieldTrip:commandline'; +end diff --git a/external/fieldtrip/forward/private/eeg_halfspace_medium_leadfield.m b/external/fieldtrip/forward/private/eeg_halfspace_medium_leadfield.m index ce980901..be79ce37 100644 --- a/external/fieldtrip/forward/private/eeg_halfspace_medium_leadfield.m +++ b/external/fieldtrip/forward/private/eeg_halfspace_medium_leadfield.m @@ -38,7 +38,7 @@ rd = rd'; rd = rd(:)'; % ensure that it is a row vector else - error('incorrect specification of dipole locations'); + ft_error('incorrect specification of dipole locations'); end Nelc = size(elc,1); @@ -67,10 +67,10 @@ invacuum = acos(dot(vol.ori,(dip1-vol.pnt)./norm(dip1-vol.pnt))) < pi/2; if invacuum - warning('dipole lies on the vacuum side of the plane'); + ft_warning('dipole lies on the vacuum side of the plane'); lf(:,(1:3) + 3*(i-1)) = NaN(Nelc,3); elseif any(R1)==0 - warning('dipole coincides with one of the electrodes'); + ft_warning('dipole coincides with one of the electrodes'); lf(:,(1:3) + 3*(i-1)) = NaN(Nelc,3); else lf(:,(1:3) + 3*(i-1)) = (r1 ./ [R1 R1 R1]) + (r2 ./ [R2 R2 R2]); @@ -87,7 +87,7 @@ ori = vol.ori; % already normalized if abs(dot(P1-pnt,ori))vol.r*0.005) - warning('electrodes do not ly on sphere surface -> using projection') + ft_warning('electrodes do not ly on sphere surface -> using projection') end elc = vol.r * elc ./ [dist dist dist]; % check whether the dipole is inside the brain [disabled for EEGLAB] % if sqrt(sum(R.^2))>=vol.r -% error('dipole is outside the brain compartment'); +% ft_error('dipole is outside the brain compartment'); % end c0 = norm(R); diff --git a/external/fieldtrip/forward/private/eeg_leadfield4.m b/external/fieldtrip/forward/private/eeg_leadfield4.m index 8254caa6..0962afdd 100644 --- a/external/fieldtrip/forward/private/eeg_leadfield4.m +++ b/external/fieldtrip/forward/private/eeg_leadfield4.m @@ -55,18 +55,18 @@ % check whether the electrode ly on the sphere, allowing 0.5% tolerance dist = sqrt(sum(elc.^2,2)); if any(abs(dist-r4)>r4*0.005) - warning('electrodes do not ly on sphere surface -> using projection') + ft_warning('electrodes do not ly on sphere surface -> using projection') end elc = r4 * elc ./ [dist dist dist]; % check whether the dipole is inside the brain [disabled for EEGLAB] % if sqrt(sum(R.^2))>=r1 -% error('dipole is outside the brain compartment'); +% ft_error('dipole is outside the brain compartment'); % end % rotate everything so that the dipole is along the pos. z-axis % only if the dipole is not in the origin or along the positive z-axis -if R(1)~=0 | R(2)~=0 +if R(1)~=0 || R(2)~=0 % compute the rotation matrix % the inverse rotation matrix is the transposed of this one val1 = norm(R); @@ -81,9 +81,8 @@ % rotate the electrodes elc = elc*rot'; elseif R(1)==0 && R(2)==0 && R(3)<0 - % dipole on negative z-axis, rotation is very simple: around x-axis - elc(2,:) = -elc(2,:); - elc(3,:) = -elc(3,:); + % dipole on negative z-axis, this case is very simple: reflect on xy-plane + elc(:,3) = -elc(:,3); else % dipole is on positive z-axis, nothing has to be done end @@ -136,7 +135,6 @@ if R(1)~=0 || R(2)~=0 lf = lf*rot; elseif R(1)==0 && R(2)==0 && R(3)<0 - lf(2,:) = -lf(2,:); - lf(3,:) = -lf(3,:); + lf(:,3) = -lf(:,3); end diff --git a/external/fieldtrip/forward/private/eeg_leadfieldb.m b/external/fieldtrip/forward/private/eeg_leadfieldb.m index 198b7f5e..cc1aa9da 100644 --- a/external/fieldtrip/forward/private/eeg_leadfieldb.m +++ b/external/fieldtrip/forward/private/eeg_leadfieldb.m @@ -41,15 +41,15 @@ % do some sanity checks if ~isfield(vol, 'bnd') - error('there are no compartment boundaries present'); + ft_error('there are no compartment boundaries present'); end if length(vol.bnd)~=length(vol.cond) - error('the number of compartments in the volume is inconsistent'); + ft_error('the number of compartments in the volume is inconsistent'); end if ~isfield(vol, 'mat') - error('there is no system matrix present'); + ft_error('there is no system matrix present'); end % determine the number of compartments @@ -73,7 +73,7 @@ elseif strcmp(ft_voltype(vol), 'openmeeg') % this is handled differently, although at the moment I don't know why else - error('unexpected size of system matrix') + ft_error('unexpected size of system matrix') end % determine the conductivity of the source compartment @@ -114,7 +114,7 @@ lf = cat(1, lf{:}); otherwise - error('unsupported type of volume conductor (%s)\n', ft_voltype(vol)); + ft_error('unsupported type of volume conductor (%s)\n', ft_voltype(vol)); end % switch ft_voltype if isfield(vol, 'mat') && ~ft_voltype(vol, 'openmeeg') diff --git a/external/fieldtrip/forward/private/eeg_slab_monopole.m b/external/fieldtrip/forward/private/eeg_slab_monopole.m index 9a6dcb20..b0f71f18 100644 --- a/external/fieldtrip/forward/private/eeg_slab_monopole.m +++ b/external/fieldtrip/forward/private/eeg_slab_monopole.m @@ -41,7 +41,7 @@ rd = rd'; rd = rd(:)'; % ensure that it is a row vector else - error('incorrect specification of pole locations'); + ft_error('incorrect specification of pole locations'); end Nelc = size(elc,1); @@ -78,10 +78,10 @@ invacuum = ~(instrip1&instrip2); if invacuum - warning('a pole lies on the vacuum side of the plane'); + ft_warning('a pole lies on the vacuum side of the plane'); lf(:,i) = NaN(Nelc,1); elseif any(R1)==0 - warning('a pole coincides with one of the electrodes'); + ft_warning('a pole coincides with one of the electrodes'); lf(:,i) = NaN(Nelc,1); else lf(:,i) = (1 ./ R1) + (1 ./ R2) + (1 ./ R3);% + (1 ./ R4); @@ -101,7 +101,7 @@ ori2 = vol.ori2; if abs(dot(P1-pnt1,ori1))3 - error(sprintf('more than three neighbours found for triangle %d', i)); + ft_error('more than three neighbours found for triangle %d', i); else for j=1:length(sel) if isempty(setdiff(intersect(tri(i,:), tri(sel(j),:)), tri(i,[1 2]))) diff --git a/external/fieldtrip/forward/private/fitsphere.m b/external/fieldtrip/forward/private/fitsphere.m index e19841cc..e0881de1 100644 --- a/external/fieldtrip/forward/private/fitsphere.m +++ b/external/fieldtrip/forward/private/fitsphere.m @@ -72,7 +72,7 @@ end if isempty(pvec) - warning('was not able to fit a sphere to the surface points'); + ft_warning('was not able to fit a sphere to the surface points'); C = [NaN NaN NaN]; R = Inf; else diff --git a/external/fieldtrip/forward/private/fixname.m b/external/fieldtrip/forward/private/fixname.m index 96a345ec..76fd5951 100644 --- a/external/fieldtrip/forward/private/fixname.m +++ b/external/fieldtrip/forward/private/fixname.m @@ -1,19 +1,20 @@ -function str = fixname(str) +function str = fixname(str, version) % FIXNAME changes all inappropriate characters in a sting into '_' -% such that it can be used as a filename or as a structure field name. If -% the string begins with a numeric digit, an 'x' is prepended. +% so that it can be used as a filename or as a field name in a structure. +% If the string begins with a digit, an 'x' is prepended. % % Use as % str = fixname(str) % % MATLAB 2014a introduces the matlab.lang.makeValidName and -% matlab.lang.makeUniqueStrings functions for constructing unique MATLAB identifiers, -% but this particular implementation also works with older MATLAB versions. +% matlab.lang.makeUniqueStrings functions for constructing unique +% identifiers, but this particular implementation also works with +% older MATLAB versions. % % See also DEBLANK -% Copyright (C) 2012-2016, Robert Oostenveld +% Copyright (C) 2012-2017, Robert Oostenveld % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -33,19 +34,48 @@ % % $Id$ -str = lower(str); -str(regexp(str,'\W')) = '_'; - -while(str(1) == '_'), str = str(2:end); end; % remove all underscore at the begin of the string -while(str(end) == '_'), str = str(1:end-1); end; % remove all underscore at the end of the string - -if int8(str(1))<58 && int8(str(1))>47 - % the string begins with a digit, prepend an 'x' - str = ['x' str]; +if nargin<2 + version = 'default'; end -% truncate the string if it's too long: MATLAB maximizes the string length to 63 characters (and throws a warning when truncating) -if numel(str)>63 - str = str(1:63); - ft_warning(sprintf('%s exceeds MATLAB''s maximum name length of 63 characters and has been truncated to %s', str, str(1:63))); +switch version + case 'default' + if isempty(str) + str='x'; + end + str = lower(str); + str(regexp(str,'\W')) = '_'; + while(str(1) == '_'), str = str(2:end); end % remove all underscore at the begin of the string + while(str(end) == '_'), str = str(1:end-1); end % remove all underscore at the end of the string + if int8(str(1))<58 && int8(str(1))>47 + % the string begins with a digit, prepend an 'x' + str = ['x' str]; + end + % truncate the string if it's too long: MATLAB maximizes the string length to 63 characters (and throws a warning when truncating) + if numel(str)>63 + str = str(1:63); + warning('%s exceeds MATLAB''s maximum name length of 63 characters and has been truncated to %s', str, str(1:63)); + end + + case '2014a' + str = matlab.lang.makeValidName(str); + + case 'X_base64encode_X' + % this uses some code from Mathworks file exchange + ft_hastoolbox('fileexchange', 1); + % the following is an encoding that can be reverted + str = strtrim(base64encode(str)); + str(str=='=') = '_'; % replace the '=' sign with '_' + str = ['X' str 'X']; % start and end with an 'X' + + case 'X_base64decode_X' + % this uses some code from Mathworks file exchange + ft_hastoolbox('fileexchange', 1); + % revert the encoding + str = str(2:end-1); % it starts and ends with 'X' + str(str=='_') = '='; % the '=' sign has been replaced with '_' + str = char(base64decode(str)); + + otherwise + error('unsupported version "%s"', version); end diff --git a/external/fieldtrip/forward/private/fixoldorg.m b/external/fieldtrip/forward/private/fixoldorg.m new file mode 100644 index 00000000..93174b7a --- /dev/null +++ b/external/fieldtrip/forward/private/fixoldorg.m @@ -0,0 +1,36 @@ +function input = fixoldorg(input, revert) + +% FIXOLDORG use "old/new" instead of "org/new" + +if nargin<2 + revert = false; +end + +if ~(isstruct(input) && numel(input)==1) + % this does not look like a montage or a sensor description + return +end + +if ~revert + from = {'labelorg', 'chantypeorg', 'chanunitorg', 'chanposorg', 'chanoriorg'}; + to = {'labelold', 'chantypeold', 'chanunitold', 'chanposold', 'chanoriold'}; +else + to = {'labelorg', 'chantypeorg', 'chanunitorg', 'chanposorg', 'chanoriorg'}; + from = {'labelold', 'chantypeold', 'chanunitold', 'chanposold', 'chanoriold'}; +end + +% replace the fields +for i=1:numel(from) + if isfield(input, from{i}) + input.(to{i}) = input.(from{i}); + input = rmfield(input, from{i}); + end +end + +% use recursion to update the subfields +fn = fieldnames(input); +for i=1:numel(fn) + if isstruct(input.(fn{i})) + input.(fn{i}) = fixoldorg(input.(fn{i}), revert); + end +end diff --git a/external/fieldtrip/forward/private/fixpos.m b/external/fieldtrip/forward/private/fixpos.m index 31cee40f..88408288 100644 --- a/external/fieldtrip/forward/private/fixpos.m +++ b/external/fieldtrip/forward/private/fixpos.m @@ -10,7 +10,7 @@ % convert to structure, otherwise the code below won't work properly ws = warning('off', 'MATLAB:structOnObject'); mesh = struct(mesh); - warning(ws); + ft_warning(ws); end if ~isa(mesh, 'struct') @@ -42,7 +42,7 @@ case 8 mesh.hex = mesh.ConnectivityList; otherwise - error('unsupported ConnectivityList') + ft_error('unsupported ConnectivityList') end % switch mesh = removefields(mesh, {'Points', 'ConnectivityList', 'Constraints', 'UnderlyingObj'}); end diff --git a/external/fieldtrip/forward/private/ft_datatype_headmodel.m b/external/fieldtrip/forward/private/ft_datatype_headmodel.m index 8fe3ac83..4d332ed6 100644 --- a/external/fieldtrip/forward/private/ft_datatype_headmodel.m +++ b/external/fieldtrip/forward/private/ft_datatype_headmodel.m @@ -132,7 +132,7 @@ elseif isfield(headmodel, 'cond') && isfield(headmodel, 'c') && isequal(headmodel.cond, headmodel.c) headmodel = rmfield(headmodel, 'c'); elseif isfield(headmodel, 'cond') && isfield(headmodel, 'c') && ~isequal(headmodel.cond, headmodel.c) - error('inconsistent specification of conductive properties for %s model', headmodel.type); + ft_error('inconsistent specification of conductive properties for %s model', headmodel.type); end case '2012' @@ -165,9 +165,9 @@ elseif strcmp(headmodel.type, 'fdm_fns') headmodel.type = 'fns'; elseif strcmp(headmodel.type, 'bem') - error('not able to convert the original ''bem'' volume type, try using headmodel.type=''dipoli'''); + ft_error('not able to convert the original ''bem'' volume type, try using headmodel.type=''dipoli'''); elseif strcmp(headmodel.type, 'avo') - error('this format is not supported anymore'); + ft_error('this format is not supported anymore'); end end @@ -183,15 +183,13 @@ elseif isfield(headmodel, 'cond') && isfield(headmodel, 'c') && isequal(headmodel.cond, headmodel.c) headmodel = rmfield(headmodel, 'cond'); elseif isfield(headmodel, 'cond') && isfield(headmodel, 'c') && ~isequal(headmodel.cond, headmodel.c) - error('inconsistent specification of conductive properties for %s model', headmodel.type); + ft_error('inconsistent specification of conductive properties for %s model', headmodel.type); end end % ensure that the geometrical units are specified - if ~isfield(headmodel, 'unit') - headmodel = ft_convert_units(headmodel); - end + headmodel = ft_determine_units(headmodel); otherwise - error('converting to version "%s" is not supported', version); + ft_error('converting to version "%s" is not supported', version); end diff --git a/external/fieldtrip/forward/private/ft_datatype_sens.m b/external/fieldtrip/forward/private/ft_datatype_sens.m index 27597439..a3c1d2ec 100644 --- a/external/fieldtrip/forward/private/ft_datatype_sens.m +++ b/external/fieldtrip/forward/private/ft_datatype_sens.m @@ -129,11 +129,11 @@ scaling = ft_getopt(varargin, 'scaling'); % should be 'amplitude' or 'amplitude/distance', the default depends on the senstype if ~isempty(amplitude) && ~any(strcmp(amplitude, {'V' 'uV' 'T' 'mT' 'uT' 'nT' 'pT' 'fT'})) - error('unsupported unit of amplitude "%s"', amplitude); + ft_error('unsupported unit of amplitude "%s"', amplitude); end if ~isempty(distance) && ~any(strcmp(distance, {'m' 'dm' 'cm' 'mm'})) - error('unsupported unit of distance "%s"', distance); + ft_error('unsupported unit of distance "%s"', distance); end if strcmp(version, 'latest') @@ -157,31 +157,12 @@ % update it to the previous standard version sens = ft_datatype_sens(sens, 'version', '2011v2'); + % rename from org to old (reverse = false) + sens = fixoldorg(sens, false); + % ensure that all numbers are represented in double precision sens = ft_struct2double(sens); - % use "old/new" rather than "org/new" - if isfield(sens, 'labelorg') - sens.labelold = sens.labelorg; - sens = rmfield(sens, 'labelorg'); - end - if isfield(sens, 'chantypeorg') - sens.chantypeold = sens.chantypeorg; - sens = rmfield(sens, 'chantypeorg'); - end - if isfield(sens, 'chanuniteorg') - sens.chanunitold = sens.chanunitorg; - sens = rmfield(sens, 'chanunitorg'); - end - if isfield(sens, 'chanposorg') - sens.chanposold = sens.chanposorg; - sens = rmfield(sens, 'chanposorg'); - end - if isfield(sens, 'chanoriorg') - sens.chanoriold = sens.chanoriorg; - sens = rmfield(sens, 'chanoriorg'); - end - % in version 2011v2 this was optional, now it is required if ~isfield(sens, 'chantype') || all(strcmp(sens.chantype, 'unknown')) sens.chantype = ft_chantype(sens); @@ -213,7 +194,7 @@ sens.tra(i,:) = sens.tra(i,:) * ft_scalingfactor(sens.chanunit{i}, amplitude); sens.chanunit{i} = amplitude; else - error('unexpected channel unit "%s" in channel %d', sens.chanunit{i}, i); + ft_error('unexpected channel unit "%s" in channel %d', sens.chanunit{i}, i); end end else @@ -244,13 +225,13 @@ sel_mm = ~cellfun(@isempty, regexp(sens.chanunit, '/mm$')); if strcmp(sens.unit, 'm') && (any(sel_dm) || any(sel_cm) || any(sel_mm)) - error('inconsistent units in input gradiometer'); + ft_error('inconsistent units in input gradiometer'); elseif strcmp(sens.unit, 'dm') && (any(sel_m) || any(sel_cm) || any(sel_mm)) - error('inconsistent units in input gradiometer'); + ft_error('inconsistent units in input gradiometer'); elseif strcmp(sens.unit, 'cm') && (any(sel_m) || any(sel_dm) || any(sel_mm)) - error('inconsistent units in input gradiometer'); + ft_error('inconsistent units in input gradiometer'); elseif strcmp(sens.unit, 'mm') && (any(sel_m) || any(sel_dm) || any(sel_cm)) - error('inconsistent units in input gradiometer'); + ft_error('inconsistent units in input gradiometer'); end % the default should be amplitude/distance for neuromag and amplitude for all others @@ -258,7 +239,7 @@ if ft_senstype(sens, 'neuromag') scaling = 'amplitude/distance'; elseif ft_senstype(sens, 'yokogawa440') - warning('asuming that the default scaling should be amplitude rather than amplitude/distance'); + ft_warning('asuming that the default scaling should be amplitude rather than amplitude/distance'); scaling = 'amplitude'; else scaling = 'amplitude'; @@ -272,7 +253,7 @@ % this channel is expressed as amplitude per distance coil = find(abs(sens.tra(i,:))~=0); if length(coil)~=2 - error('unexpected number of coils contributing to channel %d', i); + ft_error('unexpected number of coils contributing to channel %d', i); end baseline = norm(sens.coilpos(coil(1),:) - sens.coilpos(coil(2),:)); sens.tra(i,:) = sens.tra(i,:)*baseline; % scale with the baseline distance @@ -281,7 +262,7 @@ % no conversion needed else % see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=3144 - ft_warning(sprintf('unexpected channel unit "%s" in channel %d', sens.chanunit{i}, i)); + ft_warning('unexpected channel unit "%s" in channel %d', sens.chanunit{i}, i); end % if end % for @@ -294,7 +275,7 @@ % this is a magnetometer channel, no conversion needed continue elseif length(coil)~=2 - error('unexpected number of coils (%d) contributing to channel %s (%d)', length(coil), sens.label{i}, i); + ft_error('unexpected number of coils (%d) contributing to channel %s (%d)', length(coil), sens.label{i}, i); end baseline = norm(sens.coilpos(coil(1),:) - sens.coilpos(coil(2),:)); sens.tra(i,:) = sens.tra(i,:)/baseline; % scale with the baseline distance @@ -303,7 +284,7 @@ % no conversion needed else % see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=3144 - ft_warning(sprintf('unexpected channel unit "%s" in channel %d', sens.chanunit{i}, i)); + ft_warning('unexpected channel unit "%s" in channel %d', sens.chanunit{i}, i); end % if end % for @@ -315,16 +296,19 @@ sel_cm = ~cellfun(@isempty, regexp(sens.chanunit, '/cm$')); sel_mm = ~cellfun(@isempty, regexp(sens.chanunit, '/mm$')); if any(sel_m | sel_dm | sel_cm | sel_mm) - error('scaling of amplitude/distance has not been considered yet for EEG'); + ft_error('scaling of amplitude/distance has not been considered yet for EEG'); end end % if iseeg or ismeg %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% case '2011v2' - + + % rename from old to org (reverse = true) + sens = fixoldorg(sens, true); + if ~isempty(amplitude) || ~isempty(distance) || ~isempty(scaling) - warning('amplitude, distance and scaling are not supported for version "%s"', version); + ft_warning('amplitude, distance and scaling are not supported for version "%s"', version); end % This speeds up subsequent calls to ft_senstype and channelposition. @@ -357,7 +341,7 @@ sens.chanpos(selsens,:) = chanpos(selpos,:); sens.chanori(selsens,:) = chanori(selpos,:); if length(selsens)~=length(sens.label) - warning('cannot determine the position and orientation for all channels'); + ft_warning('cannot determine the position and orientation for all channels'); end else % sensor description is something else, EEG/ECoG etc @@ -369,7 +353,7 @@ % insert the determined position/orientation on the appropriate rows sens.chanpos(selsens,:) = chanpos(selpos,:); if length(selsens)~=length(sens.label) - warning('cannot determine the position and orientation for all channels'); + ft_warning('cannot determine the position and orientation for all channels'); end end end @@ -384,7 +368,7 @@ if ~isfield(sens, 'unit') % this should be done prior to calling ft_chanunit, since ft_chanunit uses this for planar neuromag channels - sens = ft_convert_units(sens); + sens = ft_determine_units(sens); end if ~isfield(sens, 'chanunit') || all(strcmp(sens.chanunit, 'unknown')) @@ -397,7 +381,7 @@ if any(strcmp(sens.type, {'meg', 'eeg', 'magnetometer', 'electrode', 'unknown'})) % this is not sufficiently informative, so better remove it - % see also http://bugzilla.fcdonders.nl/show_bug.cgi?id=1806 + % see also http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=1806 sens = rmfield(sens, 'type'); end @@ -408,7 +392,7 @@ isfield(sens, 'tra') && isfield(sens, 'coilori') && size(sens.tra,2)~=size(sens.coilori,1) || ... isfield(sens, 'chanpos') && size(sens.chanpos,1)~=length(sens.label) || ... isfield(sens, 'chanori') && size(sens.chanori,1)~=length(sens.label) - error('inconsistent number of channels in sensor description'); + ft_error('inconsistent number of channels in sensor description'); end if ismeg @@ -465,7 +449,7 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% otherwise - error('converting to version %s is not supported', version); + ft_error('converting to version %s is not supported', version); end % switch diff --git a/external/fieldtrip/forward/private/ft_getopt.m b/external/fieldtrip/forward/private/ft_getopt.m index 21ed892a..0d433115 100644 --- a/external/fieldtrip/forward/private/ft_getopt.m +++ b/external/fieldtrip/forward/private/ft_getopt.m @@ -8,19 +8,19 @@ % where the input values are % s = structure or cell-array % key = string -% default = any valid MATLAB data type +% default = any valid MATLAB data type (optional, default = []) % emptymeaningful = boolean value (optional, default = 0) % -% If the key is present as field in the structure, or as key-value -% pair in the cell-array, the corresponding value will be returned. +% If the key is present as field in the structure, or as key-value pair in the +% cell-array, the corresponding value will be returned. % -% If the key is not present, ft_getopt will return an empty array. +% If the key is not present, ft_getopt will return the default, or an empty array +% when no default was specified. % -% If the key is present but has an empty value, then the emptymeaningful -% flag specifies whether the empty value or the default value should -% be returned. If emptymeaningful==true, then an empty array will be -% returned. If emptymeaningful==false, then the specified default will -% be returned. +% If the key is present but has an empty value, then the emptymeaningful flag +% specifies whether the empty value or the default value should be returned. +% If emptymeaningful==true, then the empty array will be returned. +% If emptymeaningful==false, then the specified default will be returned. % % See also FT_SETOPT, FT_CHECKOPT @@ -60,27 +60,27 @@ else val = opt.(key); end - + elseif isa(opt, 'cell') % get the key-value from the cell-array if mod(length(opt),2) error('optional input arguments should come in key-value pairs, i.e. there should be an even number'); end - + % the 1st, 3rd, etc. contain the keys, the 2nd, 4th, etc. contain the values keys = opt(1:2:end); vals = opt(2:2:end); - + % the following may be faster than cellfun(@ischar, keys) valid = false(size(keys)); for i=1:numel(keys) valid(i) = ischar(keys{i}); end - + if ~all(valid) error('optional input arguments should come in key-value pairs, the optional input argument %d is invalid (should be a string)', i); end - + hit = find(strcmpi(key, keys)); if isempty(hit) % the requested key was not found @@ -91,7 +91,7 @@ else error('multiple input arguments with the same name'); end - + elseif isempty(opt) % no options are specified, return default val = default; diff --git a/external/fieldtrip/forward/private/ft_getopt.mexmaci64 b/external/fieldtrip/forward/private/ft_getopt.mexmaci64 index 1e499c9421e1062ba1178bd37b44ea26728740c3..48fecb34b3878cd01301ebf956190ce9f9db8af2 100755 GIT binary patch literal 9680 zcmeHNU2Ggz6~62II6tOd2d6cn&}peFm;BizC~4BB-r7!g!A>3Qv=Ly&v+G&!(Al5N z&ZO(eiL5v-ow`P*DWyVHu+#@C1P>r2A_3K+w3vrLO?Zhah$=*rvD`|9LO?BKIp3W- z-q|rmec%brmG3?0JLlYU&zyVbdiKt|{{A~R>lurzVT^5{8l@_&V{D2j%Ezd-)iEZ^ zgFVLvxu~{52Y(Tmd@^#w)(f31n`+6d8V3DIn_QhiW1#@Aby>Gv%O?C#mW!s9EG~5vnU$5nrlk8d`2t*a!Xn zN%;Gg2+G64yw*1fW!cI-q2)$oEtk%7Tst4*jc(6=;Q+WMJ|XvrEUOtgZ75mQl?3Bk z5dPXl2Vks`)e6>$Lsgc$V}miDmA5`tp;#yI>%}U|IbAM}Ws`YbE||uu{ycYBu>QC( zpUuAEWm#ALo4=@VG$;B1`~4xlTYdg;opGwN+?zQ3`JV2CcTY&d$O}y11>6Kw;K#rI z?qY1B9SX_4?=}!^0TxA)7`s3nuH4DkK9V6n(8sCcZA6FfW~@N^&BXUp^%vNpZuJWT z{Dn_3_UV8O@Z(f5&K*m?xNY{K{lk;j=I^`O*|eL6<9h?!NH^xDO}wvnsib1K-EckV zi?O}ZX%rMQvrE^K+0xFDF`};KL)feS4lC_T+Sw#chQB&Kt?d%YPzaxgyg**W;SPKvW-vp+F?E5-C2iF)l* zWzxX<18R@6drY1N*gQSDwbu__thAOWluGMK-j4J3G;b$(dxp1X zdHW=9pW^M)ynTkZn1xC!=C{)NEN?OGmDcBZ`vPyV&MK`~yOq}S)Y6R4eBy7kzG4HF z*0+exW*}U=R;g4nc;s6AJ-EH#E`#d>_bYIChF*LH+(~dh1~&`td*FTmZVp@--1FcT zz&!)*O>k$x{TW;dTpdl;Vh-F^a3kQ_z*`#Vn`Lv|v3YIA;#;BE5b7qm58C7~*9g~WgyrqvwNmVKq)RdOi)DcN3 zN{S?Y&1mVWVtc@gq-G1|SXNbX^t&f*={{$Qq~}Mql%h*{15v1kmXb~=x}~yIK9|-; z8R>NT<&{i5UfiSY-aBUOmQzn8gIIb1fmkWCEns->0hZEL#gGE>1N_R;no%@GwACx5 zi=sevx>WAcGSt&pQ9<@|Z$mI%iFP}A6o>FyvhhiAY7%sj#7H&y)J5>}v zrM1U@|L!4*dJYe>RKR1QHqaAxv-^}C8HO=E*#7p|I=EZ@?Griq1r{kqBhiNX4YQuSdM}Ca=hP2I8Rdx1ryzPNvW0S|mU;}MuQ)nLpFfar))Ue>QZ=0~2q~rDQN_>{%I9O6 znRz7nRXVmqw>e?ZZ!H@@{BoqZlP1kbDMdAvEs)475sXZqbkrTPaw${G=h*hNMkj3Q zaZ5AQ5v8D=P>mwwbn-jbOb1I7c(*;*{3g98W$gW{4R~|CohrwWQQ>DyMBP&-->Y&6 z8cFMY$AQlWfG5P+72Y)y^!o94vwr+=K(7SwaTik;x10&!7X$eF0sKk;|2lyG5Ws&8 z;0TTE{*i*p<^aY)tzRz%@U{TPiND{zCxDN*csch&0gUe)@S+3X>};e;Z{_*707y5E z%5I^GIfzniqPm6ZN2%go$0Xn!5zaBm_)b840!{s#yu*x#5y;C@<-Xehi z`QCuWe^ad3tVpoRHbt764GOq+Ya)q%Q*vQ-J96=gjmQ;?Er@{Fd|VFOj?3{4hqLZh X!&z^W;lSHoI1u}a|88HgWi$3~)uY>q literal 9832 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 delta 33 mcmZp0X>eJ<$YTBPQ|M$CMjxgvZ#D-pCP{(?Ht&$~U! delta 32 lcmZqhXz-ZugT=2, get_spm_version()<95}; + %This is to avoid crashes when trying to add SPM to the path + fallback_toolbox = 'SPM8'; case 'SPM5' dependency = {'spm', get_spm_version()==5}; + case 'SPM5UP' % version 5 or later, but not SPM 9X + dependency = {'spm', get_spm_version()>=5, get_spm_version()<95}; + %This is to avoid crashes when trying to add SPM to the path + fallback_toolbox = 'SPM5'; case 'SPM8' dependency = {'spm', get_spm_version()==8}; case 'SPM8UP' % version 8 or later, but not SPM 9X dependency = {'spm', get_spm_version()>=8, get_spm_version()<95}; - %This is to avoid crashes when trying to add SPM to the path fallback_toolbox = 'SPM8'; case 'SPM12' dependency = {'spm', get_spm_version()==12}; + case 'SPM12UP' % version 12 or later, but not SPM 9X + dependency = {'spm', get_spm_version()>=12, get_spm_version()<95}; + %This is to avoid crashes when trying to add SPM to the path + fallback_toolbox = 'SPM12'; case 'MEG-PD' dependency = {'rawdata', 'channames'}; case 'MEG-CALC' @@ -205,8 +220,7 @@ case 'MRI' % other functions in the mri section dependency = {'avw_hdr_read', 'avw_img_read'}; case 'NEUROSHARE' - dependency = {'ns_OpenFile', 'ns_SetLibrary', ... - 'ns_GetAnalogData'}; + dependency = {'ns_OpenFile', 'ns_SetLibrary', 'ns_GetAnalogData'}; case 'ARTINIS' dependency = {'read_artinis_oxy3'}; case 'BESA' @@ -234,21 +248,21 @@ case '4D-VERSION' dependency = {'read4d', 'read4dhdr'}; case {'STATS', 'STATISTICS'} - dependency = has_license('statistics_toolbox'); % check the availability of a toolbox license + dependency = has_license('statistics_toolbox'); % also check the availability of a toolbox license case {'OPTIM', 'OPTIMIZATION'} - dependency = has_license('optimization_toolbox'); % check the availability of a toolbox license + dependency = has_license('optimization_toolbox'); % also check the availability of a toolbox license case {'SPLINES', 'CURVE_FITTING'} - dependency = has_license('curve_fitting_toolbox'); % check the availability of a toolbox license + dependency = has_license('curve_fitting_toolbox'); % also check the availability of a toolbox license case 'COMM' dependency = {has_license('communication_toolbox'), 'de2bi'}; % also check the availability of a toolbox license case 'SIGNAL' - dependency = {has_license('signal_toolbox'), 'window'}; % also check the availability of a toolbox license - case 'IMAGE' - dependency = has_license('image_toolbox'); % check the availability of a toolbox license + dependency = {has_license('signal_toolbox'), 'window'}; % also check the availability of a toolbox license + case 'IMAGES' + dependency = has_license('image_toolbox'); % also check the availability of a toolbox license case {'DCT', 'DISTCOMP'} - dependency = has_license('distrib_computing_toolbox'); % check the availability of a toolbox license + dependency = has_license('distrib_computing_toolbox'); % also check the availability of a toolbox license case 'COMPILER' - dependency = has_license('compiler'); % check the availability of a toolbox license + dependency = has_license('compiler'); % also check the availability of a toolbox license case 'FASTICA' dependency = 'fpica'; case 'BRAINSTORM' @@ -260,8 +274,7 @@ case 'BCI2000' dependency = {'load_bcidat'}; case 'NLXNETCOM' - dependency = {'MatlabNetComClient', 'NlxConnectToServer', ... - 'NlxGetNewCSCData'}; + dependency = {'MatlabNetComClient', 'NlxConnectToServer', 'NlxGetNewCSCData'}; case 'DIPOLI' dependency = {'dipoli.maci', 'file'}; case 'MNE' @@ -323,17 +336,17 @@ dependency = {'plx_adchan_gains', 'mexPlex'}; case '35625-INFORMATION-THEORY-TOOLBOX' dependency = {'conditionalEntropy', 'entropy', 'jointEntropy',... - 'mutualInformation' 'nmi' 'nvi' 'relativeEntropy'}; + 'mutualInformation' 'nmi' 'nvi' 'relativeEntropy'}; case '29046-MUTUAL-INFORMATION' dependency = {'MI', 'license.txt'}; case '14888-MUTUAL-INFORMATION-COMPUTATION' dependency = {'condentropy', 'demo_mi', 'estcondentropy.cpp',... - 'estjointentropy.cpp', 'estpa.cpp', ... - 'findjointstateab.cpp', 'makeosmex.m',... - 'mutualinfo.m', 'condmutualinfo.m',... - 'entropy.m', 'estentropy.cpp',... - 'estmutualinfo.cpp', 'estpab.cpp',... - 'jointentropy.m' 'mergemultivariables.m' }; + 'estjointentropy.cpp', 'estpa.cpp', ... + 'findjointstateab.cpp', 'makeosmex.m',... + 'mutualinfo.m', 'condmutualinfo.m',... + 'entropy.m', 'estentropy.cpp',... + 'estmutualinfo.cpp', 'estpab.cpp',... + 'jointentropy.m' 'mergemultivariables.m' }; case 'PLOT2SVG' dependency = {'plot2svg.m', 'simulink2svg.m'}; case 'BRAINSUITE' @@ -352,11 +365,16 @@ dependency = {'write_wobj' 'read_wobj'}; case 'NEURONE' dependency = {'readneurone' 'readneuronedata' 'readneuroneevents'}; - + case 'BREWERMAP' + dependency = {'brewermap' 'brewermap_view'}; + case 'GTEC' + dependency = {'ghdf5read' 'ghdf5fileimport'}; + case 'MARS' + dependency = {'spm_mars_mrf'}; + % the following are FieldTrip modules/toolboxes case 'FILEIO' - dependency = {'ft_read_header', 'ft_read_data', ... - 'ft_read_event', 'ft_read_sens'}; + dependency = {'ft_read_header', 'ft_read_data', 'ft_read_event', 'ft_read_sens'}; case 'FORWARD' dependency = {'ft_compute_leadfield', 'ft_prepare_vol_sens'}; case 'PLOTTING' @@ -369,33 +387,35 @@ dependency = {'ft_spiketriggeredaverage', 'ft_spiketriggeredspectrum'}; case 'FILEEXCHANGE' dependency = is_subdir_in_fieldtrip_path('/external/fileexchange'); + case 'CELLFUNCTION' + dependency = {'cellmean', 'cellvecadd', 'cellcat'}; case {'INVERSE', 'REALTIME', 'SPECEST', 'PREPROC', ... - 'COMPAT', 'STATFUN', 'TRIALFUN', 'UTILITIES/COMPAT', ... - 'FILEIO/COMPAT', 'PREPROC/COMPAT', 'FORWARD/COMPAT', ... - 'PLOTTING/COMPAT', 'TEMPLATE/LAYOUT', 'TEMPLATE/ANATOMY' ,... - 'TEMPLATE/HEADMODEL', 'TEMPLATE/ELECTRODE', ... - 'TEMPLATE/NEIGHBOURS', 'TEMPLATE/SOURCEMODEL'} + 'COMPAT', 'STATFUN', 'TRIALFUN', 'UTILITIES/COMPAT', ... + 'FILEIO/COMPAT', 'PREPROC/COMPAT', 'FORWARD/COMPAT', ... + 'PLOTTING/COMPAT', 'TEMPLATE/LAYOUT', 'TEMPLATE/ANATOMY' ,... + 'TEMPLATE/HEADMODEL', 'TEMPLATE/ELECTRODE', ... + 'TEMPLATE/NEIGHBOURS', 'TEMPLATE/SOURCEMODEL'} dependency = is_subdir_in_fieldtrip_path(toolbox); otherwise - if ~silent, warning('cannot determine whether the %s toolbox is present', toolbox); end + if ~silent, ft_warning('cannot determine whether the %s toolbox is present', toolbox); end dependency = false; end status = is_present(dependency); if ~status && ~isempty(fallback_toolbox) - % in case of SPM8UP + % in case of SPMxUP toolbox = fallback_toolbox; end % try to determine the path of the requested toolbox if autoadd>0 && ~status - + % for core FieldTrip modules prefix = fileparts(which('ft_defaults')); if ~status status = myaddpath(fullfile(prefix, lower(toolbox)), silent); end - + % for external FieldTrip modules prefix = fullfile(fileparts(which('ft_defaults')), 'external'); if ~status @@ -407,37 +427,37 @@ feval(licensefile); end end - + % for contributed FieldTrip extensions prefix = fullfile(fileparts(which('ft_defaults')), 'contrib'); if ~status status = myaddpath(fullfile(prefix, lower(toolbox)), silent); licensefile = [lower(toolbox) '_license']; if status && exist(licensefile, 'file') - % this will execute openmeeg_license and mne_license - % which display the license on screen for three seconds + % this will execute openmeeg_license, mne_license and artinis_license + % which display the license on screen for a few seconds feval(licensefile); end end - + % for linux computers in the Donders Centre for Cognitive Neuroimaging prefix = '/home/common/matlab'; if ~status && isdir(prefix) status = myaddpath(fullfile(prefix, lower(toolbox)), silent); end - + % for windows computers in the Donders Centre for Cognitive Neuroimaging prefix = 'h:\common\matlab'; if ~status && isdir(prefix) status = myaddpath(fullfile(prefix, lower(toolbox)), silent); end - + % use the MATLAB subdirectory in your homedirectory, this works on linux and mac prefix = fullfile(getenv('HOME'), 'matlab'); if ~status && isdir(prefix) status = myaddpath(fullfile(prefix, lower(toolbox)), silent); end - + if ~status % the toolbox is not on the path and cannot be added sel = find(strcmp(url(:,1), toolbox)); @@ -447,7 +467,7 @@ msg = sprintf('the %s toolbox is not installed', toolbox); end if autoadd==1 - error(msg); + ft_error(msg); elseif autoadd==2 ft_warning(msg); else @@ -458,30 +478,35 @@ % this function is called many times in FieldTrip and associated toolboxes % use efficient handling if the same toolbox has been investigated before -if status - previous.(fixname(toolbox)) = status; -end +% if status +% previous.(fixname(toolbox)) = status; +% end % remember the previous path, allows us to determine on the next call % whether the path has been modified outise of this function -previouspath = path; +% previouspath = path; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % helper function %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function status = myaddpath(toolbox, silent) if isdeployed - warning('cannot change path settings for %s in a compiled application', toolbox); + ft_warning('cannot change path settings for %s in a compiled application', toolbox); status = 1; elseif exist(toolbox, 'dir') - if ~silent, - ws = warning('backtrace', 'off'); - warning('adding %s toolbox to your MATLAB path', toolbox); - warning(ws); % return to the previous warning level + if ~silent + ft_warning('off','backtrace'); + ft_warning('adding %s toolbox to your MATLAB path', toolbox); + ft_warning('on','backtrace'); + end + if any(~cellfun(@isempty, regexp(toolbox, {'spm2', 'spm5', 'spm8', 'spm12'}))) + % SPM needs to be added with the subdirectories + addpath(genpath(toolbox)); + else + addpath(toolbox); end - addpath(toolbox); status = 1; -elseif (~isempty(regexp(toolbox, 'spm5$', 'once')) || ~isempty(regexp(toolbox, 'spm8$', 'once')) || ~isempty(regexp(toolbox, 'spm12$', 'once'))) && exist([toolbox 'b'], 'dir') +elseif (~isempty(regexp(toolbox, 'spm2$', 'once')) || ~isempty(regexp(toolbox, 'spm5$', 'once')) || ~isempty(regexp(toolbox, 'spm8$', 'once')) || ~isempty(regexp(toolbox, 'spm12$', 'once'))) && exist([toolbox 'b'], 'dir') status = myaddpath([toolbox 'b'], silent); else status = 0; @@ -511,9 +536,9 @@ m = lasterror; if strcmp(m.identifier, 'MATLAB:license:checkouterror') if nargin>1 - warning('the %s toolbox is available, but you don''t have a license for it', toolbox); + ft_warning('the %s toolbox is available, but you don''t have a license for it', toolbox); else - warning('the function ''%s'' is available, but you don''t have a license for it', funname); + ft_warning('the function ''%s'' is available, but you don''t have a license for it', funname); end status = false; elseif strcmp(m.identifier, 'MATLAB:UndefinedFunction') @@ -529,65 +554,65 @@ % helper function %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function status = is_subdir_in_fieldtrip_path(toolbox_name) - fttrunkpath = unixpath(fileparts(which('ft_defaults'))); - fttoolboxpath = fullfile(fttrunkpath, lower(toolbox_name)); +fttrunkpath = unixpath(fileparts(which('ft_defaults'))); +fttoolboxpath = fullfile(fttrunkpath, lower(toolbox_name)); - needle=[pathsep fttoolboxpath pathsep]; - haystack = [pathsep path() pathsep]; +needle=[pathsep fttoolboxpath pathsep]; +haystack = [pathsep path() pathsep]; - status = ~isempty(findstr(needle, haystack)); +status = ~isempty(findstr(needle, haystack)); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % helper function %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function status = has_mex(name) - full_name=[name '.' mexext]; - status = (exist(full_name, 'file')==3); +full_name=[name '.' mexext]; +status = (exist(full_name, 'file')==3); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % helper function %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function v = get_spm_version() - if ~is_present('spm') - v=NaN; - return - end +if ~is_present('spm') + v=NaN; + return +end - version_str = spm('ver'); - token = regexp(version_str,'(\d*)','tokens'); - v = str2num([token{:}{:}]); +version_str = spm('ver'); +token = regexp(version_str,'(\d*)','tokens'); +v = str2num([token{:}{:}]); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % helper function %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function status = has_license(toolbox_name) - status = license('checkout', toolbox_name)==1; +status = license('checkout', toolbox_name)==1; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % helper function %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function status = is_present(dependency) - if iscell(dependency) - % use recursion - status = all(cellfun(@is_present,dependency)); - elseif islogical(dependency) - % boolean - status = all(dependency); - elseif ischar(dependency) - % name of a function - status = is_function_present_in_search_path(dependency); - elseif isa(dependency, 'function_handle') - status = dependency(); - else - assert(false,'this should not happen'); - end +if iscell(dependency) + % use recursion + status = all(cellfun(@is_present,dependency)); +elseif islogical(dependency) + % boolean + status = all(dependency); +elseif ischar(dependency) + % name of a function + status = is_function_present_in_search_path(dependency); +elseif isa(dependency, 'function_handle') + status = dependency(); +else + assert(false,'this should not happen'); +end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % helper function %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function status = is_function_present_in_search_path(function_name) - w = which(function_name); +w = which(function_name); - % must be in path and not a variable - status = ~isempty(w) && ~isequal(w, 'variable'); +% must be in path and not a variable +status = ~isempty(w) && ~isequal(w, 'variable'); diff --git a/external/fieldtrip/forward/private/ft_headcoordinates.m b/external/fieldtrip/forward/private/ft_headcoordinates.m index 2c6cd04c..66751a8f 100644 --- a/external/fieldtrip/forward/private/ft_headcoordinates.m +++ b/external/fieldtrip/forward/private/ft_headcoordinates.m @@ -50,6 +50,7 @@ % according to FTG conventions: coordsys = 'ftg' % according to Talairach conventions: coordsys = 'tal' % according to SPM conventions: coordsys = 'spm' +% according to ACPC conventions: coordsys = 'acpc' % according to PAXINOS conventions: coordsys = 'paxinos' % If coordsys is not specified, it will default to 'ctf'. % @@ -59,7 +60,7 @@ % the Y-axis goes approximately towards lpa, orthogonal to X and in the plane spanned by the fiducials % the Z-axis goes approximately towards the vertex, orthogonal to X and Y % -% The TALAIRACH and SPM coordinate systems are defined as: +% The TALAIRACH, SPM and ACPC coordinate systems are defined as: % the origin corresponds with the anterior commissure % the Y-axis is along the line from the posterior commissure to the anterior commissure % the Z-axis is towards the vertex, in between the hemispheres @@ -88,7 +89,7 @@ % the y-axis points from dorsal to ventral, i.e. from inferior to superior % the z-axis passes through bregma and lambda and points from cranial to caudal, i.e. from anterior to posterior % -% See also FT_ELECTRODEREALIGN, FT_VOLUMEREALIGN, FT_INTERACTIVEREALIGN +% See also FT_ELECTRODEREALIGN, FT_VOLUMEREALIGN, FT_INTERACTIVEREALIGN, COORDSYS2LABEL % Copyright (C) 2003-2014 Robert Oostenveld % @@ -122,19 +123,19 @@ elseif nargin==5 % do nothing else - error('incorrect specification of input parameters'); + ft_error('incorrect specification of input parameters'); end if isnumeric(coordsys) % these are for backward compatibility, but should preferably not be used any more - if coordsys==0, + if coordsys==0 coordsys = 'ctf'; - elseif coordsys==1, + elseif coordsys==1 coordsys = 'asa'; - elseif coordsys==2, + elseif coordsys==2 coordsys = 'ftg'; else - error('if coordsys is numeric, it should assume one of the values 0/1/2'); + ft_error('if coordsys is numeric, it should assume one of the values 0/1/2'); end end @@ -154,7 +155,7 @@ % compute the origin and direction of the coordinate axes in MRI coordinates switch coordsys - case {'als_ctf' 'ctf' 'bti' '4d' 'yokogawa'} + case {'ctf' 'bti' '4d' 'yokogawa'} % rename the marker points for convenience nas = fid1; lpa = fid2; rpa = fid3; extrapoint = fid4; clear fid* origin = (lpa+rpa)/2; @@ -164,7 +165,7 @@ dirx = dirx/norm(dirx); diry = diry/norm(diry); dirz = dirz/norm(dirz); - case {'als_asa' 'asa'} + case {'asa'} % rename the marker points for convenience nas = fid1; lpa = fid2; rpa = fid3; extrapoint = fid4; clear fid* dirz = cross(nas-rpa, lpa-rpa); @@ -174,7 +175,7 @@ diry = diry/norm(diry); dirz = dirz/norm(dirz); origin = rpa + dot(nas-rpa,diry)*diry; - case {'ras_itab' 'itab' 'neuromag'} + case {'itab' 'neuromag'} % rename the fiducials nas = fid1; lpa = fid2; rpa = fid3; extrapoint = fid4; clear fid* dirz = cross(rpa-lpa,nas-lpa); @@ -195,7 +196,7 @@ dirx = dirx/norm(dirx); diry = diry/norm(diry); dirz = dirz/norm(dirz); - case {'ras_tal' 'tal' 'spm'} + case {'tal' 'spm' 'acpc'} % rename the marker points for convenience ac = fid1; pc = fid2; midsagittal = fid3; extrapoint = fid4; clear fid* origin = ac; @@ -217,27 +218,27 @@ diry = diry/norm(diry); dirz = dirz/norm(dirz); otherwise - error('unrecognized headcoordinate system "%s"', coordsys); + ft_error('unrecognized headcoordinate system "%s"', coordsys); end % use the extra point to validate that it is a right-handed coordinate system if ~isempty(extrapoint) dirq = extrapoint-origin; dirq = dirq/norm(dirq); - if any(strcmp(coordsys, {'als_ctf' 'ctf' 'bti' '4d' 'yokogawa' 'ras_itab' 'itab' 'neuromag'})) + if any(strcmp(coordsys, {'ctf' 'bti' '4d' 'yokogawa' 'itab' 'neuromag'})) phi = dirq(:)'*dirz(:); if sign(phi)<0 - warning('the input coordinate system seems left-handed, flipping z-axis to keep the transformation matrix consistent'); + ft_warning('the input coordinate system seems left-handed, flipping z-axis to keep the transformation matrix consistent'); dirz = -dirz; end - elseif any(strcmp(coordsys, {'ras_tal' 'tal' 'spm'})) + elseif any(strcmp(coordsys, {'tal' 'spm' 'acpc'})) phi = dirq(:)'*dirx(:); if sign(phi)<0 - warning('the input coordinate system seems left-handed, flipping x-axis to keep the transformation matrix consistent'); + ft_warning('the input coordinate system seems left-handed, flipping x-axis to keep the transformation matrix consistent'); dirx = -dirx; end else - warning('the extra input coordinate is not used with coordsys "%s"', coordsys); + ft_warning('the extra input coordinate is not used with coordsys "%s"', coordsys); end end diff --git a/external/fieldtrip/forward/private/ft_notification.m b/external/fieldtrip/forward/private/ft_notification.m new file mode 100644 index 00000000..dc9b7369 --- /dev/null +++ b/external/fieldtrip/forward/private/ft_notification.m @@ -0,0 +1,482 @@ +function [varargout] = ft_notification(varargin) + +% FT_NOTIFICATION works mostly like the WARNING and ERROR commands in MATLAB and +% is called by FT_ERROR, FT_WARNING, FT_NOTICE, FT_INFO, FT_DEBUG. Note that you +% should not call this function directly. +% +% Some examples: +% ft_info on +% ft_info on msgId +% ft_info off +% ft_info off msgId +% ft_info once +% ft_info once msgId +% ft_info on backtrace +% ft_info off backtrace +% ft_info on verbose +% ft_info off verbose +% +% ft_info query % shows the status of all notifications +% ft_info last % shows the last notification +% ft_info clear % clears the status of all notifications +% ft_info timeout 10 % sets the timeout (for 'once') to 10 seconds +% +% See also DEFAULTID + +% Copyright (C) 2012-2017, Robert Oostenveld, J?rn M. Horschig +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +global ft_default + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% determine who is calling + +stack = dbstack('-completenames'); +% st(1) is this function +% st(2) is the calling function +switch stack(2).name + case 'ft_debug' + level = 'debug'; + case 'ft_info' + level = 'info'; + case 'ft_notice' + level = 'notice'; + case 'ft_warning' + level = 'warning'; + case 'ft_error' + level = 'error'; + otherwise + error('this function cannot be called from %s', stack(2).name); +end + +% remove this function itself and the ft_xxx calling function +stack = stack(3:end); + +% remove the non-FieldTrip functions from the path, these should not be part of the default message identifier +keep = true(size(stack)); +p = fileparts(which('ft_defaults')); +for i=1:numel(stack) + keep(i) = strncmp(p, stack(i).file, length(p)); +end +stack = stack(keep); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% handle the defaults + +if isfield(ft_default, 'notification') && isfield(ft_default.notification, level) + % this would be error, warning, notice, info, debug + s = ft_default.notification.(level); +else + s = []; +end + +% start with an empty state structure +if isempty(s) + s = struct('identifier', {}, 'state', {}, 'timestamp', {}); +end + +% set the default notification state +if ~ismember('all', {s.identifier}) + s = setstate(s, 'all', 'on'); +end + +% set the default backtrace state +defaultbacktrace = false; +if ~ismember('backtrace', {s.identifier}) + switch level + case {'debug' 'info' 'notice'} + s = setstate(s, 'backtrace', 'off'); + case 'warning' + defaultbacktrace = true; + t = warning('query', 'backtrace'); % get the default state + s = setstate(s, 'backtrace', t.state); + case 'error' + s = setstate(s, 'backtrace', 'on'); + end % switch +end + +% set the default verbose state +defaultverbose = false; +if ~ismember('verbose', {s.identifier}) + switch level + case 'warning' + defaultverbose = true; + t = warning('query', 'verbose');% get the default state + s = setstate(s, 'verbose', t.state); + otherwise + s = setstate(s, 'verbose', 'off'); + end +end + +% set the default timeout +if ~ismember('timeout', {s.identifier}) + s = setstate(s, 'timeout', 60); +end + +% set the last notification to empty +if ~ismember('last', {s.identifier}) + state.message = ''; + state.identifier = ''; + state.stack = struct('file', {}, 'name', {}, 'line', {}); + s = setstate(s, 'last', state); +end + +if strcmp(level, 'warning') + ws = warning; + % warnings should be on in general + warning on + % the backtrace is handled by this function + warning off backtrace + % the verbose message is handled by this function + warning off verbose +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% set the notification state according to the input + +if numel(varargin)>0 && (isstruct(varargin{1}) || isempty(varargin{1})) + ft_default.notification.(level) = varargin{1}; + return +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% act according to the first input argument + +if isempty(varargin) + varargin{1} = 'query'; +end + +switch varargin{1} + case 'on' + if numel(varargin)>1 + % switch a specific item on + msgId = varargin{2}; + s = setstate(s, msgId, 'on'); + if strcmp(msgId, 'backtrace') + defaultbacktrace = false; + end + if strcmp(msgId, 'verbose') + defaultverbose = false; + end + % return the message state of all + varargout{1} = getreturnstate(s, msgId); + else + % switch all on + s = setstate(s, 'all', 'on'); + % return the message state of all + varargout{1} = getreturnstate(s); + end + + case 'off' + if numel(varargin)>1 + % switch a specific item off + msgId = varargin{2}; + s = setstate(s, msgId, 'off'); + if strcmp(msgId, 'backtrace') + defaultbacktrace = false; + end + if strcmp(msgId, 'verbose') + defaultverbose = false; + end + % return the specific message state + varargout{1} = getreturnstate(s, msgId); + else + % switch all off + s = setstate(s, 'all', 'off'); + % return the message state of all + varargout{1} = getreturnstate(s); + end + + case 'once' + if numel(varargin)>1 + % switch a specific item to once + msgId = varargin{2}; + s = setstate(s, msgId, 'once'); + % return the specific message state + varargout{1} = getreturnstate(s, msgId); + else + % switch all to once + s = setstate(s, 'all', 'once'); + % return the message state of all + varargout{1} = getreturnstate(s); + end + + case 'timeout' + % set the timeout, this is used for 'once' + if ischar(varargin{2}) + s = setstate(s, 'timeout', str2double(varargin{2})); + else + s = setstate(s, 'timeout', varargin{2}); + end + + case {'last' '-last'} + % return the last notification + varargout{1} = getstate(s, 'last'); + + case {'clear' '-clear'} + % reset the notification system + s = []; + + case {'query' '-query'} + if numel(varargin)>1 + % select a specific item + msgId = varargin{2}; + if ~ismember(msgId, {s.identifier}) + error('Unknown setting or incorrect message identifier ''%s''.', msgId); + end + msgState = getstate(s, msgId); + if nargout + varargout{1} = getreturnstate(s, msgId); + elseif strcmp(msgId, 'verbose') + if istrue(msgState) + fprintf('%s output is verbose.\n', level); + else + fprintf('%s output is terse.\n', level); + end + elseif strcmp(msgId, 'backtrace') + if istrue(msgState) + fprintf('%s backtraces are enabled.\n', level); + else + fprintf('%s backtraces are disabled.\n', level); + end + else + fprintf('The state of %s ''%s'' is ''%s''\n', level, msgId, msgState); + end + else + % return all items + r = getreturnstate(s); + + if nargout + % return the state of all items + varargout{1} = r; + else + % show the state of all items that are different from the default + default = getstate(s, 'all'); + fprintf('The default %s state is ''%s''.', level, default); + r = r(~strcmp({r.state}, default)); + % don't show these + r(strcmp('verbose', {r.identifier})) = []; + r(strcmp('backtrace', {r.identifier})) = []; + if ~isempty(r) + fprintf(' Items not set to the default are\n\n'); + end + for i=1:numel(r) + fprintf(' %4s %s\n', r(i).state, r(i).identifier); + end + fprintf('\n'); + end + end + + otherwise + + if nargout + varargout{1} = getreturnstate(s); + end + + % first input might be msgId + if numel(varargin)>1 && ~isempty(regexp(varargin{1}, '^\w*:', 'once')) + msgId = varargin{1}; + varargin = varargin(2:end); % shift them all by one + else + msgId = defaultId; + end + + % get the state for this notification, it will default to the 'all' state + msgState = getstate(s, msgId); + + % errors are always to be printed + if strcmp(level, 'error') + msgState = 'on'; + end + + if strcmp(msgState, 'once') + timeout = getstate(s, 'timeout'); + since = elapsed(gettimestamp(s, msgId)); + if (since>timeout) + % the timeout has passed, update the timestamp and print the message + s = settimestamp(s, msgId, tic); + msgState = 'on'; + else + % the timeout has not yet passed, do not print the message + msgState = 'off'; + end + end + + % use an automatically generated default identifier + if isempty(msgId) + msgId = defaultId; + end + + % store the last notification + state.message = strtrim(sprintf(varargin{:})); % remove the trailing newline + state.identifier = msgId; + state.stack = stack; + s = setstate(s, 'last', state); + + if strcmp(msgState, 'on') + + if strcmp(level, 'error') + % update the global variable, we won't return here after the error + ft_default.notification.(level) = s; + % the remainder is fully handled by the ERROR function + if ~isempty(msgId) + error(msgId, varargin{:}); + else + error(varargin{:}); + end + + elseif strcmp(level, 'warning') + if ~isempty(msgId) + warning(msgId, varargin{:}); + else + warning(varargin{:}); + end + + else + % ensure there is a line end + if isempty(regexp(varargin{1}, '\\n$', 'once')) % note the double \\ + varargin{1} = [varargin{1} '\n']; + end + fprintf(varargin{:}); + + end % if level=error, warning or otherwise + + % decide whether the stack trace should be shown + if istrue(getstate(s, 'backtrace')) + for i=1:numel(stack) + % show the deepest and lowest-level function first + [p, f, x] = fileparts(stack(i).file); + if isequal(f, stack(i).name) + funname = stack(i).name; + else + funname = sprintf('%s>%s', f, stack(i).name); + end + filename = stack(i).file; + if isempty(fileparts(filename)) + % it requires the full path + filename = fullfile(pwd, filename); + end + if ft_platform_supports('html') + fprintf(' In %s at line %d\n', filename, stack(i).line, funname, stack(i).line); + else + fprintf(' In ''%s'' at line %d\n', filename, stack(i).line); + end + end + fprintf('\n'); + end + + % decide whether a verboe message should be shown + if istrue(getstate(s, 'verbose')) + if ~isempty(msgId) + fprintf('Type "ft_%s off %s" to suppress this message.\n', level, msgId) + else + fprintf('Type "ft_%s off" to suppress this message.\n', level) + end + end + + end % if msgState is on + +end % switch varargin{1} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% update the global variable +if defaultbacktrace && ~isempty(s) + % do not keep the default, it will be determined again on the next call + s = s(~strcmp({s.identifier}, 'backtrace')); +end +if defaultverbose && ~isempty(s) + % do not keep the default, it will be determined again on the next call + s = s(~strcmp({s.identifier}, 'verbose')); +end +ft_default.notification.(level) = s; + +if strcmp(level, 'warning') + % return to the original warning state + warning(ws); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTIONS +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +function r = getreturnstate(s, msgId) +if nargin<2 + r = s; + % don't return these + r(strcmp('timeout', {r.identifier})) = []; + r(strcmp('last', {r.identifier})) = []; + % don't return the timestamps + r = rmfield(r, 'timestamp'); +else + msgState = getstate(s, msgId); + r = struct('identifier', msgId, 'state', msgState); +end + +function state = getstate(s, msgId) +identifier = {s.identifier}; +sel = find(strcmp(identifier, msgId)); +if numel(sel)==1 + state = s(sel).state; + if isempty(state) + state = getstate(s, 'all'); + end +else + state = getstate(s, 'all'); +end + +function timestamp = gettimestamp(s, msgId) +identifier = {s.identifier}; +sel = find(strcmp(identifier, msgId)); +if numel(sel)==1 + timestamp = s(sel).timestamp; +else + timestamp = nan; +end + +function s = setstate(s, msgId, state) +if isempty(msgId), return; end % this happens from the command line +identifier = {s.identifier}; +sel = find(strcmp(identifier, msgId)); +if numel(sel)==1 + s(sel).state = state; +else + s(end+1).identifier = msgId; + s(end ).state = state; + s(end ).timestamp = nan; +end + +function s = settimestamp(s, msgId, timestamp) +if isempty(msgId), return; end % this happens from the command line +identifier = {s.identifier}; +sel = find(strcmp(identifier, msgId)); +if numel(sel)==1 + s(sel).timestamp = timestamp; +else + s(end+1).identifier = msgId; + s(end ).state = []; + s(end ).timestamp = timestamp; +end + +function t = elapsed(start) +if isempty(start) || isnan(start) + t = inf; +else + t = toc(start); +end diff --git a/external/fieldtrip/utilities/private/ft_platform_supports.m b/external/fieldtrip/forward/private/ft_platform_supports.m similarity index 56% rename from external/fieldtrip/utilities/private/ft_platform_supports.m rename to external/fieldtrip/forward/private/ft_platform_supports.m index 0770d385..c0676b62 100644 --- a/external/fieldtrip/utilities/private/ft_platform_supports.m +++ b/external/fieldtrip/forward/private/ft_platform_supports.m @@ -3,41 +3,43 @@ % FT_PLATFORM_SUPPORTS returns a boolean indicating whether the current platform % supports a specific capability % -% Usage: -% tf = ft_platform_supports(what) -% tf = ft_platform_supports('matlabversion', min_version, max_version) +% Use as +% status = ft_platform_supports(what) +% or +% status = ft_platform_supports('matlabversion', min_version, max_version) % -% The following values are allowed for the 'what' parameter: -% value means that the following is supported: +% The following values are allowed for the 'what' parameter, which means means that +% the specific feature explained on the right is supported: % % 'which-all' which(...,'all') -% 'exists-in-private-directory' exists(...) will look in the /private -% subdirectory to see if a file exists +% 'exists-in-private-directory' exists(...) will look in the /private subdirectory to see if a file exists % 'onCleanup' onCleanup(...) % 'alim' alim(...) % 'int32_logical_operations' bitand(a,b) with a, b of type int32 % 'graphics_objects' graphics sysem is object-oriented -% 'libmx_c_interface' libmx is supported through mex in the -% C-language (recent Matlab versions only -% support C++) -% 'stats' all statistical functions in -% FieldTrip's external/stats directory +% 'libmx_c_interface' libmx is supported through mex in the C-language (recent MATLAB versions only support C++) +% 'images' all image processing functions in FieldTrip's external/images directory +% 'signal' all signal processing functions in FieldTrip's external/signal directory +% 'stats' all statistical functions in FieldTrip's external/stats directory % 'program_invocation_name' program_invocation_name() (GNU Octave) -% 'singleCompThread' start Matlab with -singleCompThread -% 'nosplash' -nosplash -% 'nodisplay' -nodisplay -% 'nojvm' -nojvm +% 'singleCompThread' start MATLAB with -singleCompThread +% 'nosplash' start MATLAB with -nosplash +% 'nodisplay' start MATLAB with -nodisplay +% 'nojvm' start MATLAB with -nojvm % 'no-gui' start GNU Octave with --no-gui % 'RandStream.setGlobalStream' RandStream.setGlobalStream(...) % 'RandStream.setDefaultStream' RandStream.setDefaultStream(...) % 'rng' rng(...) % 'rand-state' rand('state') % 'urlread-timeout' urlread(..., 'Timeout', t) -% 'griddata-vector-input' griddata(...,...,...,a,b) with a and b -% vectors -% 'griddata-v4' griddata(...,...,...,...,...,'v4'), -% that is v4 interpolation support +% 'griddata-vector-input' griddata(...,...,...,a,b) with a and b vectors +% 'griddata-v4' griddata(...,...,...,...,...,'v4') with v4 interpolation support % 'uimenu' uimenu(...) +% 'weboptions' weboptions(...) +% 'parula' parula(...) +% 'html' html rendering in desktop +% +% See also FT_VERSION, VERSION, VER, VERLESSTHAN if ~ischar(what) error('first argument must be a string'); @@ -60,30 +62,42 @@ tf = is_matlab(); case 'int32_logical_operations' - % earlier version of Matlab don't support bitand (and similar) + % earlier version of MATLAB don't support bitand (and similar) % operations on int32 - tf = is_octave() || ~matlabversion(-inf, '2012a'); + tf = is_octave() || ~matlabversion(-Inf, '2012a'); case 'graphics_objects' - % introduced in Matlab 2014b, graphics is handled through objects; + % introduced in MATLAB 2014b, graphics is handled through objects; % previous versions use numeric handles tf = is_matlab() && matlabversion('2014b', Inf); case 'libmx_c_interface' % removed after 2013b - tf = matlabversion(-Inf, '2013b'); + tf = is_matlab() && matlabversion(-Inf, '2013b'); + + case 'images' + root_dir = fileparts(which('ft_defaults')); + external_stats_dir = fullfile(root_dir, 'external', 'images'); + + tf = has_all_functions_in_dir(external_stats_dir, {}); + + case 'signal' + root_dir = fileparts(which('ft_defaults')); + external_stats_dir = fullfile(root_dir, 'external', 'signal'); + + tf = has_all_functions_in_dir(external_stats_dir, {}); case 'stats' - root_dir=fileparts(which('ft_defaults')); - external_stats_dir=fullfile(root_dir,'external','stats'); + root_dir = fileparts(which('ft_defaults')); + external_stats_dir = fullfile(root_dir, 'external', 'stats'); - % these files are only used by other functions in the external/stats - % directory - exclude_mfiles={'common_size.m',... - 'iscomplex.m',... - 'lgamma.m'}; + % these files are only used by other functions in the external/stats directory + exclude_mfiles = { + 'common_size.m' + 'iscomplex.m' + }; - tf = has_all_functions_in_dir(external_stats_dir,exclude_mfiles); + tf = has_all_functions_in_dir(external_stats_dir, exclude_mfiles); case 'program_invocation_name' % Octave supports program_invocation_name, which returns the path @@ -91,10 +105,10 @@ tf = is_octave(); case 'singleCompThread' - tf = is_matlab() && matlabversion(7.8, inf); + tf = is_matlab() && matlabversion(7.8, Inf); - case {'nosplash','nodisplay','nojvm'} - % Only on Matlab + case {'nosplash', 'nodisplay', 'nojvm'} + % Only on MATLAB tf = is_matlab(); case 'no-gui' @@ -105,31 +119,46 @@ tf = is_matlab() && matlabversion('2008b', '2011b'); case 'RandStream.setGlobalStream' - tf = is_matlab() && matlabversion('2012a', inf); + tf = is_matlab() && matlabversion('2012a', Inf); case 'randomized_PRNG_on_startup' - tf = is_octave() || ~matlabversion(-Inf,'7.3'); + tf = is_octave() || ~matlabversion(-Inf, '7.3'); case 'rng' - % recent Matlab versions - tf = is_matlab() && matlabversion('7.12',Inf); + % recent MATLAB versions + tf = is_matlab() && matlabversion('7.12', Inf); case 'rand-state' % GNU Octave tf = is_octave(); case 'urlread-timeout' - tf = is_matlab() && matlabversion('2012b',Inf); + tf = is_matlab() && matlabversion('2012b', Inf); case 'griddata-vector-input' tf = is_matlab(); case 'griddata-v4' - tf = is_matlab() && matlabversion('2009a',Inf); + tf = is_matlab() && matlabversion('2009a', Inf); case 'uimenu' tf = is_matlab(); + case {'weboptions', 'webread', 'websave'} + tf = is_matlab() && matlabversion('2014b', Inf); + + case 'webwrite' + tf = is_matlab() && matlabversion('2015a', Inf); + + case 'boundary' + tf = is_matlab() && matlabversion('2014b', Inf); + + case 'parula' + tf = is_matlab() && matlabversion('2014b', Inf); + + case 'html' + tf = ~is_octave() && usejava('desktop') && desktop('-inuse'); + otherwise error('unsupported value for first argument: %s', what); @@ -148,7 +177,7 @@ % SUBFUNCTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function tf = is_octave() -persistent cached_tf; +persistent cached_tf if isempty(cached_tf) cached_tf = logical(exist('OCTAVE_VERSION', 'builtin')); @@ -161,21 +190,19 @@ % SUBFUNCTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function tf = has_all_functions_in_dir(in_dir, exclude_mfiles) -% returns true if all functions in in_dir are already provided by the -% platform -m_files=dir(fullfile(in_dir,'*.m')); -n=numel(m_files); +% returns true if all functions in in_dir are already provided by the platform +m_files = dir(fullfile(in_dir,'*.m')); +n = numel(m_files); -for k=1:n - m_filename=m_files(k).name; - if isempty(which(m_filename)) && ... - isempty(strmatch(m_filename,exclude_mfiles)) - tf=false; +for k = 1:n + m_filename = m_files(k).name; + if isempty(which(m_filename)) && isempty(strmatch(m_filename,exclude_mfiles)) + tf = false; return; end end -tf=true; +tf = true; end % function @@ -187,19 +214,19 @@ % MATLABVERSION checks if the current MATLAB version is within the interval % specified by min and max. % -% Use, e.g., as: -% if matlabversion(7.0, 7.9) -% % do something -% end +% Use as +% if matlabversion(7.0, 7.9) +% % do something +% end % % Both strings and numbers, as well as infinities, are supported, eg.: -% matlabversion(7.1, 7.9) % is version between 7.1 and 7.9? -% matlabversion(6, '7.10') % is version between 6 and 7.10? (note: '7.10', not 7.10) -% matlabversion(-Inf, 7.6) % is version <= 7.6? -% matlabversion('2009b') % exactly 2009b -% matlabversion('2008b', '2010a') % between two versions -% matlabversion('2008b', Inf) % from a version onwards -% etc. +% matlabversion(7.1, 7.9) % is version between 7.1 and 7.9? +% matlabversion(6, '7.10') % is version between 6 and 7.10? (note: '7.10', not 7.10) +% matlabversion(-Inf, 7.6) % is version <= 7.6? +% matlabversion('2009b') % exactly 2009b +% matlabversion('2008b', '2010a') % between two versions +% matlabversion('2008b', Inf) % from a version onwards +% etc. % % See also VERSION, VER, VERLESSTHAN @@ -209,22 +236,22 @@ % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. % -% FieldTrip is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. % -% FieldTrip is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. % -% You should have received a copy of the GNU General Public License -% along with FieldTrip. If not, see . +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . % % $Id$ -% this does not change over subsequent calls, making it persistent speeds it up +% the version does not change, making it persistent speeds up the subsequent calls persistent curVer if nargin<2 @@ -245,7 +272,9 @@ [maxY, maxAb] = parseMatlabRelease(max); inInterval = orderedComparison(minY, minAb, maxY, maxAb, year, ab); -else % perform comparison with respect to version number + +else + % perform comparison with respect to version number [major, minor] = parseMatlabVersion(curVer); [minMajor, minMinor] = parseMatlabVersion(min); [maxMajor, maxMinor] = parseMatlabVersion(max); @@ -255,6 +284,9 @@ end % function +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function [year, ab] = parseMatlabRelease(str) if (str == Inf) year = Inf; ab = Inf; @@ -266,6 +298,9 @@ end end % function +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function [major, minor] = parseMatlabVersion(ver) if (ver == Inf) major = Inf; minor = Inf; @@ -279,10 +314,13 @@ major = str2num(major); minor = str2num(strtok(rest, '.')); end -end % function +end % function -% checks if testA is in interval (lowerA,upperA); if at edges, checks if testB is in interval (lowerB,upperB). +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function inInterval = orderedComparison(lowerA, lowerB, upperA, upperB, testA, testB) +% checks if testA is in interval (lowerA,upperA); if at edges, checks if testB is in interval (lowerB,upperB). if (testA < lowerA || testA > upperA) inInterval = false; else @@ -295,5 +333,4 @@ inInterval = inInterval && (testB <= upperB); end end -end % function - +end % function diff --git a/external/fieldtrip/forward/private/ft_scalingfactor.m b/external/fieldtrip/forward/private/ft_scalingfactor.m index 804871df..ad7a8512 100644 --- a/external/fieldtrip/forward/private/ft_scalingfactor.m +++ b/external/fieldtrip/forward/private/ft_scalingfactor.m @@ -87,7 +87,7 @@ end if ~isequal(class(old), class(new)) - error('the input arguments should be of the same class'); + ft_error('the input arguments should be of the same class'); end if iscell(old) @@ -178,7 +178,7 @@ eval(sprintf('oldunit = %s;', old)); eval(sprintf('newunit = %s;', new)); if ~isequal(oldunit, newunit) - error('cannot convert %s to %s', old, new); + ft_error('cannot convert %s to %s', old, new); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/external/fieldtrip/forward/private/ft_warning.m b/external/fieldtrip/forward/private/ft_warning.m index 18b0ce00..58f3985e 100644 --- a/external/fieldtrip/forward/private/ft_warning.m +++ b/external/fieldtrip/forward/private/ft_warning.m @@ -1,39 +1,40 @@ -function [ws, warned] = ft_warning(varargin) +function varargout = ft_warning(varargin) -% FT_WARNING will throw a warning for every unique point in the -% stacktrace only, e.g. in a for-loop a warning is thrown only once. +% FT_WARNING prints a warning message on screen, depending on the verbosity +% settings of the calling high-level FieldTrip function. This function works +% similar to the standard WARNING function, but also features the "once" mode. % -% Use as one of the following -% ft_warning(string) -% ft_warning(id, string) -% Alternatively, you can use ft_warning using a timeout -% ft_warning(string, timeout) -% ft_warning(id, string, timeout) -% where timeout should be inf if you don't want to see the warning ever -% again. +% Use as +% ft_warning(...) +% with arguments similar to fprintf, or +% ft_warning(msgId, ...) +% with arguments similar to warning. % -% Use as ft_warning('-clear') to clear old warnings from the current -% stack +% You can switch of all warning messages using +% ft_warning off +% or for specific ones using +% ft_warning off msgId % -% It can be used instead of the MATLAB built-in function WARNING, thus as -% s = ft_warning(...) -% or as -% ft_warning(s) -% where s is a structure with fields 'identifier' and 'state', storing the -% state information. In other words, ft_warning accepts as an input the -% same structure it returns as an output. This returns or restores the -% states of warnings to their previous values. +% To switch them back on, you would use +% ft_warning on +% or for specific ones using +% ft_warning on msgId +% +% Warning messages are only printed once per timeout period using +% ft_warning timeout 60 +% ft_warning once +% or for specific ones using +% ft_warning once msgId % -% It can also be used as -% [s w] = ft_warning(...) -% where w is a boolean that indicates whether a warning as been thrown or not. +% You can see the most recent messages and identifier using +% ft_warning last % -% Please note that you can NOT use it like this -% ft_warning('the value is %d', 10) -% instead you should do -% ft_warning(sprintf('the value is %d', 10)) +% You can query the current on/off/once state for all messages using +% ft_warning query +% +% See also FT_ERROR, FT_WARNING, FT_NOTICE, FT_warning, FT_DEBUG, ERROR, WARNING -% Copyright (C) 2012-2016, Robert Oostenveld, J?rn M. Horschig +% Copyright (C) 2012-2017, Robert Oostenveld, J?rn M. Horschig % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -53,205 +54,12 @@ % % $Id$ -global ft_default -warned = false; -ws = []; - -stack = dbstack; -if any(strcmp({stack(2:end).file}, 'ft_warning.m')) - % don't call FT_WARNING recursively, see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=3068 - return; -end - -if nargin < 1 - error('You need to specify at least a warning message'); -end - -if isstruct(varargin{1}) - warning(varargin{1}); - return; -end - -if ~isfield(ft_default, 'warning') - ft_default.warning = []; -end -if ~isfield(ft_default.warning, 'stopwatch') - ft_default.warning.stopwatch = []; -end -if ~isfield(ft_default.warning, 'identifier') - ft_default.warning.identifier = []; -end -if ~isfield(ft_default.warning, 'ignore') - ft_default.warning.ignore = {}; -end - -% put the arguments we will pass to warning() in this cell array -warningArgs = {}; - -if nargin==3 - % calling syntax (id, msg, timeout) - - warningArgs = varargin(1:2); - msg = warningArgs{2}; - timeout = varargin{3}; - fname = [warningArgs{1} '_' warningArgs{2}]; - -elseif nargin==2 && isnumeric(varargin{2}) - % calling syntax (msg, timeout) - - warningArgs = varargin(1); - msg = warningArgs{1}; - timeout = varargin{2}; - fname = warningArgs{1}; - -elseif nargin==2 && isequal(varargin{1}, 'off') - - ft_default.warning.ignore = union(ft_default.warning.ignore, varargin{2}); - return - -elseif nargin==2 && isequal(varargin{1}, 'on') - - ft_default.warning.ignore = setdiff(ft_default.warning.ignore, varargin{2}); - return - -elseif nargin==2 && ~isnumeric(varargin{2}) - % calling syntax (id, msg) - - warningArgs = varargin(1:2); - msg = warningArgs{2}; - timeout = inf; - fname = [warningArgs{1} '_' warningArgs{2}]; - -elseif nargin==1 - % calling syntax (msg) - - warningArgs = varargin(1); - msg = warningArgs{1}; - timeout = inf; % default timeout in seconds - fname = [warningArgs{1}]; - -end - -if ismember(msg, ft_default.warning.ignore) - % do not show this warning - return; -end - -if isempty(timeout) - error('Timeout ill-specified'); -end - -if timeout ~= inf - fname = fixname(fname); % make a nice string that is allowed as fieldname in a structures - line = []; -else - % here, we create the fieldname functionA.functionB.functionC... - [tmpfname, ft_default.warning.identifier, line] = fieldnameFromStack(ft_default.warning.identifier); - if ~isempty(tmpfname), - fname = tmpfname; - clear tmpfname; - end -end - -if nargin==1 && ischar(varargin{1}) && strcmp('-clear', varargin{1}) - if strcmp(fname, '-clear') % reset all fields if called outside a function - ft_default.warning.identifier = []; - ft_default.warning.stopwatch = []; - else - if issubfield(ft_default.warning.identifier, fname) - ft_default.warning.identifier = rmsubfield(ft_default.warning.identifier, fname); - end - end - return; -end - -% and add the line number to make this unique for the last function -fname = horzcat(fname, line); - -if ~issubfield('ft_default.warning.stopwatch', fname) - ft_default.warning.stopwatch = setsubfield(ft_default.warning.stopwatch, fname, tic); -end - -now = toc(getsubfield(ft_default.warning.stopwatch, fname)); % measure time since first function call - -if ~issubfield(ft_default.warning.identifier, fname) || ... - (issubfield(ft_default.warning.identifier, fname) && now>getsubfield(ft_default.warning.identifier, [fname '.timeout'])) - - % create or reset field - ft_default.warning.identifier = setsubfield(ft_default.warning.identifier, fname, []); - - % warning never given before or timed out - ws = warning(warningArgs{:}); - ft_default.warning.identifier = setsubfield(ft_default.warning.identifier, [fname '.timeout'], now+timeout); - ft_default.warning.identifier = setsubfield(ft_default.warning.identifier, [fname '.ws'], msg); - warned = true; +if nargout + varargout{:} = ft_notification(varargin{:}); +elseif isequal(varargin, {'last'}) + % return an answer anyway + varargout{1} = ft_notification(varargin{:}); else - - % the warning has been issued before, but has not timed out yet - ws = getsubfield(ft_default.warning.identifier, [fname '.ws']); - -end - -end % function ft_warning - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% helper functions -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -function [fname, ft_previous_warnings, line] = fieldnameFromStack(ft_previous_warnings) -% stack(1) is this function, stack(2) is ft_warning -stack = dbstack('-completenames'); -if size(stack) < 3 - fname = []; - line = []; - return; -end -i0 = 3; -% ignore ft_preamble -while strfind(stack(i0).name, 'ft_preamble') - i0=i0+1; + ft_notification(varargin{:}); end -fname = horzcat(fixname(stack(end).name)); -if ~issubfield(ft_previous_warnings, fixname(stack(end).name)) - ft_previous_warnings.(fixname(stack(end).name)) = []; % iteratively build up structure fields -end - - -for i=numel(stack)-1:-1:(i0) - % skip postamble scripts - if strncmp(stack(i).name, 'ft_postamble', 12) - break; - end - - fname = horzcat(fname, '.', horzcat(fixname(stack(i).name))); % , stack(i).file - if ~issubfield(ft_previous_warnings, fname) % iteratively build up structure fields - setsubfield(ft_previous_warnings, fname, []); - end -end - -% line of last function call -line = ['.line', int2str(stack(i0).line)]; -end - -% function outcome = issubfield(strct, fname) -% substrindx = strfind(fname, '.'); -% if numel(substrindx) > 0 -% % separate the last fieldname from all former -% outcome = eval(['isfield(strct.' fname(1:substrindx(end)-1) ', ''' fname(substrindx(end)+1:end) ''')']); -% else -% % there is only one fieldname -% outcome = isfield(strct, fname); -% end -% end - -% function strct = rmsubfield(strct, fname) -% substrindx = strfind(fname, '.'); -% if numel(substrindx) > 0 -% % separate the last fieldname from all former -% strct = eval(['rmfield(strct.' fname(1:substrindx(end)-1) ', ''' fname(substrindx(end)+1:end) ''')']); -% else -% % there is only one fieldname -% strct = rmfield(strct, fname); -% end -% end diff --git a/external/fieldtrip/forward/private/ft_warp_apply.m b/external/fieldtrip/forward/private/ft_warp_apply.m index 980e1b88..fa7fa903 100644 --- a/external/fieldtrip/forward/private/ft_warp_apply.m +++ b/external/fieldtrip/forward/private/ft_warp_apply.m @@ -102,19 +102,19 @@ s = size(M); if s(1)~=3 - error('invalid size of nonlinear transformation matrix'); + ft_error('invalid size of nonlinear transformation matrix'); elseif strcmp(method, 'nonlin0') && s(2)~=1 - error('invalid size of nonlinear transformation matrix'); + ft_error('invalid size of nonlinear transformation matrix'); elseif strcmp(method, 'nonlin1') && s(2)~=4 - error('invalid size of nonlinear transformation matrix'); + ft_error('invalid size of nonlinear transformation matrix'); elseif strcmp(method, 'nonlin2') && s(2)~=10 - error('invalid size of nonlinear transformation matrix'); + ft_error('invalid size of nonlinear transformation matrix'); elseif strcmp(method, 'nonlin3') && s(2)~=20 - error('invalid size of nonlinear transformation matrix'); + ft_error('invalid size of nonlinear transformation matrix'); elseif strcmp(method, 'nonlin4') && s(2)~=35 - error('invalid size of nonlinear transformation matrix'); + ft_error('invalid size of nonlinear transformation matrix'); elseif strcmp(method, 'nonlin5') && s(2)~=56 - error('invalid size of nonlinear transformation matrix'); + ft_error('invalid size of nonlinear transformation matrix'); end if s(2)==1 @@ -143,7 +143,7 @@ yy = M(2,1) + M(2,2)*x + M(2,3)*y + M(2,4)*z + M(2,5)*x.*x + M(2,6)*x.*y + M(2,7)*x.*z + M(2,8)*y.*y + M(2,9)*y.*z + M(2,10)*z.*z + M(2,11)*x.*x.*x + M(2,12)*x.*x.*y + M(2,13)*x.*x.*z + M(2,14)*x.*y.*y + M(2,15)*x.*y.*z + M(2,16)*x.*z.*z + M(2,17)*y.*y.*y + M(2,18)*y.*y.*z + M(2,19)*y.*z.*z + M(2,20)*z.*z.*z + M(2,21)*x.*x.*x.*x + M(2,22)*x.*x.*x.*y + M(2,23)*x.*x.*x.*z + M(2,24)*x.*x.*y.*y + M(2,25)*x.*x.*y.*z + M(2,26)*x.*x.*z.*z + M(2,27)*x.*y.*y.*y + M(2,28)*x.*y.*y.*z + M(2,29)*x.*y.*z.*z + M(2,30)*x.*z.*z.*z + M(2,31)*y.*y.*y.*y + M(2,32)*y.*y.*y.*z + M(2,33)*y.*y.*z.*z + M(2,34)*y.*z.*z.*z + M(2,35)*z.*z.*z.*z + M(2,36)*x.*x.*x.*x.*x + M(2,37)*x.*x.*x.*x.*y + M(2,38)*x.*x.*x.*x.*z + M(2,39)*x.*x.*x.*y.*y + M(2,40)*x.*x.*x.*y.*z + M(2,41)*x.*x.*x.*z.*z + M(2,42)*x.*x.*y.*y.*y + M(2,43)*x.*x.*y.*y.*z + M(2,44)*x.*x.*y.*z.*z + M(2,45)*x.*x.*z.*z.*z + M(2,46)*x.*y.*y.*y.*y + M(2,47)*x.*y.*y.*y.*z + M(2,48)*x.*y.*y.*z.*z + M(2,49)*x.*y.*z.*z.*z + M(2,50)*x.*z.*z.*z.*z + M(2,51)*y.*y.*y.*y.*y + M(2,52)*y.*y.*y.*y.*z + M(2,53)*y.*y.*y.*z.*z + M(2,54)*y.*y.*z.*z.*z + M(2,55)*y.*z.*z.*z.*z + M(2,56)*z.*z.*z.*z.*z; zz = M(3,1) + M(3,2)*x + M(3,3)*y + M(3,4)*z + M(3,5)*x.*x + M(3,6)*x.*y + M(3,7)*x.*z + M(3,8)*y.*y + M(3,9)*y.*z + M(3,10)*z.*z + M(3,11)*x.*x.*x + M(3,12)*x.*x.*y + M(3,13)*x.*x.*z + M(3,14)*x.*y.*y + M(3,15)*x.*y.*z + M(3,16)*x.*z.*z + M(3,17)*y.*y.*y + M(3,18)*y.*y.*z + M(3,19)*y.*z.*z + M(3,20)*z.*z.*z + M(3,21)*x.*x.*x.*x + M(3,22)*x.*x.*x.*y + M(3,23)*x.*x.*x.*z + M(3,24)*x.*x.*y.*y + M(3,25)*x.*x.*y.*z + M(3,26)*x.*x.*z.*z + M(3,27)*x.*y.*y.*y + M(3,28)*x.*y.*y.*z + M(3,29)*x.*y.*z.*z + M(3,30)*x.*z.*z.*z + M(3,31)*y.*y.*y.*y + M(3,32)*y.*y.*y.*z + M(3,33)*y.*y.*z.*z + M(3,34)*y.*z.*z.*z + M(3,35)*z.*z.*z.*z + M(3,36)*x.*x.*x.*x.*x + M(3,37)*x.*x.*x.*x.*y + M(3,38)*x.*x.*x.*x.*z + M(3,39)*x.*x.*x.*y.*y + M(3,40)*x.*x.*x.*y.*z + M(3,41)*x.*x.*x.*z.*z + M(3,42)*x.*x.*y.*y.*y + M(3,43)*x.*x.*y.*y.*z + M(3,44)*x.*x.*y.*z.*z + M(3,45)*x.*x.*z.*z.*z + M(3,46)*x.*y.*y.*y.*y + M(3,47)*x.*y.*y.*y.*z + M(3,48)*x.*y.*y.*z.*z + M(3,49)*x.*y.*z.*z.*z + M(3,50)*x.*z.*z.*z.*z + M(3,51)*y.*y.*y.*y.*y + M(3,52)*y.*y.*y.*y.*z + M(3,53)*y.*y.*y.*z.*z + M(3,54)*y.*y.*z.*z.*z + M(3,55)*y.*z.*z.*z.*z + M(3,56)*z.*z.*z.*z.*z; else - error('invalid size of nonlinear transformation matrix'); + ft_error('invalid size of nonlinear transformation matrix'); end warped = [xx yy zz]; @@ -188,7 +188,7 @@ %error('individual2sn is not yet implemented'); warped = individual2sn(M, input); else - error('unrecognized transformation method'); + ft_error('unrecognized transformation method'); end if ~input3d diff --git a/external/fieldtrip/forward/private/halfspace_medium_leadfield.m b/external/fieldtrip/forward/private/halfspace_medium_leadfield.m index c49203e4..5a63d8cd 100644 --- a/external/fieldtrip/forward/private/halfspace_medium_leadfield.m +++ b/external/fieldtrip/forward/private/halfspace_medium_leadfield.m @@ -38,7 +38,7 @@ rd = rd'; rd = rd(:)'; % ensure that it is a row vector else - error('incorrect specification of dipole locations'); + ft_error('incorrect specification of dipole locations'); end Nelc = size(elc,1); @@ -69,10 +69,10 @@ invacuum = acos(dot(ori,(P-pnt)./norm(P-pnt))) < pi/2; if invacuum - warning('dipole lies on the vacuum side of the plane'); + ft_warning('dipole lies on the vacuum side of the plane'); lf(:,(1:3) + 3*(i-1)) = NaN(Nelc,3); elseif any(R1)==0 - warning('dipole coincides with one of the electrodes'); + ft_warning('dipole coincides with one of the electrodes'); lf(:,(1:3) + 3*(i-1)) = NaN(Nelc,3); else lf(:,(1:3) + 3*(i-1)) = (r ./ [R1 R1 R1]) + (rp ./ [R2 R2 R2]); diff --git a/external/fieldtrip/forward/private/hasyokogawa.m b/external/fieldtrip/forward/private/hasyokogawa.m index b98d91bb..cf309aab 100644 --- a/external/fieldtrip/forward/private/hasyokogawa.m +++ b/external/fieldtrip/forward/private/hasyokogawa.m @@ -74,7 +74,7 @@ elseif [0 2 2 5] == [rev_ADbitInfoM rev_ChannelInfoM rev_AmpGainM rev_MatchingInfoM] version='16bitBeta6'; else - warning('The version of the installed Yokogawa toolbox cannot be determined.'); + ft_warning('The version of the installed Yokogawa toolbox cannot be determined.'); end catch m = lasterror; diff --git a/external/fieldtrip/forward/private/headsurface.m b/external/fieldtrip/forward/private/headsurface.m index 0c77bc32..1e5677d3 100644 --- a/external/fieldtrip/forward/private/headsurface.m +++ b/external/fieldtrip/forward/private/headsurface.m @@ -87,7 +87,7 @@ % using innermost sphere radius = min(headmodel.r); otherwise - error('other surfaces cannot be constructed this way'); + ft_error('other surfaces cannot be constructed this way'); end if isfield(headmodel, 'o') origin = headmodel.o; @@ -125,13 +125,13 @@ % local spheres MEG model, this also requires a gradiometer structure grad = sens; if ~isfield(grad, 'tra') || ~isfield(grad, 'coilpos') - error('incorrect specification for the gradiometer array'); + ft_error('incorrect specification for the gradiometer array'); end Nchans = size(grad.tra, 1); Ncoils = size(grad.tra, 2); Nspheres = size(headmodel.o, 1); if Nspheres~=Ncoils - error('there should be just as many spheres as coils'); + ft_error('there should be just as many spheres as coils'); end % for each coil, determine a surface point using the corresponding sphere vec = grad.coilpos - headmodel.o; @@ -172,7 +172,7 @@ pos = headmodel.bnd(headmodel.source).pos; tri = headmodel.bnd(headmodel.source).tri; otherwise - error('other surfaces cannot be constructed this way'); + ft_error('other surfaces cannot be constructed this way'); end end @@ -211,7 +211,7 @@ tri = fliplr(tri); ori = -ori; else - warning('cannot determine the orientation of the vertex normals'); + ft_warning('cannot determine the orientation of the vertex normals'); % nothing to do end % the orientation is outward, hence shift with a negative amount diff --git a/external/fieldtrip/forward/private/icosahedron.m b/external/fieldtrip/forward/private/icosahedron.m index 2798b1f7..b6d65c34 100644 --- a/external/fieldtrip/forward/private/icosahedron.m +++ b/external/fieldtrip/forward/private/icosahedron.m @@ -25,7 +25,6 @@ % You should have received a copy of the GNU General Public License % along with FieldTrip. If not, see . % -% $Id$ tri = [ 1 2 3 diff --git a/external/fieldtrip/forward/private/icosahedron162.m b/external/fieldtrip/forward/private/icosahedron162.m index a39f3ee9..ae3bfe69 100644 --- a/external/fieldtrip/forward/private/icosahedron162.m +++ b/external/fieldtrip/forward/private/icosahedron162.m @@ -20,7 +20,6 @@ % You should have received a copy of the GNU General Public License % along with FieldTrip. If not, see . % -% $Id$ [pos, tri] = icosahedron; [pos, tri] = refine(pos, tri); diff --git a/external/fieldtrip/forward/private/icosahedron2562.m b/external/fieldtrip/forward/private/icosahedron2562.m index 26fdf53d..11752a0c 100644 --- a/external/fieldtrip/forward/private/icosahedron2562.m +++ b/external/fieldtrip/forward/private/icosahedron2562.m @@ -1,4 +1,4 @@ -function [pnt, tri] = icosahedron() +function [pnt, tri] = icosahedron2562() % ICOSAHEDRON2562 creates a 4-fold refined icosahedron diff --git a/external/fieldtrip/forward/private/icosahedron42.m b/external/fieldtrip/forward/private/icosahedron42.m index 86a1425a..833c11eb 100644 --- a/external/fieldtrip/forward/private/icosahedron42.m +++ b/external/fieldtrip/forward/private/icosahedron42.m @@ -20,7 +20,6 @@ % You should have received a copy of the GNU General Public License % along with FieldTrip. If not, see . % -% $Id$ [pos, tri] = icosahedron; [pos, tri] = refine(pos, tri); diff --git a/external/fieldtrip/forward/private/icosahedron642.m b/external/fieldtrip/forward/private/icosahedron642.m index cc4b5a15..4d932e5c 100644 --- a/external/fieldtrip/forward/private/icosahedron642.m +++ b/external/fieldtrip/forward/private/icosahedron642.m @@ -20,7 +20,6 @@ % You should have received a copy of the GNU General Public License % along with FieldTrip. If not, see . % -% $Id$ [pos, tri] = icosahedron; [pos, tri] = refine(pos, tri); diff --git a/external/fieldtrip/forward/private/inf_medium_leadfield.m b/external/fieldtrip/forward/private/inf_medium_leadfield.m index 89bd5c28..1ff42b98 100644 --- a/external/fieldtrip/forward/private/inf_medium_leadfield.m +++ b/external/fieldtrip/forward/private/inf_medium_leadfield.m @@ -35,7 +35,7 @@ rd = rd'; rd = rd(:); else - error('incorrect specification of dipole locations'); + ft_error('incorrect specification of dipole locations'); end Npnt = size(pnt,1); @@ -51,7 +51,7 @@ r = pnt - ones(Npnt,1) * rd((1:3) + 3*(i-1)); R = (4*pi*cond) * (sum(r' .^2 ) .^ 1.5)'; if any(R==0) - warning('dipole lies on boundary of volume model'); + ft_warning('dipole lies on boundary of volume model'); end lf(:,(1:3) + 3*(i-1)) = r ./ [R R R]; end diff --git a/external/fieldtrip/forward/private/istrue.m b/external/fieldtrip/forward/private/istrue.m index 79631e32..742a0997 100644 --- a/external/fieldtrip/forward/private/istrue.m +++ b/external/fieldtrip/forward/private/istrue.m @@ -1,7 +1,7 @@ function y = istrue(x) -% ISTRUE ensures that a true/false input argument like "yes", "true" -% or "on" is converted into a boolean +% ISTRUE converts an input argument like "yes/no", "true/false" or "on/off" into a +% boolean. If the input is boolean, then it will remain like that. % Copyright (C) 2009-2012, Robert Oostenveld % diff --git a/external/fieldtrip/forward/private/keyval.m b/external/fieldtrip/forward/private/keyval.m index b176ce8d..0043c72b 100644 --- a/external/fieldtrip/forward/private/keyval.m +++ b/external/fieldtrip/forward/private/keyval.m @@ -44,7 +44,7 @@ end if mod(length(varargin),2) - error('optional input arguments should come in key-value pairs, i.e. there should be an even number'); + ft_error('optional input arguments should come in key-value pairs, i.e. there should be an even number'); end % the 1st, 3rd, etc. contain the keys, the 2nd, 4th, etc. contain the values @@ -58,7 +58,7 @@ end if ~all(valid) - error('optional input arguments should come in key-value pairs, the optional input argument %d is invalid (should be a string)', i); + ft_error('optional input arguments should come in key-value pairs, the optional input argument %d is invalid (should be a string)', i); end hit = find(strcmpi(key, keys)); @@ -69,7 +69,7 @@ % the requested key was found val = vals{hit}; else - error('multiple input arguments with the same name'); + ft_error('multiple input arguments with the same name'); end if nargout>1 diff --git a/external/fieldtrip/forward/private/leadfield_openmeeg.m b/external/fieldtrip/forward/private/leadfield_openmeeg.m index 8bf64916..e47f7b66 100644 --- a/external/fieldtrip/forward/private/leadfield_openmeeg.m +++ b/external/fieldtrip/forward/private/leadfield_openmeeg.m @@ -70,7 +70,7 @@ case 'binary' om_ext = '.bin'; otherwise - error('invalid OpenMEEG output type requested'); + ft_error('invalid OpenMEEG output type requested'); end OPENMEEG_PATH = []; % '/usr/local/bin/'; % In case OpenMEEG executables omitted from PATH variable @@ -78,7 +78,7 @@ persistent ldLibraryPath0; if ispc - warning('Sorry, Windows is not yet tested'); + ft_warning('Sorry, Windows is not yet tested'); elseif isunix setenv('OMP_NUM_THREADS',num2str(CPU_LIM)); if(~ismac) % MacOS doesn't use LD_LIBRARY_PATH; in case of problems, look into "DYLD_LIBRARY_PATH" @@ -92,7 +92,7 @@ [om_status,om_errmsg] = system(fullfile(OPENMEEG_PATH,'om_assemble')); % returns 0 if om_assemble is not happy if(om_status ~= 0) - error([om_errmsg 'Unable to properly execute OpenMEEG. Please configure variable declarations and paths in this file as needed.']); + ft_error([om_errmsg 'Unable to properly execute OpenMEEG. Please configure variable declarations and paths in this file as needed.']); else clear om_status end @@ -137,10 +137,10 @@ fprintf(fid,'%.15f\t%.15f\t%.15f\t%.15f\t%.15f\t%.15f\n',sens.coilpos(ii,:),sens.coilori(ii,:)); end else - if(size(sens.tra,1) < max(chanlabel_idx) | size(sens.tra,2) ~= length(coilpos_idx) | length(coilpos_idx) ~= size(sens.coilpos,1)) + if(size(sens.tra,1) < max(chanlabel_idx) || size(sens.tra,2) ~= length(coilpos_idx) || length(coilpos_idx) ~= size(sens.coilpos,1)) % These dimensions should match; if not, some channels may have been % removed, or there's unexpected handling of MEG reference coils - error('Mismatch between number of rows in sens.tra and number of channels... possibly some channels removed or unexpected MEG reference coil configuration'); + ft_error('Mismatch between number of rows in sens.tra and number of channels... possibly some channels removed or unexpected MEG reference coil configuration'); end for ii=1:length(coilpos_idx) @@ -189,7 +189,7 @@ disp('Validating mesh...') [om_status om_msg] = system([fullfile(OPENMEEG_PATH, 'om_check_geom'), ' -g ', geomFile]) if(om_status ~= 0) % status = 0 if successful - error([om_msg, 'Aborting OpenMEEG pipeline due to above error.']); + ft_error([om_msg, 'Aborting OpenMEEG pipeline due to above error.']); end disp('Writing dipole file...') @@ -214,7 +214,7 @@ disp('Building head matrix') [om_status, om_msg] = system([fullfile(OPENMEEG_PATH, 'om_assemble'), ' -hm ', geomFile, ' ', condFile, ' ', hmFile]) if(om_status ~= 0) % status = 0 if successful - error([om_msg, 'Aborting OpenMEEG pipeline due to above error.']); + ft_error([om_msg, 'Aborting OpenMEEG pipeline due to above error.']); end end @@ -229,7 +229,7 @@ else [om_status, om_msg] = system([fullfile(OPENMEEG_PATH, 'om_minverser'), ' ', hmFile, ' ', hminvFile]) if(om_status ~= 0) % status = 0 if successful - error([om_msg, 'Aborting OpenMEEG pipeline due to above error.']); + ft_error([om_msg, 'Aborting OpenMEEG pipeline due to above error.']); end end end @@ -244,7 +244,7 @@ disp('Assembling source matrix'); [om_status, om_msg] = system([fullfile(OPENMEEG_PATH, 'om_assemble'), ' -dsm ', geomFile, ' ', condFile, ' ', dipFile{ii}, ' ' dsmFile{ii}]) if(om_status ~= 0) % status = 0 if successful - error([om_msg, 'Aborting OpenMEEG pipeline due to above error. If 4-layer BEM attempted, try 3-layer BEM (scalp, skull, brain).']); + ft_error([om_msg, 'Aborting OpenMEEG pipeline due to above error. If 4-layer BEM attempted, try 3-layer BEM (scalp, skull, brain).']); end end end @@ -271,7 +271,7 @@ disp('Calculating Contribution of Ohmic Currents') [om_status, om_msg] = system([fullfile(OPENMEEG_PATH, 'om_assemble'), ' ', cmd, ' ', geomFile, ' ', condFile, ' ' , sensorFile, ' ' , ohmicFile]) if(om_status ~= 0) % status = 0 if successful - error([om_msg, 'Aborting OpenMEEG pipeline due to above error.']); + ft_error([om_msg, 'Aborting OpenMEEG pipeline due to above error.']); end end @@ -285,7 +285,7 @@ else [om_status, om_msg] = system([fullfile(OPENMEEG_PATH, 'om_assemble'), ' -ds2mm ', dipFile{ii} ,' ', sensorFile, ' ' , scFile{ii}]) if(om_status ~= 0) % status = 0 if successful - error([om_msg, 'Aborting OpenMEEG pipeline due to above error.']); + ft_error([om_msg, 'Aborting OpenMEEG pipeline due to above error.']); end end end @@ -319,13 +319,13 @@ end end if(om_status ~= 0) % status = 0 if successful - error([om_msg, 'Aborting OpenMEEG pipeline due to above error.']); + ft_error([om_msg, 'Aborting OpenMEEG pipeline due to above error.']); end end % Import lead field/potential [g, voxels_in] = import_gain(path, basefile, ft_senstype(sens, 'eeg')); -if (voxels_in ~= voxels) & (nargout == 1); warning('Imported voxels from OpenMEEG process not the same as function input.'); end; +if (voxels_in ~= voxels) && (nargout == 1); ft_warning('Imported voxels from OpenMEEG process not the same as function input.'); end; lp = sens.tra*g; % Mchannels x (3 orientations x Nvoxels) @@ -333,7 +333,7 @@ if cleanup_flag rmdir(basepath,'s') end -if (isunix & ~ismac) +if (isunix && ~ismac) setenv('LD_LIBRARY_PATH',ldLibraryPath0); end @@ -398,7 +398,7 @@ function write_mesh(vol,path,basefile) case 'binary' om_ext = '.bin'; otherwise - error('invalid OpenMEEG output type requested'); + ft_error('invalid OpenMEEG output type requested'); end if eegflag diff --git a/external/fieldtrip/forward/private/leadfield_simbio.m b/external/fieldtrip/forward/private/leadfield_simbio.m index fbf6af60..5107816b 100644 --- a/external/fieldtrip/forward/private/leadfield_simbio.m +++ b/external/fieldtrip/forward/private/leadfield_simbio.m @@ -23,6 +23,6 @@ end lf = lf'; catch - warning('an error occurred while running simbio'); + ft_warning('an error occurred while running simbio'); rethrow(lasterror) -end \ No newline at end of file +end diff --git a/external/fieldtrip/forward/private/leadsphere_all.m b/external/fieldtrip/forward/private/leadsphere_all.m index e7a71147..345df226 100644 --- a/external/fieldtrip/forward/private/leadsphere_all.m +++ b/external/fieldtrip/forward/private/leadsphere_all.m @@ -1,5 +1,5 @@ -function out=leadsphere_chans(xloc,sensorloc,sensorori) -% usage: out=leadsphere_chans(xloc,sensorloc,sensorori) +function out=leadsphere_all(xloc,sensorloc,sensorori) +% usage: out=leadsphere_all(xloc,sensorloc,sensorori) % Copyright (C) 2003, Guido Nolte % diff --git a/external/fieldtrip/forward/private/lmoutr.m b/external/fieldtrip/forward/private/lmoutr.m index 121b8301..acb88964 100644 --- a/external/fieldtrip/forward/private/lmoutr.m +++ b/external/fieldtrip/forward/private/lmoutr.m @@ -1,4 +1,4 @@ -function [varargout] = funname(varargin) +function [varargout] = lmoutr(varargin) % LMOUTR computes the la/mu parameters of a point projected to a triangle % @@ -60,7 +60,7 @@ try % try to compile the mex file on the fly - warning('trying to compile MEX file from %s', mexsrc); + ft_warning('trying to compile MEX file from %s', mexsrc); cd(mexdir); if ispc @@ -77,7 +77,7 @@ catch % compilation failed disp(lasterr); - error('could not locate MEX file for %s', mexname); + ft_error('could not locate MEX file for %s', mexname); cd(pwdir); success = false; end diff --git a/external/fieldtrip/forward/private/lmoutr.mexa64 b/external/fieldtrip/forward/private/lmoutr.mexa64 index db385e19c20d6e51d3eece19e335e84627fbec09..eb8e4f4765beaef50b18b6103743f1aeffc3f2e8 100755 GIT binary patch delta 1218 zcmY*ZZA@Eb6u#&7^A6VAPx>)iU>4dJx|Z`zUMj5 zdwO%bn!1|$_6hSoF2Cka96V>M@o32!VigQJ|1u3c`|dI4)SfH9jhs%5*M2oH_Kh+N z%K+ahGrE8drWCX3HGoq%Xbw>vGjD?h`(vzKvqUa1@Uf*1IFLkrO{XZ)g<56OCg1WKOgiyamca;bG_)5~#}E z>Kaz9O0sUJtPk##liZ99YLzt|XN-~7`Zo0--(pd9pHzQuZ|rNW&X-M}xyD#d+?>gY zHl4_-Wxb-5T*tx9J6c`9$aE9C10JkW6n|sdoeDSz*gKZ`oWJKqMv7r zcuL&Hmzwbxu^eVluzpy1beXZ2e-K|fL$=9g^1SM+$i#6^-$Q9#Mzw5G(+c(0Iq`n= z*8YER!MYWm!kDexFDWg6ElGILyzs9Aa}*z64%o+n=;_=eZxe233(s};A@joZrZ7UC;u9A7A_6#oALd_q~qqaDpCP<~DyTdmYcE$TRtTa~z( zw{kU@-Ry=8MVAt|&CbId#wwx|_g5StQ+Tl=0yHO+u>BI;JZJ8$3d6aOF1G@A(k delta 1127 zcmYL}eQXnT7{`ClUEB4#Zg;n}>sn|xrCk}))+NM^KmrBpZnHzg&5Rc(3$SH>xI{t& zSybkROAaV>KDZDw1O7oWHO4JB%rJ%*oe|?7!arspFOg_C;v}wSf?M@`u7i2W@A*8> z-S2sx?{jYhodcbjox-?}<&W{ft_!lId?8pQu7*>t6W@H+C;jfa)z$Lpa4t03cd#|k zu1!M@;Iwv+5AbkCvlk2jwBadxnC!RqYS@7@WVhiGp&D8-AX zylvlA$XHJxwG;=P9_)1rum%r1n?3g(jAg~IE?YaqAx4Yp%#GZ>V)CskO@DbuCKc4rJv5B0DD(QL z>BL3Z64cL-i$4}eh19%ZB-ICc1dGHb*pJ)AN_ZLH5dBbx?~8uUH;?DU4P34O{}HQT z5`)s&+M%3byz`TIXq@y=|HNgp;f#&3y=y6Kx@c;-V}=oPoUGVtj^m#~NnQhoF)3I1 zcg^J`B_@8Wi>p)0k*1NPI+s-MC)K-pJsy`o^fiz`CH>|VMZKjLl0QMSGPBPRHkJ&- zYk0RL3<(rVgRmA?l?FM_9BwP^4un$6^iTd=m@~oj(~n)d{vNp+xaxs4G`Ls8X6$#b ztyYEFDE*U_+v7Xpuf*HF`#O`!v?%JYO4^#BON;SKO8>N7Ibxl% zRnq>4#y+o-_J5BK&oa2JMLkc#!2?wB1ZiHGHH=AO8}S$7=R^yY3Xq&2aS!oX;upl- z#O7JUI7-YtFpMvWJv96c;@IDY;p7;5o^IVL;wE|syNSd9(te_gYMTf2Y+-Of!XL_I zxPd>H$6zPQ-U`@@HDo`=7s+Pvb#KKJUQ*Ixro@Y-jRRbfjoa)jurn5!}0Jr+WH6qF7NzP)?J;(WDmbCS#t-pZ3 z28$K)O{l^h9P@=adrrIVJI}qlWIdkrk8*mM))+W%qgPM}#T*^)863^#2LWDGB@aPtzg;LHjS^pbUJfu~A17{!`M zjBI;kKZ(HWktn={LiAN&*cI)B5xg2*2WL@^#b67@WA(xdB@4BAZ7}9Be-0l#eUtkS DX~}#_ diff --git a/external/fieldtrip/forward/private/lmoutr.mexmaci64 b/external/fieldtrip/forward/private/lmoutr.mexmaci64 index 4079df72268abdefc3086b0facdcac955419c106..d226f9b07e5aab8aa9ae1ad2516aeb1e2293d563 100755 GIT binary patch literal 13240 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 delta 830 zcmYL{ZAcVB9L9INJ3GufPrXb%#TPCuUov!N_jYF!D_1h`&=XH111khGEfOt?@Qg$7 zSjuX_K4jnrr6l@LXMHH6Lcd2$tFkzP`!^g^?8O9M0W{D05GyfD*K)>C#V zoK^LAxsHjnAQP3f5f~Z9Oo7^IYg6Juk?vCyqwE1ApwYhowncf8^bF&j)YrP@E~^|} zUrp9@>%hATx-7D}hJ>_Q*J)~TWHAi+Fl9qUK2^%}0n_5nD~#HCN3$V{3?818V$<8jlb;$wf-2>660i=g6g6-O?w0 zCpJ~PV_iOJmBdlq%Cv%3;FErnUoc85uDPZUZjmOZ3kz_BX*miv0251Yzkj z$aTqqR8pWSDJ_spvQ<@;siYV=#c9N*&SZM4aeB-tz5RlJz&N4@?TTnxpkt1?1&IEB z^GTgD1T0q)#z2MtUIGTx`j%K^I<%Rw(8ZWSI`2{ntu}y^N~_HGbL! z@wX)3HFzvA38ukpxD{@PyP*@-!zS1a&%jX_p>T0#xAlp?g)308{}?qx4Ea> zG&j$!adD0`N3F-v;5h9#=g8sn`JMa${siB}zvn;jpZPHVhmR393B^LU;1#Y44}>Y< zweVI52}?pEw&5IHfQzvMmtrSw#D{SUK8`!_S$rP%;eI@Tuj65S3;XdyJb_>0863bN d{1vZYAezJkFo&G diff --git a/external/fieldtrip/forward/private/lmoutr.mexw64 b/external/fieldtrip/forward/private/lmoutr.mexw64 index 8ad4f5717ed062ac51e339371314fb2148f44c0d..ab5adac34f0bc2b9a2a4442b63d695307ddb8702 100755 GIT binary patch delta 1664 zcmZ8heN0b`wE2E^qk-Cob$Wq zezvWwl?C+3&;R(XrfVjhUf?nGG3oR@zLS1KzY6|IcS$YJuOozM7JZ*U{{r@Fx<1p1|>4tn7krI zzq(eMqW7+q9um@CJ|3CXazx}Yt4EvF4~MzUqv?8mn5THOTl%x${gepdwWsn!4CNgw zDKoytFnaUtDvre=JdX$y(^!${G$!z?guLjOIe%0rYE@n@p) zYCo0;d0@5upi2>iG?rQ)y?j*iCL%MW&!QC0?D3W8Kbyj>SX-OhhNV8R+KGO7O)_OA z`Q>slI2x5B(ffQcrs;(bVhJ&_noWP$^mV3x+Vq8{KOaNL$m*x0n)zp(eFR+% z8^-DlMH9Szim9@?5loej@=LMr?)@o+koJ)EqY$=Vx@}OE2aw1Q&3ddoxf7t?O^uBK zeEW24)KD%)uU7j}_34^?p1*BLO+SOkP_ClP+OgRMZ#mQAkDJL}-ecL~ZbQjXjtGG& zSE2x@0_0Drjyw?_b3D$MEO{*ifj5Kg8uF$tPkJ-ToRnF6il>t?>Ga)*Qf*$7Zy;z7 zdE@#X5qFn_ySuxabt-4X9G&q2K$)6*4kCRHcZprLHyefl#p_{3JwP8vX-IB?3g=JS z9~Szeu#|TYGk|d08`Am~l{&IX1b@CtMi|90uO~{}jo|{llU*sJLuQa$6 zLhc;Lfs1Pm-zd{2aiDo97>aoIOf7R4;zw-wEKIv@DDR2g`}(jWqQ8WZ0jMQY?Os)D z@%jcaK9N^j-KpP+_pQp`BgHh2yTnkw2xm_5F6)~y|A=9ojyajf+V)3Z3P-)X#&(&G z@icqQ_EDUGku_%e8Pnf0y?Fn4gW1@x&xSLsL|5WlXDDy*({>jv;KTOKG>PB0Z!Gu~ zuas$Z?mR=e4O*s6l;=+w$}em9q>yxa+=VN}QC^(*WR8k|pYp%QJ*wjv81rAr9x$?& zpf$4oHNCh^BTJHkpCulkUvF?y+8uN$wN#m3PsoW3LR_&DiT%(*Y>9--^R6Vn>k~)# z4OHUy@kA;i4KRV_h<5@5ydZg-U8pbv*`G$pDOiZVmAqS7$!6Qq$HXJxPT(OdUX2351 z=V3*e7>i|n3p)rN0#3rJGD$VL1+oBZMuDUgvKQ70UIpZ^0Jsw?uZ5ij7rS^L)(zeb Y9Dogjj{-m41k4QHmJ(<%+PM(%AL^#dHx+wmVe-3L{z?hT>G65Gde#k@(&KVC54I41YBwn9$I|z~RzR&Z%?{m(3 zzHU2dCynrgX6sV(*@Yabm!(LLShCNvDrrFaD0*AkW9fK0kr1lec$L7ws-&fhs3;y; z{dO8oYjzS6&*+WG+_^4vP!X=l=D4`hDwJkMZ&dj2@sgworNXamR`x4UB2$d!jamGw z&C)F1w^`aEqkw;gbzQ~Wpx#H6~e>TpueEJ;U4?ZLjAspXV5u+%Vt*6X* zoMN>5|EU=o>hkts7&j8c*sCJGAmSA>o}l`wi~nKr(`JF{GyI2WNFI}gcPa{zgTl6{l%Q&ciduwY1|AX8rW*kl4 zsE(tmaa|r_y3L()8Ihr0N0|n3@T>j?s;7NmCP&z??LqH3lnk|72tslT3V>sPirJ8- zR)lYR>X_YL-k~7y=hHo7e)s*ReT(bBr?uhj{FJs=T4L_>d})eRryrHt*~Rpijy*A$G*s`c#7AprHmXk;>KU{pU+-! zc-`NL_Z*V1B1Ltdx7JX`6#uZsp132{B37Gs0e0hNT;<)Oq-^ zIh=q|c*FE-rvKOU1l{oli?Lr#!5Ow-R-z>uY6lx|=1Ke5jI&58Vuo|u&Skt(svq%| z8|rP)dVQv$V%AXq+{EXFB<%B6t{3OnQ?6YlJ@~b0_8-;eWf4b=v z)4MFuyqp)M&$s4EQY4zEJ};^BTL`(3Pe@*>g`~b?BZ>=W&CX^7^13|nH&BD`!|Nub z2_|qi;)j5pY-eVvQ>d^e@_05O=U|suduENgp3OwH9@Zoh)%*pHwq?gG9qX+H zuHbIEund7Mcq)GI2yg{90#5L%>}Wg*t^f~U0c+r5QLn?6!8?IHum$j5;BTgetb;(k7wmC4?5JN^i79rll85+g;IJ-0wegCUG34 z;;|2Nlym;;`Og3UbB^Q8$$Qtoy)mCL&pgJM7hOj0y@j!Zpwwk z(1h|PWMDGDFrw6S-7@+to44hecy$YG+lgwMk}OzTQO){o#vXM&V`V!tQ>x1Nihs0C zD})Eho+)qSD)9awbT*#eVw5Kf?EdE(3L%qTn1u7zSMrN-$*iE@zC6-UR3& z&|A^BqL(-FrA}+k)rK)&Y{3~WcS53dTKd-?-f{nfHT{QQUcC6pe?Cd)lBc#{A!7>{ zviltwl-eS6%7^CC+D_Y;?u}SI4MbuZdY4dw1F$3#@u_kGg>ZtXyBKs1BDN;Iq?Y@%a2c$Y3-oKbvBDSN8*^_` zbmzIceH?%Q^A^UrX_NyW<@{LTHPE6|6Ub|Wf$@XKng)Xt(%)mG^h@%sMM;i&Rmpd{ zD1|2_-`gOkic;t;=%1G*-v^|I4D&P4)dWYj3{@{sOQ&dZ14Y%8yWEt!-jw_Kn-yKs zpZw*p977uz^=bnr(2sl7(i@mp6C4JTF#+@An}+<$J=$Hw|r2v}lQh6*pjA z0=Ml)imD_p9V7M_XG_G6`z7BP9NUfuB;WS{ZM%XbE)=D&;B%F)iqJoid_RDPOyPyEc1b%McH>tnyye^eYBL>Y zp+y4n_I#Hr)t-_5=JoLBntTb$z%V6)^{J?+EV!?Lb`eq*_V6_bKN4I+t$@3V0O-M@ z%gGVR2lp`CF%1DBQF&!Gc}g9|i?#;gqaJ*l!0j}}ILRaED2gJSrDcx;^8{vuM=^ws z5&BD5ir0}Bg9rCH4-Q`6k=GUS4;-N}c?<;(6)>RMkl!KkU2t;4e!dz~QKb--E;~-# zPZ&Cop3FB2?bR^0PUt#mXum)Mm>U>u9Zj-zmq>S!#P7+O$A!n%_BE-#!xmXZGw*|~ zMF#3QNNpD>uuB+fVsD~2;TOE*^C)Jtm1x=x3^n`z&jJsBE*-q~zfuWj?vOSZ#JR-* zcq8e*4MN%4Mj1Y2_V!yo-Qbl z+P{weqj+xLL!-Gnl8DEYSR9U- zc*<0|Qt1jWrJmiC+uECRTgRHS$xb7!q`H)7PsB8hL`I3FjErI;fn>yr_9&f(wZ|~b zsSK30O2mvQ>-hKfyF>xXDHWdn?tKuH`Ze)4Eb;g(#CPH>0s_IGX2l=oUO4 z2EE-p`?fJppX`wr&G+VEnM*I+XAz(H62Df^4T5eKbgQ7x3OWnGRk#&!E8teZt$N5OE=;&Eygd^^-kOi;}ZOtT`bRb$u%4G zWZ$N=5wQ$^D%+Vbf)QLq_vsI;Q;iV2+(-lt`X=7J5o;G5U-uP}KO)q;`{X90Z z1TRQFqr1kDB_nj5$*zC02=BVt8g%={F!(M zL-&&qoq7B&5Hf!3w#~Lr$@KE8+}>Rwrz+$pvDi&#fjh-u86Ey+5XY_UjlIQBUS*yqeX z(_|BBL>4p?+~z;J{V_U(wiZ<){5PrmaF-_OTG-a2!6;0MI$+LzKxLT7I;i=4-rXg3 zLZ|W{fA~r7ec$K%>wVw%J>Q-0-78n#yIL(tt_n$#JgDnYmntP`0+i+Bs3YqnNz=M~ zJzauT+9;(^vN3#0a3hhjXqu^ym{#AyrT+GEaFkEc2!+^fb*3b)tGo}!tX^F;zVLhP@2hG8|qC@?$ zkw$EYp?*hx-FAAZ;dR>u&5{Av*twbcYU!?2GQs#*lV&({=beq8D>htXC$i-#u^R}5 zv}9v*v6;wuabDc6IL0fr+c%mt^;qMVN(`L@m1#Kx|3e16``Rf$@xC=UR;3d=xdAa8d>e;;f5O8hBk%I^QligGPN#B$HwBjE>-Sbs%uXn$<&#S#O zgCr~>;@q=nn7p5oB6$-tR|^IC_9w(DQt%7~$eTQI9FoOpG?8U_W_OxSdeJP73d1oP zI&xq7!`AdwUvqX(=H4yu)J$2k5p(f}=I+mIoTauuQ)AK4y#LffMc#*5ZIZ-fDUk zvy`5v_Giu^aB5Ug<2;2gP&h+4!=XRV#)YQ$EjE{t-`8Q_!!RQMfnSkBo71#8jokkM zq7T7+mE1XU=ZZNq0Eh$Zc_?3q$PJgEoD)tX@+0*P3<**!c~1_~S?HtoF45hKl$?SD zRq2=}dYK4%m~H?|Pf1__lk0mID)n#UmYSFQF41_F&HE5n{*hd-+(Ym_27M3Ihuny! zX90$lrz}H6tLz`+IKPMQ1$vk#!bGiUXNfRDAciLgUWC6}L&7@nDy)4+BXT3A+IR6l zlIC0o-xzzZKpR1d^t_CS1LxRaMKN!P#Udc#94nx6u04xX_&XFh$rv~LU&vGvOWWK@Kyhe9e#hzJqE>LZT z%@SsKmb+k{sPcJSWq@kkx6sI4$Myy+6l1IWE`?qQH;{c3o2_*a{szKLF~{*3fKOv;+ptFB(zZfBhfx5+GC>qv1m`AW$BEYs&2$n1B2?2F`P2hU}7K@ z(+x8zb;aXqENG0b5zwy9_+~IV6jsASP)-iT4K)%^tkP8Rzv;U4wqK{-4#b;^_3H^W z9#KPsLBr6aNi`hTld6Gv#DZpMQ0>>v1G;W3Pek3W292-^+oCd7)JOO77j2xi=;dGf zfAX`Z^S^uS3;yxle&k*`vE;v4mvyq(d3(jXP&J~cw3BlQDaTdr)l4Cu?ZUu&!q@uE@sP=Laisw{5 zlYLQ^^zNbaFoqe^l=X z;_!S#yL(3y&9fof>N!;S#4kEvUI)R+x;;3Iv86guduOy{Hx~x#7 zqTl1eT$X z_c5aMqIF5G<<~i1xA5`^e9I2`GCsTtKeY-!y9yr{c;$$guXA`_%u_;!z_&ObLq%y} zy_Q_X32rWZssE*GDcnB($E-^lKaK0z7PRX?h(yc|~@o%JtC6(VBsMhxeNvUKp eO83LHcLF5N9(hoK1_adH#;#piGul?JH#s30oqgyZU6uP delta 32 kcmZp$X|S2_fyMjZr_hOCe3+CXH#;#piGul?JH#s30qeRAi~s-t diff --git a/external/fieldtrip/forward/private/meg_leadfield1.mexw64 b/external/fieldtrip/forward/private/meg_leadfield1.mexw64 index c74501647a01fee1e28023e012640df8e9e0cd52..637143e23c2290dc3c1bfc01bb301d41dd26920b 100755 GIT binary patch delta 32 lcmZqhXz-Zufo0M2r;!uC_%OX$xY>!(Neay0+#y}T0RRYM4=(@! delta 32 kcmZqhXz-ZufhCyvbLhk`K1>-GH#;#pNrCyBJESW(0Nlk4i2wiq diff --git a/external/fieldtrip/forward/private/mesh2edge.m b/external/fieldtrip/forward/private/mesh2edge.m index 71b4c0e4..4fc082ae 100644 --- a/external/fieldtrip/forward/private/mesh2edge.m +++ b/external/fieldtrip/forward/private/mesh2edge.m @@ -99,7 +99,7 @@ end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% SUBFUNCTION, see http://bugzilla.fcdonders.nl/show_bug.cgi?id=1833#c12 +% SUBFUNCTION, see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=1833#c12 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function indx = findsingleoccurringrows(X) [X, indx] = sortrows(X); diff --git a/external/fieldtrip/forward/private/normals.m b/external/fieldtrip/forward/private/normals.m index 67eca678..03c0f8c3 100644 --- a/external/fieldtrip/forward/private/normals.m +++ b/external/fieldtrip/forward/private/normals.m @@ -28,12 +28,12 @@ if nargin<3 opt='vertex'; -elseif (opt(1)=='v' | opt(1)=='V') +elseif (opt(1)=='v' || opt(1)=='V') opt='vertex'; -elseif (opt(1)=='t' | opt(1)=='T') +elseif (opt(1)=='t' || opt(1)=='T') opt='triangle'; else - error('invalid optional argument'); + ft_error('invalid optional argument'); end npnt = size(pnt,1); diff --git a/external/fieldtrip/forward/private/plgndr.c b/external/fieldtrip/forward/private/plgndr.c new file mode 100644 index 00000000..d476d0b1 --- /dev/null +++ b/external/fieldtrip/forward/private/plgndr.c @@ -0,0 +1,123 @@ +/* + * The original plgndr function was implemented using some code from + * Numerical Recipes in C. However, it was not allowed to release that code + * as open source. The new implementation below is using some code from + * the GNU Scientific Library (http://www.gnu.org/software/gsl). + * + * Copyright (C) 2002-2006 Robert Oostenveld + * Copyright (C) 2006, Thomas Hartmann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include "mex.h" + +double legendre_Pmm(double m, double x) +{ + if(m == 0) + { + return 1.0; + } + else + { + double p_mm = 1.0; + double root_factor = sqrt(1.0-x)*sqrt(1.0+x); + double fact_coeff = 1.0; + int i; + for(i=1; i<=m; i++) + { + p_mm *= -fact_coeff * root_factor; + fact_coeff += 2.0; + } + return p_mm; + } +} + +double plgndr(int l, int m, double x) +{ + /* these are constant, but can only be assigned after checking the input arguments */ + double dif, sum, t_d, t_s, exp_check, err_amp; + + double p_mm, p_mmp1; + double result; + + /* determine whether we have correct input arguments */ + if (m < 0 || m > l || fabs(x) > 1.0) + mexErrMsgTxt ("Bad arguments in routine plgndr"); + + dif = l-m; + sum = l+m; + t_d = ( dif == 0.0 ? 0.0 : 0.5 * dif * (log(dif)-1.0) ); + t_s = ( dif == 0.0 ? 0.0 : 0.5 * sum * (log(sum)-1.0) ); + exp_check = 0.5 * log(2.0*l+1.0) + t_d - t_s; + err_amp = 1.0 / (0.00000000001 + fabs(1.0-fabs(x))); + p_mm = legendre_Pmm(m, x); + p_mmp1 = x * (2*m + 1) * p_mm; + + /* P_m^m(x) and P_{m+1}^m(x) */ + + if(l == m) + { + result = p_mm; + } + else if(l == m + 1) + { + result = p_mmp1; + } + else + { + /* + * upward recurrence: (l-m) P(l,m) = (2l-1) z P(l-1,m) - (l+m-1) P(l-2,m) + * start at P(m,m), P(m+1,m) + */ + + double p_ellm2 = p_mm; + double p_ellm1 = p_mmp1; + double p_ell = 0.0; + int ell; + + for(ell=(int)m+2; ell <= l; ell++) + { + p_ell = (x*(2*ell-1)*p_ellm1 - (ell+m-1)*p_ellm2) / (ell-m); + p_ellm2 = p_ellm1; + p_ellm1 = p_ell; + } + result = p_ell; + } + return result; +} + +void +mexFunction (int nlhs, mxArray * plhs[], int nrhs, const mxArray * prhs[]) +{ + int l, m; + double x; + double *pd; + + if (nrhs != 3) + mexErrMsgTxt ("invalid number of arguments for PLGNDR"); + + l = mxGetScalar (prhs[0]); + m = mxGetScalar (prhs[1]); + x = mxGetScalar (prhs[2]); + + plhs[0] = mxCreateDoubleMatrix (1, 1, mxREAL); + pd = mxGetData (plhs[0]); + pd[0] = plgndr(l, m, x); + + return; +} diff --git a/external/fieldtrip/forward/private/plgndr.m b/external/fieldtrip/forward/private/plgndr.m index 4796f6c8..8012d84a 100644 --- a/external/fieldtrip/forward/private/plgndr.m +++ b/external/fieldtrip/forward/private/plgndr.m @@ -1,4 +1,4 @@ -function [varargout] = funname(varargin) +function [varargout] = plgndr(varargin) % PLGNDR associated Legendre function % @@ -33,31 +33,30 @@ % compile the missing mex file on the fly % remember the original working directory pwdir = pwd; +pwdir_ressetter=onCleanup(@()cd(pwdir)); % determine the name and full path of this function funname = mfilename('fullpath'); mexsrc = [funname '.c']; [mexdir, mexname] = fileparts(funname); -try +mexfullpath=fullfile(mexdir,sprintf('%s.%s',mexname,mexext())); +disp(mexfullpath); +has_mex_func=@()exist(mexfullpath,'file'); + +if ~has_mex_func() % try to compile the mex file on the fly - warning('trying to compile MEX file from %s', mexsrc); + ft_warning('trying to compile MEX file from %s', mexsrc); cd(mexdir); mex(mexsrc); - cd(pwdir); - success = true; - -catch - % compilation failed - disp(lasterr); - error('could not locate MEX file for %s', mexname); - cd(pwdir); - success = false; -end -if success - % execute the mex file that was juist created - funname = mfilename; - funhandle = str2func(funname); - [varargout{1:nargout}] = funhandle(varargin{:}); + if ~has_mex_func() + ft_error('could not locate / compile MEX file for %s in %s', ... + mexname, mexfullpath); + end end + +% execute the mex file that was juist created +funname = mfilename; +funhandle = str2func(funname); +[varargout{1:nargout}] = funhandle(varargin{:}); diff --git a/external/fieldtrip/forward/private/plgndr.mexmaci64 b/external/fieldtrip/forward/private/plgndr.mexmaci64 index 150761817ac3a5560e95ce3bad034bb254698484..4433ed690bfec047ba593a38df65b483a1457369 100755 GIT binary patch literal 8768 zcmeHNU2GIp6uz@9w3NbZ2_jmQ!B|uIDQ!#?VhFpim2E5tv_Mhdy6w)k8}^Uc*}4UR z#@fgVCHv@u55^}SG||KueL&l-S}aBcBLXGZ#7GvaNnH~{h++NC%$>5`TH}KcKFmq( zJ@@>5_uMmgvO9C<{GH$KmN6!kFviN!oM^E*jP-*PJ%E;UFvfXnV_U1Cn%+@BAqg3n z3^0s15$C#^)XlLePsbadZ`$6*Ttp<7nnSZMWxa(W=W#vJ9-mSb=l9A&)3j80kStAk zW32*juF#oyyh{zmR1Lafyf+2jI^j>UNY&KL$gd+BiQijrG2Xbqa|t|>r>$4$Eyj6A zT-Sn;PN68qQ)JVyMc6Ibil3G%l$<9bF9joh9*hK{hCKaxbP2qD0)XUV3=5k$=V})Z zXuhy&YK!wbEAZ+?5XrRXW+U2nSv1Z)?pAk!m$lz!;k4ff*UFXiNQlRK!tK!zkLlX1 zcorPp0EKzc{wTaIoQHh>gy$4M3gU=JF2tk!tUX6|TBjF{^X8^)&o+9Rtb0s>lE_L- zF(l>^3nQGu{rm`Hz4hdxnD=oxxV85UHRLu7lHjz535M*GkmrHFvx2cV!09&Jjz&a2 zR-+ow{X84>BEI5pjMdQ5Jfp9D_(A&lb>$~2GR;pucW~lS=!~V!LsUftTWQJQM3rc? z9*U(LEOKcvpWd}L6l@PC>-;_7rsZGwtAznG{gVKa*xE!~BXnvVt5(%Dh)KwQ9ooHo z&Y&dI{abqCx*D$ARG8Oeh@o}9ubBLCArC?(T7^b-l4-p**%h!WU{}DdfL($Aq5`|T zshy2V9Y5vdwo!15 z_g?#$eu5EDa|Q$OHSZaLwYjuhdkzk8-1`lt`5Hmr%X@C+TJn;_ds@3FYn7AMVuM{;_1Wd;Rs7mjHRrK?AvU1i^DQV%)vNJFubKn6~O@ zHajjE2^`J#kLgFqzZ$0gv12`$@;e}&Mf&HF_E#AHh-@xnJcjJ9OfBI-1IxMQ7a+lD zGC))(FMri2x49mmOs(gO!u4E21lBXL5K}LB3kVaXG%2!APzi@7jtzLKCFJrg5Pm?r zFtAzjte-TjnTZz%Hak$JL1>P*!n5QPB*Rh}grY6?FgBo<|B1^5gi91n;P8i-fjELT zgau|yj|(~ZK&CI_7|`cS`618xTgQgHeV;pDa37#ro9i*^y~n-V-D=d_n>yE&y4825 zM6X0yH(~+V)5ySk^66|Zc+MlQzU@7Eq&!Q{KqQSra%TM`$yJS)KSKojl)8qC*-cpf-({vy1NL^N1-iQ`+Y~;O6^>)0EFh*0RK@vUh(*H|ped5`W#`Nq^i6@X{ z!ZS@F4ko1$ST(;?TEQFy$re)wk`C`=Qqn0oE6d8$u*{}6y=V6Cin%`$d{FRF!DmL; z8oL5^1?&pg6|gH{SHP}-T>-lSb_MJT*cGrVU{~P(UV*9=PUFOJu?vT3e&bM`x8qzG zhu}L7u{1m6ta9;ia7DFNpJ~?nalZbTa!Dxi74g^E0rXETJHP!En1-n%(PWpxt zHeQVvA(Qm}Wc>cLH0hu>8z$YkUP;H2tIFeTF$3Waj7DNp4}$yM)J_$zoK(I&9A;d+f1)Z*Rgi>Pia5RgvtLnItZQiw#Z{cKJIp-UU&E+b-2eap literal 8800 zcmeHNU2GIp6u#STVUfaYi5di?1F;DLE+v4rQFIr!vK5MjE>N`bvfG_)S9fR2>@1WY zV@=g$gH8H?@$W%=(8LE5^ohhoTBuqSu^Jv46Jrx&vKUNs!H5JIzcX{E-Q8Nki-`|& zl6%iR=iYPfIp3Yxow;|ux&G_T*^Id=8Dk!lc_`Pa7<(C<=pK~b3dT4OH?@aNRcYld z6`7FXlfexmPQ@n;4hd8f-mN5i6b;&Pe_g`gv%U7 z4kcq#_A~jj-O=@H+fG?cwK!LC%~_XTkFHIN&nq0+{zxufOS;~QapXK1xs^XzIFdyO zBp3UmeC=zPh7fKc6wbFbZ{OM!Y_{)N8A>8MFxiyYKH-e~6yG0C!KM#1TJZ$%-Z_^HtR z6bJoo%tSq~zoV#gP`2A12JQ+x}%&1e*7&Iv^ z`KlW5hqfy&tr!dCem=Z3yQCm_A6O0DIp{t+E7kTDjllLI_~nAsF%P@?A;9^&>@h3zvhK^Cp-Ga&Yj_T2Y%`S>9&^V&+ z9@tue=!OD~=Z`*-8y(Q+7z5$C#{J{K5@WtMhEabD`wRV_SAd-{&e)D9n=gS6Jg*!w z$U{MTX7qW=YBMaqg@Ih*j@0Q)|v$Z42eTLT+;Z^-7%*xPs*K^kg17_Hh0v zIHf!uI(Ed9SA{eI$(!E?Y3+BPB2{*pDifOgqiBV4Uo_|3_vPvT8W6xbXF@SikXBzq z`JI&c{F^ro14fmIPd4K->ULwrjkejW<=*PC@+1D5C*&Nv@|c0<`Yx1-qIW-%?GBY$w2q_wDMO$Yi8PT9(F7o<#R_)XiX_a{^*~vu|hm3+9k69}OuNR#5 zWJpiDA4_RVM9^K}^C8>c5BP+9oDLX40Tk-T{*6gb3K@GjChbAJ6bFv>c{v?lOBi1- z&iiRc&&6Dm+eLkrj1d;SRVKezCVyN-vd~u+&m6Ac`}`TF5AO+Qt48#L#Oc8RElx2T_@951hVxNL57tq ZLFp>byuRqMSJrBZH7yO!{73(h&KFq2f44b_fXNrLZHop*;-~a&Q3=D<< delta 33 mcmZp0XmFVDgT?RPr_hOie3+jwGj8@~oGAtt*!)6Vf&%~p{|ghFfn~|_r;!uC_%QQGGH!NebQA{*Z0?Y#-~<5p5e>iq delta 33 lcmZp0X>ghFfhCmrbLhk`KFpmS44a)99mT-{n>!>bI04-E3>g3b diff --git a/external/fieldtrip/forward/private/project_elec.m b/external/fieldtrip/forward/private/project_elec.m index 9cb599e0..0454e10a 100644 --- a/external/fieldtrip/forward/private/project_elec.m +++ b/external/fieldtrip/forward/private/project_elec.m @@ -34,7 +34,7 @@ Nelc = size(elc,1); el = zeros(Nelc, 4); -% this is a work-around for http://bugzilla.fcdonders.nl/show_bug.cgi?id=2369 +% this is a work-around for http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2369 elc = double(elc); pnt = double(pnt); tri = double(tri); diff --git a/external/fieldtrip/forward/private/projecttri.m b/external/fieldtrip/forward/private/projecttri.m index 729f0ab5..f18a34e7 100644 --- a/external/fieldtrip/forward/private/projecttri.m +++ b/external/fieldtrip/forward/private/projecttri.m @@ -48,7 +48,7 @@ prj = elproj(pnt); tri = delaunay(prj(:,1), prj(:,2)); otherwise - error('unsupported method'); + ft_error('unsupported method'); end diff --git a/external/fieldtrip/forward/private/ptriproj.m b/external/fieldtrip/forward/private/ptriproj.m index 49b78585..2f482b1a 100644 --- a/external/fieldtrip/forward/private/ptriproj.m +++ b/external/fieldtrip/forward/private/ptriproj.m @@ -1,4 +1,4 @@ -function [varargout] = funname(varargin) +function [varargout] = ptriproj(varargin) % PTRIPROJ projects a point onto the plane going through a triangle % @@ -42,7 +42,7 @@ try % try to compile the mex file on the fly - warning('trying to compile MEX file from %s', mexsrc); + ft_warning('trying to compile MEX file from %s', mexsrc); cd(mexdir); if ispc @@ -59,7 +59,7 @@ catch % compilation failed disp(lasterr); - error('could not locate MEX file for %s', mexname); + ft_error('could not locate MEX file for %s', mexname); cd(pwdir); success = false; end diff --git a/external/fieldtrip/forward/private/ptriproj.mexa64 b/external/fieldtrip/forward/private/ptriproj.mexa64 index f81b3dc2867014088cf87682d39cefede563e615..1717147bf2c1be2e3467712a33a9e0b6279d7765 100755 GIT binary patch delta 1189 zcmY*ZZERCz6u#&7dtbMAZS8KM-G==@a4iy&(adZsv~p{@1jm**M4b`0OwA0+wArGQ z)UO*>DV&99GD3*{FflR8oyh_O!7T!R6pe`k&4`J{4JTpMIoPJJ=WXZ2H@WAz=Q;0r z-se3{?`ZdEcdpYGUn3M&{BX}_@^Do#Sw)P(ap$I`)2A{WTN0h^k-*TmjlulL1H<|( zI7QL#)vh8~sJ@l{+{(U_Bj>LbtTewtI=Ol(sNkiQA+W*n>H#1{&}a$qQcm zO7e+j(>uDUU9D%oRts?}T78mj1%?~?j>~2Gd4u{9Zlv8VLMIh2g0G-jFpLk5TyBT zA&k>6wU;pWH|-~Mk~Uw^-zq@bj@PPW7{R%!2-IM$QVp9iM)7HUg5pU$pj6jhA!qHp zC01eI{)Sj?7I&6etb*VtYL=b~JgIb$*W0jmmyLr7r~&wE1R@{)et(<|aT-j5-zCw&*p zBqs+VwzQicCkSaw2I_6Ol`MxEW&eE!E(PjK>`HN`UC~Q|XN}bV;|7;O5^{uY`ghA4 zT}D};YUReD2+bI+i%{&Tdx`I)_ZgJKkHa&#FWe2|cqQCKb5kM_n8ajchwW5lQQfD% O8*u~wvYgx`8vX%q)043P delta 1131 zcmYL}eQXnT7{`Cl^<}-TPG4;22@}OY~c@^IM)Cp zYRop|ghKJr1#krMuYrjXZx3WT`(t1a6wngJ^*+cCv73Je(^p?W0GtuzC<>Kr^F%HhpqNUpcjwXZ^IFMz5H=l zhu@Wt+jf*Q)?J%jg4Z2xEI341g+Dmb?wfYTO465?EbY>=Lc5f{Qj%oLs9jG~WMI>F zk!svo*D%+sYNn)S4kWb%`!xf+O3tk{45M9&RK$3q(6xws%L?u&W!NGI zVFbJ63l04kn^foksMf~x&kEGK`Mc4d4{Kc1`{ zfETc#Dg+7KRuzEN*jp74+*5e2DpOmZU0QtSuem)FteC&++KPST>Q6eGfHa(NHPVgx z-nB-MOXytu_hScdaY36cDveQlM(Uo8KNsH;-+KA0d_KQX)qYlUmIPf|h@Vn>CT!{< z%Ry@$<=-*7JZjFjAD?kAg>n5A_r37yUh4Q3Xj1l5i;!nhniDqh5OL79lUBvao zPl!8->Dz{Jm^d?O7@rcmY58l!^ZyuzLtyL)`s*GdZlIg6lQ{4%^VF`wuE1J{P%cB$wpohUnH+PAXHd|l%veXSb%<-pmPI) zH)Od;x&|@qt#;;x*~`3Q37uSY3^#lI(2x7PQ8!EVhW?|%KL)?Fl-D*$?gvC w;g#fni%Mi0Jt!|mI$#h-BWu8do@f-_!(_BcJY6~8Lq8F91OGmJ^nhUc4`;P_#Q*>R diff --git a/external/fieldtrip/forward/private/ptriproj.mexmaci64 b/external/fieldtrip/forward/private/ptriproj.mexmaci64 index 0a66a1cda8966143afc6d31867cf79fdfa0eb53a..4e2c04d79783bfa34c33d91e64371f8faffe78e3 100755 GIT binary patch literal 13304 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 Hn}+%ii(P(s literal 13360 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 diff --git a/external/fieldtrip/forward/private/ptriproj.mexw32 b/external/fieldtrip/forward/private/ptriproj.mexw32 index 1c274de1ec0d8e87e575dd4dc4ec7aab1898613d..caf4b04a31c23b3580069fdcff64e55851170fbe 100755 GIT binary patch delta 964 zcmYk4e{2(F7{}jtz3WEpi=(?r8k=VHv_ zMi8Zh{-MpQX8I-=)EG1o30ur!6NiZtjYX712)Mum8W6Mj8bJ##P=PSt>sI6aanJMp zem{5blPB+%t}R_7LKzIs_PljA2+Mp4Y^yo4jYr{5IF|nflA27}3qZD@Jd$EVP0Sk? zCl_?K42Lv!eL{R!)t(pY)2rHnR&`iPNs3RaDI98Gol0E1Q#D*%ckxAst*J|hOf_}! zR9#Y}|8rcvge0F{U|6R=F5>^^*Z32HR1FvZ-o+Ok7D$SK40Fz0We%V0-6L~OSzJ?P zpYkVj&Q)C(@=oj*Qv$Dbj4IeS=OAR{ZYH$(SUsVLBFRTioCRC3;Q7} ziJelUSXu0rbuF6~AMqYF2siLy^*#TD^oqTuqC9hqhrCnp7{B11fUSIY?aG!p4*(}a zBXT9DPG2lMu#^o#NjoKRg8x}N0H5dU>MmK4pHCNWVl%zpigB5;M|C;#3Fm6DMeLAz zK`wrRB=y`T1<2>8U5zxxZwN&bpi8iPTzg zCO_(X7}ie)|jv?TA*Tj6HDQD5f$Cj_+moAdALKBaR1^1Fghs2N30 zeIt4h4Wp0I6zU5f5C0v0sG}<~7r7h(hS%^LjfQUAYS_j>&g*&i? zyKpb=!<+FoJc`Hh=lC!_iqGKl_!7Q`n@NZuaxYm;5~Pm|kWGY>aWX-^B;Sw&WQxp? zn&{F@^!DgW(NCg(MT4}57zWJf~wYkq6wl-OBSfkcn zYoB$G-C;-VRd%=ixV_%qY9F+JvVXIEw3)7;chWGW^cngb9i}hSt@JheCjEep(a-1} z`V}qE1N1PRrl;sEJxAwg+Z76y1Aye+@}TR`4X72}f$m0OWT8%!K)vW`G>A5!S5Ovh MM?26i-oE0{zd@{9Hvj+t delta 952 zcmXw%YiLwQ7=~xESJRC-rfG7z*|m{Gp<=@Cq`*xvyxSbTIi3Mu9rgE zNCn#j7Ang~8y&F41PLvT7t~r-+p4IjiwQLlXtg(7OiEhE3t@?xhG?74N!h*Oqx?- z+|n^mG-*B)e@dN5D~TCL(k$*MVRiLNL=4VCyAZM_P33`Wz*K--aS*q~q4-K-DPbJ4 ztT-r}7@HD@WL?jG69@Q4hYxP$yBs~9Ba&q{XEXB7Uha3^gadrS`8_P;$6ZUkV>SS8 z`@7{x?u<;PR~E8%DAQ(E+~DJ`?QjckasN|Q`TI!bW%k$RYobrOtXa)?#X(D%zKkmN zS*o#oE-^I3KbyA~PV&_0pJjwSgxF`44qBgiEHC$9<$6|oqV@i=DgYGeT{CS*4jU6AJwjY9S6n&_XF9$WZ+pKPjhQU+H2Y+?MLlr?Y1_mJ<%Zc;YwVE zF>b^$yc2(ddvG7_$5-%m{1YCO0&vW+B2A2~u!kZ;L(k|wvv z1exh1rNMac^WdGJCv-V95V{o_3H=?K4i)NNeYxJCH|zWK{rYMBtlk>l7XB#Q6aFTA zHoVZNG?p632pemRW~1G>WLz_THKq+0eUX;Y3R+Fq(H7cDx6^j|A^n(sN_**-^e8<= z&(QPq3LT`w^cR|;W3>7KeMFy9P!7N{`KN5C5UI$IDo_;)pgPouqUas8741Opqa^A^ KU+|iW;r{^%8&mlJ diff --git a/external/fieldtrip/forward/private/ptriproj.mexw64 b/external/fieldtrip/forward/private/ptriproj.mexw64 index 997761e6be39b826caa6b71bd051d63817d256d9..0421d849afc5d1449461b2f6a0dc51f234a0444f 100755 GIT binary patch delta 1756 zcmYjRe{54#6u!6Z!){&IcH0}<*r45BVGM?a4jeL|!>V_-8puWhI246UO#EZfK7ybb zNvTqvgUJnlh$N0E5u<->G|>#BjK~i&#?K|noC!og-yD%Sfek`@e)o05H9hD1&N<(E z=iGbWdpjC-G_+mwefr1EwPgG^OiH~Di=B`>By!Tp5U2EU%bodr0sWdTOAXS9rRBFw zLYU^z&kKx?Q8imc$I_8Cmc?3~t9^u|Gg`#1AD$4pmk_2t%@nV`dL0tDyukz!ZC`ycskh4v>t}L>@lxAAJueyFKC^1j%io)oqW6GrSnq< zr3iH`#3qh}UG9q`F867DR_fjq52bR-Za+fl8@w|k@ZvrT6r#95BBZI-HSfeWODqSO zGrIRtW`!Ekryv?}RiOD!#f?EmTpptTZTml2Fp>OqJjnx@`)MR~Iul3t3164hWbN(k z<;Sx^bp1YO4ej7dou6CAM)~hfg={KzM-5|;W0C0JsD$7*DGa{y3m(q?Y@;oo z5W{~@7G5{~FQ)G`{r9FnV){~eG#meg>RJ4jw~JsvL!OEf(|*KO8M0OI!~jc5_Z6_D z^e2zF-hC>JAkppG(~U`L=bTDPK_r6R!%~ZxwIZd_4<&tR=cZ7%Mc{GV_97@Fub0RLmOJoTICsH zh*qZ^5KdMWLZsiZnX61}H4Foan_`Mq=T88=52Z8G?NUPUbdbcoYV|RUatkqwFMS9g zF(0)5fa%Yew~2Y8+NongU8nULaz83zT6uuK2pn=DAW3} zq3tLba*rFsiMIwH0z-8$?W`ehL2gLx!aG3pS8-(<)Nh*VgOAjjbB&qV&9CPwMGMWm zG!H4JMU{{tm!&g#+?UsE-|i86R1)JKvSbvD#ZQ+1VEALu8vZS&-)j18PJYR9@@PRh zrGeD!!rN3{jn}FwNQf`fLNa$bNHZRi)x2`r$36w;Wx=RdO9(kRoseOez<$I%KrbJh zHpe4Wc(usSc;u?Eb1S*Oc)2{0{l-Vg4cM^2)Z4}1T5aN6pQ`qHZ7mb61-?>%8)6KB zXJKyei@>`@glqs0Oe17JY%6#>@GA_l1H1!x8^d&five>n#u0EYa51bMJOoU@hQZr` z&tlB1Dzc8O1bH21t0JTsxC=HHybag~s{+3UEW`9+@DAV*tPxzS$b+>vfCqr}uy?>W M0B5G=`!Cr31BCYdCIA2c delta 1741 zcmYjRZERCj7(S=%g>GxtyN_GDjlu1>l?}Er=)j4?b)mprS`}m%z=5z~I)dcIOL9+|J~ zm!U+Z9Fs?UM&o>`�U)eVj`x*_fkf-AooY8*xVUN#m~!7o+;LaV5ijYBH>Zj8SB9 zQ{YLR#$C$BDON2kUH%3dCn@$~V=%4i->G=Z%hr<@qPk&pfHvvpRsE6?V=o9Y^{0*r z5$XwG6K{k);_wZR__c9YYHC3qr9#T-JV9v->(8or=#UKx-YgRcX>IgWpMKsJ%SUC< z5bsphYPH6cgZn?Ih%j-(lShoJvjyK=VH5>cpM8{WPK{*axISR5u2weeYM}d>=&q+} z_JI4i%{k4c+zP$IN^+MJe|g(9Cm2?R30ss9;yy)1tQug=x$o^Q^b%qQ7Fcmw;`|RQ z{%pkyR{YG0s}axL`GvNr@jvAO0%xYQ3@ugv276;l1)L|w)TEFV080up>`~848=4hD z5^2wCX*g+IaW*MzKp~i(jC%U3c7Vnfx3+fUZ@{qgH?G0Gob9edS2J{BIV%y17cE0( zN?XxZ6F8;mSd*%|v#nx1+bS+oTxglne+AauLrX0f1_Z~FrF}eowX~ld6Kgs;k;KZ> z`vzmhvy<+|Lzq@l!s9n-ZZlcTW1B8=R z6%ZMJJFHbE+D+4h;ud$&<^CODTtsV7Fv|$Rbs&kUI&C4W{EJ+TuXo{L67xfA=damh zy(X3y)z6;f>L&f1DNR5crd7Qxp0}f74U)u&R&cMh8BEK;>RJ?e;vB^B85$GfGd3-# z>Ov87z5&)-ddWt9a_?Ri%wWa5ZDbFP^aRrMdSp?zqW(oZ7H z@y`TbzNzJ?`uC=E2(@e404_Z-p2U;gP`_fSKfI&X-ECIoZFaLjDc)$+h5J!b^{5gu zrC_F_uvLWzoO&MLqtb)y{X*3l$s}R+PvL3$FgqpfT)iU~Rsy@M7_;KDR%}Pa6)eYc zH4$5Q*#k@30#mxqHhKN@6V~Rvo4(0j_ZF?$=jKzlC^e?^1ZY^l)D#>urN`#+om|ot zRqE!NTi7q&wG~;V*!p6&S5B#%swlcn zr6zn(wLwDs**21WIENg-C23++CGYqPab7l99l{GgUQEb12FGuap9G3*qGUxLSK-ql zgSc`Eb}qyMiyEZ4>Ty3IqZs2HQ_n3rWq0s@?x{Lic67{5&2hVr5E(W&et{u^r-4_C z3E2ZKm*5&~jDB diff --git a/external/fieldtrip/forward/private/routlm.mexa64 b/external/fieldtrip/forward/private/routlm.mexa64 index c1433c22c11571f1b18658f2e0cf8a62a9ceae72..5c50308b475a182ab63c9708e92871f4ff3e8a48 100755 GIT binary patch delta 1259 zcmY*ZYitx%6rMBt=4-D8gq#8AaK$K`CF&ax~8dxOl7Q*$+PK)hLX1+P! zIp@3Ixi^_}E$3Q#_t*ygTy72a?Y$tIy+-gq;?r>2z5c`D*5Ll+Xyf5;AKQ0w#ZMLI zlT4cgHxGjvn75eVh^FLy4Sd9jGeSg%kgbdlJ26GD+=*?rH-$Va$JMGuVeF6!(P@|A z6fU#hgU`^DpMo9uV*U;5p?r=z7{or=Z@WZ3n#Gu98@}RbD6~={BMy&Qn#Hp5X0hRN zMs!*3XjdJr&~d;Fy6nrc;ZxK>SaH&xJ^Ts_r{F_KzRuNU%dPF;4h{=KQW zx4kOYHsQ`PmJwH8%!rc7VEB0^Axh@3!A;G~RS`!Ul+gxh{M@ zuoFXK2-aaj3_t*Pivga^;@jdz9t0c~Bk&#G6u)`$&;!Pf{3aeAB->;&Ii~xXqChFyo+b#QrLr6-Ca1b!Tqw36AW%-j??;=)&Pv+U3VpPW3-?OQn;^Rx_YQP1KBXtnk6#t808#t7kcW;j z(mqaeIWmlm5^f;;i|_+NGs!+A3=<~F<7UE-37ZHj?lE?ZaGDP0JYhQ>*6)O8=;j?f z$8DkGtsrcoi)tbqcu4hxZqn8l9NfymeiuIDm0&f#;Eh8y_IZn8E1soyH(vG@C$8LK ztVS@-M_j6T}*rT0zmnR_h9tX+Agf8mirZWB_N$>JJ+ z1d6one#Ya8zyL3Jv{dktl@~;mOJa7xqi@J@f(KJ2Ywe-AFyz5*3K#q+~AM zotiCj!CXGyYmmm<#EIOz$YS2bnNeC*V3N2_OKa{4*MZ11QCI o!+m@$)&e7VJyu0UzIYs7#@cv|EhQU@LG7cs2k8HF_Hi)%2j7B{n*aa+ delta 1175 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 literal 13360 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 TwbJRa=WLAJZKd%L|2z2)Sw*#( diff --git a/external/fieldtrip/forward/private/routlm.mexw32 b/external/fieldtrip/forward/private/routlm.mexw32 index 62cc27d65aa872ca63a7ecee2ae5b08ae9533f03..f32719c33d0cf3a23addb300635502876961433c 100755 GIT binary patch delta 32 lcmZp$Xt0>@gQZjES>(h&K1@;%HhVFi5(4u#ONhK+2LR;v4MqR} delta 32 lcmZp$Xt0>@gC+3ar_hOie3*{R-t5JAN(ju~EFtoO9RLBy4-WtU diff --git a/external/fieldtrip/forward/private/routlm.mexw64 b/external/fieldtrip/forward/private/routlm.mexw64 index 7433da2005bcdcf1a21bd6cf2a94984cc59e8725..c48f43521e995b7e3fdfdd3d30794e2006fb7626 100755 GIT binary patch delta 32 lcmZp0XmFVDfMx0Pr;!t%_%L;3Z#H6V5(V=&?-29g1OWUX4w3)> delta 32 lcmZp0XmFVDfF*+YbLhk;K1>|5HybfFiGul?cZhj#0szq(3-ka0 diff --git a/external/fieldtrip/forward/private/solid_angle.m b/external/fieldtrip/forward/private/solid_angle.m index c984e803..47e65c67 100644 --- a/external/fieldtrip/forward/private/solid_angle.m +++ b/external/fieldtrip/forward/private/solid_angle.m @@ -1,4 +1,4 @@ -function [varargout] = funname(varargin) +function [varargout] = solid_angle(varargin) % SOLID_ANGLE of a planar triangle as seen from the origin % @@ -33,7 +33,6 @@ % You should have received a copy of the GNU General Public License % along with FieldTrip. If not, see . % -% $Id$ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % The first section contains the plain MATLAB implementation. The mex file @@ -79,7 +78,7 @@ % w = 2 * atan2 (nom, den); % return % else -% error('invalid input'); +% ft_error('invalid input'); % end % compile the missing mex file on the fly @@ -93,7 +92,7 @@ try % try to compile the mex file on the fly - warning('trying to compile MEX file from %s', mexsrc); + ft_warning('trying to compile MEX file from %s', mexsrc); cd(mexdir); if ispc @@ -111,7 +110,7 @@ catch % compilation failed disp(lasterr); - error('could not locate MEX file for %s', mexname); + ft_error('could not locate MEX file for %s', mexname); cd(pwdir); success = false; end diff --git a/external/fieldtrip/forward/private/solid_angle.mexa64 b/external/fieldtrip/forward/private/solid_angle.mexa64 index d94d91903daba7af06c027953cbd8f5bc78e29f4..a09e02e630aae3124abc1c336d5d1a1d3a101109 100755 GIT binary patch delta 1247 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 diff --git a/external/fieldtrip/forward/private/solid_angle.mexw32 b/external/fieldtrip/forward/private/solid_angle.mexw32 index dda325cac0d7aa134388ff413a50572953861617..6ffabebf93b9126092295ed7c1f25ba324aa865b 100755 GIT binary patch delta 32 lcmZp0XmFVDgQZ30S>(h&K1{byZT4c+5(o1)S4ecQ0|4tG4PXEO delta 32 kcmZp0XmFVDgC*eKr_hOie3*LMHhVE@iG%r@D1 - if ~isequaln(sens{j}, sens{1}) - removesens = 1; - warning('sensor information does not seem to be consistent across the input arguments'); - break; + ft_error('cannot append this data'); + end +end +ft_info('concatenating over the "%s" dimension\n', cfg.appenddim); + +% ft_selectdata cannot create the union of the data contained in cell-arrays +% make a dummy without the actual data, but keep trialinfo/sampleinfo/grad/elec/opto +% also remove the topo/unmixing/topolabel, if present, otherwise it is not +% possible to concatenate raw and comp data. Note that in append_common the +% topo etc. is removed anyhow, when appenddim = 'chan' +dummy = cell(size(varargin)); +for i=1:numel(varargin) + dummy{i} = removefields(varargin{i}, {'trial', 'time'}); + if strcmp(cfg.appenddim, 'chan') + dummy{i} = removefields(dummy{i}, {'topo', 'unmixing', 'topolabel'}); + end + % add a dummy data field, this causes the datatype to become 'chan' + dummy{i}.dummy = ones(numel(dummy{i}.label),1); + dummy{i}.dummydimord = 'chan'; +end + +% don't do any data appending inside the common function +cfg.parameter = {}; +% use a low-level function that is shared with the other ft_appendxxx functions +% this will handle the trialinfo/sampleinfo/grad/elec/opto +data = append_common(cfg, dummy{:}); +% this is the actual data field that will be appended further down +cfg.parameter = {'trial'}; + +switch cfg.appenddim + case 'chan' + if isequaltime + ntrl = length(varargin{1}.trial); + dat = varargin{1}.trial; + lab = varargin{1}.label(:); + for i=2:numel(varargin) + for j=1:ntrl + dat{j} = cat(1, dat{j}, varargin{i}.trial{j}); + end + lab = cat(1, lab, varargin{i}.label(:)); end + data.trial = dat; + data.time = varargin{1}.time; + data.label = lab; % replace the one from append_common + else + ft_error('data has different time, cannot append over channels'); end - end -end - -% check whether the data are obtained from the same datafile in case either -% (1) we have sampleinfos and they are not identical or (2) we don't have -% sampleinfos -removesampleinfo = 0; -removetrialinfo = 0; -try - origfile1 = ft_findcfg(varargin{1}.cfg, 'datafile'); - for j=2:Ndata - hassampleinfos = isfield(varargin{1}, 'sampleinfo') &&... - isfield(varargin{j}, 'sampleinfo'); - - if ((hassampleinfos &&... - ~isequal(varargin{1}.sampleinfo, varargin{j}.sampleinfo)) ||... - ~hassampleinfos) &&... - ~isempty(origfile1) && ~strcmp(origfile1, ft_findcfg(varargin{j}.cfg, 'datafile')) - removesampleinfo = 1; - warning('input data comes from different datafiles; removing sampleinfo field'); - break; - end - end -catch err - if strcmp(err.identifier, 'MATLAB:nonExistentField') - % this means no data.cfg is present; should not be treated as a fatal error - fprintf('cannot determine from which datafiles the data is taken\n'); - else - % not sure which error, probably a bigger problem - throw(err); - end -end - -catlabel = all(sum(order~=0,2)==1); -cattrial = any(sum(order~=0,2)==Ndata); -shuflabel = cattrial && ~all(all(order-repmat(order(:,1),[1 Ndata])==0)); -prunelabel = cattrial && sum(sum(order~=0,2)==Ndata)1 - error('ambiguous dimord for concatenation'); - end - - % if any of these are present, concatenate - % if not prepend the dimord with rpt (and thus shift the dimensions) - - % here we need to check whether the other dimensions are the same. if - % not, consider some tolerance. - boolval1 = checkchan(varargin{:}, 'identical'); - boolval2 = checkfreq(varargin{:}, 'identical', tol); - if isfield(varargin{1}, 'time'), - boolval3 = checktime(varargin{:}, 'identical', tol); + elseif checkfreq(varargin{:}, 'unique', cfg.tolerance) && checktime(varargin{:}, 'identical', cfg.tolerance) + cfg.appenddim = 'freq'; + elseif checktime(varargin{:}, 'unique', cfg.tolerance) && checkfreq(varargin{:}, 'identical', cfg.tolerance) + cfg.appenddim = 'time'; + elseif checkchan(varargin{:}, 'unique') + cfg.appenddim = 'chan'; else - boolval3 = true; - end - - if any([boolval2 boolval3]==false) - error('appending across observations is not possible, because the frequency and/or temporal dimensions are incompatible'); - end - - % select and reorder the channels that are in every dataset - tmpcfg = []; - tmpcfg.channel = cfg.channel; - tmpcfg.tolerance = cfg.tolerance; - [varargin{:}] = ft_selectdata(tmpcfg, varargin{:}); - for i=1:Ndata - [cfg_rolledback, varargin{i}] = rollback_provenance(cfg, varargin{i}); + ft_error('cfg.appenddim should be specified'); end - cfg = cfg_rolledback; - - % update the dimord - if catdim==0 - freq.dimord = ['rpt_',varargin{1}.dimord]; - % FIXME append dof + else + if checkchan(varargin{:}, 'identical') && checkfreq(varargin{:}, 'identical', cfg.tolerance) + cfg.appenddim = 'rpt'; + elseif checkfreq(varargin{:}, 'unique', cfg.tolerance) + cfg.appenddim = 'freq'; + elseif checkchan(varargin{:}, 'unique') + cfg.appenddim = 'chan'; else - freq.dimord = varargin{1}.dimord; - % FIXME append dof - % before append cumtapcnt cumsumcnt trialinfo check if there's a - % subfield in each dataset. Append fields of different dataset might - % lead in empty and/or non-existing fields in a particular dataset - hascumsumcnt = []; - hascumtapcnt = []; - hastrialinfo = []; - for i=1:Ndata - if isfield(varargin{i},'cumsumcnt'); - hascumsumcnt(end+1) = 1; - else - hascumsumcnt(end+1) = 0; - end - if isfield(varargin{i},'cumtapcnt'); - hascumtapcnt(end+1) = 1; - else - hascumtapcnt(end+1) = 0; - end - if isfield(varargin{i},'trialinfo'); - hastrialinfo(end+1) = 1; - else - hastrialinfo(end+1) = 0; - end - end - - % screen concatenable fields - if ~checkfreq(varargin{:}, 'identical', tol) - error('the freq fields of the input data structures are not equal'); - else - freq.freq=varargin{1}.freq; - end - if ~sum(hascumsumcnt)==0 && ~(sum(hascumsumcnt)==Ndata); - error('the cumsumcnt fields of the input data structures are not equal'); - else - iscumsumcnt=unique(hascumsumcnt); - end - if ~sum(hascumtapcnt)==0 && ~(sum(hascumtapcnt)==Ndata); - error('the cumtapcnt fields of the input data structures are not equal'); - else - iscumtapcnt=unique(hascumtapcnt); - end - if ~sum(hastrialinfo)==0 && ~(sum(hastrialinfo)==Ndata); - error('the trialinfo fields of the input data structures are not equal'); - else - istrialinfo=unique(hastrialinfo); - end - - % concatenating fields - for i=1:Ndata; - if iscumsumcnt; - cumsumcnt{i}=varargin{i}.cumsumcnt; - end - if iscumtapcnt; - cumtapcnt{i}=varargin{i}.cumtapcnt; - end - if istrialinfo; - trialinfo{i}=varargin{i}.trialinfo; - end - end - - % fill in the rest of the descriptive fields - if iscumsumcnt; - freq.cumsumcnt = cat(catdim,cumsumcnt{:}); - clear cumsumcnt; - end - if iscumtapcnt; - freq.cumtapcnt = cat(catdim,cumtapcnt{:}); - clear cumtapcnt; - end - if istrialinfo; - freq.trialinfo = cat(catdim,trialinfo{:}); - clear trialinfo; - end - end - - freq.label = varargin{1}.label; - freq.freq = varargin{1}.freq; - if isfield(varargin{1}, 'time'), freq.time = varargin{1}.time; end - - case 'chan' - catdim = find(strcmp('chan', dimtok)); - if isempty(catdim) - % try chancmb - catdim = find(strcmp('chancmb', dimtok)); - elseif numel(catdim)>1 - error('ambiguous dimord for concatenation'); - end - - % check whether all channels are unique and throw an error if not - [boolval, list] = checkchan(varargin{:}, 'unique'); - if ~boolval - error('the input data structures have non-unique channels, concatenation across channel is not possible'); - end - - if isfield(varargin{1}, 'time') - if ~checktime(varargin{:}, 'identical', tol) - error('the input data structures have non-identical time bins, concatenation across channels not possible'); - end - end - - if ~checkfreq(varargin{:}, 'identical', tol) - error('the input data structures have non-identical frequency bins, concatenation across channels not possible'); - end - - % update the channel description - freq.label = list; - - % fill in the rest of the descriptive fields - freq.freq = varargin{1}.freq; - if isfield(varargin{1}, 'time'), freq.time = varargin{1}.time; end - freq.dimord = varargin{1}.dimord; - - case 'freq' - catdim = find(strcmp('freq', dimtok)); - - % check whether all frequencies are unique and throw an error if not - [boolval, list] = checkfreq(varargin{:}, 'unique', tol); - if ~boolval - error('the input data structures have non-unique frequency bins, concatenation across frequency is not possible'); - end - - if ~checkchan(varargin{:}, 'identical') - error('the input data structures have non-identical channels, concatenation across frequency not possible'); - end - if isfield(varargin{1}, 'time') - if ~checktime(varargin{:}, 'identical', tol) - error('the input data structures have non-identical time bins, concatenation across channels not possible'); - end - end - - % update the frequency description - freq.freq = list(:)'; - - % fill in the rest of the descriptive fields - freq.label = varargin{1}.label; - freq.dimord = varargin{1}.dimord; - if isfield(varargin{1}, 'time'), freq.time = varargin{1}.time; end - - case 'time' - catdim = find(strcmp('time', dimtok)); - - % check whether all time points are unique and throw an error if not - [boolval, list] = checktime(varargin{:}, 'unique', tol); - if ~boolval - error('the input data structures have non-unique time bins, concatenation across time is not possible'); - end - - if ~checkchan(varargin{:}, 'identical') - error('the input data structures have non-identical channels, concatenation across time not possible'); - end - if ~checkfreq(varargin{:}, 'identical', tol) - error('the input data structures have non-identical frequency bins, concatenation across time not possible'); - end - - % update the time description - freq.time = list(:)'; - - % fill in the rest of the descriptive fields - freq.label = varargin{1}.label; - freq.freq = varargin{1}.freq; - freq.dimord = varargin{1}.dimord; - - otherwise - error('it is not allowed to concatenate across dimension %s',cfg.appenddim); -end - -param = cfg.parameter; -if ~iscell(param), param = {param}; end - -% are we appending along the channel dimension? -catchan = strcmp(cfg.appenddim, 'chan'); -chandim = find(strcmp('chan', dimtok)); - -% concatenate the numeric data -for k = 1:numel(param) - tmp = cell(1,Ndata); - - % get the numeric data 'param{k}' if present - for m = 1:Ndata - - if ~isfield(varargin{m}, param{k}) - error('parameter %s is not present in all data sets', param{k}); + ft_error('cfg.appenddim should be specified'); end - tmp{m} = varargin{m}.(param{k}); - - % if we are not appending along the channel dimension, make sure we - % reorder the channel dimension across the different data sets. At this - % point we can be sure that all data sets have identical channels. - if ~catchan && m > 1 - [a,b] = match_str(varargin{1}.label, varargin{m}.label); - if ~all(a==b) - tmp{m} = reorderdim(tmp{m}, chandim, b); - end - end - end - - if catdim==0, - ndim = length(size(tmp{1})); - freq.(param{k}) = permute(cat(ndim+1,tmp{:}),[ndim+1 1:ndim]); - else - freq.(param{k}) = cat(catdim,tmp{:}); - end -end % for k = 1:numel(param) - -% deal with the sensor information, if present -if isfield(varargin{1}, 'grad') || isfield(varargin{1}, 'elec') - keepsensinfo = true; - - if isfield(varargin{1}, 'grad'), sensfield = 'grad'; end - if isfield(varargin{1}, 'elec'), sensfield = 'elec'; end - - for k = 2:Ndata - keepsensinfo = keepsensinfo && isequaln(varargin{1}.(sensfield), varargin{k}.(sensfield)); end +end +fprintf('concatenating over the "%s" dimension\n', cfg.appenddim); - if keepsensinfo, - freq.(sensfield) = varargin{1}.(sensfield); +if isempty(cfg.parameter) + fn = fieldnames(varargin{1}); + for i=2:numel(varargin) + fn = intersect(fn, fieldnames(varargin{i})); end + cfg.parameter = setdiff(fn, ignorefields('appendfreq')); +elseif ischar(cfg.parameter) + cfg.parameter = {cfg.parameter}; end +assert(~isempty(cfg.parameter), 'cfg.parameter should be specified'); + +% use a low-level function that is shared with the other ft_appendxxx functions +freq = append_common(cfg, varargin{:}); % do the general cleanup and bookkeeping at the end of the function ft_postamble debug ft_postamble trackconfig -ft_postamble previous varargin +ft_postamble previous varargin ft_postamble provenance freq -ft_postamble history freq -ft_postamble savevar freq - - -%--------------------------------------------- -% subfunction to check uniqueness of freq bins -function [boolval, faxis] = checkfreq(varargin) - -% last input is always the required string -tol = varargin{end}; -required = varargin{end-1}; -varargin = varargin(1:end-2); - -Ndata = numel(varargin); -Nfreq = zeros(1,Ndata); -faxis = zeros(1,0); -for i=1:Ndata - Nfreq(i) = numel(varargin{i}.freq); - faxis = [faxis;varargin{i}.freq(:)]; -end - -if strcmp(required, 'unique') - boolval = numel(unique(faxis))==numel(faxis) && ~all(isnan(faxis)); - % the second condition is included when the freq is set to dummy nan -elseif strcmp(required, 'identical') - % the number of frequency bins needs at least to be the same across - % inputs - boolval = all(Nfreq==Nfreq(1)); - if boolval - % then check whether the axes are equal - faxis = reshape(faxis, Nfreq(1), []); - boolval = all(all(abs(faxis - repmat(faxis(:,1), 1, Ndata)). +% +% $Id$ + +% these are used by the ft_preamble/ft_postamble function and scripts +ft_revision = '$Id$'; +ft_nargin = nargin; +ft_nargout = nargout; + +% do the general setup of the function +ft_defaults +ft_preamble init +ft_preamble debug +ft_preamble loadvar varargin +ft_preamble provenance varargin +ft_preamble trackconfig + +% the ft_abort variable is set to true or false in ft_preamble_init +if ft_abort + return +end + +% check if the input data is valid for this function +% and ensure it is up to the latest standards +for i=1:length(varargin) + assert(ft_datatype(varargin{i}, 'sens'), 'incorrect input, should be a grad/elec/opto structure'); + varargin{i} = ft_datatype_sens(varargin{i}); +end + +% do a basic check whether the senstype, units, and coordinate systems match +senstype = cell(1,length(varargin)); +for i=1:length(varargin) + senstype{i} = ft_senstype(varargin{i}); +end +typematch = all(strcmp(senstype{1}, senstype)); + +unitmatch = 1; +if isfield(varargin{1}, 'unit') + unit = cell(1,length(varargin)); + for i=1:length(varargin) + unit{i} = varargin{i}.unit; + end + unitmatch = all(strcmp(unit{1}, unit)); +end + +coordsysmatch = 1; +if isfield(varargin{1}, 'coordsys') + coordsys = cell(1,length(varargin)); + for i=1:length(varargin) + coordsys{i} = varargin{i}.coordsys; + end + coordsysmatch = all(strcmp(coordsys{1}, coordsys)); +end + +if ~typematch || ~unitmatch || ~coordsysmatch + ft_error('the senstype, units, or coordinate systems of the inputs do not match'); +end + +% keep these fields (when present) in the output +sens = keepfields(varargin{1}, {'type', 'unit', 'coordsys'}); + +% make inventory +haselecpos = 0; +hascoilpos = 0; +hascoilori = 0; +haschanori = 0; +hasoptopos = 0; +hastra = 0; +haslabelold = 0; +haschanposold = 0; +for i=1:length(varargin) + % the following fields should be present in any sens structure + if isfield(varargin{i}, 'label') + label{i} = varargin{i}.label(:); % ensure column orientation + end + if isfield(varargin{i}, 'chanpos') + chanpos{i} = varargin{i}.chanpos; + end + + % some the following fields are likely present in a sens structure + if isfield(varargin{i}, 'elecpos') % EEG + elecpos{i} = varargin{i}.elecpos; + haselecpos = 1; + end + if isfield(varargin{i}, 'coilpos') % MEG + coilpos{i} = varargin{i}.coilpos; + hascoilpos = 1; + end + if isfield(varargin{i}, 'coilori') % MEG + coilori{i} = varargin{i}.coilori; + hascoilori = 1; + end + if isfield(varargin{i}, 'chanori') % MEG + chanori{i} = varargin{i}.chanori; + haschanori = 1; + end + if isfield(varargin{i}, 'optopos') % NIRS + optopos{i} = varargin{i}.optopos; + hasoptopos = 1; + end + if isfield(varargin{i}, 'tra') % tra + tra{i} = varargin{i}.tra; + hastra = 1; + end + + % the following fields might be present in a sens structure + if isfield(varargin{i}, 'labelold') + labelold{i} = varargin{i}.labelold(:); % ensure column orientation + haslabelold = 1; + end + if isfield(varargin{i}, 'chanposold') + chanposold{i} = varargin{i}.chanposold; + haschanposold = 1; + end +end + +% concatenate the main fields and remove duplicates +sens.label = cat(1,label{:}); +[~, labidx] = unique(sens.label); +labidx = sort(labidx); +if ~isequal(numel(labidx), numel(sens.label)) + fprintf('removing duplicate labels\n') + sens.label = sens.label(labidx); +end + +sens.chanpos = cat(1,chanpos{:}); +[~, chanidx] = unique(sens.chanpos, 'rows'); +chanidx = sort(chanidx); +if ~isequal(numel(chanidx), size(sens.chanpos,1)) + fprintf('removing duplicate channels\n') + sens.chanpos = sens.chanpos(chanidx,:); + if ~isequal(labidx, chanidx) % check for matching order + ft_error('inconsistent order or number of channel labels and positions') + end +end +if ~isequal(numel(sens.label), size(sens.chanpos,1)) % check for matching number + ft_error('inconsistent number of channel labels and positions') +end +if haschanori + sens.chanori = cat(1,chanori{:}); + if ~isequal(numel(chanidx), size(sens.chanpos,1)) + sens.chanori = sens.chanori(chanidx,:); % chanori should match chanpos + end +end + +if hastra && ~any(cellfun(@isempty, tra)) + sens.tra = []; + for t = 1:numel(tra) + trarow = [1:size(tra{t},1)]+size(sens.tra,1); + tracol = [1:size(tra{t},2)]+size(sens.tra,2); + sens.tra(trarow, tracol) = tra{t}; + end +end + +if haselecpos + sens.elecpos = cat(1,elecpos{:}); + [~, elecidx, elecidx2] = unique(sens.elecpos, 'rows'); + [elecidx, elecord] = sort(elecidx); % sort and keep track of the order + if ~isequal(numel(elecidx), size(sens.elecpos,1)) + fprintf('removing duplicate electrodes\n') + sens.elecpos = sens.elecpos(elecidx,:); + end + if isfield(sens, 'tra') + % shape duplicates into a single column, if necessary + for idx = 1:numel(elecidx) + tmp(:, idx) = sum(sens.tra(chanidx, find(elecord(idx)==elecidx2)),2); + end + sens.tra = tmp; + % check for expected size and non-empty rows or columns + if ~isequal(size(sens.tra,1), size(sens.chanpos,1)) || ~isequal(size(sens.tra,2), size(sens.elecpos,1)) ... + || any(any(sens.tra,1)==0) || any(any(sens.tra,2)==0) + fprintf('removing inconsistent tra matrix\n') + sens = rmfield(sens, 'tra'); + end + end +end + +if hasoptopos + sens.optopos = cat(1,optopos{:}); + [~, optoidx, optoidx2] = unique(sens.optopos, 'rows'); + [optoidx, optoord] = sort(optoidx); % sort and keep track of the order + if ~isequal(numel(optoidx), size(sens.optopos,1)) + fprintf('removing duplicate optodes\n') + sens.optopos = sens.optopos(optoidx,:); + end + if isfield(sens, 'tra') + % shape duplicates into a single column, if necessary + for idx = 1:numel(optoidx) + tmp(:, idx) = sum(sens.tra(chanidx, find(optoord(idx)==optoidx2)),2); + end + sens.tra = tmp; + % check for expected size and non-empty rows or columns + if ~isequal(size(sens.tra,1), size(sens.chanpos,1)) || ~isequal(size(sens.tra,2), size(sens.optopos,1)) ... + || any(any(sens.tra,1)==0) || any(any(sens.tra,2)==0) + fprintf('removing inconsistent tra matrix\n') + sens = rmfield(sens, 'tra'); + end + end +end + +if hascoilpos + sens.coilpos = cat(1,coilpos{:}); + [~, coilidx, coilidx2] = unique(sens.coilpos, 'rows'); + [coilidx, coilord] = sort(coilidx); % sort and keep track of the order + if ~isequal(numel(coilidx), size(sens.coilpos,1)) + fprintf('removing duplicate coils\n') + sens.coilpos = sens.coilpos(coilidx,:); + end + if isfield(sens, 'tra') + % shape duplicates into a single column, if necessary + for idx = 1:numel(coilidx) + tmp(:, idx) = sum(sens.tra(chanidx, find(coilord(idx)==coilidx2)),2); + end + sens.tra = tmp; + % check for expected size and non-empty rows or columns + if ~isequal(size(sens.tra,1), size(sens.chanpos,1)) || ~isequal(size(sens.tra,2), size(sens.coilpos,1)) ... + || any(any(sens.tra,1)==0) || any(any(sens.tra,2)==0) + fprintf('removing inconsistent tra matrix\n') + sens = rmfield(sens, 'tra'); + end + end +end +if hascoilori + sens.coilori = cat(1,coilori{:}); + if ~isequal(numel(coilidx), size(sens.coilori,1)) + sens.coilori = sens.coilori(coilidx,:); % coilori should match coilpos + end +end + +% keep the following fields only when identical across inputs +if haslabelold && all(strcmp(labelold{1}, labelold)) % labeloldmatch + sens.labelold = labelold{1}; +end +if haschanposold && all(isequal(chanposold{1}, chanposold{:})) % chanposoldmatch + sens.chanposold = chanposold{1}; +end + +% ensure up-to-date and consistent output sensor description +sens = ft_datatype_sens(sens); + +% do the general cleanup and bookkeeping at the end of the function +ft_postamble debug +ft_postamble trackconfig +ft_postamble previous varargin +ft_postamble provenance sens +ft_postamble history sens +ft_postamble savevar sens diff --git a/external/fieldtrip/ft_appendsource.m b/external/fieldtrip/ft_appendsource.m index 303fa42f..fcb9d153 100644 --- a/external/fieldtrip/ft_appendsource.m +++ b/external/fieldtrip/ft_appendsource.m @@ -76,7 +76,7 @@ dimordmatch = all(strcmp(dimord{1}, dimord)); if ~dimordmatch - error('the dimords of the input data structures are not equal'); + ft_error('the dimords of the input data structures are not equal'); end % create the output structure from scratch @@ -116,7 +116,7 @@ elseif boolval1 && boolval2 && ~boolval3 cfg.appenddim = 'time'; else - error('the input datasets have multiple non-identical dimensions, this function only appends one dimension at a time'); + ft_error('the input datasets have multiple non-identical dimensions, this function only appends one dimension at a time'); end else if boolval1 && boolval2 @@ -140,7 +140,7 @@ elseif numel(catdim)==1 % this is OK elseif numel(catdim)>1 - error('ambiguous dimord for concatenation'); + ft_error('ambiguous dimord for concatenation'); end % if any of these are present, concatenate @@ -162,7 +162,7 @@ end if any([boolval1 boolval2 boolval3]==false) - error('appending across observations is not possible, because the spatial, spectral and/or temporal dimensions are incompatible'); + ft_error('appending across observations is not possible, because the spatial, spectral and/or temporal dimensions are incompatible'); end % select and reorder the channels that are in every dataset @@ -188,17 +188,17 @@ hascumtapcnt = []; hastrialinfo = []; for i=1:Ndata - if isfield(varargin{i},'cumsumcnt'); + if isfield(varargin{i}, 'cumsumcnt'); hascumsumcnt(end+1) = 1; else hascumsumcnt(end+1) = 0; end - if isfield(varargin{i},'cumtapcnt'); + if isfield(varargin{i}, 'cumtapcnt'); hascumtapcnt(end+1) = 1; else hascumtapcnt(end+1) = 0; end - if isfield(varargin{i},'trialinfo'); + if isfield(varargin{i}, 'trialinfo'); hastrialinfo(end+1) = 1; else hastrialinfo(end+1) = 0; @@ -207,22 +207,22 @@ % screen concatenable fields if ~checkfreq(varargin{:}, 'identical', tol) - error('the freq fields of the input data structures are not equal'); + ft_error('the freq fields of the input data structures are not equal'); else source.freq=varargin{1}.freq; end if ~sum(hascumsumcnt)==0 && ~(sum(hascumsumcnt)==Ndata); - error('the cumsumcnt fields of the input data structures are not equal'); + ft_error('the cumsumcnt fields of the input data structures are not equal'); else iscumsumcnt=unique(hascumsumcnt); end if ~sum(hascumtapcnt)==0 && ~(sum(hascumtapcnt)==Ndata); - error('the cumtapcnt fields of the input data structures are not equal'); + ft_error('the cumtapcnt fields of the input data structures are not equal'); else iscumtapcnt=unique(hascumtapcnt); end if ~sum(hastrialinfo)==0 && ~(sum(hastrialinfo)==Ndata); - error('the trialinfo fields of the input data structures are not equal'); + ft_error('the trialinfo fields of the input data structures are not equal'); else istrialinfo=unique(hastrialinfo); end @@ -262,24 +262,24 @@ case 'pos' % FIXME - error('this functionality does not work.....yet'); + ft_error('this functionality does not work.....yet'); case 'freq' % FIXME - error('this functionality does not work.....yet'); + ft_error('this functionality does not work.....yet'); case 'time' % FIXME - error('this functionality does not work.....yet'); + ft_error('this functionality does not work.....yet'); otherwise - error('it is not allowed to concatenate across dimension %s',cfg.appenddim); + ft_error('it is not allowed to concatenate across dimension %s',cfg.appenddim); end param = cfg.parameter; if iscell(param) && numel(param)>1 - error('it is not possible yet to append multiple parameters in a single call'); + ft_error('it is not possible yet to append multiple parameters in a single call'); elseif iscell(param) param = param{1}; end @@ -291,7 +291,7 @@ for m = 1:Ndata if ~isfield(varargin{m}, param) - error('parameter %s is not present in all data sets', param); + ft_error('parameter %s is not present in all data sets', param); end tmp{m} = varargin{m}.(param); diff --git a/external/fieldtrip/ft_appendspike.m b/external/fieldtrip/ft_appendspike.m index 0147f1ae..27ef246b 100644 --- a/external/fieldtrip/ft_appendspike.m +++ b/external/fieldtrip/ft_appendspike.m @@ -72,7 +72,7 @@ label = cat(1, label, spike{i}.label(:)); end if length(unique(label))~=length(label) - error('not all channel labels are unique'); + ft_error('not all channel labels are unique'); end % concatenate the spikes @@ -99,7 +99,7 @@ % check the validity of the channel labels label = cat(1, data.label(:), spike.label(:)); if length(unique(label))~=length(label) - error('not all channel labels are unique'); + ft_error('not all channel labels are unique'); end if isfield(data, 'cfg') @@ -109,14 +109,14 @@ end if isempty(trl); - error('could not find the trial information in the continuous data'); + ft_error('could not find the trial information in the continuous data'); end try FirstTimeStamp = data.hdr.FirstTimeStamp; TimeStampPerSample = data.hdr.TimeStampPerSample; catch - error('could not find the timestamp information in the continuous data'); + ft_error('could not find the timestamp information in the continuous data'); end for i=1:length(spike.label) diff --git a/external/fieldtrip/ft_appendtimelock.m b/external/fieldtrip/ft_appendtimelock.m index 14866232..fbb84cc6 100644 --- a/external/fieldtrip/ft_appendtimelock.m +++ b/external/fieldtrip/ft_appendtimelock.m @@ -1,24 +1,24 @@ function [timelock] = ft_appendtimelock(cfg, varargin) -% FT_APPENDTIMELOCK concatenates multiple timelock (ERP/ERF) data -% structures that have been processed seperately. If the input data -% structures contain different channels, it will be concatenated along the -% channel direction. If the channels are identical in the input data -% structures, the data will be concatenated along the repetition dimension. +% FT_APPENDTIMELOCK concatenates multiple timelock (ERP/ERF) data structures that +% have been processed seperately. If the input data structures contain different +% channels, it will be concatenated along the channel direction. If the channels are +% identical in the input data structures, the data will be concatenated along the +% repetition dimension. % % Use as % combined = ft_appendtimelock(cfg, timelock1, timelock2, ...) % % The configuration can optionally contain -% cfg.appenddim = String. The dimension to concatenate over (default: -% 'auto'). -% 'chan' and 'rpt' possible (even if averaged data) -% cfg.channel = Nx1 cell-array with selection of channels (default = 'all'), -% see FT_CHANNELSELECTION for details +% cfg.appenddim = string, the dimension to concatenate over which to append, +% this can be 'chan' and 'rpt' (default is automatic) +% cfg.tolerance = scalar, tolerance to determine how different the time axes +% are allowed to still be considered compatible (default = 1e-5) % -% See also FT_TIMELOCKANALYSIS, FT_APPENDDATA, FT_APPENDFREQ, FT_APPENDSOURCE +% See also FT_TIMELOCKANALYSIS, FT_DATATYPE_TIMELOCK, FT_APPENDDATA, FT_APPENDFREQ, +% FT_APPENDSENS, FT_APPENDSOURCE -% Copyright (C) 2011, Robert Oostenveld +% Copyright (C) 2011-2017, Robert Oostenveld % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -56,191 +56,58 @@ return end -Ndata = length(varargin); - % check if the input data is valid for this function -for i=1:Ndata - varargin{i} = ft_checkdata(varargin{i}, 'datatype', 'timelock', 'feedback', 'yes', 'hassampleinfo', 'ifmakessense'); +for i=1:length(varargin) + % FIXME: what about timelock+comp? + varargin{i} = ft_checkdata(varargin{i}, 'datatype', {'timelock', 'timelock+comp'}, 'feedback', 'yes', 'hassampleinfo', 'ifmakessense'); end % set the defaults cfg.channel = ft_getopt(cfg, 'channel', 'all'); -cfg.appenddim = ft_getopt(cfg, 'appenddim', 'auto'); +cfg.parameter = ft_getopt(cfg, 'parameter', []); +cfg.appenddim = ft_getopt(cfg, 'appenddim', []); cfg.tolerance = ft_getopt(cfg, 'tolerance', 1e-5); - -% ensure that all inputs are sufficiently consistent -if ~checktime(varargin{:}, 'identical', cfg.tolerance); - error('this function requires identical time axes for all input structures'); -end - -dimord = cell(1,Ndata); -for i=1:Ndata - dimord{i} = varargin{i}.dimord; -end -dimordmatch = all(strcmp(dimord{1}, dimord)); -if ~dimordmatch - error('the dimords of the input data structures are not equal'); +cfg.appendsens = ft_getopt(cfg, 'appendsens', 'no'); + +if isempty(cfg.appenddim) || strcmp(cfg.appenddim, 'auto') + if checkchan(varargin{:}, 'identical') && checktime(varargin{:}, 'identical', cfg.tolerance) + cfg.appenddim = 'rpt'; + elseif checktime(varargin{:}, 'identical', cfg.tolerance) && ~checkchan(varargin{:}, 'unique') + cfg.appenddim = 'rpt'; + elseif checkchan(varargin{:}, 'unique') + cfg.appenddim = 'chan'; + elseif checktime(varargin{:}, 'unique', cfg.tolerance) + cfg.appenddim = 'time'; + else + ft_error('cfg.appenddim should be specified'); + end end +fprintf('concatenating over the "%s" dimension\n', cfg.appenddim); -% determine over which dimension to append if not user-specified -switch cfg.appenddim - case 'auto' - [boolval, list] = checkchan(varargin{:}, 'unique'); - if boolval - cfg.appenddim='chan'; - else - cfg.appenddim='rpt'; - end +if isempty(cfg.parameter) + fn = fieldnames(varargin{1}); + for i=2:numel(varargin) + fn = intersect(fn, fieldnames(varargin{i})); + end + cfg.parameter = setdiff(fn, ignorefields('appendtimelock')); +elseif ischar(cfg.parameter) + cfg.parameter = {cfg.parameter}; end +assert(~isempty(cfg.parameter), 'cfg.parameter should be specified'); -% start with the initial output structure -timelock = []; -timelock.time = varargin{1}.time; -ntime = length(timelock.time); - -switch cfg.appenddim - case 'chan' - for i=2:length(varargin) % check if any channels in common - if ~isempty(ft_channelselection(varargin{1}.label,varargin{i}.label)) - error('Cannot concatenate over channels since some channels are in common'); - end - end - % no channels in common; append over channels - nchan = zeros(size(varargin)); - for i=1:length(varargin) - nchan(i) = length(varargin{i}.label); - end - chansel = cumsum([1 nchan]); - timelock.label = cell(0,1); - - hascov = isfield(varargin{1}, 'cov') && numel(size(varargin{1}.cov))==3; - if hascov, warning('Concatenating over channels does not allow for keeping covariance information'); end - - if isfield(varargin{1}, 'trial') - timelock.dimord = 'rpt_chan_time'; - - % these don't make sense when concatenating the avg - hastrialinfo = isfield(varargin{1}, 'trialinfo'); - hassampleinfo = isfield(varargin{1}, 'sampleinfo'); - - ntrial = size(varargin{1}.trial,1); - - - timelock.trial = zeros(ntrial, sum(nchan), ntime); - if hastrialinfo, timelock.trialinfo = varargin{1}.trialinfo; end - if hassampleinfo, timelock.sampleinfo = varargin{1}.sampleinfo; end - - for i=1:length(varargin) - % copy the desired data into the output structure - begchan = chansel(i); - endchan = chansel(i+1)-1; - timelock.trial(:,begchan:endchan,:) = varargin{i}.trial; - timelock.label = [timelock.label; varargin{i}.label(:)]; - end % for varargin - timelock.avg = permute(mean(timelock.trial,1),[2 3 1]); - timelock.var = permute(var(timelock.trial,0,1),[2 3 1]); - timelock.dimord = 'rpt_chan_time'; - - else - - - timelock.avg = zeros(sum(nchan), ntime); - - for i=1:length(varargin) - % copy the desired data into the output structure - begchan = chansel(i); - endchan = chansel(i+1)-1; - timelock.avg(begchan:endchan,:) = varargin{i}.avg; - timelock.var(begchan:endchan,:) = varargin{i}.var; - timelock.dof(begchan:endchan,:) = varargin{i}.dof; - timelock.label = [timelock.label; varargin{i}.label(:)]; - end % for varargin - - % keep grad? Should be ok for different channels of same dataset - timelock.grad=varargin{1}.grad; - timelock.dimord = 'chan_time'; - end - - - case 'rpt' % append over trial or dataset dimension - % select the channels that are in every dataset - tmpcfg = []; - tmpcfg.channel = cfg.channel; - tmpcfg.tolerance = cfg.tolerance; - [varargin{:}] = ft_selectdata(tmpcfg, varargin{:}); - for i=1:Ndata - [cfg_rolledback, varargin{i}] = rollback_provenance(cfg, varargin{i}); - end - cfg = cfg_rolledback; - - timelock.label = varargin{1}.label; - nchan = numel(timelock.label); - if nchan<1 - error('No channels in common'); - end - - hascov = isfield(varargin{1}, 'cov') && numel(size(varargin{1}.cov))==3; - if isfield(varargin{1}, 'trial') - % these don't make sense when concatenating the avg - hastrialinfo = isfield(varargin{1}, 'trialinfo'); - hassampleinfo = isfield(varargin{1}, 'sampleinfo'); - - ntrial = zeros(size(varargin)); - for i=1:length(varargin) - ntrial(i) = size(varargin{i}.trial, 1); - end - trialsel = cumsum([1 ntrial]); - - timelock.trial = zeros(sum(ntrial), nchan, ntime); - if hastrialinfo, timelock.trialinfo = zeros(sum(ntrial), size(varargin{1}.trialinfo,2)); end - if hassampleinfo, timelock.sampleinfo = zeros(sum(ntrial), size(varargin{1}.sampleinfo,2)); end - if hascov, timelock.cov = zeros(sum(ntrial), nchan, nchan); end - - for i=1:length(varargin) - % copy the desired data into the output structure - begtrial = trialsel(i); - endtrial = trialsel(i+1)-1; - chansel = match_str(cfg.channel, varargin{i}.label); - timelock.trial(begtrial:endtrial,:,:) = varargin{i}.trial(:,chansel,:); - if hastrialinfo, timelock.trialinfo(begtrial:endtrial,:) = varargin{i}.trialinfo(:,:); end - if hassampleinfo, timelock.sampleinfo(begtrial:endtrial,:) = varargin{i}.sampleinfo(:,:); end - if hascov, timelock.cov(begtrial:endtrial,:,:) = varargin{i}.cov(:,chansel,chansel); end - end % for varargin - timelock.avg = permute(mean(timelock.trial,1),[2 3 1]); - timelock.var = permute(var(timelock.trial,0,1),[2 3 1]); - - elseif isfield(varargin{1}, 'avg') - - ntrial = numel(varargin); - timelock.trial = zeros(ntrial, nchan, ntime); - if hascov, timelock.cov = zeros(sum(ntrial),nchan,nchan); end - - for i=1:length(varargin) - % copy the desired data into the output structure - chansel = match_str(cfg.channel, varargin{i}.label); - timelock.trial(i,:,:) = varargin{i}.avg(chansel,:); - if hascov, timelock.cov(i,:,:) = varargin{i}.cov(chansel,chansel); end - end % for varargin - end - timelock.dimord = 'rpt_chan_time'; - otherwise - error('it is not allowed to concatenate across dimension %s',cfg.appenddim); +if any(strcmp(cfg.parameter, 'avg')) && any(strcmp(cfg.parameter, 'trial')) + ft_warning('appending the individual trials, not the averages'); + % also prevent var and dof from being appended + cfg.parameter = setdiff(cfg.parameter, {'avg', 'var', 'dof'}); end -% deal with the sensor information, if present -if isfield(varargin{1}, 'grad') || isfield(varargin{1}, 'elec') - keepsensinfo = true; +% use a low-level function that is shared with the other ft_appendxxx functions +timelock = append_common(cfg, varargin{:}); - if isfield(varargin{1}, 'grad'), sensfield = 'grad'; end - if isfield(varargin{1}, 'elec'), sensfield = 'elec'; end - - for k = 2:Ndata - keepsensinfo = keepsensinfo && isequaln(varargin{1}.(sensfield), varargin{k}.(sensfield)); - end - - if keepsensinfo, - timelock.(sensfield) = varargin{1}.(sensfield); - end +if isfield(timelock, 'avg') && ~isfield(timelock, 'trial') + ft_warning('renaming the appended averages to "trial"'); + timelock.trial = timelock.avg; + timelock = rmfield(timelock, 'avg'); end % do the general cleanup and bookkeeping at the end of the function diff --git a/external/fieldtrip/ft_artifact_clip.m b/external/fieldtrip/ft_artifact_clip.m index 2ab686a9..04e91052 100644 --- a/external/fieldtrip/ft_artifact_clip.m +++ b/external/fieldtrip/ft_artifact_clip.m @@ -80,18 +80,18 @@ cfg = ft_checkconfig(cfg, 'renamedval', {'continuous', 'continuous', 'yes'}); % set default rejection parameters for clip artifacts if necessary. -if ~isfield(cfg,'artfctdef'), cfg.artfctdef = []; end; -if ~isfield(cfg.artfctdef,'clip'), cfg.artfctdef.clip = []; end; -if ~isfield(cfg.artfctdef.clip,'channel'), cfg.artfctdef.clip.channel = 'all'; end; -if ~isfield(cfg.artfctdef.clip,'timethreshold'), cfg.artfctdef.clip.timethreshold = 0.010; end; -if ~isfield(cfg.artfctdef.clip,'amplthreshold'), cfg.artfctdef.clip.amplthreshold = 0.000; end; -if ~isfield(cfg.artfctdef.clip,'pretim'), cfg.artfctdef.clip.pretim = 0.000; end; -if ~isfield(cfg.artfctdef.clip,'psttim'), cfg.artfctdef.clip.psttim = 0.000; end; -if ~isfield(cfg, 'headerformat'), cfg.headerformat = []; end; -if ~isfield(cfg, 'dataformat'), cfg.dataformat = []; end; +if ~isfield(cfg, 'artfctdef'), cfg.artfctdef = []; end +if ~isfield(cfg.artfctdef, 'clip'), cfg.artfctdef.clip = []; end +if ~isfield(cfg.artfctdef.clip, 'channel'), cfg.artfctdef.clip.channel = 'all'; end +if ~isfield(cfg.artfctdef.clip, 'timethreshold'), cfg.artfctdef.clip.timethreshold = 0.010; end +if ~isfield(cfg.artfctdef.clip, 'amplthreshold'), cfg.artfctdef.clip.amplthreshold = 0.000; end +if ~isfield(cfg.artfctdef.clip, 'pretim'), cfg.artfctdef.clip.pretim = 0.000; end +if ~isfield(cfg.artfctdef.clip, 'psttim'), cfg.artfctdef.clip.psttim = 0.000; end +if ~isfield(cfg, 'headerformat'), cfg.headerformat = []; end +if ~isfield(cfg, 'dataformat'), cfg.dataformat = []; end % for backward compatibility -if isfield(cfg.artfctdef.clip,'sgn') +if isfield(cfg.artfctdef.clip, 'sgn') cfg.artfctdef.clip.channel = cfg.artfctdef.clip.sgn; cfg.artfctdef.clip = rmfield(cfg.artfctdef.clip, 'sgn'); end @@ -105,19 +105,19 @@ if ~hasdata cfg = ft_checkconfig(cfg, 'dataset2files', 'yes'); cfg = ft_checkconfig(cfg, 'required', {'headerfile', 'datafile'}); - hdr = ft_read_header(cfg.headerfile,'headerformat', cfg.headerformat); + hdr = ft_read_header(cfg.headerfile, 'headerformat', cfg.headerformat); trl = cfg.trl; else data = ft_checkdata(data, 'hassampleinfo', 'yes'); cfg = ft_checkconfig(cfg, 'forbidden', {'dataset', 'headerfile', 'datafile'}); hdr = ft_fetch_header(data); - if isfield(data, 'sampleinfo'), + if isfield(data, 'sampleinfo') trl = data.sampleinfo; for k = 1:numel(data.trial) trl(k,3) = time2offset(data.time{k}, data.fsample); end else - error('the input data does not contain a valid description of the sampleinfo'); + ft_error('the input data does not contain a valid description of the sampleinfo'); end end diff --git a/external/fieldtrip/ft_artifact_ecg.m b/external/fieldtrip/ft_artifact_ecg.m index 68597ed7..3047bc48 100644 --- a/external/fieldtrip/ft_artifact_ecg.m +++ b/external/fieldtrip/ft_artifact_ecg.m @@ -79,27 +79,27 @@ cfg = ft_checkconfig(cfg, 'renamedval', {'continuous', 'continuous', 'yes'}); % this subfield is required -if ~isfield(cfg,'artfctdef'), cfg.artfctdef = []; end -if ~isfield(cfg.artfctdef,'ecg'), cfg.artfctdef.ecg = []; end +if ~isfield(cfg, 'artfctdef'), cfg.artfctdef = []; end +if ~isfield(cfg.artfctdef, 'ecg'), cfg.artfctdef.ecg = []; end cfg.artfctdef = ft_checkconfig(cfg.artfctdef, 'renamed', {'blc', 'demean'}); cfg.artfctdef = ft_checkconfig(cfg.artfctdef, 'renamed', {'blcwindow' 'baselinewindow'}); % set default rejection parameters for eog artifacts if necessary. -if ~isfield(cfg.artfctdef.ecg,'channel'), cfg.artfctdef.ecg.channel = {'ECG'}; end -if ~isfield(cfg.artfctdef.ecg,'method'), cfg.artfctdef.ecg.method = 'zvalue'; end -if ~isfield(cfg.artfctdef.ecg,'cutoff'), cfg.artfctdef.ecg.cutoff = 3; end -if ~isfield(cfg.artfctdef.ecg,'padding'), cfg.artfctdef.ecg.padding = 0.5; end -if ~isfield(cfg.artfctdef.ecg,'inspect'), cfg.artfctdef.ecg.inspect = {'MLT' 'MRT'}; end -if ~isfield(cfg.artfctdef.ecg,'pretim'), cfg.artfctdef.ecg.pretim = 0.05; end -if ~isfield(cfg.artfctdef.ecg,'psttim'), cfg.artfctdef.ecg.psttim = 0.3; end -if ~isfield(cfg.artfctdef.ecg,'mindist'), cfg.artfctdef.ecg.mindist = 0.5; end -if ~isfield(cfg.artfctdef.ecg,'feedback'), cfg.artfctdef.ecg.feedback = 'yes'; end +if ~isfield(cfg.artfctdef.ecg, 'channel'), cfg.artfctdef.ecg.channel = {'ECG'}; end +if ~isfield(cfg.artfctdef.ecg, 'method'), cfg.artfctdef.ecg.method = 'zvalue'; end +if ~isfield(cfg.artfctdef.ecg, 'cutoff'), cfg.artfctdef.ecg.cutoff = 3; end +if ~isfield(cfg.artfctdef.ecg, 'padding'), cfg.artfctdef.ecg.padding = 0.5; end +if ~isfield(cfg.artfctdef.ecg, 'inspect'), cfg.artfctdef.ecg.inspect = {'MLT' 'MRT'}; end +if ~isfield(cfg.artfctdef.ecg, 'pretim'), cfg.artfctdef.ecg.pretim = 0.05; end +if ~isfield(cfg.artfctdef.ecg, 'psttim'), cfg.artfctdef.ecg.psttim = 0.3; end +if ~isfield(cfg.artfctdef.ecg, 'mindist'), cfg.artfctdef.ecg.mindist = 0.5; end +if ~isfield(cfg.artfctdef.ecg, 'feedback'), cfg.artfctdef.ecg.feedback = 'yes'; end if ~isfield(cfg, 'headerformat'), cfg.headerformat = []; end if ~isfield(cfg, 'dataformat'), cfg.dataformat = []; end -if ~strcmp(cfg.artfctdef.ecg.method, 'zvalue'), - error('method "%s" is not applicable', cfg.artfctdef.ecg.method); +if ~strcmp(cfg.artfctdef.ecg.method, 'zvalue') + ft_error('method "%s" is not applicable', cfg.artfctdef.ecg.method); end % the data is either passed into the function by the user or read from file with cfg.inputfile @@ -108,19 +108,19 @@ if ~hasdata cfg = ft_checkconfig(cfg, 'dataset2files', 'yes'); cfg = ft_checkconfig(cfg, 'required', {'headerfile', 'datafile'}); - hdr = ft_read_header(cfg.headerfile,'headerformat', cfg.headerformat); + hdr = ft_read_header(cfg.headerfile, 'headerformat', cfg.headerformat); trl = cfg.trl; else data = ft_checkdata(data, 'hassampleinfo', 'yes'); cfg = ft_checkconfig(cfg, 'forbidden', {'dataset', 'headerfile', 'datafile'}); hdr = ft_fetch_header(data); - if isfield(data, 'sampleinfo'), + if isfield(data, 'sampleinfo') trl = data.sampleinfo; for k = 1:numel(data.trial) trl(k,3) = time2offset(data.time{k}, data.fsample); end else - error('the input data does not contain a valid description of the sampleinfo'); + ft_error('the input data does not contain a valid description of the sampleinfo'); end end @@ -135,9 +135,9 @@ fltpadding = 0; if numecgsgn<1 - error('no ECG channels selected'); + ft_error('no ECG channels selected'); elseif numecgsgn>1 - error('only one ECG channel can be selected'); + ft_error('only one ECG channel can be selected'); end % set default cfg.continuous @@ -181,7 +181,7 @@ end accept = strcmp(cfg.artfctdef.ecg.feedback, 'no'); -while accept == 0, +while accept == 0 h = figure; plot(trace);zoom; hold on; @@ -190,8 +190,8 @@ xlabel('samples'); ylabel('zscore'); - fprintf(['\ncurrent ',artfctdef.method,' threshold = %1.3f'], artfctdef.cutoff); - response = input('\nkeep the current value (y/n) ?\n','s'); + fprintf(['\ncurrent %s threshold = %1.3f'], artfctdef.method, artfctdef.cutoff); + response = input('\nkeep the current value (y/n) ?\n', 's'); switch response case 'n' oldcutoff = artfctdef.cutoff; @@ -200,10 +200,10 @@ oldcutoff = artfctdef.cutoff; accept = 1; otherwise - warning('unrecognised response, assuming no'); + ft_warning('unrecognised response, assuming no'); oldcutoff = artfctdef.cutoff; artfctdef.cutoff = input('\nenter new value \n'); - end; + end close end @@ -246,7 +246,7 @@ ntrlok = ntrlok + 1; elseif hasdata dum = ft_fetch_data(data, 'header', hdr, 'begsample', trl(j,1), 'endsample', trl(j,2), 'chanindx', sgnind, 'checkboundary', strcmp(cfg.continuous, 'no'), 'docheck', 0); - if any(~isfinite(dum(:))), + if any(~isfinite(dum(:))) else ntrlok = ntrlok + 1; dat = dat + ft_preproc_baselinecorrect(dum); @@ -262,7 +262,7 @@ acceptpre = strcmp(cfg.artfctdef.ecg.feedback, 'no'); acceptpst = strcmp(cfg.artfctdef.ecg.feedback, 'no'); -while acceptpre == 0 || acceptpst == 0, +while acceptpre == 0 || acceptpst == 0 h = figure; subplot(2,1,1); plot(time, dat(end, :)); abc = axis; @@ -276,9 +276,9 @@ rectangle('Position', [xpos ypos width height], 'FaceColor', 'r'); hold on; plot(time, dat(1:end-1, :), 'b'); - if acceptpre == 0, + if acceptpre == 0 fprintf(['\ncurrent pre-peak interval = %1.3f'], artfctdef.pretim); - response = input('\nkeep the current value (y/n) ?\n','s'); + response = input('\nkeep the current value (y/n) ?\n', 's'); switch response case 'n' oldpretim = artfctdef.pretim; @@ -287,13 +287,13 @@ oldpretim = artfctdef.pretim; acceptpre = 1; otherwise - warning('unrecognised response, assuming no'); + ft_warning('unrecognised response, assuming no'); oldpretim = artfctdef.pretim; end end - if acceptpst == 0 && acceptpre == 1, + if acceptpst == 0 && acceptpre == 1 fprintf(['\ncurrent post-peak interval = %1.3f'], artfctdef.psttim); - response = input('\nkeep the current value (y/n) ?\n','s'); + response = input('\nkeep the current value (y/n) ?\n', 's'); switch response case 'n' oldpsttim = artfctdef.psttim; @@ -302,7 +302,7 @@ oldpsttim = artfctdef.psttim; acceptpst = 1; otherwise - warning('unrecognised response, assuming no'); + ft_warning('unrecognised response, assuming no'); oldpsttim = artfctdef.psttim; end end diff --git a/external/fieldtrip/ft_artifact_eog.m b/external/fieldtrip/ft_artifact_eog.m index 3108fdbd..9db3a292 100644 --- a/external/fieldtrip/ft_artifact_eog.m +++ b/external/fieldtrip/ft_artifact_eog.m @@ -92,15 +92,9 @@ cfg = ft_checkconfig(cfg, 'renamedval', {'continuous', 'continuous', 'yes'}); % set default rejection parameters -if ~isfield(cfg,'artfctdef'), cfg.artfctdef = []; end -if ~isfield(cfg.artfctdef,'eog'), cfg.artfctdef.eog = []; end -if ~isfield(cfg.artfctdef.eog,'method'), cfg.artfctdef.eog.method = 'zvalue'; end - -% for backward compatibility -if isfield(cfg.artfctdef.eog,'sgn') - cfg.artfctdef.eog.channel = cfg.artfctdef.eog.sgn; - cfg.artfctdef.eog = rmfield(cfg.artfctdef.eog, 'sgn'); -end +cfg.artfctdef = ft_getopt(cfg, 'artfctdef', []); +cfg.artfctdef.eog = ft_getopt(cfg.artfctdef, 'eog', []); +cfg.artfctdef.eog.method = ft_getopt(cfg.artfctdef.eog, 'method', 'zvalue'); if isfield(cfg.artfctdef.eog, 'artifact') fprintf('eog artifact detection has already been done, retaining artifacts\n'); @@ -109,64 +103,45 @@ end if ~strcmp(cfg.artfctdef.eog.method, 'zvalue') - error('EOG artifact detection only works with cfg.method=''zvalue'''); + ft_error('EOG artifact detection only works with cfg.method=''zvalue'''); end -% the following fields should be supported for backward compatibility -if isfield(cfg.artfctdef.eog,'pssbnd'), - cfg.artfctdef.eog.bpfreq = cfg.artfctdef.eog.pssbnd; - cfg.artfctdef.eog.bpfilter = 'yes'; - cfg.artfctdef.eog = rmfield(cfg.artfctdef.eog,'pssbnd'); -end; -dum = 0; -if isfield(cfg.artfctdef.eog,'pretim'), - dum = max(dum, cfg.artfctdef.eog.pretim); - cfg.artfctdef.eog = rmfield(cfg.artfctdef.eog,'pretim'); -end -if isfield(cfg.artfctdef.eog,'psttim'), - dum = max(dum, cfg.artfctdef.eog.psttim); - cfg.artfctdef.eog = rmfield(cfg.artfctdef.eog,'psttim'); -end -if dum - cfg.artfctdef.eog.artpadding = max(dum); -end -if isfield(cfg.artfctdef.eog,'padding'), - cfg.artfctdef.eog.trlpadding = cfg.artfctdef.eog.padding; - cfg.artfctdef.eog = rmfield(cfg.artfctdef.eog,'padding'); -end +% for backward compatibility +cfg.artfctdef.eog = ft_checkconfig(cfg.artfctdef.eog, 'renamed', {'sgn', 'channel'}); +cfg.artfctdef.eog = ft_checkconfig(cfg.artfctdef.eog, 'renamed', {'passbnd', 'bpfreq'}); +cfg.artfctdef.eog = ft_checkconfig(cfg.artfctdef.eog, 'renamed', {'padding', 'trlpadding'}); +artpadding_oldstyle = max(ft_getopt(cfg.artfctdef.eog, 'pretim', 0), ft_getopt(cfg.artfctdef.eog, 'psttim', 0)); + % settings for preprocessing -if ~isfield(cfg.artfctdef.eog,'bpfilter'), cfg.artfctdef.eog.bpfilter = 'yes'; end -if ~isfield(cfg.artfctdef.eog,'bpfilttype'), cfg.artfctdef.eog.bpfilttype = 'but'; end -if ~isfield(cfg.artfctdef.eog,'bpfreq'), cfg.artfctdef.eog.bpfreq = [1 15]; end -if ~isfield(cfg.artfctdef.eog,'bpfiltord'), cfg.artfctdef.eog.bpfiltord = 4; end -if ~isfield(cfg.artfctdef.eog,'hilbert'), cfg.artfctdef.eog.hilbert = 'yes'; end +cfg.artfctdef.eog.bpfilter = ft_getopt(cfg.artfctdef.eog, 'bpfilter', 'yes'); +cfg.artfctdef.eog.bpfreq = ft_getopt(cfg.artfctdef.eog, 'bpfreq', [1 15]); +cfg.artfctdef.eog.bpfiltord = ft_getopt(cfg.artfctdef.eog, 'bpfiltor', 4); +cfg.artfctdef.eog.bpfilttype = ft_getopt(cfg.artfctdef.eog, 'bpfilttype', 'but'); +cfg.artfctdef.eog.hilbert = ft_getopt(cfg.artfctdef.eog, 'hilbert', 'yes'); + % settings for the zvalue subfunction -if ~isfield(cfg.artfctdef.eog,'channel'), cfg.artfctdef.eog.channel = 'EOG'; end -if ~isfield(cfg.artfctdef.eog,'trlpadding'), cfg.artfctdef.eog.trlpadding = 0.5; end -if ~isfield(cfg.artfctdef.eog,'artpadding'), cfg.artfctdef.eog.artpadding = 0.1; end -if ~isfield(cfg.artfctdef.eog,'fltpadding'), cfg.artfctdef.eog.fltpadding = 0.1; end -if ~isfield(cfg.artfctdef.eog,'cutoff'), cfg.artfctdef.eog.cutoff = 4; end +cfg.artfctdef.eog.channel = ft_getopt(cfg.artfctdef.eog, 'channel', 'EOG'); +cfg.artfctdef.eog.trlpadding = ft_getopt(cfg.artfctdef.eog, 'trlpadding', 0.5); +cfg.artfctdef.eog.fltpadding = ft_getopt(cfg.artfctdef.eog, 'fltpadding', 0.1); +cfg.artfctdef.eog.artpadding = max(ft_getopt(cfg.artfctdef.eog, 'artpadding', 0.1), artpadding_oldstyle); +cfg.artfctdef.eog.cutoff = ft_getopt(cfg.artfctdef.eog, 'cutoff', 4); % construct a temporary configuration that can be passed onto artifact_zvalue -tmpcfg = []; -tmpcfg.trl = cfg.trl; +tmpcfg = cfg; tmpcfg.artfctdef.zvalue = cfg.artfctdef.eog; -if isfield(cfg, 'continuous'), tmpcfg.continuous = cfg.continuous; end -if isfield(cfg, 'dataformat'), tmpcfg.dataformat = cfg.dataformat; end -if isfield(cfg, 'headerformat'), tmpcfg.headerformat = cfg.headerformat; end -% call the zvalue artifact detection function +tmpcfg.artfctdef = rmfield(tmpcfg.artfctdef, 'eog'); -% the data is either passed into the function by the user or read from file with cfg.inputfile +% call the zvalue artifact detection function, where the data is either passed +% into the function by the user or read from file with cfg.inputfile hasdata = exist('data', 'var'); - if ~hasdata - cfg = ft_checkconfig(cfg, 'dataset2files', 'yes'); - cfg = ft_checkconfig(cfg, 'required', {'headerfile', 'datafile'}); - tmpcfg.datafile = cfg.datafile; - tmpcfg.headerfile = cfg.headerfile; + tmpcfg = ft_checkconfig(tmpcfg, 'dataset2files', 'yes'); + tmpcfg = ft_checkconfig(tmpcfg, 'required', {'headerfile', 'datafile'}); [tmpcfg, artifact] = ft_artifact_zvalue(tmpcfg); else + tmpcfg.artfctdef.zvalue.trlpadding = 0; + tmpcfg.artfctdef.zvalue.fltpadding = 0; + ft_warning('trlpadding and fltpadding are set to zero to avoid filter problems with NaN, see bug3193 for details'); [tmpcfg, artifact] = ft_artifact_zvalue(tmpcfg, data); end - cfg.artfctdef.eog = tmpcfg.artfctdef.zvalue; diff --git a/external/fieldtrip/ft_artifact_jump.m b/external/fieldtrip/ft_artifact_jump.m index 7d48d835..4ce6f5e0 100644 --- a/external/fieldtrip/ft_artifact_jump.m +++ b/external/fieldtrip/ft_artifact_jump.m @@ -89,15 +89,9 @@ cfg = ft_checkconfig(cfg, 'renamedval', {'continuous', 'continuous', 'yes'}); % set default rejection parameters -if ~isfield(cfg,'artfctdef'), cfg.artfctdef = []; end -if ~isfield(cfg.artfctdef,'jump'), cfg.artfctdef.jump = []; end -if ~isfield(cfg.artfctdef.jump,'method'), cfg.artfctdef.jump.method = 'zvalue'; end - -% for backward compatibility -if isfield(cfg.artfctdef.jump,'sgn') - cfg.artfctdef.jump.channel = cfg.artfctdef.jump.sgn; - cfg.artfctdef.jump = rmfield(cfg.artfctdef.jump, 'sgn'); -end +cfg.artfctdef = ft_getopt(cfg, 'artfctdef', []); +cfg.artfctdef.jump = ft_getopt(cfg.artfctdef, 'jump', []); +cfg.artfctdef.jump.method = ft_getopt(cfg.artfctdef.jump, 'method', 'zvalue'); if isfield(cfg.artfctdef.jump, 'artifact') fprintf('jump artifact detection has already been done, retaining artifacts\n'); @@ -106,63 +100,44 @@ end if ~strcmp(cfg.artfctdef.jump.method, 'zvalue') - error(sprintf('jump artifact detection only works with cfg.method=''zvalue''')); + ft_error('jump artifact detection only works with cfg.method=''zvalue'''); end -% the following fields should be supported for backward compatibility -dum = 0; -if isfield(cfg.artfctdef.jump,'pretim'), - dum = max(dum, cfg.artfctdef.jump.pretim); - cfg.artfctdef.jump = rmfield(cfg.artfctdef.jump,'pretim'); -end -if isfield(cfg.artfctdef.jump,'psttim'), - dum = max(dum, cfg.artfctdef.jump.psttim); - cfg.artfctdef.jump = rmfield(cfg.artfctdef.jump,'psttim'); -end -if dum - cfg.artfctdef.jump.artpadding = max(dum); -end -if isfield(cfg.artfctdef.jump,'padding'), - cfg.artfctdef.jump.trlpadding = cfg.artfctdef.jump.padding; - cfg.artfctdef.jump = rmfield(cfg.artfctdef.jump,'padding'); -end +% for backward compatibility +cfg.artfctdef.jump = ft_checkconfig(cfg.artfctdef.jump, 'renamed', {'sgn', 'channel'}); +cfg.artfctdef.jump = ft_checkconfig(cfg.artfctdef.jump, 'renamed', {'passbnd', 'bpfreq'}); +cfg.artfctdef.jump = ft_checkconfig(cfg.artfctdef.jump, 'renamed', {'padding', 'trlpadding'}); +artpadding_oldstyle = max(ft_getopt(cfg.artfctdef.jump, 'pretim', 0), ft_getopt(cfg.artfctdef.jump, 'psttim', 0)); + % settings for preprocessing -if ~isfield(cfg.artfctdef.jump,'medianfilter'), cfg.artfctdef.jump.medianfilter = 'yes'; end -if ~isfield(cfg.artfctdef.jump,'medianfiltord'), cfg.artfctdef.jump.medianfiltord = 9; end -if ~isfield(cfg.artfctdef.jump,'absdiff'), cfg.artfctdef.jump.absdiff = 'yes'; end % compute abs(diff(data)), whereas the order of rectify=yes in combination with derivative=yes would be diff(abs(data)) due to the ordering in preproc +cfg.artfctdef.jump.medianfilter = ft_getopt(cfg.artfctdef.jump, 'medianfilter', 'yes'); +cfg.artfctdef.jump.medianfiltord = ft_getopt(cfg.artfctdef.jump, 'medianfiltord', 9); +cfg.artfctdef.jump.absdiff = ft_getopt(cfg.artfctdef.jump, 'absdiff', 'yes'); % compute abs(diff(data)), whereas the order of rectify=yes in combination with derivative=yes would be diff(abs(data)) due to the ordering in preproc + % settings for the zvalue subfunction -if ~isfield(cfg.artfctdef.jump,'cutoff'), cfg.artfctdef.jump.cutoff = 20; end -if ~isfield(cfg.artfctdef.jump,'channel'), cfg.artfctdef.jump.channel = 'MEG'; end -if ~isfield(cfg.artfctdef.jump,'cumulative'), cfg.artfctdef.jump.cumulative = 'no'; end -if isfield(cfg, 'padding') && cfg.padding~=0 - if ~isfield(cfg.artfctdef.jump,'trlpadding'), cfg.artfctdef.jump.trlpadding = 0.5*cfg.padding; end - if ~isfield(cfg.artfctdef.jump,'artpadding'), cfg.artfctdef.jump.artpadding = 0.5*cfg.padding; end - if ~isfield(cfg.artfctdef.jump,'fltpadding'), cfg.artfctdef.jump.fltpadding = 0; end -else - if ~isfield(cfg.artfctdef.jump,'trlpadding'), cfg.artfctdef.jump.trlpadding = 0; end - if ~isfield(cfg.artfctdef.jump,'artpadding'), cfg.artfctdef.jump.artpadding = 0; end - if ~isfield(cfg.artfctdef.jump,'fltpadding'), cfg.artfctdef.jump.fltpadding = 0; end -end +cfg.padding = ft_getopt(cfg, 'padding', 0); +cfg.artfctdef.jump.cutoff = ft_getopt(cfg.artfctdef.jump, 'cutoff', 20); +cfg.artfctdef.jump.channel = ft_getopt(cfg.artfctdef.jump, 'channel', 'MEG'); +cfg.artfctdef.jump.cumulative = ft_getopt(cfg.artfctdef.jump, 'cumulative', 'no'); +cfg.artfctdef.jump.trlpadding = ft_getopt(cfg.artfctdef.jump, 'trlpadding', 0.5*cfg.padding); % account for bleeding of dftfilter ringing +cfg.artfctdef.jump.fltpadding = ft_getopt(cfg.artfctdef.jump, 'fltpadding', 0.5*cfg.padding); +cfg.artfctdef.jump.artpadding = ft_getopt(cfg.artfctdef.jump, 'artpadding', 0.5*cfg.padding); % construct a temporary configuration that can be passed onto artifact_zvalue -tmpcfg = []; -tmpcfg.trl = cfg.trl; +tmpcfg = cfg; tmpcfg.artfctdef.zvalue = cfg.artfctdef.jump; -if isfield(cfg, 'continuous'), tmpcfg.continuous = cfg.continuous; end -if isfield(cfg, 'dataformat'), tmpcfg.dataformat = cfg.dataformat; end -if isfield(cfg, 'headerformat'), tmpcfg.headerformat = cfg.headerformat; end +tmpcfg.artfctdef = rmfield(tmpcfg.artfctdef, 'jump'); -% the data is either passed into the function by the user or read from file with cfg.inputfile +% call the zvalue artifact detection function, where the data is either passed +% into the function by the user or read from file with cfg.inputfile hasdata = exist('data', 'var'); - if ~hasdata - cfg = ft_checkconfig(cfg, 'dataset2files', 'yes'); - cfg = ft_checkconfig(cfg, 'required', {'headerfile', 'datafile'}); - tmpcfg.datafile = cfg.datafile; - tmpcfg.headerfile = cfg.headerfile; + tmpcfg = ft_checkconfig(tmpcfg, 'dataset2files', 'yes'); + tmpcfg = ft_checkconfig(tmpcfg, 'required', {'headerfile', 'datafile'}); [tmpcfg, artifact] = ft_artifact_zvalue(tmpcfg); else + tmpcfg.artfctdef.zvalue.fltpadding = 0; + ft_warning('trlpadding and fltpadding are set to zero to avoid filter problems with NaN, see bug3193 for details'); [tmpcfg, artifact] = ft_artifact_zvalue(tmpcfg, data); end - cfg.artfctdef.jump = tmpcfg.artfctdef.zvalue; diff --git a/external/fieldtrip/ft_artifact_muscle.m b/external/fieldtrip/ft_artifact_muscle.m index d354b427..8ee13e6c 100644 --- a/external/fieldtrip/ft_artifact_muscle.m +++ b/external/fieldtrip/ft_artifact_muscle.m @@ -93,15 +93,9 @@ cfg = ft_checkconfig(cfg, 'renamedval', {'continuous', 'continuous', 'yes'}); % set default rejection parameters -if ~isfield(cfg,'artfctdef'), cfg.artfctdef = []; end -if ~isfield(cfg.artfctdef,'muscle'), cfg.artfctdef.muscle = []; end -if ~isfield(cfg.artfctdef.muscle,'method'), cfg.artfctdef.muscle.method = 'zvalue'; end - -% for backward compatibility -if isfield(cfg.artfctdef.muscle,'sgn') - cfg.artfctdef.muscle.channel = cfg.artfctdef.muscle.sgn; - cfg.artfctdef.muscle = rmfield(cfg.artfctdef.muscle, 'sgn'); -end +cfg.artfctdef = ft_getopt(cfg, 'artfctdef', []); +cfg.artfctdef.muscle = ft_getopt(cfg.artfctdef, 'muscle', []); +cfg.artfctdef.muscle.method = ft_getopt(cfg.artfctdef.muscle, 'method', 'zvalue'); if isfield(cfg.artfctdef.muscle, 'artifact') fprintf('muscle artifact detection has already been done, retaining artifacts\n'); @@ -110,65 +104,46 @@ end if ~strcmp(cfg.artfctdef.muscle.method, 'zvalue') - error(sprintf('muscle artifact detection only works with cfg.method=''zvalue''')); + ft_error('muscle artifact detection only works with cfg.method=''zvalue'''); end -% the following settings should be supported for backward compatibility -if isfield(cfg.artfctdef.muscle,'pssbnd'), - cfg.artfctdef.muscle.bpfreq = cfg.artfctdef.muscle.pssbnd; - cfg.artfctdef.muscle.bpfilter = 'yes'; - cfg.artfctdef.muscle = rmfield(cfg.artfctdef.muscle,'pssbnd'); -end; -dum = 0; -if isfield(cfg.artfctdef.muscle,'pretim'), - dum = max(dum, cfg.artfctdef.muscle.pretim); - cfg.artfctdef.muscle = rmfield(cfg.artfctdef.muscle,'pretim'); -end -if isfield(cfg.artfctdef.muscle,'psttim'), - dum = max(dum, cfg.artfctdef.muscle.psttim); - cfg.artfctdef.muscle = rmfield(cfg.artfctdef.muscle,'psttim'); -end -if dum - cfg.artfctdef.muscle.artpadding = max(dum); -end -if isfield(cfg.artfctdef.muscle,'padding'), - cfg.artfctdef.muscle.trlpadding = cfg.artfctdef.muscle.padding; - cfg.artfctdef.muscle = rmfield(cfg.artfctdef.muscle,'padding'); -end +% for backward compatibility +cfg.artfctdef.muscle = ft_checkconfig(cfg.artfctdef.muscle, 'renamed', {'sgn', 'channel'}); +cfg.artfctdef.muscle = ft_checkconfig(cfg.artfctdef.muscle, 'renamed', {'passbnd', 'bpfreq'}); +cfg.artfctdef.muscle = ft_checkconfig(cfg.artfctdef.muscle, 'renamed', {'padding', 'trlpadding'}); +artpadding_oldstyle = max(ft_getopt(cfg.artfctdef.muscle, 'pretim', 0), ft_getopt(cfg.artfctdef.muscle, 'psttim', 0)); % settings for preprocessing -if ~isfield(cfg.artfctdef.muscle,'bpfilter'), cfg.artfctdef.muscle.bpfilter = 'yes'; end -if ~isfield(cfg.artfctdef.muscle,'bpfreq'), cfg.artfctdef.muscle.bpfreq = [110 140]; end -if ~isfield(cfg.artfctdef.muscle,'bpfiltord'), cfg.artfctdef.muscle.bpfiltord = 8; end -if ~isfield(cfg.artfctdef.muscle,'bpfilttype'), cfg.artfctdef.muscle.bpfilttype = 'but'; end -if ~isfield(cfg.artfctdef.muscle,'hilbert'), cfg.artfctdef.muscle.hilbert = 'yes'; end -if ~isfield(cfg.artfctdef.muscle,'boxcar'), cfg.artfctdef.muscle.boxcar = 0.2; end +cfg.artfctdef.muscle.bpfilter = ft_getopt(cfg.artfctdef.muscle, 'bpfilter', 'yes'); +cfg.artfctdef.muscle.bpfreq = ft_getopt(cfg.artfctdef.muscle, 'bpfreq', [110 140]); +cfg.artfctdef.muscle.bpfiltord = ft_getopt(cfg.artfctdef.muscle, 'bpfiltor', 8); +cfg.artfctdef.muscle.bpfilttype = ft_getopt(cfg.artfctdef.muscle, 'bpfilttype', 'but'); +cfg.artfctdef.muscle.hilbert = ft_getopt(cfg.artfctdef.muscle, 'hilbert', 'yes'); +cfg.artfctdef.muscle.boxcar = ft_getopt(cfg.artfctdef.muscle, 'boxcar', 0.2); + % settings for the zvalue subfunction -if ~isfield(cfg.artfctdef.muscle,'channel'), cfg.artfctdef.muscle.channel = 'MEG'; end -if ~isfield(cfg.artfctdef.muscle,'trlpadding'), cfg.artfctdef.muscle.trlpadding = 0.1; end -if ~isfield(cfg.artfctdef.muscle,'fltpadding'), cfg.artfctdef.muscle.fltpadding = 0.1; end -if ~isfield(cfg.artfctdef.muscle,'artpadding'), cfg.artfctdef.muscle.artpadding = 0.1; end -if ~isfield(cfg.artfctdef.muscle,'cutoff'), cfg.artfctdef.muscle.cutoff = 4; end +cfg.artfctdef.muscle.channel = ft_getopt(cfg.artfctdef.muscle, 'channel', 'MEG'); +cfg.artfctdef.muscle.trlpadding = ft_getopt(cfg.artfctdef.muscle, 'trlpadding', 0.1); +cfg.artfctdef.muscle.fltpadding = ft_getopt(cfg.artfctdef.muscle, 'fltpadding', 0.1); +cfg.artfctdef.muscle.artpadding = max(ft_getopt(cfg.artfctdef.muscle, 'artpadding', 0.1), artpadding_oldstyle); +cfg.artfctdef.muscle.cutoff = ft_getopt(cfg.artfctdef.muscle, 'cutoff', 4); + % construct a temporary configuration that can be passed onto artifact_zvalue -tmpcfg = []; -tmpcfg.trl = cfg.trl; +tmpcfg = cfg; tmpcfg.artfctdef.zvalue = cfg.artfctdef.muscle; -if isfield(cfg, 'continuous'), tmpcfg.continuous = cfg.continuous; end -if isfield(cfg, 'dataformat'), tmpcfg.dataformat = cfg.dataformat; end -if isfield(cfg, 'headerformat'), tmpcfg.headerformat = cfg.headerformat; end -% call the zvalue artifact detection function +tmpcfg.artfctdef = rmfield(tmpcfg.artfctdef, 'muscle'); -% the data is either passed into the function by the user or read from file with cfg.inputfile +% call the zvalue artifact detection function, where the data is either passed +% into the function by the user or read from file with cfg.inputfile hasdata = exist('data', 'var'); - if ~hasdata - cfg = ft_checkconfig(cfg, 'dataset2files', 'yes'); - cfg = ft_checkconfig(cfg, 'required', {'headerfile', 'datafile'}); - tmpcfg.datafile = cfg.datafile; - tmpcfg.headerfile = cfg.headerfile; + tmpcfg = ft_checkconfig(tmpcfg, 'dataset2files', 'yes'); + tmpcfg = ft_checkconfig(tmpcfg, 'required', {'headerfile', 'datafile'}); [tmpcfg, artifact] = ft_artifact_zvalue(tmpcfg); else + tmpcfg.artfctdef.zvalue.trlpadding = 0; + tmpcfg.artfctdef.zvalue.fltpadding = 0; + ft_warning('trlpadding and fltpadding are set to zero to avoid filter problems with NaN, see bug3193 for details'); [tmpcfg, artifact] = ft_artifact_zvalue(tmpcfg, data); end - cfg.artfctdef.muscle = tmpcfg.artfctdef.zvalue; diff --git a/external/fieldtrip/ft_artifact_nan.m b/external/fieldtrip/ft_artifact_nan.m new file mode 100644 index 00000000..d8c64689 --- /dev/null +++ b/external/fieldtrip/ft_artifact_nan.m @@ -0,0 +1,83 @@ +function [cfg, artifact] = ft_artifact_nan(cfg, data) + +% FT_ARTIFACT_NAN identifies artifacts that are indicated in the data as nan (not a number) values. +% +% Use as +% [cfg, artifact] = ft_artifact_eog(cfg, data) +% +% The output argument "artifact" is a Nx2 matrix comparable to the +% "trl" matrix of FT_DEFINETRIAL. The first column of which specifying the +% beginsamples of an artifact period, the second column contains the +% endsamples of the artifactperiods. +% +% To facilitate data-handling and distributed computing you can use +% cfg.inputfile = ... +% If you specify this option the input data will be read from a *.mat +% file on disk. This mat files should contain only a single variable named 'data', +% corresponding to the input structure. +% +% See also FT_REJECTARTIFACT, FT_ARTIFACT_CLIP, FT_ARTIFACT_ECG, FT_ARTIFACT_EOG, +% FT_ARTIFACT_JUMP, FT_ARTIFACT_MUSCLE, FT_ARTIFACT_THRESHOLD, FT_ARTIFACT_ZVALUE + +% Copyright (C) 2017, Robert Oostenveld +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +% these are used by the ft_preamble/ft_postamble function and scripts +ft_revision = '$Id$'; +ft_nargin = nargin; +ft_nargout = nargout; + +% do the general setup of the function +ft_defaults +ft_preamble init +ft_preamble debug +ft_preamble loadvar data +ft_preamble provenance data +ft_preamble trackconfig + +% the ft_abort variable is set to true or false in ft_preamble_init +if ft_abort + return +end + +data = ft_checkdata(data, 'datatype', 'raw', 'hassampleinfo', 'yes'); + +artifact = zeros(0,2); + +for i=1:numel(data.trial) + tmp = any(isnan(data.trial{i}),1); + if any(tmp) + % there can be multiple segments with nans + begsample = find(diff([0 tmp])>0); + endsample = find(diff([tmp 0])<0); + for j=1:numel(begsample) + artifact(end+1,:) = [begsample(j) endsample(j)] + data.sampleinfo(i,1) - 1; + end + end +end % for each trial + +% remember the details that were used here +cfg.artfctdef.nan = []; +cfg.artfctdef.nan.artifact = artifact; + +% do the general cleanup and bookkeeping at the end of the function +ft_postamble debug +ft_postamble trackconfig +ft_postamble previous data diff --git a/external/fieldtrip/ft_artifact_threshold.m b/external/fieldtrip/ft_artifact_threshold.m index 5740f560..005555c4 100644 --- a/external/fieldtrip/ft_artifact_threshold.m +++ b/external/fieldtrip/ft_artifact_threshold.m @@ -90,10 +90,10 @@ cfg = ft_checkconfig(cfg, 'renamedval', {'continuous', 'continuous', 'yes'}); % set default rejection parameters for clip artifacts if necessary -if ~isfield(cfg, 'artfctdef'), cfg.artfctdef = []; end -if ~isfield(cfg.artfctdef,'threshold'), cfg.artfctdef.threshold = []; end -if ~isfield(cfg, 'headerformat'), cfg.headerformat = []; end -if ~isfield(cfg, 'dataformat'), cfg.dataformat = []; end +if ~isfield(cfg, 'artfctdef'), cfg.artfctdef = []; end +if ~isfield(cfg.artfctdef, 'threshold'), cfg.artfctdef.threshold = []; end +if ~isfield(cfg, 'headerformat'), cfg.headerformat = []; end +if ~isfield(cfg, 'dataformat'), cfg.dataformat = []; end % copy the specific configuration for this function out of the master cfg artfctdef = cfg.artfctdef.threshold; @@ -179,20 +179,20 @@ % test the min, max and range against the specified thresholds if ~isempty(artfctdef.min) && minvalartfctdef.max - fprintf('threshold artifact scanning: trial %d from %d exceeds max-threshold\n', trlop, numtrl); + ft_info('threshold artifact scanning: trial %d from %d exceeds max-threshold\n', trlop, numtrl); artifact(end+1,1:2) = cfg.trl(trlop,1:2); elseif ~isempty(artfctdef.range) && worstChanRange>artfctdef.range - fprintf('threshold artifact scanning: trial %d from %d exceeds range-threshold; max-range channel = %s\n', trlop, numtrl, hdr.label{channelindx(worstChanInd)}); + ft_info('threshold artifact scanning: trial %d from %d exceeds range-threshold; max-range channel = %s\n', trlop, numtrl, hdr.label{channelindx(worstChanInd)}); artifact(end+1,1:2) = cfg.trl(trlop,1:2); else - fprintf('threshold artifact scanning: trial %d from %d is ok\n', trlop, numtrl); + ft_info('threshold artifact scanning: trial %d from %d is ok\n', trlop, numtrl); end end -fprintf('detected %d artifacts\n', size(artifact,1)); +ft_info('detected %d artifacts\n', size(artifact,1)); % remember the details that were used here cfg.artfctdef.threshold = artfctdef; diff --git a/external/fieldtrip/ft_artifact_tms.m b/external/fieldtrip/ft_artifact_tms.m index cc9ea795..85632abc 100644 --- a/external/fieldtrip/ft_artifact_tms.m +++ b/external/fieldtrip/ft_artifact_tms.m @@ -112,14 +112,14 @@ cfg = ft_checkconfig(cfg, 'renamed', {'datatype', 'continuous'}); cfg = ft_checkconfig(cfg, 'renamedval', {'continuous', 'continuous', 'yes'}); cfg = ft_checkconfig(cfg, 'required', 'method'); -cfg = ft_checkconfig(cfg, 'allowedval',{'method','detect','marker'}); +cfg = ft_checkconfig(cfg, 'allowedval', {'method', 'detect', 'marker'}); % set default rejection parameters -if ~isfield(cfg,'artfctdef'), cfg.artfctdef = []; end -if ~isfield(cfg,'method'), cfg.method = 'detect'; end -if ~isfield(cfg.artfctdef,'tms'), cfg.artfctdef.tms = []; end -if ~isfield(cfg,'prestim'), cfg.prestim = 0.005; end -if ~isfield(cfg,'poststim'), cfg.poststim = 0.010; end +if ~isfield(cfg, 'artfctdef'), cfg.artfctdef = []; end +if ~isfield(cfg, 'method'), cfg.method = 'detect'; end +if ~isfield(cfg.artfctdef, 'tms'), cfg.artfctdef.tms = []; end +if ~isfield(cfg, 'prestim'), cfg.prestim = 0.005; end +if ~isfield(cfg, 'poststim'), cfg.poststim = 0.010; end if isfield(cfg.artfctdef.tms, 'artifact') fprintf('tms artifact detection has already been done, retaining artifacts\n'); @@ -130,14 +130,14 @@ switch cfg.method case 'detect' % settings for preprocessing - if ~isfield(cfg.artfctdef.tms,'derivative'), cfg.artfctdef.tms.derivative = 'yes'; end + if ~isfield(cfg.artfctdef.tms, 'derivative'), cfg.artfctdef.tms.derivative = 'yes'; end % settings for the zvalue subfunction - if ~isfield(cfg.artfctdef.tms,'method'), cfg.artfctdef.tms.method = 'zvalue'; end - if ~isfield(cfg.artfctdef.tms,'channel'), cfg.artfctdef.tms.channel = 'all'; end - if ~isfield(cfg.artfctdef.tms,'trlpadding'), cfg.artfctdef.tms.trlpadding = 0.1; end - if ~isfield(cfg.artfctdef.tms,'fltpadding'), cfg.artfctdef.tms.fltpadding = 0.1; end - if ~isfield(cfg.artfctdef.tms,'artpadding'), cfg.artfctdef.tms.artpadding = 0.01; end - if ~isfield(cfg.artfctdef.tms,'cutoff'), cfg.artfctdef.tms.cutoff = 4; end + if ~isfield(cfg.artfctdef.tms, 'method'), cfg.artfctdef.tms.method = 'zvalue'; end + if ~isfield(cfg.artfctdef.tms, 'channel'), cfg.artfctdef.tms.channel = 'all'; end + if ~isfield(cfg.artfctdef.tms, 'trlpadding'), cfg.artfctdef.tms.trlpadding = 0.1; end + if ~isfield(cfg.artfctdef.tms, 'fltpadding'), cfg.artfctdef.tms.fltpadding = 0.1; end + if ~isfield(cfg.artfctdef.tms, 'artpadding'), cfg.artfctdef.tms.artpadding = 0.01; end + if ~isfield(cfg.artfctdef.tms, 'cutoff'), cfg.artfctdef.tms.cutoff = 4; end % construct a temporary configuration that can be passed onto artifact_zvalue tmpcfg = []; tmpcfg.trl = cfg.trl; @@ -186,12 +186,12 @@ case 'marker' % Check if the cfg is correct for this method cfg = ft_checkconfig(cfg, 'dataset2files', 'yes'); - ft_checkconfig(cfg, 'required','trialdef'); + ft_checkconfig(cfg, 'required', 'trialdef'); cfg.trialfun = ft_getopt(cfg, 'trialfun', 'ft_trialfun_general'); trialdef = cfg.trialdef; trialdef.prestim = cfg.prestim; trialdef.poststim = cfg.poststim; - cfg.trialdef = ft_checkconfig(trialdef,'required',{'eventvalue','eventtype'}); + cfg.trialdef = ft_checkconfig(trialdef, 'required', {'eventvalue', 'eventtype'}); % Get the trialfun cfg.trialfun = ft_getuserfun(cfg.trialfun, 'trialfun'); @@ -205,7 +205,7 @@ cfg.artfctdef.tms.artifact = artifact; fprintf('found %d events\n', size(artifact,1)); otherwise - error('unsupported method'); % This should be redundant as ft_checkconfig does not allow other methods than the supported ones. + ft_error('unsupported method'); % This should be redundant as ft_checkconfig does not allow other methods than the supported ones. end cfg = rmfield(cfg, 'method'); % FIXME - not removing this causes problems when passing to ft_preprocessing diff --git a/external/fieldtrip/ft_artifact_zvalue.m b/external/fieldtrip/ft_artifact_zvalue.m index d14c6079..dea82acd 100644 --- a/external/fieldtrip/ft_artifact_zvalue.m +++ b/external/fieldtrip/ft_artifact_zvalue.m @@ -192,7 +192,7 @@ if isfield(cfg.artfctdef.zvalue, 'ntrial') && cfg.artfctdef.zvalue.ntrial>0 pertrial = cfg.artfctdef.zvalue.ntrial; else - error('you should specify cfg.artfctdef.zvalue.ntrial, and it should be > 0'); + ft_error('you should specify cfg.artfctdef.zvalue.ntrial, and it should be > 0'); end end @@ -209,7 +209,7 @@ % check whether the value for trlpadding makes sense if cfg.artfctdef.zvalue.trlpadding > 0 % negative trlpadding is allowed with in-memory data - error('you cannot use positive trlpadding with in-memory data'); + ft_error('you cannot use positive trlpadding with in-memory data'); end % check if the input data is valid for this function data = ft_checkdata(data, 'datatype', 'raw', 'hassampleinfo', 'yes'); @@ -254,7 +254,7 @@ thresholdsum = strcmp(cfg.artfctdef.zvalue.cumulative, 'yes'); if numsgn<1 - error('no channels selected'); + ft_error('no channels selected'); end % read the data and apply preprocessing options @@ -267,9 +267,9 @@ if strcmp(cfg.memory, 'low') % store nothing in memory if hasdata - dat = ft_fetch_data(data, 'header', hdr, 'begsample', trl(trlop,1)-fltpadding, 'endsample', trl(trlop,2)+fltpadding, 'chanindx', sgnind, 'checkboundary', strcmp(cfg.continuous,'no'), 'skipcheckdata', 1); + dat = ft_fetch_data(data, 'header', hdr, 'begsample', trl(trlop,1)-fltpadding, 'endsample', trl(trlop,2)+fltpadding, 'chanindx', sgnind, 'checkboundary', strcmp(cfg.continuous, 'no'), 'skipcheckdata', 1); else - dat = ft_read_data(cfg.datafile, 'header', hdr, 'begsample', trl(trlop,1)-fltpadding, 'endsample', trl(trlop,2)+fltpadding, 'chanindx', sgnind, 'checkboundary', strcmp(cfg.continuous,'no'), 'dataformat', cfg.dataformat); + dat = ft_read_data(cfg.datafile, 'header', hdr, 'begsample', trl(trlop,1)-fltpadding, 'endsample', trl(trlop,2)+fltpadding, 'chanindx', sgnind, 'checkboundary', strcmp(cfg.continuous, 'no'), 'dataformat', cfg.dataformat); end dat = preproc(dat, cfg.artfctdef.zvalue.channel, offset2time(0, hdr.Fs, size(dat,2)), cfg.artfctdef.zvalue, fltpadding, fltpadding); @@ -298,9 +298,9 @@ end else % store all data in memory, saves computation time if hasdata - dat{trlop} = ft_fetch_data(data, 'header', hdr, 'begsample', trl(trlop,1)-fltpadding, 'endsample', trl(trlop,2)+fltpadding, 'chanindx', sgnind, 'checkboundary', strcmp(cfg.continuous,'no'), 'skipcheckdata', 1); + dat{trlop} = ft_fetch_data(data, 'header', hdr, 'begsample', trl(trlop,1)-fltpadding, 'endsample', trl(trlop,2)+fltpadding, 'chanindx', sgnind, 'checkboundary', strcmp(cfg.continuous, 'no'), 'skipcheckdata', 1); else - dat{trlop} = ft_read_data(cfg.datafile, 'header', hdr, 'begsample', trl(trlop,1)-fltpadding, 'endsample', trl(trlop,2)+fltpadding, 'chanindx', sgnind, 'checkboundary', strcmp(cfg.continuous,'no'), 'dataformat', cfg.dataformat); + dat{trlop} = ft_read_data(cfg.datafile, 'header', hdr, 'begsample', trl(trlop,1)-fltpadding, 'endsample', trl(trlop,2)+fltpadding, 'chanindx', sgnind, 'checkboundary', strcmp(cfg.continuous, 'no'), 'dataformat', cfg.dataformat); end dat{trlop} = preproc(dat{trlop}, cfg.artfctdef.zvalue.channel, offset2time(0, hdr.Fs, size(dat{trlop},2)), cfg.artfctdef.zvalue, fltpadding, fltpadding); @@ -361,9 +361,9 @@ if strcmp(cfg.memory, 'low') % store nothing in memory (note that we need to preproc AGAIN... *yawn* fprintf('.'); if hasdata - dat = ft_fetch_data(data, 'header', hdr, 'begsample', trl(trlop,1)-fltpadding, 'endsample', trl(trlop,2)+fltpadding, 'chanindx', sgnind, 'checkboundary', strcmp(cfg.continuous,'no')); + dat = ft_fetch_data(data, 'header', hdr, 'begsample', trl(trlop,1)-fltpadding, 'endsample', trl(trlop,2)+fltpadding, 'chanindx', sgnind, 'checkboundary', strcmp(cfg.continuous, 'no')); else - dat = ft_read_data(cfg.datafile, 'header', hdr, 'begsample', trl(trlop,1)-fltpadding, 'endsample', trl(trlop,2)+fltpadding, 'chanindx', sgnind, 'checkboundary', strcmp(cfg.continuous,'no'), 'dataformat', cfg.dataformat); + dat = ft_read_data(cfg.datafile, 'header', hdr, 'begsample', trl(trlop,1)-fltpadding, 'endsample', trl(trlop,2)+fltpadding, 'chanindx', sgnind, 'checkboundary', strcmp(cfg.continuous, 'no'), 'dataformat', cfg.dataformat); end dat = preproc(dat, cfg.artfctdef.zvalue.channel, offset2time(0, hdr.Fs, size(dat,2)), cfg.artfctdef.zvalue, fltpadding, fltpadding); zmax{trlop} = -inf + zeros(1,size(dat,2)); @@ -412,9 +412,9 @@ % for trlop = 1:numtrl % fprintf('.'); % if hasdata -% dat{trlop} = ft_fetch_data(data, 'header', hdr, 'begsample', trl(trlop,1)-fltpadding, 'endsample', trl(trlop,2)+fltpadding, 'chanindx', sgnind(sgnlop), 'checkboundary', strcmp(cfg.continuous,'no')); +% dat{trlop} = ft_fetch_data(data, 'header', hdr, 'begsample', trl(trlop,1)-fltpadding, 'endsample', trl(trlop,2)+fltpadding, 'chanindx', sgnind(sgnlop), 'checkboundary', strcmp(cfg.continuous, 'no')); % else -% dat{trlop} = read_data(cfg.datafile, 'header', hdr, 'begsample', trl(trlop,1)-fltpadding, 'endsample', trl(trlop,2)+fltpadding, 'chanindx', sgnind(sgnlop), 'checkboundary', strcmp(cfg.continuous,'no')); +% dat{trlop} = read_data(cfg.datafile, 'header', hdr, 'begsample', trl(trlop,1)-fltpadding, 'endsample', trl(trlop,2)+fltpadding, 'chanindx', sgnind(sgnlop), 'checkboundary', strcmp(cfg.continuous, 'no')); % end % dat{trlop} = preproc(dat{trlop}, cfg.artfctdef.zvalue.channel(sgnlop), hdr.Fs, cfg.artfctdef.zvalue, [], fltpadding, fltpadding); % % accumulate the sum and the sum-of-squares @@ -572,7 +572,7 @@ artend = find(diff([artval 0])==-1); artifact = [artbeg(:) artend(:)]; -if strcmp(cfg.artfctdef.zvalue.artfctpeak,'yes') +if strcmp(cfg.artfctdef.zvalue.artfctpeak, 'yes') cnt=1; shift=opt.trl(1,1)-1; for tt=1:opt.numtrl @@ -623,7 +623,7 @@ function artval_cb(h, eventdata) artval = cell(1,opt.numtrl); for trlop=1:opt.numtrl - if opt.thresholdsum, + if opt.thresholdsum % threshold the accumulated z-values artval{trlop} = opt.zsum{trlop}>opt.threshold; else @@ -653,7 +653,7 @@ function artval_cb(h, eventdata) % if the user specifies that the trial is not OK % reject the whole trial if there is no extra-threshold data, % otherwise use the artifact as found by the thresholding - if opt.thresholdsum && opt.keep(trlop)==-1, + if opt.thresholdsum && opt.keep(trlop)==-1 % threshold the accumulated z-values artval{trlop} = opt.zsum{trlop}>opt.threshold; elseif opt.keep(trlop)==-1 @@ -711,7 +711,7 @@ function keyboard_cb(h, eventdata) % If a mouseclick was made, use that value. If not, determine the key that % corresponds to the uicontrol element that was activated. -if isa(eventdata,'matlab.ui.eventdata.ActionData') % only the case when clicked with mouse +if isa(eventdata, 'matlab.ui.eventdata.ActionData') % only the case when clicked with mouse curKey = get(h, 'userdata'); elseif isa(eventdata, 'matlab.ui.eventdata.KeyData') % only when key was pressed if isempty(eventdata.Character) && any(strcmp(eventdata.Key, {'control', 'shift', 'alt', '0'})) @@ -728,7 +728,7 @@ function keyboard_cb(h, eventdata) elseif isempty(eventdata) % matlab2012b returns an empty double upon a mouse click curKey = get(h, 'userdata'); else - error('cannot process user input, please report this on http://bugzilla.fieldtriptoolbox.org including your MATLAB version'); + ft_error('cannot process user input, please report this on http://bugzilla.fieldtriptoolbox.org including your MATLAB version'); end h = getparent(h); % otherwise h is empty if isa [...].ActionData @@ -942,9 +942,9 @@ function redraw_cb(h, eventdata) end if ~isempty(opt.data) - data = ft_fetch_data(opt.data, 'header', hdr, 'begsample', trl(trlop,1), 'endsample', trl(trlop,2), 'chanindx', sgnind, 'checkboundary', strcmp(cfg.continuous,'no')); + data = ft_fetch_data(opt.data, 'header', hdr, 'begsample', trl(trlop,1), 'endsample', trl(trlop,2), 'chanindx', sgnind, 'checkboundary', strcmp(cfg.continuous, 'no')); else - data = ft_read_data(cfg.datafile, 'header', hdr, 'begsample', trl(trlop,1), 'endsample', trl(trlop,2), 'chanindx', sgnind, 'checkboundary', strcmp(cfg.continuous,'no')); + data = ft_read_data(cfg.datafile, 'header', hdr, 'begsample', trl(trlop,1), 'endsample', trl(trlop,2), 'chanindx', sgnind, 'checkboundary', strcmp(cfg.continuous, 'no')); end %data = preproc(data, '', hdr.Fs, artcfg, [], artcfg.fltpadding, artcfg.fltpadding); str = sprintf('trial %3d, channel %s', opt.trlop, hdr.label{sgnind}); @@ -958,7 +958,7 @@ function redraw_cb(h, eventdata) if isempty(get(opt.h1, 'children')) for k = 1:opt.numtrl xval = opt.trl(k,1):opt.trl(k,2); - if opt.thresholdsum, + if opt.thresholdsum yval = opt.zsum{k}; else yval = opt.zmax{k}; @@ -975,7 +975,7 @@ function redraw_cb(h, eventdata) if isempty(boxhandle) % draw it xval = trl(opt.trlop,1):trl(opt.trlop,2); - if opt.thresholdsum, + if opt.thresholdsum yval = opt.zsum{opt.trlop}; else yval = opt.zmax{opt.trlop}; @@ -984,7 +984,7 @@ function redraw_cb(h, eventdata) else % update it xval = trl(opt.trlop,1):trl(opt.trlop,2); - if opt.thresholdsum, + if opt.thresholdsum yval = opt.zsum{opt.trlop}; else yval = opt.zmax{opt.trlop}; @@ -999,7 +999,7 @@ function redraw_cb(h, eventdata) % they have to be drawn for k = 1:opt.numtrl xval = trl(k,1):trl(k,2); - if opt.thresholdsum, + if opt.thresholdsum yval = opt.zsum{k}; else yval = opt.zmax{k}; @@ -1013,7 +1013,7 @@ function redraw_cb(h, eventdata) % they can be updated for k = 1:opt.numtrl xval = trl(k,1):trl(k,2); - if opt.thresholdsum, + if opt.thresholdsum yval = opt.zsum{k}; else yval = opt.zmax{k}; diff --git a/external/fieldtrip/ft_audiovideobrowser.m b/external/fieldtrip/ft_audiovideobrowser.m index 7205e231..c0720f55 100644 --- a/external/fieldtrip/ft_audiovideobrowser.m +++ b/external/fieldtrip/ft_audiovideobrowser.m @@ -94,7 +94,7 @@ function ft_audiovideobrowser(cfg, data) % in principle it would be possible to read it from cfg.datafile, but the % synchronization information will not automatically be present, as that % requires parsing one of the trigger channels - error('the data header is not available') + ft_error('the data header is not available') end assert(isfield(datahdr, 'FirstTimeStamp'), 'sycnhronization information is missing in the data header'); @@ -108,7 +108,7 @@ function ft_audiovideobrowser(cfg, data) fprintf('using data.sampleinfo\n'); trl = data.sampleinfo; else - error('the EEG/MEG data segments should be specified'); + ft_error('the EEG/MEG data segments should be specified'); end numtrl = size(trl,1); @@ -219,13 +219,13 @@ function ft_audiovideobrowser(cfg, data) switch response case 'n' if trllop==numtrl - warning('already at the last trial'); + ft_warning('already at the last trial'); else trllop = trllop+1; end case 'p' if trllop==1 - warning('already at first trial'); + ft_warning('already at first trial'); else trllop = trllop-1; end diff --git a/external/fieldtrip/ft_channelnormalise.m b/external/fieldtrip/ft_channelnormalise.m index ba75b0a6..cb78b3c4 100644 --- a/external/fieldtrip/ft_channelnormalise.m +++ b/external/fieldtrip/ft_channelnormalise.m @@ -1,13 +1,20 @@ function [dataout] = ft_channelnormalise(cfg, data) -% FT_CHANNELNORMALISE shifts and scales all channles of the the input data -% to a mean of zero and a standard deviation of one. +% FT_CHANNELNORMALISE shifts and scales all channels of the the input data. +% The default behavior is to subtract each channel's mean, and scale to a +% standard deviation of 1, for each channel individually. % % Use as % [dataout] = ft_channelnormalise(cfg, data) % % The configuration can contain +% cfg.channel = 'all', or a selection of channels % cfg.trials = 'all' or a selection given as a 1xN vector (default = 'all') +% cfg.demean = 'yes' or 'no' (or boolean value) (default = 'yes') +% cfg.method = 'perchannel', or 'acrosschannel', computes the +% standard deviation per channel, or across all channels. +% The latter method leads to the same scaling across +% channels and preserves topographical distributions % % To facilitate data-handling and distributed computing you can use % cfg.inputfile = ... @@ -57,8 +64,21 @@ return end +cfg = ft_checkconfig(cfg, 'allowedval', {'method', 'perchannel', 'acrosschannel'}); + % set the defaults +cfg.channel = ft_getopt(cfg, 'channel', 'all'); cfg.trials = ft_getopt(cfg, 'trials', 'all', 1); +cfg.demean = ft_getopt(cfg, 'demean', 'yes'); +cfg.method = ft_getopt(cfg, 'method', 'perchannel'); % or acrosschannel +dodemean = istrue(cfg.demean); +doperchannel = strcmp(cfg.method, 'perchannel'); + +% select channels and trials of interest, by default this will select all channels and trials +tmpcfg = keepfields(cfg, {'trials', 'channel', 'showcallinfo'}); +data = ft_selectdata(tmpcfg, data); +% restore the provenance information +[cfg, data] = rollback_provenance(cfg, data); % store original datatype dtype = ft_datatype(data); @@ -67,7 +87,7 @@ data = ft_checkdata(data, 'datatype', 'raw', 'feedback', 'yes'); % select trials of interest -tmpcfg = keepfields(cfg, 'trials'); +tmpcfg = keepfields(cfg, {'trials', 'showcallinfo'}); data = ft_selectdata(tmpcfg, data); % restore the provenance information [cfg, data] = rollback_provenance(cfg, data); @@ -94,17 +114,37 @@ end % compute the mean and std +n = zeros(numel(data.label), numel(data.trial)); for k = 1:ntrl - n(k,1) = size(data.trial{k},2); - datsum = datsum + sum(data.trial{k},2); - datssq = datssq + sum(data.trial{k}.^2,2); + n(:,k) = sum(~isnan(data.trial{k}),2); + datsum = datsum + nansum(data.trial{k},2); + datssq = datssq + nansum(data.trial{k}.^2,2); +end +datmean = datsum./nansum(n, 2); % apply the mean per channel always +if ~doperchannel + % update the intermediate variables in order to compute std across channels + datsum(:) = nansum(datsum); + datssq(:) = nansum(datssq); + n = repmat(nansum(n, 1), size(n, 1), 1); end -datmean = datsum./sum(n); -datstd = sqrt( (datssq - (datsum.^2)./sum(n))./sum(n)); %quick way to compute std from sum and sum-of-squared values +datstd = sqrt( (datssq - (datsum.^2)./nansum(n, 2))./nansum(n, 2)); %quick way to compute std from sum and sum-of-squared values + +% keep mean and std in output cfg +if dodemean + cfg.mu = datmean; +else + cfg.mu = []; +end +cfg.sigma = datstd; % demean and normalise for k = 1:ntrl - dataout.trial{k} = (data.trial{k}-datmean(:,ones(1,n(k))))./datstd(:,ones(1,n(k))); + onesvec = ones(1,size(data.trial{k},2)); + if dodemean + dataout.trial{k} = (data.trial{k}-datmean(:,onesvec))./datstd(:,onesvec); + else + dataout.trial{k} = data.trial{k}./datstd(:,onesvec); + end end % convert back to input type if necessary diff --git a/external/fieldtrip/ft_channelrepair.m b/external/fieldtrip/ft_channelrepair.m index faa01573..6206a347 100644 --- a/external/fieldtrip/ft_channelrepair.m +++ b/external/fieldtrip/ft_channelrepair.m @@ -4,15 +4,12 @@ % plain average of of all neighbours, by a weighted average of all neighbours, by an % interpolation based on a surface Laplacian, or by spherical spline interpolating (see % Perrin et al., 1989). -% -% The weighted neighbour approach cannot be used reliably to repair multiple bad channels -% that lie next to each other. % % Use as % [interp] = ft_channelrepair(cfg, data) % % The configuration must contain -% cfg.method = 'weighted', 'average', 'spline' or 'slap' (default = 'weighted') +% cfg.method = 'weighted', 'average', 'spline', 'slap' or 'nan' (default = 'weighted') % cfg.badchannel = cell-array, see FT_CHANNELSELECTION for details % cfg.missingchannel = cell-array, see FT_CHANNELSELECTION for details % cfg.neighbours = neighbourhood structure, see also FT_PREPARE_NEIGHBOURS @@ -20,6 +17,9 @@ % cfg.lambda = regularisation parameter (default = 1e-5, not for method 'distance') % cfg.order = order of the polynomial interpolation (default = 4, not for method 'distance') % +% The weighted neighbour approach cannot be used reliably to repair multiple bad channels +% that lie next to each other. +% % If you want to reconstruct channels that are absent in your data, those channels may % also be missing from the sensor definition (grad, elec or opto) and determining the % neighbours is non-trivial. In that case you must use a complete sensor definition from @@ -33,6 +33,10 @@ % cfg.opto = structure with optode definition, see FT_DATATYPE_SENS % cfg.optofile = name of file containing the optode definition, see FT_READ_SENS % +% This function only interpolates data over space, not over time. If you want to +% interpolate using temporal information, e.g. using a segment of data before and +% after the nan-marked artifact, you should use FT_INTERPOLATENAN. +% % To facilitate data-handling and distributed computing you can use % cfg.inputfile = ... % cfg.outputfile = ... @@ -41,7 +45,7 @@ % files should contain only a single variable, corresponding with the % input/output structure. % -% See also FT_MEGREALIGN, FT_MEGPLANAR, FT_PREPARE_NEIGHBOURS +% See also FT_MEGREALIGN, FT_MEGPLANAR, FT_PREPARE_NEIGHBOURS, FT_INTERPOLATENAN % Copyright (C) 2004-2009, Robert Oostenveld % Copyright (C) 2012-2013, J?rn M. Horschig, Jason Farquhar @@ -83,7 +87,7 @@ end % check if the input cfg is valid for this function -cfg = ft_checkconfig(cfg, 'renamedval', {'method', 'nearest', 'weighted'}); +cfg = ft_checkconfig(cfg, 'renamedval', {'method', 'nearest', 'weighted'}); % set the default configuration cfg.badchannel = ft_getopt(cfg, 'badchannel', {}); @@ -94,11 +98,11 @@ cfg.order = ft_getopt(cfg, 'order', []); % subfunction will handle this % check if the input cfg is valid for this function -if strcmp(cfg.method, 'weighted'); +if strcmp(cfg.method, 'weighted') cfg = ft_checkconfig(cfg, 'required', {'neighbours'}); end -% store original datatype +% store the original datatype dtype = ft_datatype(data); % check if the input data is valid for this function @@ -111,38 +115,47 @@ % restore the provenance information [cfg, data] = rollback_provenance(cfg, data); -% prefer sens from cfg over sens from data -try - sens = ft_fetch_sens(cfg); -catch - sens = ft_fetch_sens(cfg, data); +if strcmp(cfg.method, 'nan') + % this does not require the spatial information of the channels + sens = []; + sens.chanpos = zeros(0, 3); + sens.label = cell(0, 1); +else + % this requires the spatial information of the channels + try + % prefer sens from cfg over sens from data + sens = ft_fetch_sens(cfg); + catch + sens = ft_fetch_sens(cfg, data); + end end % determine the type of data -iseeg = ft_senstype(sens, 'eeg'); -ismeg = ft_senstype(sens, 'meg'); +iseeg = ft_senstype(sens, 'eeg'); +ismeg = ft_senstype(sens, 'meg'); isnirs = ft_senstype(sens, 'opto'); % check if any of the channel positions contains NaNs; this happens when % component data are backprojected to the sensor level if any(isnan(sens.chanpos(:))) - error('The channel positions contain NaNs; this prohibits correct behavior of the function. Please replace the input channel definition with one that contains valid channel positions'); + ft_error('The channel positions contain NaNs; this prohibits correct behavior of the function. Please replace the input channel definition with one that contains valid channel positions'); end if ismeg && ~any(strcmp(ft_senstype(sens), {'ctf151', 'ctf275', 'bti148', 'bti248', 'babysquid74'})) % MEG systems with only magnetometers or axial gradiometers are easy, planar systems are not - warning('be careful when using "%s" - mixing of sensor types (e.g. magnetometers and gradiometers) can lead to wrong data. Check your neighbour-structure thoroughly', ft_senstype(sens)); + ft_warning('be careful when using "%s" - mixing of sensor types (e.g. magnetometers and gradiometers) can lead to wrong data. Check your neighbour-structure thoroughly', ft_senstype(sens)); end -channels = ft_channelselection(cfg.badchannel, data.label); -% get selection of channels that are missing -cfg.missingchannel = [cfg.missingchannel cfg.badchannel(~ismember(cfg.badchannel, channels))]; -% get the selection of channels that are bad -cfg.badchannel = channels; +% get selection of channels that are missing and/or bad +cfg.missingchannel = cat(1, cfg.missingchannel(:), cfg.badchannel); +cfg.missingchannel = setdiff(cfg.missingchannel, data.label); +cfg.badchannel = ft_channelselection(cfg.badchannel, data.label); +fprintf('There are %d bad channels\n', length(cfg.badchannel)); +fprintf('There are %d missing channels\n', length(cfg.missingchannel)); % warn if weighted neighbour approach (see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=634) if ~isempty(cfg.missingchannel) && strcmp(cfg.method, 'weighted') - warning('Reconstructing missing channels using the weighted neighbour approach is not recommended!'); + ft_warning('Reconstructing missing channels using the weighted neighbour approach is not recommended!'); end % store the realigned data in a new structure @@ -152,22 +165,22 @@ % first repair badchannels if strcmp(cfg.method, 'weighted') || strcmp(cfg.method, 'average') - + if ~isempty(cfg.badchannel) - [goodchanlabels,goodchanindcs] = setdiff(data.label,cfg.badchannel); + [goodchanlabels, goodchanindcs] = setdiff(data.label, cfg.badchannel); goodchanindcs = sort(goodchanindcs); % undo automatical sorting by setdiff connectivityMatrix = channelconnectivity(cfg, data); connectivityMatrix = connectivityMatrix(:, goodchanindcs); % all chans x good chans - - Ntrials = length(data.trial); - Nchans = length(data.label); - - repair = eye(Nchans,Nchans); + + ntrials = length(data.trial); + nchans = length(data.label); + + repair = eye(nchans, nchans); badindx = match_str(data.label, cfg.badchannel); - + for k=badindx' fprintf('repairing channel %s\n', data.label{k}); - repair(k,k) = 0; + repair(k, k) = 0; l = goodchanindcs(connectivityMatrix(k, :)); % get bad channels out [a, b] = setdiff(data.label(l), data.label(badindx)); @@ -180,21 +193,21 @@ badsensindx = a(b); fprintf('\tusing neighbour %s\n', sens.label{goodsensindx}); if strcmp(cfg.method, 'weighted') - distance = sqrt(sum((sens.chanpos(goodsensindx,:) - repmat(sens.chanpos(badsensindx, :), numel(goodsensindx), 1)).^2, 2)); + distance = sqrt(sum((sens.chanpos(goodsensindx, :) - repmat(sens.chanpos(badsensindx, :), numel(goodsensindx), 1)).^2, 2)); elseif strcmp(cfg.method, 'average') - distance = 1; + distance = 1; end - repair(k,l) = (1./distance); - repair(k,l) = repair(k,l) ./ sum(repair(k,l)); + repair(k, l) = (1./distance); + repair(k, l) = repair(k, l) ./ sum(repair(k, l)); end - + % use sparse matrix to speed up computations repair = sparse(repair); - + % compute the repaired data for each trial fprintf('\n'); - fprintf('repairing bad channels for %i trials %d', Ntrials); - for i=1:Ntrials + fprintf('repairing bad channels for %i trials %d', ntrials); + for i=1:ntrials fprintf('.'); interp.trial{i} = repair * data.trial{i}; end @@ -203,31 +216,31 @@ fprintf('no bad channels to repair\n'); interp.trial = data.trial; end - + if ~isempty(cfg.missingchannel) fprintf('Interpolated missing channels will be concatenated.\n'); - - Nchans = length(interp.label); - Ntrials = length(interp.trial); - + + nchans = length(interp.label); + ntrials = length(interp.trial); + % interpolation missing channels goodchanindcs = 1:numel(data.label); for chan=1:numel(cfg.missingchannel) interp.label{end+1} = cfg.missingchannel{chan}; % creating dummy trial data - for i=1:Ntrials + for i=1:ntrials interp.trial{i}(end+1, :) = 0; end end connectivityMatrix = channelconnectivity(cfg, interp); connectivityMatrix = connectivityMatrix(:, goodchanindcs); % all chans x good chans - - repair = eye(Nchans,Nchans); + + repair = eye(nchans, nchans); missingindx = match_str(interp.label, cfg.missingchannel); unable = []; for k=missingindx' fprintf('trying to reconstruct missing channel %s\n', interp.label{k}); - repair(k,k) = 0; + repair(k, k) = 0; l = goodchanindcs(connectivityMatrix(k, :)); % get bad channels out [a, b] = setdiff(data.label(l), interp.label(missingindx)); @@ -244,33 +257,33 @@ badsensindx = a(b); fprintf('\tusing neighbour %s\n', sens.label{goodsensindx}); if strcmp(cfg.method, 'weighted') - distance = sqrt(sum((sens.chanpos(goodsensindx,:) - repmat(sens.chanpos(badsensindx, :), numel(goodsensindx), 1)).^2, 2)); + distance = sqrt(sum((sens.chanpos(goodsensindx, :) - repmat(sens.chanpos(badsensindx, :), numel(goodsensindx), 1)).^2, 2)); elseif strcmp(cfg.method, 'average') - distance = 1; + distance = 1; end - repair(k,l) = (1./distance); - repair(k,l) = repair(k,l) ./ sum(repair(k,l)); + repair(k, l) = (1./distance); + repair(k, l) = repair(k, l) ./ sum(repair(k, l)); end end - + % use sparse matrix to speed up computations repair = sparse(repair); - + fprintf('\n'); % compute the missing data for each trial and remove those could not be % reconstructed fprintf('\n'); - fprintf('interpolating missing channel for %i trials %d', Ntrials); - for i=1:Ntrials + fprintf('interpolating missing channel for %i trials %d', ntrials); + for i=1:ntrials fprintf('.'); interp.trial{i} = repair * interp.trial{i}; interp.trial{i}(unable, :) = []; end - + interp.label(unable) = []; fprintf('\n'); end - + elseif strcmp(cfg.method, 'spline') || strcmp(cfg.method, 'slap') if ~isempty(cfg.badchannel) || ~isempty(cfg.missingchannel) fprintf('Spherical spline and surface Laplacian interpolation will treat bad and missing channels the same. Missing channels will be concatenated at the end of your data structure.\n'); @@ -283,22 +296,22 @@ try, chanori = sens.chanori(sensidx, :); end try, chantype = sens.chantype(sensidx, :); end try, chanunit = sens.chanunit(sensidx, :); end - + fprintf('Checking spherical fit... '); [c, r] = fitsphere(chanpos); d = chanpos - repmat(c, numel(find(sensidx)), 1); d = sqrt(sum(d.^2, 2)); d = mean(abs(d) / r); if abs(d-1) > 0.1 - warning('bad spherical fit (residual: %.2f%%). The interpolation will be inaccurate.', 100*(d-1)); + ft_warning('bad spherical fit (residual: %.2f%%). The interpolation will be inaccurate.', 100*(d-1)); elseif abs(d-1) < 0.01 fprintf('perfect spherical fit (residual: %.1f%%)\n', 100*(d-1)); else fprintf('good spherical fit (residual: %.1f%%)\n', 100*(d-1)); end - + if strcmp(cfg.method, 'slap') - warning('''slap'' method is not fully supported - be careful in interpreting your results'); + ft_warning('''slap'' method is not fully supported - be careful in interpreting your results'); end % move missing channels to the end missidx = find(ismember(label, cfg.missingchannel)); @@ -306,55 +319,76 @@ label(missidx) = []; chanpos(end+1:end+numel(missidx), :) = chanpos(missidx, :); chanpos(missidx, :) = []; - + % select good channels only for interpolation - [goodchanlabels,goodchanindcs] = setdiff(label,badchannels); + [goodchanlabels, goodchanindcs] = setdiff(label, badchannels); allchans = false; if isempty(goodchanindcs) goodchanindcs = 1:numel(label); allchans = true; - warning('No good channels found - interpolating based on all channels'); + ft_warning('No good channels found - interpolating based on all channels'); end % undo automatical sorting by setdiff goodchanindcs = sort(goodchanindcs); % only take good channels that are in data (and remember how they are sorted) [dataidx, sensidx] = match_str(data.label, label(goodchanindcs)); - + % interpolate fprintf('computing weight matrix...'); - repair = sphericalSplineInterpolate(chanpos(goodchanindcs(sensidx),:)',chanpos', cfg.lambda, cfg.order, cfg.method); + repair = sphericalSplineInterpolate(chanpos(goodchanindcs(sensidx), :)', chanpos', cfg.lambda, cfg.order, cfg.method); fprintf(' done!\n'); - + if ~allchans % only use the rows corresponding to the channels that actually need interpolation - repair(goodchanindcs(sensidx),:) = 0; + repair(goodchanindcs(sensidx), :) = 0; for k = 1:numel(sensidx) i = strcmp(label(goodchanindcs(sensidx(k))), label(goodchanindcs(sensidx))); repair(goodchanindcs(sensidx(k)), i) = 1; end end % else all rows need to be interpolated - - % compute the missing data for each trial and remove those could not be - % reconstructed - Ntrials = length(data.trial); + + % compute the missing data for each trial and remove those could not be reconstructed + ntrials = length(data.trial); fprintf('\n'); - fprintf('interpolating channels for %i trials %d', Ntrials); - for i=1:Ntrials + fprintf('interpolating channels for %i trials %d', ntrials); + for i=1:ntrials fprintf('.'); interp.trial{i} = repair * data.trial{i}(dataidx, :); end fprintf('\n'); % update channels labels due to reordering by interp.label = label; - + +elseif strcmp(cfg.method, 'nan') + % copy the original data over to the output data structure + interp.trial = data.trial; + if ~isempty(cfg.badchannel) + for k=1:length(cfg.badchannel) + fprintf('inserting nan into bad channel %s\n', cfg.badchannel{k}); + end + badindx = match_str(interp.label, cfg.badchannel); + for i=1:numel(interp.trial) + interp.trial{i}(badindx, :) = nan; + end + end % bad channels + if ~isempty(cfg.missingchannel) + for k=1:length(cfg.missingchannel) + fprintf('inserting nan into missing channel %s\n', cfg.missingchannel{k}); + end + interp.label = cat(1, interp.label(:), cfg.missingchannel(:)); + for i=1:numel(interp.trial) + interp.trial{i} = cat(1, interp.trial{i}, nan(length(cfg.missingchannel), length(interp.time{i}))); + end + end % missing channels + else - error('unknown method "%s" for interpolation', cfg.method); + ft_error('unknown method "%s" for interpolation', cfg.method); end % copy the additional fields over to the newly interpolated data datafields = fieldnames(data); interpfields = fieldnames(interp); -exfields = setdiff(datafields,interpfields); +exfields = setdiff(datafields, interpfields); for f = 1:length(exfields) interp.(exfields{f}) = data.(exfields{f}); end diff --git a/external/fieldtrip/ft_channelselection.m b/external/fieldtrip/ft_channelselection.m deleted file mode 100644 index a008dc79..00000000 --- a/external/fieldtrip/ft_channelselection.m +++ /dev/null @@ -1,492 +0,0 @@ -function [channel] = ft_channelselection(desired, datachannel, senstype) - -% FT_CHANNELSELECTION makes a selection of EEG and/or MEG channel labels. -% This function translates the user-specified list of channels into channel -% labels as they occur in the data. This channel selection procedure can be -% used throughout FieldTrip. -% -% Use as: -% channel = ft_channelselection(desired, datachannel) -% -% You can specify a mixture of real channel labels and of special strings, -% or index numbers that will be replaced by the corresponding channel -% labels. Channels that are not present in the raw datafile are -% automatically removed from the channel list. -% -% E.g. the input 'channel' can be: -% 'all' is replaced by all channels in the datafile -% 'gui' a graphical user interface will pop up to select the channels -% 'C*' is replaced by all channels that match the wildcard, e.g. C1, C2, C3, ... -% '*1' is replaced by all channels that match the wildcard, e.g. C1, P1, F1, ... -% 'M*1' is replaced by all channels that match the wildcard, e.g. MEG0111, MEG0131, MEG0131, ... -% 'meg' is replaced by all MEG channels (works for CTF, 4D, Neuromag and Yokogawa) -% 'megref' is replaced by all MEG reference channels (works for CTF and 4D) -% 'meggrad' is replaced by all MEG gradiometer channels (works for Yokogawa and Neuromag-306) -% 'megmag' is replaced by all MEG magnetometer channels (works for Yokogawa and Neuromag-306) -% 'eeg' is replaced by all recognized EEG channels (this is system dependent) -% 'eeg1020' is replaced by 'Fp1', 'Fpz', 'Fp2', 'F7', 'F3', ... -% 'eog' is replaced by all recognized EOG channels -% 'ecg' is replaced by all recognized ECG channels -% 'nirs' is replaced by all channels recognized as NIRS channels -% 'emg' is replaced by all channels in the datafile starting with 'EMG' -% 'lfp' is replaced by all channels in the datafile starting with 'lfp' -% 'mua' is replaced by all channels in the datafile starting with 'mua' -% 'spike' is replaced by all channels in the datafile starting with 'spike' -% 10 is replaced by the 10th channel in the datafile -% -% Other channel groups are -% 'EEG1010' with approximately 90 electrodes -% 'EEG1005' with approximately 350 electrodes -% 'EEGCHWILLA' for Dorothee Chwilla's electrode caps (used at the DCC) -% 'EEGBHAM' for the 128 channel EEG system used in Birmingham -% 'EEGREF' for mastoid and ear electrodes (M1, M2, LM, RM, A1, A2) -% 'MZ' for MEG zenith -% 'ML' for MEG left -% 'MR' for MEG right -% 'MLx', 'MRx' and 'MZx' with x=C,F,O,P,T for left/right central, frontal, occipital, parietal and temporal -% -% You can also exclude channels or channel groups using the following syntax -% {'all', '-POz', '-Fp1', -EOG'} -% -% See also FT_PREPROCESSING, FT_SENSLABEL, FT_MULTIPLOTER, FT_MULTIPLOTTFR, -% FT_SINGLEPLOTER, FT_SINGLEPLOTTFR - -% Note that the order of channels that is returned should correspond with -% the order of the channels in the data. - -% Copyright (C) 2003-2014, Robert Oostenveld -% -% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org -% for the documentation and details. -% -% FieldTrip is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. -% -% FieldTrip is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with FieldTrip. If not, see . -% -% $Id$ - -% this is to avoid a recursion loop -persistent recursion - -if isempty(recursion) - recursion = false; -end - -if nargin<3 - senstype = ft_senstype(datachannel); -end - -if ~iscell(datachannel) - if ischar(datachannel) - datachannel = {datachannel}; - else - error('please specify the data channels as a cell-array'); - end -end - -if ~ischar(desired) && ~isnumeric(desired) && ~iscell(desired) - error('please specify the desired channels as a cell-array or a string'); -end - -% start with the list of desired channels, this will be pruned/expanded -channel = desired; - -if length(datachannel)~=length(unique(datachannel)) - warning('discarding non-unique channel names'); - sel = false(size(datachannel)); - for i=1:length(datachannel) - sel(i) = sum(strcmp(datachannel, datachannel{i}))==1; - end - datachannel = datachannel(sel); -end - -if any(size(channel) == 0) - % there is nothing to do if it is empty - return -end - -if ~iscell(datachannel) - % ensure that a single input argument like 'all' also works - datachannel = {datachannel}; -end - -if isnumeric(channel) - % remove channels tha fall outside the range - channel = channel(channel>=1 & channel<=numel(datachannel)); - % change index into channelname - channel = datachannel(channel); - return -end - -if ~iscell(channel) - % ensure that a single input argument like 'all' also works - % the case of a vector with channel indices has already been dealt with - channel = {channel}; -end - -% ensure that both inputs are column vectors -channel = channel(:); -datachannel = datachannel(:); - -% remove channels that occur more than once, this sorts the channels alphabetically -[channel, indx] = unique(channel); -% undo the sorting, make the order identical to that of the data channels -[dum, indx] = sort(indx); -channel = channel(indx); - -[dataindx, chanindx] = match_str(datachannel, channel); -if length(chanindx)==length(channel) - % there is a perfect match between the channels and the datachannels, only some reordering is needed - channel = channel(chanindx); - % no need to look at channel groups - return -end - -% define the known groups with channel labels -labelall = datachannel; -label1020 = ft_senslabel('eeg1020'); % use external helper function -label1010 = ft_senslabel('eeg1010'); % use external helper function -label1005 = ft_senslabel('eeg1005'); % use external helper function -labelchwilla = {'Fz', 'Cz', 'Pz', 'F7', 'F8', 'LAT', 'RAT', 'LT', 'RT', 'LTP', 'RTP', 'OL', 'OR', 'FzA', 'Oz', 'F7A', 'F8A', 'F3A', 'F4A', 'F3', 'F4', 'P3', 'P4', 'T5', 'T6', 'P3P', 'P4P'}'; -labelbham = {'P9', 'PPO9h', 'PO7', 'PPO5h', 'PPO3h', 'PO5h', 'POO9h', 'PO9', 'I1', 'OI1h', 'O1', 'POO1', 'PO3h', 'PPO1h', 'PPO2h', 'POz', 'Oz', 'Iz', 'I2', 'OI2h', 'O2', 'POO2', 'PO4h', 'PPO4h', 'PO6h', 'POO10h', 'PO10', 'PO8', 'PPO6h', 'PPO10h', 'P10', 'P8', 'TPP9h', 'TP7', 'TTP7h', 'CP5', 'TPP7h', 'P7', 'P5', 'CPP5h', 'CCP5h', 'CP3', 'P3', 'CPP3h', 'CCP3h', 'CP1', 'P1', 'Pz', 'CPP1h', 'CPz', 'CPP2h', 'P2', 'CPP4h', 'CP2', 'CCP4h', 'CP4', 'P4', 'P6', 'CPP6h', 'CCP6h', 'CP6', 'TPP8h', 'TP8', 'TPP10h', 'T7', 'FTT7h', 'FT7', 'FC5', 'FCC5h', 'C5', 'C3', 'FCC3h', 'FC3', 'FC1', 'C1', 'CCP1h', 'Cz', 'FCC1h', 'FCz', 'FFC1h', 'Fz', 'FFC2h', 'FC2', 'FCC2h', 'CCP2h', 'C2', 'C4', 'FCC4h', 'FC4', 'FC6', 'FCC6h', 'C6', 'TTP8h', 'T8', 'FTT8h', 'FT8', 'FT9', 'FFT9h', 'F7', 'FFT7h', 'FFC5h', 'F5', 'AFF7h', 'AF7', 'AF5h', 'AFF5h', 'F3', 'FFC3h', 'F1', 'AF3h', 'Fp1', 'Fpz', 'Fp2', 'AFz', 'AF4h', 'F2', 'FFC4h', 'F4', 'AFF6h', 'AF6h', 'AF8', 'AFF8h', 'F6', 'FFC6h', 'FFT8h', 'F8', 'FFT10h', 'FT10'}; -labelref = {'M1', 'M2', 'LM', 'RM', 'A1', 'A2'}'; -labeleog = datachannel(strncmp('EOG', datachannel, length('EOG'))); % anything that starts with EOG -labeleog = [labeleog(:); {'HEOG', 'VEOG', 'VEOG-L', 'VEOG-R', 'hEOG', 'vEOG', 'Eye_Ver', 'Eye_Hor'}']; % or any of these -labelecg = datachannel(strncmp('ECG', datachannel, length('ECG'))); -labelemg = datachannel(strncmp('EMG', datachannel, length('EMG'))); -labellfp = datachannel(strncmp('lfp', datachannel, length('lfp'))); -labelmua = datachannel(strncmp('mua', datachannel, length('mua'))); -labelspike = datachannel(strncmp('spike', datachannel, length('spike'))); -labelnirs = datachannel(~cellfun(@isempty, regexp(datachannel, sprintf('%s%s', regexptranslate('wildcard','Rx*-Tx*[*]'), '$')))); - -% use regular expressions to deal with the wildcards -labelreg = false(size(datachannel)); -findreg = []; -for i=1:length(channel) - if length(channel{i}) < 1 - continue; - end - - if strcmp((channel{i}(1)), '-') - % skip channels to be excluded - continue; - end - - rexp = sprintf('%s%s%s', '^', regexptranslate('wildcard',channel{i}), '$'); - lreg = ~cellfun(@isempty, regexp(datachannel, rexp)); - if any(lreg) - labelreg = labelreg | lreg; - findreg = [findreg; i]; - end -end - -if ~isempty(findreg) - findreg = unique(findreg); % remove multiple occurances due to multiple wildcards - labelreg = datachannel(labelreg); -end - -% initialize all the system-specific variables to empty -labelmeg = []; -labelmeggrad = []; -labelmegref = []; -labelmegmag = []; -labeleeg = []; - -switch senstype - - case {'yokogawa', 'yokogawa160', 'yokogawa160_planar', 'yokogawa64', 'yokogawa64_planar', 'yokogawa440', 'yokogawa440_planar'} - % Yokogawa axial gradiometers channels start with AG, hardware planar gradiometer - % channels start with PG, magnetometers start with M - megax = strncmp('AG', datachannel, length('AG')); - megpl = strncmp('PG', datachannel, length('PG')); - megmag = strncmp('M', datachannel, length('M' )); - megind = logical( megax + megpl + megmag); - labelmeg = datachannel(megind); - labelmegmag = datachannel(megmag); - labelmeggrad = datachannel(megax | megpl); - - case {'ctf64'} - labelml = datachannel(~cellfun(@isempty, regexp(datachannel, '^SL'))); % left MEG channels - labelmr = datachannel(~cellfun(@isempty, regexp(datachannel, '^SR'))); % right MEG channels - labelmeg = cat(1, labelml, labelmr); - labelmegref = [datachannel(strncmp('B' , datachannel, 1)); - datachannel(strncmp('G' , datachannel, 1)); - datachannel(strncmp('P' , datachannel, 1)); - datachannel(strncmp('Q' , datachannel, 1)); - datachannel(strncmp('R' , datachannel, length('G' )))]; - - case {'ctf', 'ctf275', 'ctf151', 'ctf275_planar', 'ctf151_planar'} - % all CTF MEG channels start with "M" - % all CTF reference channels start with B, G, P, Q or R - % all CTF EEG channels start with "EEG" - labelmeg = datachannel(strncmp('M' , datachannel, length('M' ))); - labelmegref = [datachannel(strncmp('B' , datachannel, 1)); - datachannel(strncmp('G' , datachannel, 1)); - datachannel(strncmp('P' , datachannel, 1)); - datachannel(strncmp('Q' , datachannel, 1)); - datachannel(strncmp('R' , datachannel, length('G' )))]; - labeleeg = datachannel(strncmp('EEG', datachannel, length('EEG'))); - - % Not sure whether this should be here or outside the switch or - % whether these specifications should be supported for systems - % other than CTF. - labelmz = datachannel(strncmp('MZ' , datachannel, length('MZ' ))); % central MEG channels - labelml = datachannel(strncmp('ML' , datachannel, length('ML' ))); % left MEG channels - labelmr = datachannel(strncmp('MR' , datachannel, length('MR' ))); % right MEG channels - labelmlc = datachannel(strncmp('MLC', datachannel, length('MLC'))); - labelmlf = datachannel(strncmp('MLF', datachannel, length('MLF'))); - labelmlo = datachannel(strncmp('MLO', datachannel, length('MLO'))); - labelmlp = datachannel(strncmp('MLP', datachannel, length('MLP'))); - labelmlt = datachannel(strncmp('MLT', datachannel, length('MLT'))); - labelmrc = datachannel(strncmp('MRC', datachannel, length('MRC'))); - labelmrf = datachannel(strncmp('MRF', datachannel, length('MRF'))); - labelmro = datachannel(strncmp('MRO', datachannel, length('MRO'))); - labelmrp = datachannel(strncmp('MRP', datachannel, length('MRP'))); - labelmrt = datachannel(strncmp('MRT', datachannel, length('MRT'))); - labelmzc = datachannel(strncmp('MZC', datachannel, length('MZC'))); - labelmzf = datachannel(strncmp('MZF', datachannel, length('MZF'))); - labelmzo = datachannel(strncmp('MZO', datachannel, length('MZO'))); - labelmzp = datachannel(strncmp('MZP', datachannel, length('MZP'))); - - case {'bti', 'bti248', 'bti248grad', 'bti148', 'bti248_planar', 'bti148_planar'} - % all 4D-BTi MEG channels start with "A" - % all 4D-BTi reference channels start with M or G - - labelmeg = datachannel(myregexp('^A[0-9]+$', datachannel)); - labelmegref = [datachannel(myregexp('^M[CLR][xyz][aA]*$', datachannel)); datachannel(myregexp('^G[xyz][xyz]A$', datachannel)); datachannel(myregexp('^M[xyz][aA]*$', datachannel))]; - labelmegrefa = datachannel(~cellfun(@isempty,strfind(datachannel, 'a'))); - labelmegrefc = datachannel(strncmp('MC', datachannel, 2)); - labelmegrefg = datachannel(myregexp('^G[xyz][xyz]A$', datachannel)); - labelmegrefl = datachannel(strncmp('ML', datachannel, 2)); - labelmegrefr = datachannel(strncmp('MR', datachannel, 2)); - labelmegrefm = datachannel(myregexp('^M[xyz][aA]*$', datachannel)); - - case {'neuromag122' 'neuromag122alt'} - % all neuromag MEG channels start with MEG - % all neuromag EEG channels start with EEG - labelmeg = datachannel(strncmp('MEG', datachannel, length('MEG'))); - labeleeg = datachannel(strncmp('EEG', datachannel, length('EEG'))); - - case {'neuromag306' 'neuromag306alt'} - % all neuromag MEG channels start with MEG - % all neuromag EEG channels start with EEG - % all neuromag-306 gradiometers follow pattern MEG*2,MEG*3 - % all neuromag-306 magnetometers follow pattern MEG*1 - labelmeg = datachannel(strncmp('MEG', datachannel, length('MEG'))); - labeleeg = datachannel(strncmp('EEG', datachannel, length('EEG'))); - - labelmeggrad = labelmeg(~cellfun(@isempty, regexp(labelmeg, '^MEG.*[23]$'))); - labelmegmag = labelmeg(~cellfun(@isempty, regexp(labelmeg, '^MEG.*1$'))); - - case {'ant128', 'biosemi64', 'biosemi128', 'biosemi256', 'egi32', 'egi64', 'egi128', 'egi256', 'eeg1020', 'eeg1010', 'eeg1005', 'ext1020'} - % use an external helper function to define the list with EEG channel names - labeleeg = ft_senslabel(ft_senstype(datachannel)); - - case {'itab153' 'itab28' 'itab28_old'} - % all itab MEG channels start with MAG - labelmeg = datachannel(strncmp('MAG', datachannel, length('MAG'))); - -end % switch ft_senstype - -% figure out if there are bad channels or channel groups that should be excluded -findbadchannel = strncmp('-', channel, length('-')); % bad channels start with '-' -badchannel = channel(findbadchannel); -if ~isempty(badchannel) - for i=1:length(badchannel) - badchannel{i} = badchannel{i}(2:end); % remove the '-' from the channel label - end - badchannel = ft_channelselection(badchannel, datachannel); % support exclusion of channel groups -end - -% determine if any of the known groups is mentioned in the channel list -findall = find(strcmp(channel, 'all')); -% findreg (for the wildcards) is dealt with in the channel group specification above -findmeg = find(strcmpi(channel, 'MEG')); -findemg = find(strcmpi(channel, 'EMG')); -findecg = find(strcmpi(channel, 'ECG')); -findeeg = find(strcmpi(channel, 'EEG')); -findeeg1020 = find(strcmpi(channel, 'EEG1020')); -findeeg1010 = find(strcmpi(channel, 'EEG1010')); -findeeg1005 = find(strcmpi(channel, 'EEG1005')); -findeegchwilla = find(strcmpi(channel, 'EEGCHWILLA')); -findeegbham = find(strcmpi(channel, 'EEGBHAM')); -findeegref = find(strcmpi(channel, 'EEGREF')); -findmegref = find(strcmpi(channel, 'MEGREF')); -findmeggrad = find(strcmpi(channel, 'MEGGRAD')); -findmegmag = find(strcmpi(channel, 'MEGMAG')); -findmegrefa = find(strcmpi(channel, 'MEGREFA')); -findmegrefc = find(strcmpi(channel, 'MEGREFC')); -findmegrefg = find(strcmpi(channel, 'MEGREFG')); -findmegrefl = find(strcmpi(channel, 'MEGREFL')); -findmegrefr = find(strcmpi(channel, 'MEGREFR')); -findmegrefm = find(strcmpi(channel, 'MEGREFM')); -findeog = find(strcmpi(channel, 'EOG')); -findmz = find(strcmp(channel, 'MZ' )); -findml = find(strcmp(channel, 'ML' )); -findmr = find(strcmp(channel, 'MR' )); -findmlc = find(strcmp(channel, 'MLC')); -findmlf = find(strcmp(channel, 'MLF')); -findmlo = find(strcmp(channel, 'MLO')); -findmlp = find(strcmp(channel, 'MLP')); -findmlt = find(strcmp(channel, 'MLT')); -findmrc = find(strcmp(channel, 'MRC')); -findmrf = find(strcmp(channel, 'MRF')); -findmro = find(strcmp(channel, 'MRO')); -findmrp = find(strcmp(channel, 'MRP')); -findmrt = find(strcmp(channel, 'MRT')); -findmzc = find(strcmp(channel, 'MZC')); -findmzf = find(strcmp(channel, 'MZF')); -findmzo = find(strcmp(channel, 'MZO')); -findmzp = find(strcmp(channel, 'MZP')); -findnirs = find(strcmpi(channel, 'NIRS')); -findlfp = find(strcmpi(channel, 'lfp')); -findmua = find(strcmpi(channel, 'mua')); -findspike = find(strcmpi(channel, 'spike')); -findgui = find(strcmpi(channel, 'gui')); - -% remove any occurences of groups in the channel list -channel([ - findall - findreg - findmeg - findemg - findecg - findeeg - findeeg1020 - findeeg1010 - findeeg1005 - findeegchwilla - findeegbham - findeegref - findmegref - findmeggrad - findmegmag - findeog - findmz - findml - findmr - findmlc - findmlf - findmlo - findmlp - findmlt - findmrc - findmrf - findmro - findmrp - findmrt - findmzc - findmzf - findmzo - findmzp - findlfp - findmua - findspike - findnirs - findgui - ]) = []; - -% add the full channel labels to the channel list -if findall, channel = [channel; labelall]; end -if findreg, channel = [channel; labelreg]; end -if findmeg, channel = [channel; labelmeg]; end -if findecg, channel = [channel; labelecg]; end -if findemg, channel = [channel; labelemg]; end -if findeeg, channel = [channel; labeleeg]; end -if findeeg1020, channel = [channel; label1020]; end -if findeeg1010, channel = [channel; label1010]; end -if findeeg1005, channel = [channel; label1005]; end -if findeegchwilla, channel = [channel; labelchwilla]; end -if findeegbham, channel = [channel; labelbham]; end -if findeegref, channel = [channel; labelref]; end -if findmegref, channel = [channel; labelmegref]; end -if findmeggrad, channel = [channel; labelmeggrad]; end -if findmegmag, channel = [channel; labelmegmag]; end -if findmegrefa, channel = [channel; labelmegrefa]; end -if findmegrefc, channel = [channel; labelmegrefc]; end -if findmegrefg, channel = [channel; labelmegrefg]; end -if findmegrefl, channel = [channel; labelmegrefl]; end -if findmegrefr, channel = [channel; labelmegrefr]; end -if findmegrefm, channel = [channel; labelmegrefm]; end -if findeog, channel = [channel; labeleog]; end -if findmz , channel = [channel; labelmz ]; end -if findml , channel = [channel; labelml ]; end -if findmr , channel = [channel; labelmr ]; end -if findmlc, channel = [channel; labelmlc]; end -if findmlf, channel = [channel; labelmlf]; end -if findmlo, channel = [channel; labelmlo]; end -if findmlp, channel = [channel; labelmlp]; end -if findmlt, channel = [channel; labelmlt]; end -if findmrc, channel = [channel; labelmrc]; end -if findmrf, channel = [channel; labelmrf]; end -if findmro, channel = [channel; labelmro]; end -if findmrp, channel = [channel; labelmrp]; end -if findmrt, channel = [channel; labelmrt]; end -if findmzc, channel = [channel; labelmzc]; end -if findmzf, channel = [channel; labelmzf]; end -if findmzo, channel = [channel; labelmzo]; end -if findmzp, channel = [channel; labelmzp]; end -if findlfp, channel = [channel; labellfp]; end -if findmua, channel = [channel; labelmua]; end -if findspike, channel = [channel; labelspike]; end -if findnirs, channel = [channel; labelnirs]; end - -% remove channel labels that have been excluded by the user -badindx = match_str(channel, badchannel); -channel(badindx) = []; - -% remove channel labels that are not present in the data -chanindx = match_str(channel, datachannel); - -channel = channel(chanindx); - -if findgui - indx = select_channel_list(datachannel, match_str(datachannel, channel), 'Select channels'); - channel = datachannel(indx); -end - -% remove channels that occur more than once, this sorts the channels alphabetically -channel = unique(channel); - -if isempty(channel) && ~recursion - % try whether only lowercase channel labels makes a difference - recursion = true; - channel = ft_channelselection(desired, lower(datachannel)); - recursion = false; - % undo the conversion to lowercase, this sorts the channels alphabetically - [c, ia, ib] = intersect(channel, lower(datachannel)); - channel = datachannel(ib); -end - -if isempty(channel) && ~recursion - % try whether only uppercase channel labels makes a difference - recursion = true; - channel = ft_channelselection(desired, upper(datachannel)); - recursion = false; - % undo the conversion to uppercase, this sorts the channels alphabetically - [c, ia, ib] = intersect(channel, lower(datachannel)); - channel = datachannel(ib); -end - -% undo the sorting, make the order identical to that of the data channels -[tmp, indx] = match_str(datachannel, channel); -channel = channel(indx); - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% helper function -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -function match = myregexp(pat, list) -match = false(size(list)); -for i=1:numel(list) - match(i) = ~isempty(regexp(list{i}, pat, 'once')); -end - diff --git a/external/fieldtrip/ft_clusterplot.m b/external/fieldtrip/ft_clusterplot.m index ac5a4898..340ec72f 100644 --- a/external/fieldtrip/ft_clusterplot.m +++ b/external/fieldtrip/ft_clusterplot.m @@ -4,20 +4,21 @@ % % Use as % ft_clusterplot(cfg, stat) -% where the input data is obtained from FT_TIMELOCKSTATISTICS or FT_FREQSTATISTICS -% and the configuration options can be +% where the input data is obtained from FT_TIMELOCKSTATISTICS or FT_FREQSTATISTICS. +% +% The configuration options can be % cfg.alpha = number, highest cluster p-value to be plotted max 0.3 (default = 0.05) -% cfg.highlightseries = 1x5 cell-array, highlight option series with 'on','labels' or 'numbers' (default {'on','on','on','on','on'} for p < [0.01 0.05 0.1 0.2 0.3] -% cfg.highlightsymbolseries = 1x5 vector, highlight marker symbol series (default ['*','x','+','o','.'] for p < [0.01 0.05 0.1 0.2 0.3] +% cfg.highlightseries = 1x5 cell-array, highlight option series with 'on', 'labels' or 'numbers' (default {'on', 'on', 'on', 'on', 'on'} for p < [0.01 0.05 0.1 0.2 0.3] +% cfg.highlightsymbolseries = 1x5 vector, highlight marker symbol series (default ['*', 'x', '+', 'o', '.'] for p < [0.01 0.05 0.1 0.2 0.3] % cfg.highlightsizeseries = 1x5 vector, highlight marker size series (default [6 6 6 6 6] for p < [0.01 0.05 0.1 0.2 0.3]) % cfg.highlightcolorpos = color of highlight marker for positive clusters (default = [0 0 0]) % cfg.highlightcolorneg = color of highlight marker for negative clusters (default = [0 0 0]) % cfg.subplotsize = layout of subplots ([h w], default [3 5]) % cfg.saveaspng = string, filename of the output figures (default = 'no') +% cfg.visible = string, 'on' or 'off' whether figure will be visible (default = 'on') % -% You can also specify cfg options that apply to FT_TOPOPLOTTFR, except for -% cfg.xlim, any of the FT_TOPOPLOTTFR highlight options, cfg.comment and -% cfg.commentpos. +% You can also specify all cfg options that apply to FT_TOPOPLOTER or FT_TOPOPLOTTFR, +% except for cfg.xlim, any of the highlight options, cfg.comment and cfg.commentpos. % % To facilitate data-handling and distributed computing you can use % cfg.inputfile = ... @@ -25,10 +26,9 @@ % file on disk. This mat files should contain only a single variable named 'data', % corresponding to the input structure. % -% See also: -% FT_TOPOPLOTTFR, FT_TOPOPLOTER, FT_SINGLEPLOTER +% See also FT_TOPOPLOTTFR, FT_TOPOPLOTER, FT_MOVIEPLOTTFR, FT_MOVIEPLOTER -% Copyright (C) 2007, Ingrid Nieuwenhuis, F.C. Donders Centre +% Copyright (C) 2007, F.C. Donders Centre, Ingrid Nieuwenhuis % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -66,6 +66,8 @@ return end +ws = ft_warning('off', 'FieldTrip:getdimord:warning_dimord_could_not_be_determined'); + % check if the input data is valid for this function stat = ft_checkdata(stat, 'datatype', {'timelock', 'freq'}, 'feedback', 'yes'); @@ -90,22 +92,24 @@ 'commentpos'}); % set the defaults -cfg.marker = ft_getopt(cfg, 'marker', 'off'); -cfg.alpha = ft_getopt(cfg, 'alpha', 0.05); -cfg.highlightseries = ft_getopt(cfg, 'highlightseries', {'on','on','on','on','on'}); -cfg.highlightsymbolseries = ft_getopt(cfg, 'highlightsymbolseries', ['*','x','+','o','.']); -cfg.highlightsizeseries = ft_getopt(cfg, 'highlightsizeseries', [6 6 6 6 6]); -cfg.hllinewidthseries = ft_getopt(cfg, 'hllinewidthseries', [1 1 1 1 1]); -cfg.highlightcolorpos = ft_getopt(cfg, 'highlightcolorpos', [0 0 0]); -cfg.highlightcolorneg = ft_getopt(cfg, 'highlightcolorneg', [0 0 0]); -cfg.parameter = ft_getopt(cfg, 'parameter', 'stat'); -cfg.saveaspng = ft_getopt(cfg, 'saveaspng', 'no'); -cfg.subplotsize = ft_getopt(cfg, 'subplotsize', [3 5]); -cfg.feedback = ft_getopt(cfg, 'feedback', 'text'); +cfg.highlightseries = ft_getopt(cfg, 'highlightseries', {'on', 'on', 'on', 'on', 'on'}); +cfg.highlightsymbolseries = ft_getopt(cfg, 'highlightsymbolseries', ['*', 'x', '+', 'o', '.']); +cfg.highlightsizeseries = ft_getopt(cfg, 'highlightsizeseries', [6 6 6 6 6]); +cfg.hllinewidthseries = ft_getopt(cfg, 'hllinewidthseries', [1 1 1 1 1]); +cfg.highlightfontsizeseries = ft_getopt(cfg, 'highlightfontsizeseries', [8 8 8 8 8]); +cfg.highlightcolorpos = ft_getopt(cfg, 'highlightcolorpos', [0 0 0]); +cfg.highlightcolorneg = ft_getopt(cfg, 'highlightcolorneg', [0 0 0]); +cfg.marker = ft_getopt(cfg, 'marker', 'off'); +cfg.alpha = ft_getopt(cfg, 'alpha', 0.05); +cfg.parameter = ft_getopt(cfg, 'parameter', 'stat'); +cfg.saveaspng = ft_getopt(cfg, 'saveaspng', 'no'); +cfg.subplotsize = ft_getopt(cfg, 'subplotsize', [3 5]); +cfg.feedback = ft_getopt(cfg, 'feedback', 'text'); +cfg.visible = ft_getopt(cfg, 'visible', 'on'); % error if cfg.highlightseries is not a cell, for possible confusion with cfg-options if ~iscell(cfg.highlightseries) - error('cfg.highlightseries should be a cell-array of strings') + ft_error('cfg.highlightseries should be a cell-array of strings') end % get the options that are specific for topoplotting @@ -124,13 +128,13 @@ switch dimord case 'chan' is2D = false; - + case 'chan_time' is2D = true; - + case 'chan_freq' is2D = true; - + case 'chan_freq_time' % no more than two dimensions are supported, we can ignore singleton dimensions is2D = true; @@ -145,17 +149,16 @@ if isfield(stat, 'negclusterslabelmat') stat.negclusterslabelmat = reshape(stat.negclusterslabelmat, dimsiz([1 3])); end - elseif dimsiz(3)==1 stat = rmfield(stat, 'time'); stat.dimord = 'chan_freq'; % no need to remove the singleton dimension at the end else - error('this only works if either frequency or time is a singleton dimension'); + ft_error('this only works if either frequency or time is a singleton dimension'); end - + otherwise - error('unsupported dimord %s', dimord); + ft_error('unsupported dimord %s', dimord); end % switch dimord % these are not valid any more @@ -172,20 +175,20 @@ time = stat.freq; end -if issubfield(stat, 'cfg.correcttail') && ((strcmp(stat.cfg.correcttail,'alpha') || strcmp(stat.cfg.correcttail,'prob')) && (stat.cfg.tail == 0)); - if ~(cfg.alpha >= stat.cfg.alpha); - warning(['the pvalue you plot: cfg.alpha = ' num2str(cfg.alpha) ' is higher than the correcttail option you tested: stat.cfg.alpha = ' num2str(stat.cfg.alpha)]); +if issubfield(stat, 'cfg.correcttail') && ((strcmp(stat.cfg.correcttail, 'alpha') || strcmp(stat.cfg.correcttail, 'prob')) && (stat.cfg.tail == 0)); + if ~(cfg.alpha >= stat.cfg.alpha) + ft_warning(['the pvalue you plot: cfg.alpha = ' num2str(cfg.alpha) ' is higher than the correcttail option you tested: stat.cfg.alpha = ' num2str(stat.cfg.alpha)]); end end % find significant clusters sigpos = []; signeg = []; -haspos = isfield(stat,'posclusters'); -hasneg = isfield(stat,'negclusters'); +haspos = isfield(stat, 'posclusters'); +hasneg = isfield(stat, 'negclusters'); if haspos == 0 && hasneg == 0 - fprintf('%s\n','no significant clusters in data; nothing to plot') + fprintf('%s\n', 'no significant clusters in data; nothing to plot') else if haspos for iPos = 1:length(stat.posclusters) @@ -202,11 +205,11 @@ Nsigpos = length(sigpos); Nsigneg = length(signeg); Nsigall = Nsigpos + Nsigneg; - + if Nsigall == 0 - error('no clusters present with a p-value lower than the specified alpha, nothing to plot') + ft_error('no clusters present with a p-value lower than the specified alpha, nothing to plot') end - + % make clusterslabel matrix per significant cluster if haspos posCLM = stat.posclusterslabelmat; @@ -222,7 +225,7 @@ sigposCLM = []; probpos = []; end - + if hasneg negCLM = stat.negclusterslabelmat; signegCLM = zeros(size(negCLM)); @@ -237,41 +240,41 @@ signegCLM = []; probneg = []; end - - fprintf('%s%i%s%g%s\n','There are ',Nsigall,' clusters smaller than alpha (',cfg.alpha,')') - + + fprintf('There are %d clusters smaller than alpha (%g)\n', Nsigall, cfg.alpha); + if is2D % define time or freq window per cluster for iPos = 1:length(sigpos) possum_perclus = sum(sigposCLM(:,:,iPos),1); %sum over chans for each time- or freq-point - ind_min = min(find(possum_perclus~=0)); - ind_max = max(find(possum_perclus~=0)); + ind_min = find(possum_perclus~=0, 1 ); + ind_max = find(possum_perclus~=0, 1, 'last' ); time_perclus = [time(ind_min) time(ind_max)]; if hastime - fprintf('%s%s%s%s%s%s%s%s%s%s%s\n','Positive cluster: ',num2str(sigpos(iPos)),', pvalue: ',num2str(probpos(iPos)),' (',hlsignpos(iPos),')',', t = ',num2str(time_perclus(1)),' to ',num2str(time_perclus(2))) + fprintf('%s%s%s%s%s%s%s%s%s%s%s\n', 'Positive cluster: ',num2str(sigpos(iPos)), ', pvalue: ',num2str(probpos(iPos)), ' (',hlsignpos(iPos), ')', ', t = ',num2str(time_perclus(1)), ' to ',num2str(time_perclus(2))) elseif hasfreq - fprintf('%s%s%s%s%s%s%s%s%s%s%s\n','Positive cluster: ',num2str(sigpos(iPos)),', pvalue: ',num2str(probpos(iPos)),' (',hlsignpos(iPos),')',', f = ',num2str(time_perclus(1)),' to ',num2str(time_perclus(2))) + fprintf('%s%s%s%s%s%s%s%s%s%s%s\n', 'Positive cluster: ',num2str(sigpos(iPos)), ', pvalue: ',num2str(probpos(iPos)), ' (',hlsignpos(iPos), ')', ', f = ',num2str(time_perclus(1)), ' to ',num2str(time_perclus(2))) end end for iNeg = 1:length(signeg) negsum_perclus = sum(signegCLM(:,:,iNeg),1); - ind_min = min(find(negsum_perclus~=0)); - ind_max = max(find(negsum_perclus~=0)); + ind_min = find(negsum_perclus~=0, 1 ); + ind_max = find(negsum_perclus~=0, 1, 'last' ); time_perclus = [time(ind_min) time(ind_max)]; if hastime time_perclus = [time(ind_min) time(ind_max)]; - fprintf('%s%s%s%s%s%s%s%s%s%s%s\n','Negative cluster: ',num2str(signeg(iNeg)),', pvalue: ',num2str(probneg(iNeg)),' (',hlsignneg(iNeg),')',', t = ',num2str(time_perclus(1)),' to ',num2str(time_perclus(2))) + fprintf('%s%s%s%s%s%s%s%s%s%s%s\n', 'Negative cluster: ',num2str(signeg(iNeg)), ', pvalue: ',num2str(probneg(iNeg)), ' (',hlsignneg(iNeg), ')', ', t = ',num2str(time_perclus(1)), ' to ',num2str(time_perclus(2))) elseif hasfreq - fprintf('%s%s%s%s%s%s%s%s%s%s%s\n','Negative cluster: ',num2str(signeg(iNeg)),', pvalue: ',num2str(probneg(iNeg)),' (',hlsignneg(iNeg),')',', f = ',num2str(time_perclus(1)),' to ',num2str(time_perclus(2))) + fprintf('%s%s%s%s%s%s%s%s%s%s%s\n', 'Negative cluster: ',num2str(signeg(iNeg)), ', pvalue: ',num2str(probneg(iNeg)), ' (',hlsignneg(iNeg), ')', ', f = ',num2str(time_perclus(1)), ' to ',num2str(time_perclus(2))) end end - + % define time- or freq-window containing all significant clusters possum = sum(sigposCLM,3); %sum over Chans for timevector possum = sum(possum,1); negsum = sum(signegCLM,3); negsum = sum(negsum,1); - + if haspos && hasneg allsum = possum + negsum; elseif haspos @@ -279,20 +282,20 @@ else allsum = negsum; end - - ind_timewin_min = min(find(allsum~=0)); - ind_timewin_max = max(find(allsum~=0)); + + ind_timewin_min = find(allsum~=0, 1 ); + ind_timewin_max = find(allsum~=0, 1, 'last' ); timewin = time(ind_timewin_min:ind_timewin_max); - + else for iPos = 1:length(sigpos) - fprintf('%s%s%s%s%s%s%s\n','Positive cluster: ',num2str(sigpos(iPos)),', pvalue: ',num2str(probpos(iPos)),' (',hlsignpos(iPos),')') + fprintf('%s%s%s%s%s%s%s\n', 'Positive cluster: ',num2str(sigpos(iPos)), ', pvalue: ',num2str(probpos(iPos)), ' (',hlsignpos(iPos), ')') end for iNeg = 1:length(signeg) - fprintf('%s%s%s%s%s%s%s\n','Negative cluster: ',num2str(signeg(iNeg)),', pvalue: ',num2str(probneg(iNeg)),' (',hlsignneg(iNeg),')') + fprintf('%s%s%s%s%s%s%s\n', 'Negative cluster: ',num2str(signeg(iNeg)), ', pvalue: ',num2str(probneg(iNeg)), ' (',hlsignneg(iNeg), ')') end end - + % setup highlight options for all clusters and make comment for 1D data compos = []; comneg = []; @@ -301,62 +304,72 @@ cfgtopo.highlight{iPos} = cfg.highlightseries{1}; cfgtopo.highlightsymbol{iPos} = cfg.highlightsymbolseries(1); cfgtopo.highlightsize{iPos} = cfg.highlightsizeseries(1); + cfgtopo.highlightfontsize{iPos} = cfg.highlightfontsizeseries(1); elseif stat.posclusters(sigpos(iPos)).prob < 0.05 cfgtopo.highlight{iPos} = cfg.highlightseries{2}; cfgtopo.highlightsymbol{iPos} = cfg.highlightsymbolseries(2); cfgtopo.highlightsize{iPos} = cfg.highlightsizeseries(2); + cfgtopo.highlightfontsize{iPos} = cfg.highlightfontsizeseries(2); elseif stat.posclusters(sigpos(iPos)).prob < 0.1 cfgtopo.highlight{iPos} = cfg.highlightseries{3}; cfgtopo.highlightsymbol{iPos} = cfg.highlightsymbolseries(3); cfgtopo.highlightsize{iPos} = cfg.highlightsizeseries(3); + cfgtopo.highlightfontsize{iPos} = cfg.highlightfontsizeseries(3); elseif stat.posclusters(sigpos(iPos)).prob < 0.2 cfgtopo.highlight{iPos} = cfg.highlightseries{4}; cfgtopo.highlightsymbol{iPos} = cfg.highlightsymbolseries(4); cfgtopo.highlightsize{iPos} = cfg.highlightsizeseries(4); + cfgtopo.highlightfontsize{iPos} = cfg.highlightfontsizeseries(4); elseif stat.posclusters(sigpos(iPos)).prob < 0.3 cfgtopo.highlight{iPos} = cfg.highlightseries{5}; cfgtopo.highlightsymbol{iPos} = cfg.highlightsymbolseries(5); cfgtopo.highlightsize{iPos} = cfg.highlightsizeseries(5); + cfgtopo.highlightfontsize{iPos} = cfg.highlightfontsizeseries(5); end cfgtopo.highlightcolor{iPos} = cfg.highlightcolorpos; - compos = strcat(compos,cfgtopo.highlightsymbol{iPos}, 'p=',num2str(probpos(iPos)),' '); % make comment, only used for 1D data + compos = strcat(compos,cfgtopo.highlightsymbol{iPos}, 'p=',num2str(probpos(iPos)), ' '); % make comment, only used for 1D data end - + for iNeg = 1:length(signeg) if stat.negclusters(signeg(iNeg)).prob < 0.01 cfgtopo.highlight{length(sigpos)+iNeg} = cfg.highlightseries{1}; cfgtopo.highlightsymbol{length(sigpos)+iNeg} = cfg.highlightsymbolseries(1); cfgtopo.highlightsize{length(sigpos)+iNeg} = cfg.highlightsizeseries(1); + cfgtopo.highlightfontsize{length(sigpos)+iNeg} = cfg.highlightfontsizeseries(1); elseif stat.negclusters(signeg(iNeg)).prob < 0.05 cfgtopo.highlight{length(sigpos)+iNeg} = cfg.highlightseries{2}; cfgtopo.highlightsymbol{length(sigpos)+iNeg} = cfg.highlightsymbolseries(2); cfgtopo.highlightsize{length(sigpos)+iNeg} = cfg.highlightsizeseries(2); + cfgtopo.highlightfontsize{length(sigpos)+iNeg} = cfg.highlightfontsizeseries(2); elseif stat.negclusters(signeg(iNeg)).prob < 0.1 cfgtopo.highlight{length(sigpos)+iNeg} = cfg.highlightseries{3}; cfgtopo.highlightsymbol{length(sigpos)+iNeg} = cfg.highlightsymbolseries(3); cfgtopo.highlightsize{length(sigpos)+iNeg} = cfg.highlightsizeseries(3); + cfgtopo.highlightfontsize{length(sigpos)+iNeg} = cfg.highlightfontsizeseries(3); elseif stat.negclusters(signeg(iNeg)).prob < 0.2 cfgtopo.highlight{length(sigpos)+iNeg} = cfg.highlightseries{4}; cfgtopo.highlightsymbol{length(sigpos)+iNeg} = cfg.highlightsymbolseries(4); cfgtopo.highlightsize{length(sigpos)+iNeg} = cfg.highlightsizeseries(4); + cfgtopo.highlightfontsize{length(sigpos)+iNeg} = cfg.highlightfontsizeseries(4); elseif stat.negclusters(signeg(iNeg)).prob < 0.3 cfgtopo.highlight{length(sigpos)+iNeg} = cfg.highlightseries{5}; cfgtopo.highlightsymbol{length(sigpos)+iNeg} = cfg.highlightsymbolseries(5); cfgtopo.highlightsize{length(sigpos)+iNeg} = cfg.highlightsizeseries(5); + cfgtopo.highlightfontsize{length(sigpos)+iNeg} = cfg.highlightfontsizeseries(5); end cfgtopo.highlightcolor{length(sigpos)+iNeg} = cfg.highlightcolorneg; - comneg = strcat(comneg,cfgtopo.highlightsymbol{length(sigpos)+iNeg}, 'p=',num2str(probneg(iNeg)),' '); % make comment, only used for 1D data + comneg = strcat(comneg,cfgtopo.highlightsymbol{length(sigpos)+iNeg}, 'p=',num2str(probneg(iNeg)), ' '); % make comment, only used for 1D data end - + if is2D Npl = length(timewin); else Npl = 1; end - + numSubplots = prod(cfg.subplotsize); Nfig = ceil(Npl/numSubplots); - + % put channel indexes in list if is2D for iPl = 1:Npl @@ -377,20 +390,18 @@ end end end - - % this does not work, because the progress tracker is also used inside ft_topoplotTFR - % ft_progress('init', cfg.feedback, 'making subplots...'); - % ft_progress(count/Npl, 'making subplot %d from %d', count, Npl); - % ft_progress('close'); - + count = 0; + ft_progress('init', cfg.feedback, 'making subplots...'); + ft_progress(count/Npl, 'making subplot %d from %d', count, Npl); + % make plots for iPl = 1:Nfig - figure; + f = figure('visible', cfg.visible); if is2D if iPl < Nfig for iT = 1:numSubplots - PlN = (iPl-1)*numSubplots + iT; %plotnumber + PlN = (iPl-1)*numSubplots + iT; % plotnumber cfgtopo.xlim = [time(ind_timewin_min+PlN-1) time(ind_timewin_min+PlN-1)]; cfgtopo.highlightchannel = list{PlN}; if hastime @@ -406,7 +417,7 @@ end elseif iPl == Nfig for iT = 1:Npl-(numSubplots*(Nfig-1)) - PlN = (iPl-1)*numSubplots + iT; %plotnumber + PlN = (iPl-1)*numSubplots + iT; % plotnumber cfgtopo.xlim = [time(ind_timewin_min+PlN-1) time(ind_timewin_min+PlN-1)]; cfgtopo.highlightchannel = list{PlN}; if hastime @@ -423,21 +434,27 @@ end else cfgtopo.highlightchannel = list{1}; - cfgtopo.comment = strcat(compos,comneg); + cfgtopo.comment = strcat(compos, comneg); cfgtopo.commentpos = 'title'; count = count+1; fprintf('making subplot %d from %d\n', count, Npl); ft_topoplotTFR(cfgtopo, stat); end - % save figure - if isequal(cfg.saveaspng,'no'); + if isequal(cfg.saveaspng, 'no') + % nothing to do else + % save figure filename = strcat(cfg.saveaspng, '_fig', num2str(iPl)); - print(gcf,'-dpng',filename); + print(gcf, '-dpng', filename); end end end +ft_progress('close'); + +% return to previous warning settings +ft_warning(ws); + % do the general cleanup and bookkeeping at the end of the function ft_postamble debug ft_postamble trackconfig diff --git a/external/fieldtrip/ft_combineplanar.m b/external/fieldtrip/ft_combineplanar.m index 5ecafa74..66e18be5 100644 --- a/external/fieldtrip/ft_combineplanar.m +++ b/external/fieldtrip/ft_combineplanar.m @@ -11,16 +11,11 @@ % % The configuration can contain % cfg.method = 'sum', 'svd', 'abssvd', or 'complex' (default = 'sum') -% -% In the case of ERFs, the configuration can contain +% cfg.updatesens = 'no' or 'yes' (default = 'yes') +% and for timelocked input data (i.e. ERFs), the configuration can also contain % cfg.demean = 'yes' or 'no' (default = 'no') % cfg.baselinewindow = [begin end] % -% After combining the planar data, the planar gradiometer definition does not -% match the data any more and therefore it is removed from the data. With -% cfg.combinegrad = 'yes' -% the function will try to reconstruct the axial gradiometer definition. -% % To facilitate data-handling and distributed computing you can use % cfg.inputfile = ... % cfg.outputfile = ... @@ -91,23 +86,24 @@ cfg.trials = ft_getopt(cfg, 'trials', 'all', 1); cfg.feedback = ft_getopt(cfg, 'feedback', 'none'); cfg.method = ft_getopt(cfg, 'method', 'sum'); +cfg.updatesens = ft_getopt(cfg, 'updatesens', 'yes'); if isfield(cfg, 'baseline') - warning('only supporting cfg.baseline for backwards compatibility, please update your cfg'); + ft_warning('only supporting cfg.baseline for backwards compatibility, please update your cfg'); cfg.demean = 'yes'; cfg.baselinewindow = cfg.baseline; end israw = ft_datatype(data, 'raw'); -isfreq = ft_datatype(data, 'freq'); istimelock = ft_datatype(data, 'timelock'); -if isfield(data, 'dimord'), +isfreq = ft_datatype(data, 'freq'); +if isfield(data, 'dimord') dimord = data.dimord; end % select trials of interest if ~strcmp(cfg.trials, 'all') - error('trial selection has not been implemented yet') % first fix ft_checkdata (see above) + ft_error('trial selection has not been implemented yet') % first fix ft_checkdata (see above) end % find the combination of horizontal and vertical channels that should be combined @@ -132,7 +128,7 @@ % perform baseline correction if strcmp(cfg.demean, 'yes') if ~(istimelock || israw) - error('baseline correction is only supported for timelocked or raw input data') + ft_error('baseline correction is only supported for timelocked or raw input data') end if ischar(cfg.baselinewindow) && strcmp(cfg.baselinewindow, 'all') cfg.baselinewindow = [-inf inf]; @@ -146,29 +142,29 @@ end if isfreq - + switch cfg.method case 'sum' - if isfield(data, 'powspctrm'), + if isfield(data, 'powspctrm') % compute the power of each planar channel, by summing the horizontal and vertical gradients - dimtok = tokenize(dimord,'_'); + dimtok = tokenize(dimord, '_'); catdim = strmatch('chan',dimtok); - if catdim==1, + if catdim==1 combined = data.powspctrm(sel_dH,:,:,:) + data.powspctrm(sel_dV,:,:,:); other = data.powspctrm(sel_other,:,:,:); - elseif catdim==2, + elseif catdim==2 combined = data.powspctrm(:,sel_dH,:,:,:) + data.powspctrm(:,sel_dV,:,:,:); other = data.powspctrm(:,sel_other,:,:,:); else - error('unsupported dimension order of frequency data'); + ft_error('unsupported dimension order of frequency data'); end data.powspctrm = cat(catdim, combined, other); data.label = cat(1, lab_comb(:), lab_other(:)); else - error('cfg.method = ''%s'' only works for frequency data with powspctrm', cfg.method); + ft_error('cfg.method = ''%s'' only works for frequency data with powspctrm', cfg.method); end case 'svd' - if isfield(data, 'fourierspctrm'), + if isfield(data, 'fourierspctrm') fbin = nearest(data.freq, cfg.foilim(1)):nearest(data.freq, cfg.foilim(2)); Nrpt = size(data.fourierspctrm,1); Nsgn = length(sel_dH); @@ -191,7 +187,7 @@ fourier(:,j,k,:) = transpose(dum); data.ori{k} = ori; % to change into a cell data.eta{k} = sin_val(1)/sum(sin_val(2:end)); % to change into a cell - + %for m = 1:Ntim % dum = data.fourierspctrm(:,[sel_dH(j) sel_dV(j)],fbin(k),m); % timbin = find(~isnan(dum(:,1))); @@ -206,18 +202,18 @@ data.label = cat(1, lab_comb(:), lab_other(:)); data.freq = data.freq(fbin); else - error('cfg.method = ''%s'' only works for frequency data with fourierspctrm', cfg.method); + ft_error('cfg.method = ''%s'' only works for frequency data with fourierspctrm', cfg.method); end otherwise - error('cfg.method = ''%s'' is not supported for frequency data', cfg.method); + ft_error('cfg.method = ''%s'' is not supported for frequency data', cfg.method); end % switch method - + elseif (israw || istimelock) - if istimelock, + if istimelock % convert timelock to raw data = ft_checkdata(data, 'datatype', 'raw', 'feedback', 'yes'); end - + switch cfg.method case 'sum' Nrpt = length(data.trial); @@ -227,16 +223,16 @@ data.trial{k} = [combined; other]; end data.label = cat(1, lab_comb(:), lab_other(:)); - + case 'complex' Nrpt = length(data.trial); for k = 1:Nrpt - combined = data.trial{1}(sel_dH,:)*i + data.trial{1}(sel_dV,:); + combined = data.trial{k}(sel_dH,:)*1i + data.trial{k}(sel_dV,:); other = data.trial{k}(sel_other,:); data.trial{k} = [combined; other]; end data.label = cat(1, lab_comb(:), lab_other(:)); - + case {'svd' 'abssvd'} Nrpt = length(data.trial); Nsgn = length(sel_dH); @@ -271,24 +267,24 @@ end data.trial = trial; data.label = cat(1, lab_comb(:), lab_other(:)); - + otherwise - error('cfg.method = ''%s'' is not supported for timelocked or raw data', cfg.method); + ft_error('cfg.method = ''%s'' is not supported for timelocked or raw data', cfg.method); end % switch method - - if istimelock, + + if istimelock % convert raw to timelock data = ft_checkdata(data, 'datatype', 'timelock', 'feedback', 'yes'); end - + else - error('unsupported input data'); + ft_error('unsupported input data'); end % which ft_datatype % remove the fields for which the planar gradient could not be combined data = removefields(data, {'crsspctrm', 'labelcmb'}); -if isfield(data, 'grad') +if strcmp(cfg.updatesens, 'yes') && isfield(data, 'grad') % update the grad and only retain the channel related info [sel_dH, sel_comb] = match_str(data.grad.label, planar(:,1)); % indices of the horizontal channels [sel_dV ] = match_str(data.grad.label, planar(:,2)); % indices of the vertical channels @@ -313,7 +309,7 @@ lab_other ]; newtype = [ - repmat({'unknown'}, numel(sel_comb), 1) % combined planar + repmat({'unknown'}, numel(sel_comb), 1) % combined planar data.grad.chantype(sel_other(:)) % keep the known channel details ]; newunit = [ @@ -324,15 +320,26 @@ newgrad.chanpos = newpos; newgrad.chanori = newori; newgrad.label = newlabel; - newgrad.newtype = newtype; - newgrad.newunit = newunit; + newgrad.chantype = newtype; + newgrad.chanunit = newunit; newgrad.unit = data.grad.unit; newgrad.type = [data.grad.type '_combined']; + % remember the original channel position details + if isfield(data.grad, 'chanposold') + newgrad = copyfields(data.grad, newgrad, {'chanposold', 'chanoriold', 'labelold', 'chantypeold', 'chanunitold'}); + else + newgrad.labelold = data.grad.label; + newgrad.chanposold = data.grad.chanpos; + newgrad.chanoriold = data.grad.chanori; + newgrad.chantypeold = data.grad.chantype; + newgrad.chanunitold = data.grad.chanunit; + end + + % replace it with the updated gradiometer description data.grad = newgrad; end - % convert back to input type if necessary if istimelock data = ft_checkdata(data, 'datatype', 'timelock'); diff --git a/external/fieldtrip/ft_componentanalysis.m b/external/fieldtrip/ft_componentanalysis.m index f82a38dd..605ef278 100644 --- a/external/fieldtrip/ft_componentanalysis.m +++ b/external/fieldtrip/ft_componentanalysis.m @@ -8,15 +8,17 @@ % % Use as % [comp] = ft_componentanalysis(cfg, data) +% where cfg is a configuration structure and the input data is obtained from +% FT_PREPROCESSING or from FT_TIMELOCKANALYSIS. % -% where the data comes from FT_PREPROCESSING and the configuration -% structure can contain +% The configuration should contain % cfg.method = 'runica', 'fastica', 'binica', 'pca', 'svd', 'jader', 'varimax', 'dss', 'cca', 'sobi', 'white' or 'csp' (default = 'runica') % cfg.channel = cell-array with channel selection (default = 'all'), see FT_CHANNELSELECTION for details % cfg.trials = 'all' or a selection given as a 1xN vector (default = 'all') % cfg.numcomponent = 'all' or number (default = 'all') % cfg.demean = 'no' or 'yes', whether to demean the input data (default = 'yes') % cfg.updatesens = 'no' or 'yes' (default = 'yes') +% cfg.feedback = 'no', 'text', 'textbar', 'gui' (default = 'text') % % The runica method supports the following method-specific options. The values that % these options can take can be found with HELP RUNICA. @@ -174,6 +176,7 @@ end % check if the input data is valid for this function +istimelock = ft_datatype(data, 'timelock'); data = ft_checkdata(data, 'datatype', 'raw', 'feedback', 'yes'); % check if the input cfg is valid for this function @@ -191,34 +194,39 @@ cfg.normalisesphere = ft_getopt(cfg, 'normalisesphere', 'yes'); cfg.cellmode = ft_getopt(cfg, 'cellmode', 'no'); cfg.doscale = ft_getopt(cfg, 'doscale', 'yes'); -cfg.updatesens = ft_getopt(cfg, 'updatesens', 'yes'); +cfg.updatesens = ft_getopt(cfg, 'updatesens', 'yes'); +cfg.feedback = ft_getopt(cfg, 'feedback', 'text'); % select channels, has to be done prior to handling of previous (un)mixing matrix cfg.channel = ft_channelselection(cfg.channel, data.label); +if istrue(cfg.cellmode) + ft_hastoolbox('cellfunction', 1); +end + if isfield(cfg, 'topo') && isfield(cfg, 'topolabel') - warning(['Specifying cfg.topo (= mixing matrix) to determine component '... + ft_warning(['Specifying cfg.topo (= mixing matrix) to determine component '... 'timecourses in specified data is deprecated; please specify an '... 'unmixing matrix instead with cfg.unmixing. '... 'Using cfg.unmixing=pinv(cfg.topo) for now to reproduce old behaviour.']); - + cfg.unmixing = pinv(cfg.topo); cfg = rmfield(cfg, 'topo'); end if isfield(cfg, 'unmixing') && isfield(cfg, 'topolabel') % use the previously determined unmixing matrix on this dataset - + % test whether all required channels are present in the data [datsel, toposel] = match_str(cfg.channel, cfg.topolabel); if length(toposel)~=length(cfg.topolabel) - error('not all channels that are required for the unmixing are present in the data'); + ft_error('not all channels that are required for the unmixing are present in the data'); end - + % ensure that all data channels not used in the unmixing should be removed from the channel selection tmpchan = match_str(cfg.channel, cfg.topolabel); cfg.channel = cfg.channel(tmpchan); - + % update some settings where there is no further choice to be made by the user cfg.numcomponent = 'all'; cfg.method = 'predetermined unmixing matrix'; @@ -231,7 +239,7 @@ cfg.icasso.mode = ft_getopt(cfg.icasso, 'mode', 'both'); cfg.icasso.Niter = ft_getopt(cfg.icasso, 'Niter', 15); cfg.icasso.method = ft_getopt(cfg.icasso, 'method', 'fastica'); - + cfg.fastica = ft_getopt(cfg, 'fastica', []); case 'fastica' % additional options, see FASTICA for details @@ -257,11 +265,11 @@ cfg.csp.classlabels = ft_getopt(cfg.csp, 'classlabels'); case 'bsscca' % additional options, see BSSCCA for details - cfg.bsscca = ft_getopt(cfg, 'bsscca', []); - cfg.bsscca.delay = ft_getopt(cfg.bsscca, 'delay', 1); + cfg.bsscca = ft_getopt(cfg, 'bsscca', []); + cfg.bsscca.refdelay = ft_getopt(cfg.bsscca, 'refdelay', 1); + cfg.bsscca.chandelay = ft_getopt(cfg.bsscca, 'chandelay', 0); if strcmp(cfg.cellmode, 'no') - fprintf('switching to cell-mode for method ''bsscca''\n'); - cfg.cellmode = 'yes'; + ft_error('cfg.mehod = ''bsscca'' requires cfg.cellmode = ''yes'''); end otherwise % do nothing @@ -278,7 +286,7 @@ Ntrials = length(data.trial); Nchans = length(data.label); if Nchans==0 - error('no channels were selected'); + ft_error('no channels were selected'); end % default is to compute just as many components as there are channels in the data @@ -306,7 +314,9 @@ if strcmp(cfg.doscale, 'yes') % determine the scaling of the data, scale it to approximately unity % this will improve the performance of some methods, esp. fastica - scale = norm((data.trial{1}*data.trial{1}')./size(data.trial{1},2)); + tmp = data.trial{1}; + tmp(~isfinite(tmp)) = 0; % ensure that the scaling is a finite value + scale = norm((tmp*tmp')./size(tmp,2)); clear tmp; scale = sqrt(scale); if scale ~= 0 fprintf('scaling data with 1 over %f\n', scale); @@ -321,7 +331,7 @@ end if strcmp(cfg.method, 'sobi') - + % concatenate all the data into a 3D matrix respectively 2D (sobi) fprintf('concatenating data'); Nsamples = Nsamples(1); @@ -340,28 +350,28 @@ else dat = shiftdim(dat,1); end - + elseif strcmp(cfg.method, 'csp') - + % concatenate the trials into two data matrices, one for each class sel1 = find(cfg.csp.classlabels==1); sel2 = find(cfg.csp.classlabels==2); if min(length(sel1), length(sel2)) == 0 - error('CSP requires class labels!'); + ft_error('CSP requires class labels!'); end if length(sel1)+length(sel2)~=length(cfg.csp.classlabels) - warning('not all trials belong to class 1 or 2'); + ft_warning('not all trials belong to class 1 or 2'); end dat1 = cat(2, data.trial{sel1}); dat2 = cat(2, data.trial{sel2}); fprintf('concatenated data matrix size for class 1 is %dx%d\n', size(dat1,1), size(dat1,2)); fprintf('concatenated data matrix size for class 2 is %dx%d\n', size(dat2,1), size(dat2,2)); - + elseif ~strcmp(cfg.method, 'predetermined unmixing matrix') && strcmp(cfg.cellmode, 'no') % concatenate all the data into a 2D matrix unless we already have an % unmixing matrix or unless the user request it otherwise fprintf('concatenating data'); - + dat = zeros(Nchans, sum(Nsamples)); for trial=1:Ntrials fprintf('.'); @@ -371,25 +381,32 @@ end fprintf('\n'); fprintf('concatenated data matrix size %dx%d\n', size(dat,1), size(dat,2)); - + + hasdatanans = any(~isfinite(dat(:))); + if hasdatanans + fprintf('data contains nans, only using the non-nan samples\n'); + finitevals = sum(~isfinite(dat))==0; + dat = dat(:,finitevals); + end else fprintf('not concatenating data\n'); dat = data.trial; + % FIXME cellmode processing is not nan-transparent yet end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % perform the component analysis fprintf('starting decomposition using %s\n', cfg.method); switch cfg.method - + case 'icasso' % check whether the required low-level toolboxes are installed ft_hastoolbox('icasso', 1); - + if strcmp(cfg.icasso.method, 'fastica') ft_hastoolbox('fastica', 1); cfg.fastica.numOfIC = cfg.numcomponent; - + optarg = ft_cfg2keyval(cfg.(cfg.icasso.method)); sR = icassoEst(cfg.icasso.mode, dat, cfg.icasso.Niter, optarg{:}); elseif strcmp(cfg.icasso.method, 'dss') @@ -397,7 +414,7 @@ tmpcfg = rmfield(cfg, 'icasso'); tmpcfg.method = cfg.icasso.method; tmpdata = data; - + % initialize the variables to hold the output sR.W = cell(cfg.icasso.Niter, 1); sR.A = cell(cfg.icasso.Niter, 1); @@ -414,13 +431,13 @@ sR.mode = cfg.icasso.mode; sR.rdim = size(tmp.topo,2); else - error('only ''fastica'' or ''dss'' is supported as method for icasso'); + ft_error('only ''fastica'' or ''dss'' is supported as method for icasso'); end % do the rest of the icasso related processing - sR = icassoCluster(sR,'strategy','AL','simfcn','abscorr','s2d','sim2dis','L',cfg.numcomponent); - sR = icassoProjection(sR,'cca','s2d','sqrtsim2dis','epochs',75); - [Iq, mixing, unmixing, ~, index2centrotypes]=icassoResult(sR,cfg.numcomponent); + sR = icassoCluster(sR, 'strategy', 'AL', 'simfcn', 'abscorr', 's2d', 'sim2dis', 'L',cfg.numcomponent); + sR = icassoProjection(sR, 'cca', 's2d', 'sqrtsim2dis', 'epochs', 75); + [Iq, mixing, unmixing, ~, index2centrotypes] = icassoResult(sR,cfg.numcomponent); % this step is done, because in icassoResult mixing is determined to be % pinv(unmixing), which yields strange results. Better take it from the @@ -432,19 +449,19 @@ end %[Iq, mixing, unmixing, dat] = icassoShow(sR, 'estimate', 'off', 'L', cfg.numcomponent); - + % sort the output according to Iq [srt, ix] = sort(-Iq); % account for NaNs mixing = mixing(:, ix); unmixing = unmixing(ix, :); - + cfg.icasso.Iq = Iq(ix); cfg.icasso.sR = rmfield(sR, 'signal'); % keep the rest of the information - + case 'fastica' % check whether the required low-level toolboxes are installed ft_hastoolbox('fastica', 1); % see http://www.cis.hut.fi/projects/ica/fastica - + if ~defaultNumCompsUsed &&... (~isfield(cfg, 'fastica') || ~isfield(cfg.fastica, 'numOfIC')) % user has specified cfg.numcomponent and not specified @@ -454,9 +471,9 @@ isfield(cfg, 'fastica') && isfield(cfg.fastica, 'numOfIC') % user specified both cfg.numcomponent and cfg.fastica.numOfIC, % unsure which one to use - error('you can specify either cfg.fastica.numOfIC or cfg.numcomponent (they will have the same effect), but not both'); + ft_error('you can specify either cfg.fastica.numOfIC or cfg.numcomponent (they will have the same effect), but not both'); end - + try % construct key-value pairs for the optional arguments optarg = ft_cfg2keyval(cfg.fastica); @@ -473,12 +490,12 @@ % forward original error rethrow(me); end - + case 'runica' % check whether the required low-level toolboxes are installed % see http://www.sccn.ucsd.edu/eeglab ft_hastoolbox('eeglab', 1); - + if ~defaultNumCompsUsed &&... (~isfield(cfg, 'runica') || ~isfield(cfg.runica, 'pca')) % user has specified cfg.numcomponent and not specified @@ -488,26 +505,26 @@ isfield(cfg, 'runica') && isfield(cfg.runica, 'pca') % user specified both cfg.numcomponent and cfg.runica.pca, % unsure which one to use - error('you can specify either cfg.runica.pca or cfg.numcomponent (they will have the same effect), but not both'); + ft_error('you can specify either cfg.runica.pca or cfg.numcomponent (they will have the same effect), but not both'); end - + % construct key-value pairs for the optional arguments optarg = [ft_cfg2keyval(cfg.runica) {'reset_randomseed' 0}]; % let FieldTrip deal with the random seed handling [weights, sphere] = runica(dat, optarg{:}); - + % scale the sphering matrix to unit norm - if strcmp(cfg.normalisesphere, 'yes'), + if strcmp(cfg.normalisesphere, 'yes') sphere = sphere./norm(sphere); end - + unmixing = weights*sphere; mixing = []; - + case 'binica' % check whether the required low-level toolboxes are installed % see http://www.sccn.ucsd.edu/eeglab ft_hastoolbox('eeglab', 1); - + if ~defaultNumCompsUsed &&... (~isfield(cfg, 'binica') || ~isfield(cfg.binica, 'pca')) % user has specified cfg.numcomponent and not specified @@ -517,96 +534,96 @@ isfield(cfg, 'binica') && isfield(cfg.binica, 'pca') % user specified both cfg.numcomponent and cfg.binica.pca, % unsure which one to use - error('you can specify either cfg.binica.pca or cfg.numcomponent (they will have the same effect), but not both'); + ft_error('you can specify either cfg.binica.pca or cfg.numcomponent (they will have the same effect), but not both'); end - + % construct key-value pairs for the optional arguments optarg = ft_cfg2keyval(cfg.binica); [weights, sphere] = binica(dat, optarg{:}); - + % scale the sphering matrix to unit norm - if strcmp(cfg.normalisesphere, 'yes'), + if strcmp(cfg.normalisesphere, 'yes') sphere = sphere./norm(sphere); end - + unmixing = weights*sphere; mixing = []; - + case 'jader' % check whether the required low-level toolboxes are installed % see http://www.sccn.ucsd.edu/eeglab ft_hastoolbox('eeglab', 1); - + unmixing = jader(dat, cfg.numcomponent); mixing = []; - + case 'varimax' % check whether the required low-level toolboxes are installed % see http://www.sccn.ucsd.edu/eeglab ft_hastoolbox('eeglab', 1); - + unmixing = varimax(dat); mixing = []; - + case 'cca' % check whether the required low-level toolboxes are installed % see http://www.sccn.ucsd.edu/eeglab ft_hastoolbox('cca', 1); - + [y, w] = ccabss(dat); unmixing = w'; mixing = []; - + case 'pca' % compute data cross-covariance matrix C = (dat*dat')./(size(dat,2)-1); - + % eigenvalue decomposition (EVD) [E,D] = eig(C); - + % sort eigenvectors in descending order of eigenvalues d = cat(2,(1:1:Nchans)',diag(D)); - d = sortrows(d,[-2]); - + d = sortrows(d, -2); + % return the desired number of principal components unmixing = E(:,d(1:cfg.numcomponent,1))'; mixing = []; - + clear C D E d - + case 'kpca' - + % linear kernel (same as normal covariance) %kern = @(X,y) (sum(bsxfun(@times, X, y),2)); - + % polynomial kernel degree 2 %kern = @(X,y) (sum(bsxfun(@times, X, y),2).^2); - + % RBF kernel kern = @(X,y) (exp(-0.5* sqrt(sum(bsxfun(@minus, X, y).^2, 2)))); - + % compute kernel matrix C = zeros(Nchans,Nchans); - ft_progress('init', 'text', 'computing kernel matrix...'); + ft_progress('init', cfg.feedback, 'computing kernel matrix...'); for k = 1:Nchans - ft_progress(k/Nchans); + ft_progress(k/Nchans, 'computing kernel matrix %d from %d', k, Nchans); C(k,:) = kern(dat, dat(k,:)); end ft_progress('close'); - + % eigenvalue decomposition (EVD) [E,D] = eig(C); - + % sort eigenvectors in descending order of eigenvalues d = cat(2,(1:1:Nchans)',diag(D)); - d = sortrows(d,[-2]); - + d = sortrows(d, -2); + % return the desired number of principal components unmixing = E(:,d(1:cfg.numcomponent,1))'; mixing = []; - + clear C D E d - + case 'svd' % it is more memory efficient to use the (non-scaled) covariance if cfg.numcomponentnumel(data.label) + for m = 1:(size(mixing,1)-numel(data.label)) + data.label{end+1} = sprintf('refchan%03d',m); + end + end + + % remember the canonical correlations + cfg.bsscca.rho = rho; + case 'parafac' - error('parafac is not supported anymore in ft_componentanalysis'); - + ft_error('parafac is not supported anymore in ft_componentanalysis'); + otherwise - error('unknown method for component analysis'); + ft_error('unknown method for component analysis'); end % switch method % make sure we have both mixing and unmixing matrices @@ -769,7 +797,7 @@ elseif isempty(mixing) && isempty(unmixing) % this sanity check is needed to catch convergence problems in fastica % see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=1519 - error('the component unmixing failed'); + ft_error('the component unmixing failed'); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -805,7 +833,7 @@ comp.unmixing = unmixing; % get the labels -if strcmp(cfg.method, 'predetermined unmixing matrix'), +if strcmp(cfg.method, 'predetermined unmixing matrix') prefix = 'component'; else prefix = cfg.method; @@ -816,43 +844,39 @@ end comp.topolabel = data.label(:); -% apply the montage also to the elec/grad, if present if isfield(data, 'grad') sensfield = 'grad'; - if strcmp(cfg.updatesens, 'yes') - fprintf('applying the backprojection matrix to the gradiometer description\n'); - else - fprintf('not applying the backprojection matrix to the gradiometer description\n'); - end -elseif isfield(data, 'elec') && isfield(data.elec, 'tra') +elseif isfield(data, 'elec') sensfield = 'elec'; - if strcmp(cfg.updatesens, 'yes') - fprintf('applying the backprojection matrix to the electrode description\n'); - else - fprintf('not applying the backprojection matrix to the electrode description\n'); - end +elseif isfield(data, 'opto') + sensfield = 'opto'; else - fprintf('not applying the backprojection matrix to the sensor description\n'); sensfield = []; end -if ~isempty(sensfield) && strcmp(cfg.updatesens, 'yes') - % construct a montage and apply it to the sensor description - montage = []; - montage.labelorg = data.label; - montage.labelnew = comp.label; - montage.tra = unmixing; - comp.(sensfield) = ft_apply_montage(data.(sensfield), montage, 'balancename', 'comp', 'keepunused', 'yes'); - % The output sensor array cannot simply be interpreted as the input - % sensor array, hence the type should be removed to allow autodetection - % See also http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=1806 - if isfield(comp.(sensfield), 'type') - comp.(sensfield) = rmfield(comp.(sensfield), 'type'); +% apply the linear projection also to the sensor description +if ~isempty(sensfield) + if strcmp(cfg.updatesens, 'yes') + fprintf('also applying the unmixing matrix to the %s structure\n', sensfield); + % construct a montage and apply it to the sensor description + montage = []; + montage.labelold = data.label; + montage.labelnew = comp.label; + montage.tra = unmixing; + comp.(sensfield) = ft_apply_montage(data.(sensfield), montage, 'balancename', 'comp', 'keepunused', 'yes'); + + % The output sensor array cannot simply be interpreted as the input + % sensor array, hence the type should be removed to allow autodetection + % See also http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=1806 + if isfield(comp.(sensfield), 'type') + comp.(sensfield) = rmfield(comp.(sensfield), 'type'); + end + else + fprintf('not applying the unmixing matrix to the %s structure\n', sensfield); + % simply copy it over + comp.(sensfield) = data.(sensfield); end -elseif ~isempty(sensfield) && strcmp(cfg.updatesens, 'no') - % simply copy it over - comp.(sensfield) = data.(sensfield); -end +end % if sensfield % copy the sampleinfo into the output if isfield(data, 'sampleinfo') @@ -864,6 +888,11 @@ comp.trialinfo = data.trialinfo; end +% convert back to input type if necessary +if istimelock + comp = ft_checkdata(comp, 'datatype', 'timelock+comp'); +end + % do the general cleanup and bookkeeping at the end of the function ft_postamble debug ft_postamble trackconfig diff --git a/external/fieldtrip/ft_conjunctionanalysis.m b/external/fieldtrip/ft_conjunctionanalysis.m index ad146e2d..bf7d964b 100644 --- a/external/fieldtrip/ft_conjunctionanalysis.m +++ b/external/fieldtrip/ft_conjunctionanalysis.m @@ -58,7 +58,7 @@ % input check ndatasets = length(varargin); if ndatasets<2 - error('not enough input arguments; there should be at least two'); + ft_error('not enough input arguments; there should be at least two'); end % check if the input data is valid for this function for i = 1:ndatasets @@ -92,7 +92,7 @@ % equal size input check if ~isequal(size(data1.stat), size(data2.stat)) - error('the input arguments have different sizes'); + ft_error('the input arguments have different sizes'); end % prepare the output data structure @@ -128,7 +128,7 @@ % equal size input check if ~isequal(size(data1.avg.pow), size(data2.avg.pow)) - error('the input arguments have different sizes'); + ft_error('the input arguments have different sizes'); end conjunction = data1; @@ -149,7 +149,7 @@ % equal size input check if ~isequal(size(data1.stat), size(data2.stat)) - error('the input arguments have different sizes'); + ft_error('the input arguments have different sizes'); end % prepare the output data structure @@ -185,7 +185,7 @@ % equal size input check if ~isequal(size(data1.powspctrm), size(data2.powspctrm)) - error('the input arguments have different sizes'); + ft_error('the input arguments have different sizes'); end conjunction = data1; @@ -196,7 +196,7 @@ % equal size input check if ~isequal(size(data1.avg), size(data2.avg)) - error('the input arguments have different sizes'); + ft_error('the input arguments have different sizes'); end conjunction = data1; diff --git a/external/fieldtrip/ft_connectivityanalysis.m b/external/fieldtrip/ft_connectivityanalysis.m index 170dfc4e..a6b49add 100644 --- a/external/fieldtrip/ft_connectivityanalysis.m +++ b/external/fieldtrip/ft_connectivityanalysis.m @@ -155,7 +155,7 @@ hasrpt = (isfield(data, 'dimord') && ~isempty(strfind(data.dimord, 'rpt'))) || (isfield(data, 'avg') && isfield(data.avg, 'mom')) || (isfield(data, 'trial') && isfield(data.trial, 'mom')); % FIXME old-fashioned pcc data dojack = strcmp(cfg.jackknife, 'yes'); normrpt = 0; % default, has to be overruled e.g. in plv, because of single replicate normalisation -normpow = 1; % default, has to be overruled e.g. in csd, +normpow = 1; % default, has to be overruled e.g. in csd % select trials of interest if ~strcmp(cfg.trials, 'all') @@ -166,12 +166,12 @@ end % select channels/channelcombination of interest and set the cfg-options accordingly -if isfield(data, 'label'), +if isfield(data, 'label') selchan = cell(0, 1); - if ~isempty(cfg.channelcmb) && ~isequal(cfg.channelcmb, {'all' 'all'}), + if ~isempty(cfg.channelcmb) && ~isequal(cfg.channelcmb, {'all' 'all'}) tmpcmb = ft_channelcombination(cfg.channelcmb, data.label); tmpchan = unique(tmpcmb(:)); - cfg.channelcmb = ft_channelcombination(cfg.channelcmb, tmpchan, 1); + cfg.channelcmb = ft_channelcombination(cfg.channelcmb(:, 1:2), tmpchan, 1); selchan = [selchan;unique(cfg.channelcmb(:))]; end @@ -184,12 +184,14 @@ tmpcfg = []; tmpcfg.channel = unique(selchan); data = ft_selectdata(tmpcfg, data); + % restore the provenance information + [cfg, data] = rollback_provenance(cfg, data); elseif isfield(data, 'labelcmb') cfg.channel = ft_channelselection(cfg.channel, unique(data.labelcmb(:))); if ~isempty(cfg.partchannel) - error('partialisation is only possible without linearly indexed bivariate data'); + ft_error('partialisation is only possible without linearly indexed bivariate data'); end - if ~isempty(cfg.channelcmb), + if ~isempty(cfg.channelcmb) % FIXME do something extra here end % FIXME call selectdata @@ -204,40 +206,40 @@ switch cfg.method case {'coh' 'csd'} if ~isempty(cfg.partchannel) - if hasrpt && ~hasjack, - warning('partialisation on single trial observations is not supported, removing trial dimension'); + if hasrpt && ~hasjack + ft_warning('partialisation on single trial observations is not supported, removing trial dimension'); try data = ft_checkdata(data, 'datatype', {'freqmvar' 'freq'}, 'cmbrepresentation', 'fullfast'); inparam = 'crsspctrm'; hasrpt = 0; catch - error('partial coherence/csd is only supported for input allowing for a all-to-all csd representation'); + ft_error('partial coherence/csd is only supported for input allowing for a all-to-all csd representation'); end else try data = ft_checkdata(data, 'datatype', {'freqmvar' 'freq'}, 'cmbrepresentation', 'full'); inparam = 'crsspctrm'; catch - error('partial coherence/csd is only supported for input allowing for a all-to-all csd representation'); + ft_error('partial coherence/csd is only supported for input allowing for a all-to-all csd representation'); end end else - data = ft_checkdata(data, 'datatype', {'freqmvar' 'freq' 'source'}); + data = ft_checkdata(data, 'datatype', {'freqmvar' 'freq' 'source' 'source+mesh'}); inparam = 'crsspctrm'; end - if strcmp(cfg.method, 'csd'), + if strcmp(cfg.method, 'csd') normpow = 0; outparam = 'crsspctrm'; - elseif strcmp(cfg.method, 'coh'), + elseif strcmp(cfg.method, 'coh') outparam = 'cohspctrm'; end dtype = ft_datatype(data); switch dtype case 'source' - if isempty(cfg.refindx), error('indices of reference voxels need to be specified'); end - % if numel(cfg.refindx)>1, error('more than one reference voxel is not yet supported'); end + if isempty(cfg.refindx), ft_error('indices of reference voxels need to be specified'); end + % if numel(cfg.refindx)>1, ft_error('more than one reference voxel is not yet supported'); end otherwise end % FIXME think of accommodating partial coherence for source data with only a few references @@ -246,25 +248,25 @@ inparam = 'crsspctrm'; outparam = 'wplispctrm'; debiaswpli = 0; - if hasjack, error('to compute wpli, data should be in rpt format'); end + if hasjack, ft_error('to compute wpli, data should be in rpt format'); end case {'wpli_debiased'} data = ft_checkdata(data, 'datatype', {'freqmvar' 'freq'}); inparam = 'crsspctrm'; outparam = 'wpli_debiasedspctrm'; debiaswpli = 1; - if hasjack, error('to compute wpli, data should be in rpt format'); end + if hasjack, ft_error('to compute wpli, data should be in rpt format'); end case {'ppc'} data = ft_checkdata(data, 'datatype', {'freqmvar' 'freq'}); inparam = 'crsspctrm'; outparam = 'ppcspctrm'; weightppc = 0; - if hasjack, error('to compute ppc, data should be in rpt format'); end + if hasjack, ft_error('to compute ppc, data should be in rpt format'); end case {'wppc'} data = ft_checkdata(data, 'datatype', {'freqmvar' 'freq'}); inparam = 'crsspctrm'; outparam = 'wppcspctrm'; weightppc = 1; - if hasjack, error('to compute wppc, data should be in rpt format'); end + if hasjack, ft_error('to compute wppc, data should be in rpt format'); end case {'plv'} data = ft_checkdata(data, 'datatype', {'freqmvar' 'freq' 'source'}); inparam = 'crsspctrm'; @@ -282,40 +284,43 @@ inparam = 'cov'; outparam = cfg.method; case {'amplcorr' 'powcorr'} - data = ft_checkdata(data, 'datatype', {'freqmvar' 'freq' 'source'}); + data = ft_checkdata(data, 'datatype', {'freqmvar' 'freq' 'source' 'source+mesh'}); dtype = ft_datatype(data); switch dtype case {'freq' 'freqmvar'} inparam = 'powcovspctrm'; - case 'source' + case {'source' 'source+mesh'} inparam = 'powcov'; - if isempty(cfg.refindx), error('indices of reference voxels need to be specified'); end - % if numel(cfg.refindx)>1, error('more than one reference voxel is not yet supported'); end + if isempty(cfg.refindx), ft_error('indices of reference voxels need to be specified'); end + % if numel(cfg.refindx)>1, ft_error('more than one reference voxel is not yet supported'); end otherwise end outparam = [cfg.method, 'spctrm']; - case {'granger' 'instantaneous_causality' 'total_interdependence'} + case {'granger' 'instantaneous_causality' 'total_interdependence' 'transfer' 'iis'} % create subcfg for the spectral factorization if ~isfield(cfg, 'granger') cfg.granger = []; end cfg.granger.conditional = ft_getopt(cfg.granger, 'conditional', 'no'); cfg.granger.block = ft_getopt(cfg.granger, 'block', []); - if isfield(cfg, 'channelcmb'), - cfg.granger.channelcmb = cfg.channelcmb; - cfg = rmfield(cfg, 'channelcmb'); - end + cfg.granger.channelcmb = ft_getopt(cfg.granger, 'channelcmb', cfg.channelcmb); + cfg = removefields(cfg, 'channelcmb'); data = ft_checkdata(data, 'datatype', {'mvar' 'freqmvar' 'freq'}); inparam = {'transfer', 'noisecov', 'crsspctrm'}; if strcmp(cfg.method, 'granger'), outparam = 'grangerspctrm'; end if strcmp(cfg.method, 'instantaneous_causality'), outparam = 'instantspctrm'; end if strcmp(cfg.method, 'total_interdependence'), outparam = 'totispctrm'; end - + if strcmp(cfg.method, 'transfer'), outparam = {'transfer' 'noisecov' 'crsspctrm'}; end + if strcmp(cfg.method, 'iis'), outparam = 'iis'; end % check whether the frequency bins are more or less equidistant dfreq = diff(data.freq)./mean(diff(data.freq)); assert(all(dfreq>0.999) && all(dfreq<1.001), ['non equidistant frequency bins are not supported for method ',cfg.method]); - case {'dtf' 'pdc'} + case {'ddtf'} + data = ft_checkdata(data, 'datatype', {'freqmvar' 'freq'}); + inparam = {'transfer' 'crsspctrm'}; + outparam = [cfg.method, 'spctrm']; + case {'dtf' 'pdc' 'gpdc'} data = ft_checkdata(data, 'datatype', {'freqmvar' 'freq'}); inparam = 'transfer'; outparam = [cfg.method, 'spctrm']; @@ -367,7 +372,7 @@ case {'di'} % wat eigenlijk? otherwise - error('unknown method % s', cfg.method); + ft_error('unknown method % s', cfg.method); end dtype = ft_datatype(data); @@ -379,7 +384,7 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % data bookkeeping - check whether the required inparam is present in the data %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -if any(~isfield(data, inparam)) || (isfield(data, 'crsspctrm') && (ischar(inparam) && strcmp(inparam, 'crsspctrm'))), +if any(~isfield(data, inparam)) || (isfield(data, 'crsspctrm') && (ischar(inparam) && strcmp(inparam, 'crsspctrm'))) if iscell(inparam) % in the case of multiple inparams, use the first one to check the % input data (e.g. checking for 'transfer' for requested granger) @@ -400,9 +405,9 @@ powindx = []; end elseif strcmp(inparam, 'powcovspctrm') - if isfield(data, 'powspctrm'), + if isfield(data, 'powspctrm') [data, powindx] = univariate2bivariate(data, 'powspctrm', 'powcovspctrm', dtype, 'demeanflag', strcmp(cfg.removemean, 'yes'), 'cmb', cfg.channelcmb, 'sqrtflag', strcmp(cfg.method, 'amplcorr')); - elseif isfield(data, 'fourierspctrm'), + elseif isfield(data, 'fourierspctrm') [data, powindx] = univariate2bivariate(data, 'fourierspctrm', 'powcovspctrm', dtype, 'demeanflag', strcmp(cfg.removemean, 'yes'), 'cmb', cfg.channelcmb, 'sqrtflag', strcmp(cfg.method, 'amplcorr')); end elseif strcmp(inparam, 'transfer') @@ -416,11 +421,15 @@ data = ft_checkdata(data, 'cmbrepresentation', 'full'); end - % convert the inparam back to cell array in the case of granger - if strcmp(cfg.method, 'granger') || strcmp(cfg.method, 'instantaneous_causality') || strcmp(cfg.method, 'total_interdependence') + % convert the inparam back to cell array in the case of granger + if any(strcmp(cfg.method, {'granger' 'instantaneous_causality' 'total_interdependence' 'transfer' 'iis'})) inparam = {'transfer' 'noisecov' 'crsspctrm'}; tmpcfg = ft_checkconfig(cfg, 'createsubcfg', {'granger'}); optarg = ft_cfg2keyval(tmpcfg.granger); + elseif strcmp(cfg.method, 'ddtf') + inparam = {'transfer' 'crsspctrm'}; + tmpcfg = ft_checkconfig(cfg, 'createsubcfg', {'ddtf'}); + optarg = ft_cfg2keyval(tmpcfg.ddtf); else tmpcfg = ft_checkconfig(cfg, 'createsubcfg', {cfg.method}); optarg = ft_cfg2keyval(tmpcfg.(cfg.method)); @@ -430,11 +439,11 @@ data = ft_connectivity_csd2transfer(data, optarg{:}); end - case 'source' + case {'source' 'source+mesh'} if ischar(cfg.refindx) && strcmp(cfg.refindx, 'all') cfg.refindx = 1:size(data.pos,1); elseif ischar(cfg.refindx) - error('cfg.refindx should be a 1xN vector, or ''all'''); + ft_error('cfg.refindx should be a 1xN vector, or ''all'''); end if strcmp(inparam, 'crsspctrm') [data, powindx, hasrpt] = univariate2bivariate(data, 'mom', 'crsspctrm', dtype, 'cmb', cfg.refindx, 'keeprpt', 0); @@ -461,8 +470,8 @@ % do some additional work if single trial normalisation is required % for example when plv needs to be computed -if normrpt && hasrpt, - if strcmp(inparam, 'crsspctrm'), +if normrpt && hasrpt + if strcmp(inparam, 'crsspctrm') tmp = data.(inparam); nrpt = size(tmp, 1); ft_progress('init', cfg.feedback, 'normalising...'); @@ -500,9 +509,9 @@ end % check if jackknife is required -if hasrpt && dojack && hasjack, +if hasrpt && dojack && hasjack % do nothing -elseif hasrpt && dojack && ~(exist('debiaswpli', 'var') || exist('weightppc', 'var')), +elseif hasrpt && dojack && ~(exist('debiaswpli', 'var') || exist('weightppc', 'var')) % compute leave-one-outs % assume the inparam(s) are well-behaved, i.e. they have the 'rpt' % dimension as the first dimension @@ -588,7 +597,7 @@ case 'amplcorr' % amplitude correlation - if isfield(data, 'dimord'), + if isfield(data, 'dimord') dimord = data.dimord; else dimord = data.([inparam, 'dimord']); @@ -599,7 +608,7 @@ case 'powcorr' % power correlation - if isfield(data, 'dimord'), + if isfield(data, 'dimord') dimord = data.dimord; else dimord = data.([inparam, 'dimord']); @@ -608,10 +617,39 @@ if exist('powindx', 'var'), optarg = cat(2, optarg, {'powindx', powindx}); end [datout, varout, nrpt] = ft_connectivity_corr(data.(inparam), optarg{:}); - case {'granger' 'instantaneous_causality' 'total_interdependence'} + case 'transfer' + % the necessary stuff has already been computed + datout = data.transfer; + noisecov = data.noisecov; + crsspctrm = data.crsspctrm; + if ~hasrpt + datout = shiftdim(datout,1); + noisecov = shiftdim(noisecov,1); + crsspctrm = shiftdim(crsspctrm,1); + end + case {'granger' 'instantaneous_causality' 'total_interdependence' 'iis'} % granger causality - if ft_datatype(data, 'freq') || ft_datatype(data, 'freqmvar'), - if isfield(data, 'labelcmb') && ~istrue(cfg.granger.conditional), + if ft_datatype(data, 'freq') || ft_datatype(data, 'freqmvar') + if isfield(data, 'labelcmb') && isfield(cfg.granger, 'sfmethod') && strcmp(cfg.granger.sfmethod, 'bivariate_conditional') + % create a powindx variable that ft_connectivity_granger can use to + % do the conditioning + [indx, label, blockindx, blocklabel] = labelcmb2indx(data.labelcmb); + cmbindx12 = labelcmb2indx(cfg.granger.channelcmb(:,1:2), label); + cmbindx23 = labelcmb2indx(cfg.granger.channelcmb(:,2:3), label); + cmbindx = [cmbindx12 cmbindx23(:,2); cmbindx12(:,[2 1]) cmbindx23(:,2)]; + + powindx.cmbindx = indx; + powindx.blockindx = blockindx; + powindx.outindx = cmbindx; + + newlabelcmb = cell(size(cmbindx,1),2); + for k = 1:size(newlabelcmb,1) + newlabelcmb{k,1} = sprintf('%s|%s',label{cmbindx(k,2)},label{cmbindx(k,3)}); % deliberate swap of 2/1 as per the conventional definition in conditional granger computation + newlabelcmb{k,2} = sprintf('%s|%s',label{cmbindx(k,1)},label{cmbindx(k,3)}); + end + data.labelcmb = newlabelcmb; + + elseif isfield(data, 'labelcmb') && ~istrue(cfg.granger.conditional) % multiple pairwise non-parametric transfer functions % linearly indexed @@ -629,15 +667,14 @@ % ix = ((k-1)*4+1):k*4; % powindx(ix, :) = [1 1;4 1;1 4;4 4] + (k-1)*4; % end - powindx = []; - if isfield(data, 'label'), + if isfield(data, 'label') % this field should be removed data = rmfield(data, 'label'); end - elseif isfield(data, 'labelcmb') && istrue(cfg.granger.conditional), + elseif isfield(data, 'labelcmb') && istrue(cfg.granger.conditional) % conditional (blockwise) needs linearly represented cross-spectra, % that have been produced by ft_connectivity_csd2transfer % @@ -647,8 +684,7 @@ % first element, while the rest is partialed out. % tmp{k, 2} represents the ordered blocks where the driving block % is left out - - + blocks = unique(data.blockindx); nblocks = numel(blocks); @@ -668,7 +704,16 @@ newlabelcmb{cnt, 2} = data.block(m).name; end end - [cmbindx, n] = blockindx2cmbindx(data.labelcmb, {data.label data.blockindx}, tmp); + + % make a temporary label list + tmp2 = cell(numel(data.labelcmb),1); + for m = 1:numel(data.labelcmb) + tok = tokenize(data.labelcmb{m}, '['); + tmp2{m} = tok{1}; + end + label = unique(tmp2); + + [cmbindx, n] = blockindx2cmbindx(data.labelcmb, {label data.blockindx}, tmp); powindx.cmbindx = cmbindx; powindx.n = n; data.labelcmb = newlabelcmb; @@ -677,13 +722,25 @@ % this field should be removed data = rmfield(data, 'label'); end - + elseif isfield(cfg.granger, 'block') && ~isempty(cfg.granger.block) + % make a temporary label list + if isfield(data, 'label') + label = data.label; + else + tmp = cell(numel(data.labelcmb),1); + for m = 1:numel(data.labelcmb) + tok = tokenize(data.labelcmb{m}, '['); + tmp{m} = tok{1}; + end + label = unique(tmp); + end + % blockwise granger for k = 1:numel(cfg.granger.block) %newlabel{k, 1} = cat(2, cfg.granger.block(k).label{:}); newlabel{k,1} = cfg.granger.block(k).name; - powindx{k,1} = match_str(data.label, cfg.granger.block(k).label); + powindx{k,1} = match_str(label, cfg.granger.block(k).label); end data.label = newlabel; else @@ -694,40 +751,47 @@ if strcmp(cfg.method, 'granger'), methodstr = 'granger'; end if strcmp(cfg.method, 'instantaneous_causality'), methodstr = 'instantaneous'; end if strcmp(cfg.method, 'total_interdependence'), methodstr = 'total'; end + if strcmp(cfg.method, 'iis'), methodstr = 'iis'; end optarg = {'hasjack', hasjack, 'method', methodstr, 'powindx', powindx, 'dimord', data.dimord}; [datout, varout, nrpt] = ft_connectivity_granger(data.transfer, data.noisecov, data.crsspctrm, optarg{:}); + if strcmp(cfg.method, 'iis') + data.freq = nan; + end else - error('granger for time domain data is not yet implemented'); + ft_error('granger for time domain data is not yet implemented'); end - case 'dtf' + case {'dtf' 'ddtf'} % directed transfer function - if isfield(data, 'labelcmb'), + if isfield(data, 'labelcmb') powindx = labelcmb2indx(data.labelcmb); else powindx = []; end optarg = {'feedback', cfg.feedback, 'powindx', powindx, 'hasjack', hasjack}; hasrpt = ~isempty(strfind(data.dimord, 'rpt')); - if hasrpt, - nrpt = size(data.(inparam), 1); - datin = data.(inparam); + if hasrpt + nrpt = size(data.transfer, 1); + datin = data.transfer; else nrpt = 1; - datin = reshape(data.(inparam), [1 size(data.(inparam))]); + datin = reshape(data.transfer, [1 size(data.transfer)]); + data.crsspctrm = reshape(data.crsspctrm, [1 size(data.crsspctrm)]); end + if strcmp(cfg.method, 'ddtf'), optarg = cat(2, optarg, {'crsspctrm' data.crsspctrm}); end [datout, varout, nrpt] = ft_connectivity_dtf(datin, optarg{:}); - case 'pdc' + case {'pdc' 'gpdc'} % partial directed coherence - if isfield(data, 'labelcmb'), + if isfield(data, 'labelcmb') powindx = labelcmb2indx(data.labelcmb); else powindx = []; end optarg = {'feedback', cfg.feedback, 'powindx', powindx, 'hasjack', hasjack}; + if strcmp(cfg.method, 'gpdc'), optarg = cat(2, optarg, {'noisecov' data.noisecov}); end hasrpt = ~isempty(strfind(data.dimord, 'rpt')); - if hasrpt, + if hasrpt nrpt = size(data.(inparam), 1); datin = data.(inparam); else @@ -754,14 +818,34 @@ % HACK dimord = getdimord(data, 'mom'); dimtok = tokenize(dimord, '_'); - posdim = find(strcmp(dimtok,'{pos}')); + posdim = find(strcmp(dimtok, '{pos}')); posdim = 4; % we concatenate across positions... - rptdim = find(~cellfun('isempty',strfind(dimtok,'rpt'))); + rptdim = find(~cellfun('isempty',strfind(dimtok, 'rpt'))); rptdim = rptdim-1; % the posdim has to be taken into account... dat = cat(4, data.mom{data.inside}); dat = permute(dat,[posdim rptdim setdiff(1:ndims(dat),[posdim rptdim])]); datout = ft_connectivity_powcorr_ortho(dat, optarg{:}); + + % HACK continued: format the output according to the inside and + % refindx specifications + if ischar(cfg.refindx) && strcmp(cfg.refindx, 'all') + % create all-to-all output + tmp = zeros(numel(data.inside)); + tmp(data.inside,data.inside) = datout; + datout = tmp; + clear tmp; + + outdimord = 'pos_pos_freq'; + else + % create all-to-few output + tmp = zeros(numel(data.inside), numel(cfg.refindx)); + tmp(data.inside, :) = datout; + datout = tmp; + clear tmp; + + outdimord = 'pos_pos_freq'; + end elseif strcmp(data.dimord, 'rpttap_chan_freq') % loop over all frequencies [nrpttap, nchan, nfreq] = size(data.fourierspctrm); @@ -774,7 +858,7 @@ % HACK otherwise I don't know how to inform the code further down about the dimord data.dimord = 'rpttap_chan_chan_freq'; else - error('unsupported data representation'); + ft_error('unsupported data representation'); end varout = []; nrpt = numel(data.cumtapcnt); @@ -783,8 +867,8 @@ % mutual information using the information breakdown toolbox % presence of the toolbox is checked in the low-level function - if ~strcmp(dtype, 'raw') && (numel(cfg.mi.lags)>1 || cfg.mi.lags~=0), - error('computation of lagged mutual information is only possible with ''raw'' data in the input'); + if ~strcmp(dtype, 'raw') && (numel(cfg.mi.lags)>1 || cfg.mi.lags~=0) + ft_error('computation of lagged mutual information is only possible with ''raw'' data in the input'); end switch dtype @@ -797,14 +881,14 @@ if ischar(cfg.refindx) && strcmp(cfg.refindx, 'all') outdimord = 'chan_chan'; - elseif numel(cfg.refindx)==1, + elseif numel(cfg.refindx)==1 outdimord = 'chan'; else - error('at present cfg.refindx should be either ''all'', or scalar'); + ft_error('at present cfg.refindx should be either ''all'', or scalar'); end if numel(cfg.mi.lags)>1 data.time = cfg.mi.lags./data.fsample; - outdimord = [outdimord,'_time']; + outdimord = [outdimord, '_time']; else data = rmfield(data, 'time'); end @@ -815,15 +899,15 @@ data = rmfield(data, 'time'); if ischar(cfg.refindx) && strcmp(cfg.refindx, 'all') outdimord = 'chan_chan'; - elseif numel(cfg.refindx)==1, + elseif numel(cfg.refindx)==1 outdimord = 'chan'; else - error('at present cfg.refindx should be either ''all'', or scalar'); + ft_error('at present cfg.refindx should be either ''all'', or scalar'); end %data.dimord = 'chan_chan'; case 'freq' - error('not yet implemented'); + ft_error('not yet implemented'); case 'source' % for the time being work with mom % dat = cat(2, data.mom{data.inside}).'; @@ -843,30 +927,30 @@ case 'xcorr' % cross-correlation function - error('method %s is not yet implemented', cfg.method); + ft_error('method %s is not yet implemented', cfg.method); case 'spearman' % spearman's rank correlation - error('method %s is not yet implemented', cfg.method); + ft_error('method %s is not yet implemented', cfg.method); case 'di' % directionality index - error('method %s is not yet implemented', cfg.method); + ft_error('method %s is not yet implemented', cfg.method); otherwise - error('unknown method %s', cfg.method); + ft_error('unknown method %s', cfg.method); end % switch method % remove the auto combinations if necessary -> FIXME this is granger specific and thus could move to ft_connectivity_granger -if (strcmp(cfg.method, 'granger') || strcmp(cfg.method, 'instantaneous_causality') || strcmp(cfg.method, 'total_interdependence')) && isfield(cfg, 'granger') && isfield(cfg.granger, 'sfmethod') && strcmp(cfg.granger.sfmethod, 'bivariate'), +if (strcmp(cfg.method, 'granger') || strcmp(cfg.method, 'instantaneous_causality') || strcmp(cfg.method, 'total_interdependence')) && isfield(cfg, 'granger') && isfield(cfg.granger, 'sfmethod') && strcmp(cfg.granger.sfmethod, 'bivariate') % remove the auto-combinations based on the order in the data switch dtype case {'freq' 'freqmvar'} keepchn = 1:size(datout, 1); keepchn = mod(keepchn, 4)==2 | mod(keepchn, 4)==3; datout = datout(keepchn, :, :, :, :); - if ~isempty(varout), + if ~isempty(varout) varout = varout(keepchn, :, :, :, :); end data.labelcmb = data.labelcmb(keepchn, :); @@ -875,14 +959,14 @@ end end -if exist('powindx', 'var') && ~isempty(powindx), +if exist('powindx', 'var') && ~isempty(powindx) % based on powindx switch dtype case {'freq' 'freqmvar'} - if isfield(data, 'labelcmb') && ~isstruct(powindx), + if isfield(data, 'labelcmb') && ~isstruct(powindx) keepchn = powindx(:, 1) ~= powindx(:, 2); datout = datout(keepchn, :, :, :, :); - if ~isempty(varout), + if ~isempty(varout) if all(size(varout)==size(nrpt)) nrpt = nrpt(keepchn, :, :, :, :); end @@ -897,14 +981,14 @@ keepchn = ~remove; datout = datout(keepchn, :, :, :, :); - if ~isempty(varout), + if ~isempty(varout) varout = varout(keepchn, :, :, :, :); end inside = false(zeros(1, size(data.pos, 1))); inside(data.inside) = true; inside = inside(keepchn); - data.inside = find(inside)'; - data.outside = find(inside==0)'; +% data.inside = find(inside)'; +% data.outside = find(inside==0)'; data.pos = data.pos(keepchn, :); end % switch dtype end @@ -912,15 +996,11 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % create the output structure %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + switch dtype - case {'freq' 'freqmvar'}, - stat = []; - if isfield(data, 'label'), - stat.label = data.label; - end - if isfield(data, 'labelcmb'), - stat.labelcmb = data.labelcmb; - + case {'freq' 'freqmvar'} + stat = keepfields(data, {'label', 'labelcmb', 'grad', 'elec'}); + if isfield(data, 'labelcmb') % ensure the correct dimord in case the input was 'powandcsd' data.dimord = strrep(data.dimord, 'chan_', 'chancmb_'); end @@ -932,22 +1012,24 @@ end end stat.dimord = dimord(2:end); - stat.(outparam) = datout; - if ~isempty(varout), - stat.([outparam, 'sem']) = (varout./nrpt).^0.5; + if ~iscell(outparam) + stat.(outparam) = datout; + if ~isempty(varout) + stat.([outparam, 'sem']) = (varout./nrpt).^0.5; + end + else + stat.(outparam{1}) = datout; + for k = 2:numel(outparam) + if exist(outparam{k}, 'var') + stat.(outparam{k}) = eval(outparam{k}); + end + end end case 'timelock' - stat = []; - if isfield(data, 'label'), - stat.label = data.label; - end - if isfield(data, 'labelcmb'), - stat.labelcmb = data.labelcmb; - end - + stat = keepfields(data, {'label', 'labelcmb', 'grad', 'elec'}); % deal with the dimord - if exist('outdimord', 'var'), + if exist('outdimord', 'var') stat.dimord = outdimord; else % guess @@ -962,25 +1044,40 @@ end stat.(outparam) = datout; - if ~isempty(varout), + if ~isempty(varout) stat.([outparam, 'sem']) = (varout./nrpt).^0.5; end - case 'source' - stat = keepfields(data, {'pos', 'dim', 'transform', 'inside', 'outside'}); + case {'source' 'source+mesh'} + stat = keepfields(data, {'pos', 'dim', 'transform', 'inside', 'outside' 'tri'}); stat.(outparam) = datout; - if ~isempty(varout), + if ~isempty(varout) stat.([outparam, 'sem']) = (varout/nrpt).^0.5; end + % deal with the dimord + if exist('outdimord', 'var') + stat.dimord = outdimord; + else + % guess + tok = tokenize(getdimord(data, inparam), '_'); + dimord = ''; + for k = 1:numel(tok) + if isempty(strfind(tok{k}, 'rpt')) + dimord = [dimord, '_', tok{k}]; + end + end + stat.dimord = dimord(2:end); + end + case 'raw' stat = []; stat.label = data.label; stat.(outparam) = datout; - if ~isempty(varout), + if ~isempty(varout) stat.([outparam, 'sem']) = (varout/nrpt).^0.5; end - if exist('outdimord', 'var'), + if exist('outdimord', 'var') stat.dimord = outdimord; end end % switch dtype @@ -995,8 +1092,6 @@ if isfield(data, 'freq'), stat.freq = data.freq; end if isfield(data, 'time'), stat.time = data.time; end end -if isfield(data, 'grad'), stat.grad = data.grad; end -if isfield(data, 'elec'), stat.elec = data.elec; end if exist('dof', 'var'), stat.dof = dof; end % do the general cleanup and bookkeeping at the end of the function @@ -1022,7 +1117,7 @@ %---fill the matrix for k = 1:nrpt - if k==1, + if k==1 begsmp = 1+nnans; endsmp = nsmp(1)+nnans; else diff --git a/external/fieldtrip/ft_connectivityplot.m b/external/fieldtrip/ft_connectivityplot.m index 13133a56..970f4923 100644 --- a/external/fieldtrip/ft_connectivityplot.m +++ b/external/fieldtrip/ft_connectivityplot.m @@ -9,18 +9,21 @@ % % The input data is a structure containing the output to FT_CONNECTIVITYANALYSIS % using a frequency domain metric of connectivity. Consequently the input -% data should have a dimord of 'chan_chan_freq'. +% data should have a dimord of 'chan_chan_freq', or 'chan_chan_freq_time'. % % The cfg can have the following options: % cfg.parameter = string, the functional parameter to be plotted (default = 'cohspctrm') % cfg.xlim = selection boundaries over first dimension in data (e.g., freq) % 'maxmin' or [xmin xmax] (default = 'maxmin') +% cfg.ylim = selection boundaries over second dimension in data +% (i.e. ,time, if present), 'maxmin', or [ymin ymax] +% (default = 'maxmin') % cfg.zlim = plotting limits for color dimension, 'maxmin', 'maxabs' or [zmin zmax] (default = 'maxmin') % cfg.channel = list of channels to be included for the plotting (default = 'all'), see FT_CHANNELSELECTION for details % % See also FT_CONNECTIVITYANALYSIS, FT_CONNECTIVITYSIMULATION, FT_MULTIPLOTCC, FT_TOPOPLOTCC -% Copyright (C) 2011-2013, Jan-Mathijs Schoffelen +% Copyright (C) 2011-2017, Jan-Mathijs Schoffelen % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -65,8 +68,10 @@ cfg.channel = ft_getopt(cfg, 'channel', 'all'); cfg.parameter = ft_getopt(cfg, 'parameter', 'cohspctrm'); cfg.zlim = ft_getopt(cfg, 'zlim', 'maxmin'); +cfg.ylim = ft_getopt(cfg, 'ylim', 'maxmin'); cfg.xlim = ft_getopt(cfg, 'xlim', 'maxmin'); cfg.graphcolor = ft_getopt(cfg, 'graphcolor', 'brgkywrgbkywrgbkywrgbkyw'); +if ischar(cfg.graphcolor), cfg.graphcolor = cfg.graphcolor(:); end % check if the input data is valid for this function % ensure that the input is correct @@ -74,26 +79,46 @@ dtype = cell(Ndata, 1); iname = cell(Ndata+1, 1); for k = 1:Ndata + if ischar(cfg.parameter) + cfg.parameter = repmat({cfg.parameter}, [1 Ndata]); + end + + % check whether all requested parameters are the same. If not, rename + % this, because otherwise a call to ft_selectdata (below) won't work + if ~all(strcmp(cfg.parameter,cfg.parameter{1})) + fprintf('different types of connectivity are to be displayed in the same figure\n'); + varargin{k}.connectivity = varargin{k}.(cfg.parameter{k}); + varargin{k} = rmfield(varargin{k}, cfg.parameter{k}); + if isfield(varargin{k}, [cfg.parameter{k} 'dimord']) + varargin{k}.connectivitydimord = varargin{k}.([cfg.parameter{k} 'dimord']); + varargin{k} = rmfield(varargin{k}, [cfg.parameter{k} 'dimord']); + end + cfg.parameter{k} = 'connectivity'; + else + % don't worry + end + % check if the input data is valid for this function varargin{k} = ft_checkdata(varargin{k}, 'datatype', {'timelock', 'freq'}); dtype{k} = ft_datatype(varargin{k}); % convert into the the supported dimord - if strcmp(varargin{k}.dimord, 'chan_chan_freq') - % that's ok - elseif strcmp(varargin{k}.dimord, 'chancmb_freq') - % convert into 'chan_chan_freq' - varargin{k} = ft_checkdata(varargin{k}, 'cmbrepresentation', 'full'); - else - error('the data should have a dimord of %s or %s', 'chan_chan_freq', 'chancmb_freq'); + switch varargin{k}.dimord + case {'chan_chan_freq' 'chan_chan_freq_time'} + % that's ok + case {'chancmb_freq' 'chancmb_freq_time'} + % convert into 'chan_chan_freq' + varargin{k} = ft_checkdata(varargin{k}, 'cmbrepresentation', 'full'); + otherwise + ft_error('the data should have a dimord of %s or %s', 'chan_chan_freq', 'chancmb_freq'); end % this is needed for correct treatment of graphcolor later on - if nargin>1, + if nargin>1 if ~isempty(inputname(k+1)) iname{k+1} = inputname(k+1); else - iname{k+1} = ['input',num2str(k,'%02d')]; + iname{k+1} = ['input',num2str(k, '%02d')]; end else % not yet supported @@ -101,25 +126,44 @@ end end -if Ndata >1, +if Ndata >1 if ~all(strcmp(dtype{1}, dtype)) - error('input data are of different type; this is not supported'); + ft_error('input data are of different type; this is not supported'); end end % ensure that the data in all inputs has the same channels, time-axis, etc. -tmpcfg = keepfields(cfg, {'channel'}); +tmpcfg = keepfields(cfg, {'channel', 'showcallinfo'}); [varargin{:}] = ft_selectdata(tmpcfg, varargin{:}); % restore the provenance information [cfg, varargin{:}] = rollback_provenance(cfg, varargin{:}); +% check presence of time / freq axes +hasfreq = isfield(varargin{1}, 'freq'); +hastime = isfield(varargin{1}, 'time'); +if hasfreq && hastime + if Ndata>1 + ft_error('when the input data contains time-frequency representations, only a single data argument is allowed'); + end + xparam = 'time'; + yparam = 'freq'; +elseif hasfreq + xparam = 'freq'; + yparam = ''; +elseif hastime + xparam = 'time'; + yparam = ''; +end + + + % Get physical min/max range of x: -if ischar(cfg.xlim) && strcmp(cfg.xlim,'maxmin') +if ischar(cfg.xlim) && strcmp(cfg.xlim, 'maxmin') xmin = inf; xmax = -inf; for k = 1:Ndata - xmin = min(xmin,varargin{k}.freq(1)); - xmax = max(xmax,varargin{k}.freq(end)); + xmin = min(xmin,varargin{k}.(xparam)(1)); + xmax = max(xmax,varargin{k}.(xparam)(end)); end else xmin = cfg.xlim(1); @@ -127,18 +171,35 @@ end cfg.xlim = [xmin xmax]; -% Get physical min/max range of z: -if ischar(cfg.zlim) && strcmp(cfg.zlim,'maxmin') +% Get physical min/max range of y: +if ischar(cfg.ylim) && strcmp(cfg.ylim, 'maxmin') && ~isempty(yparam) + ymin = inf; + ymax = -inf; + for k = 1:Ndata + ymin = min(ymin,varargin{k}.(yparam)(1)); + ymax = max(ymax,varargin{k}.(yparam)(end)); + end +elseif ~isempty(yparam) + ymin = cfg.ylim(1); + ymax = cfg.ylim(2); +elseif isempty(yparam) + ymin = []; + ymax = []; +end +cfg.ylim = [ymin ymax]; + +% Get physical min/max range of z, which is the functional data: +if ischar(cfg.zlim) && strcmp(cfg.zlim, 'maxmin') zmin = inf; zmax = -inf; for k = 1:Ndata - zmin = min(zmin,min(varargin{k}.(cfg.parameter)(:))); - zmax = max(zmax,max(varargin{k}.(cfg.parameter)(:))); + zmin = min(zmin,min(varargin{k}.(cfg.parameter{k})(:))); + zmax = max(zmax,max(varargin{k}.(cfg.parameter{k})(:))); end -elseif ischar(cfg.zlim) && strcmp(cfg.zlim,'maxabs') +elseif ischar(cfg.zlim) && strcmp(cfg.zlim, 'maxabs') zmax = -inf; for k = 1:Ndata - zmax = max(zmax,max(abs(varargin{k}.(parameter)(:)))); + zmax = max(zmax,max(abs(varargin{k}.(cfg.parameter{k})(:)))); end zmin = -zmax; else @@ -181,27 +242,35 @@ end end - ft_plot_text(0.5, (numel(varargin{k}.label)+1).*1.2-0.5, sprintf(colorLabels), 'interpreter', 'none', 'horizontalalignment', 'right'); + ft_plot_text(0.5, (numel(varargin{k}.label)+1).*1.2-0.5, sprintf(colorLabels), 'horizontalalignment', 'right'); return; else data = varargin{1}; end -if ~isfield(data, cfg.parameter) - error('the data does not contain the requested parameter %s', cfg.parameter); +if ~isfield(data, cfg.parameter{1}) + ft_error('the data does not contain the requested parameter %s', cfg.parameter{1}); end % get the selection of the data tmpcfg = []; -tmpcfg.frequency = cfg.xlim; +if hasfreq && hastime + tmpcfg.latency = cfg.xlim; + tmpcfg.frequency = cfg.ylim; +elseif hasfreq + tmpcfg.frequency = cfg.xlim; +elseif hastime + tmpcfg.latency = cfg.xlim; +end data = ft_selectdata(tmpcfg, data); % restore the provenance information [cfg, data] = rollback_provenance(cfg, data); -dat = data.(cfg.parameter); +dat = data.(cfg.parameter{k}); nchan = numel(data.label); -nfreq = numel(data.freq); +if hasfreq, nfreq = numel(data.freq); end +if hastime, ntime = numel(data.time); end if (isfield(cfg, 'holdfig') && cfg.holdfig==0) || ~isfield(cfg, 'holdfig') cla; @@ -214,19 +283,34 @@ ix = k; iy = nchan - m + 1; % use the convention of the row-channel causing the column-channel - tmp = reshape(dat(m,k,:), [nfreq 1]); - ft_plot_vector(tmp, 'width', 1, 'height', 1, 'hpos', ix.*1.2, 'vpos', iy.*1.2, 'vlim', cfg.zlim, 'box', 'yes', 'color', cfg.graphcolor(1)); - if k==1, + if hastime && hasfreq + tmp = reshape(dat(m,k,:,:), [nfreq ntime]); + ft_plot_matrix(tmp, 'width', 1, 'height', 1, 'hpos', ix.*1.2, 'vpos', iy.*1.2, 'clim', cfg.zlim, 'box', 'yes'); + elseif hasfreq + tmp = reshape(dat(m,k,:), [nfreq 1]); + ft_plot_vector(tmp, 'width', 1, 'height', 1, 'hpos', ix.*1.2, 'vpos', iy.*1.2, 'vlim', cfg.zlim, 'box', 'yes', 'color', cfg.graphcolor(1,:)); + elseif hastime + ft_error('plotting data with only a time axis is not supported yet'); + end + if k==1 % first column, plot scale on y axis + if hastime && hasfreq + val1 = cfg.ylim(1); + val2 = cfg.ylim(2); + elseif hasfreq + val1 = cfg.zlim(1); + val2 = cfg.zlim(2); + elseif hastime + end fontsize = 10; - ft_plot_text( ix.*1.2-0.5,iy.*1.2-0.5,num2str(cfg.zlim(1),3),'HorizontalAlignment','Right','VerticalAlignment','Middle','Fontsize',fontsize,'Interpreter','none'); - ft_plot_text( ix.*1.2-0.5,iy.*1.2+0.5,num2str(cfg.zlim(2),3),'HorizontalAlignment','Right','VerticalAlignment','Middle','Fontsize',fontsize,'Interpreter','none'); + ft_plot_text(ix.*1.2-0.5, iy.*1.2-0.5, num2str(val1,3), 'HorizontalAlignment', 'Right', 'VerticalAlignment', 'Middle', 'FontSize', fontsize); + ft_plot_text(ix.*1.2-0.5, iy.*1.2+0.5, num2str(val2,3), 'HorizontalAlignment', 'Right', 'VerticalAlignment', 'Middle', 'FontSize', fontsize); end - if m==nchan, + if m==nchan % bottom row, plot scale on x axis fontsize = 10; - ft_plot_text( ix.*1.2-0.5,iy.*1.2-0.5,num2str(data.freq(1 ),3),'HorizontalAlignment','Center','VerticalAlignment','top','Fontsize',fontsize,'Interpreter','none'); - ft_plot_text( ix.*1.2+0.5,iy.*1.2-0.5,num2str(data.freq(end),3),'HorizontalAlignment','Center','VerticalAlignment','top','Fontsize',fontsize,'Interpreter','none'); + ft_plot_text(ix.*1.2-0.5, iy.*1.2-0.5, num2str(cfg.xlim(1),3), 'HorizontalAlignment', 'Center', 'VerticalAlignment', 'top', 'FontSize', fontsize); + ft_plot_text(ix.*1.2+0.5, iy.*1.2-0.5, num2str(cfg.xlim(2),3), 'HorizontalAlignment', 'Center', 'VerticalAlignment', 'top', 'FontSize', fontsize); end end end @@ -234,13 +318,13 @@ % add channel labels on grand X and Y axes for k = 1:nchan - ft_plot_text(0.5, (nchan + 1 - k).*1.2, data.label{k}, 'Interpreter', 'none', 'horizontalalignment', 'right'); - ft_plot_text(k.*1.2, (nchan + 1) .*1.2-0.5, data.label{k}, 'Interpreter', 'none', 'horizontalalignment', 'left', 'rotation', 90); + ft_plot_text(0.5, (nchan + 1 - k).*1.2, data.label{k}, 'horizontalalignment', 'right'); + ft_plot_text(k.*1.2, (nchan + 1) .*1.2-0.5, data.label{k}, 'horizontalalignment', 'left', 'rotation', 90); end % add 'from' and 'to' labels -ft_plot_text(-0.5, (nchan + 1)/1.7, '\it{from}', 'rotation', 90); -ft_plot_text((nchan + 1)/1.7, (nchan + 1)*1.2+0.4, '\it{to}'); +ft_plot_text(-0.5, (nchan + 1)/1.7, '\it{from}', 'interpreter', 'tex', 'rotation', 90); +ft_plot_text((nchan + 1)/1.7, (nchan + 1)*1.2+0.4, '\it{to}', 'interpreter', 'tex'); axis([-0.2 (nchan+1).*1.2+0.2 0 (nchan+1).*1.2+0.2]); axis off; diff --git a/external/fieldtrip/ft_connectivitysimulation.m b/external/fieldtrip/ft_connectivitysimulation.m index 50d9a8a0..7dfedfd5 100644 --- a/external/fieldtrip/ft_connectivitysimulation.m +++ b/external/fieldtrip/ft_connectivitysimulation.m @@ -8,7 +8,7 @@ % [data] = ft_connectivitysimulation(cfg) % % where the configuration structure should contain: -% cfg.method = string, can be 'linear_mix', 'mvnrnd', 'ar' (see below) +% cfg.method = string, can be 'linear_mix', 'mvnrnd', 'ar', 'ar_reverse' (see below) % cfg.nsignal = scalar, number of signals % cfg.ntrials = scalar, number of trials % cfg.triallength = in seconds @@ -66,7 +66,7 @@ % deviation of white noise superimposed on top % of the simulated signals % -% Method 'ar' implements an multivariate autoregressive model to generate +% Method 'ar' implements a multivariate autoregressive model to generate % the data. % % Required cfg options: @@ -78,6 +78,23 @@ % cfg.noisecov = matrix, [nsignal x nsignal] specifying the covariance % matrix of the innovation process % +% Method 'ar_reverse' implements a multivariate autoregressive +% autoregressive model to generate the data, where the model coefficients +% are reverse-computed, based on the interaction pattern specified. +% +% Required cfg options: +% cfg.coupling = nxn matrix, specifying coupling strength, rows causing +% column +% cfg.delay = nxn matrix, specifying the delay, in seconds, from one +% signal's spectral component to the other signal, rows +% causing column +% cfg.ampl = nxn matrix, specifying the amplitude +% cfg.bpfreq = nxnx2 matrix, specifying the lower and upper frequencies +% of the bands that are transmitted, rows causing column +% +% The generated signals will have a spectrum that is 1/f + additional +% band-limited components, as specified in the cfg. +% % See also FT_FREQSIMULATION, FT_DIPOLESIMULATION, FT_SPIKESIMULATION, % FT_CONNECTIVITYANALYSIS @@ -140,6 +157,9 @@ cfg.demean = ft_getopt(cfg, 'demean', 'yes'); cfg.absnoise = ft_getopt(cfg, 'absnoise', 1); cfg = ft_checkconfig(cfg, 'required', {'covmat' 'delay'}); + case {'ar_reverse'} + % reverse engineered high order ar-model + cfg = ft_checkconfig(cfg, 'required', {'coupling' 'delay' 'ampl' 'bpfreq'}); otherwise end @@ -149,8 +169,9 @@ tim = (0:nsmp-1)./cfg.fsample; % create the labels +label = cell(cfg.nsignal,1); for k = 1:cfg.nsignal - label{k,1} = ['signal',num2str(k,'%03d')]; + label{k,1} = ['signal',num2str(k, '%03d')]; end switch cfg.method @@ -167,27 +188,34 @@ % 13, 2011. This swaps the directional influence for existing scripts. end for k = 1:cfg.ntrials - tmp = zeros(nsignal, nsmp+nlag); - noise = mvnrnd(zeros(nsignal,1), cfg.noisecov, nsmp+nlag)'; + tmp = zeros(nsignal, nsmp+ceil(nlag*1.05)); + noise = mvnrnd(zeros(nsignal,1), cfg.noisecov, ceil(nsmp+nlag*1.05))'; state0 = zeros(nsignal*nlag, 1); for m = 1:nlag indx = ((m-1)*nsignal+1):m*nsignal; state0(indx) = params(indx,:)'*noise(:,m); end - tmp(:,1:nlag) = fliplr(reshape(state0, [nsignal nlag])); + tmp(:,1:nlag) = flip(reshape(state0, [nsignal nlag]),2); - for m = (nlag+1):(nsmp+nlag) - state0 = reshape(fliplr(tmp(:,(m-nlag):(m-1))), [nlag*nsignal 1]); + for m = (nlag+1):(nsmp+ceil(nlag*1.05)) + state0 = reshape(flip(tmp(:,(m-nlag):(m-1)),2), [nlag*nsignal 1]); tmp(:, m) = params'*state0 + noise(:,m); end - trial{k} = tmp(:,nlag+1:end); + trial{k} = tmp(:,(ceil(nlag*1.05)+1):end); if any(cfg.absnoise>0) trial{k} = trial{k} + diag(cfg.absnoise)*randn(size(trial{k})); end time{k} = tim; end + % create the output data + simulated = []; + simulated.trial = trial; + simulated.time = time; + simulated.fsample = cfg.fsample; + simulated.label = label; + case {'linear_mix'} fltpad = 50; %hard coded to avoid filtering artifacts @@ -195,7 +223,7 @@ delay = delay - min(delay(:)); %make explicitly >= 0 maxdelay = max(delay(:)); - if iscell(cfg.mix), + if iscell(cfg.mix) %each trial has different mix mix = cfg.mix; else @@ -210,12 +238,12 @@ nmixsignal = size(mix{1}, 2); %number of "mixing signals" nsignal = size(mix{1}, 1); - if numel(size(mix{1}))==2, + if numel(size(mix{1}))==2 %mix is static, no function of time for tr = 1:cfg.ntrials mix{tr} = mix{tr}(:,:,ones(1,nsmp+maxdelay)); end - elseif numel(size(mix{1}))==3 && size(mix{1},3)==nsmp, + elseif numel(size(mix{1}))==3 && size(mix{1},3)==nsmp %mix changes with time for tr = 1:cfg.ntrials mix{tr} = cat(3,mix{tr},mix{tr}(:,:,nsmp*ones(1,maxdelay))); @@ -272,17 +300,149 @@ % define time axis for this trial time{k} = tim; end + + % create the output data + simulated = []; + simulated.trial = trial; + simulated.time = time; + simulated.fsample = cfg.fsample; + simulated.label = label; + case 'ar_reverse' + % generate a spectral transfer matrix, and a cross-spectral matrix + % according to the specifications + + % predefine some variables + fstep = 1/5; + fs = cfg.fsample; + Nyq = fs./2; + foi = (0:fstep:Nyq); + omega = foi./fs; + n = numel(foi); + + % local renaming + nsignal = cfg.nsignal; + fband = cfg.bpfreq; + coupling = cfg.coupling; + ampl = cfg.ampl; + delay = cfg.delay; + + % create a 1/f spectrum + slope = 0.5; + oneoverf = sqrt(max(omega(2)./10,omega).^-slope); % takes sqrt for amplitude + oneoverf = oneoverf./oneoverf(1); + %oneoverf(1) = 0; + %z = firws_filter(5.*fs, fs, Nyq./1.01); + %z = z(1:numel(foi));%.*exp(-1i.*pi.*foi.*rand(1)./100); + %oneoverf = z.*oneoverf; + + % convert into indices + findx = fband; + for k = 1:numel(fband) + if isfinite(fband(k)) + findx(k) = nearest(foi, fband(k)); + end + end + + % allocate some memory + mask = false(nsignal, nsignal, n); + krn = zeros(size(mask)); + phi = zeros(size(krn)); + dat = zeros(size(krn)); + coupling_ampl = zeros(size(krn)); + + for k = 1:nsignal + for m = 1:nsignal + if all(isfinite(squeeze(findx(k,m,:)))) + mask(k,m,findx(k,m,1):findx(k,m,2)) = true; + end + krn(k,m,mask(k,m,:)) = hanning(sum(mask(k,m,:)))'; + + phi(k,m,:) = 2.*pi.*delay(k,m).*foi; + %phi(k,m,:) = phi(k,m,:).*mask(k,m,:); + %phi(k,m,mask(k,m,:)) = phi(k,m,mask(k,m,:))-mean(phi(k,m,mask(k,m,:))); + if all(isfinite(squeeze(findx(k,m,:)))) + phi(k,m,1:findx(k,m,1)) = phi(k,m,findx(k,m,1)); + phi(k,m,findx(k,m,2):end) = phi(k,m,findx(k,m,2)); + phi(k,m,:) = phi(k,m,:)-mean(phi(k,m,:)); + end + + coupling_ampl(k,m,:) = coupling(k,m).*krn(k,m,:); + end + end + + % this matrix contains the intrinsic amplitude spectra on the diagonal + for k = 1:nsignal + if all(isfinite(squeeze(fband(k,k,:)))) + z = firws_filter((1/fstep).*fs, fs, [fband(k,k,1) fband(k,k,2)]); + z = z(1:numel(foi));%.*exp(-1i.*pi.*foi.*rand(1)./100); + z = z.*ampl(k,k); + + plateau = nearest(foi,fband(k,k,1)):nearest(foi,fband(k,k,2)); + oneoverf(plateau) = mean(abs(oneoverf(plateau))); + dat(k,k,:) = -(abs(oneoverf)+abs(z)).*exp(1i.*(angle(z)+angle(oneoverf))); + else + dat(k,k,:) = oneoverf; + end + end + + % now we can create a spectral transfer matrix + tf = zeros(nsignal,nsignal,n)+1i.*zeros(nsignal,nsignal,n); + for k = 1:nsignal + for m = 1:nsignal + if k~=m && all(isfinite(squeeze(fband(k,m,:)))) + z = firws_filter((1/fstep).*fs, fs, [fband(k,m,1) fband(k,m,2)]); + z = z(1:numel(foi)); + tf(m,k,:) = coupling(k,m).*exp(-1i.*phi(k,m,:)).*shiftdim(z,-1); % deliberate index swap! + + elseif k==m + tf(k,m,:) = dat(k,m,:); + end + end + end + + % create the cross spectral matrix + c = zeros(size(tf)); + for k = 1:n + c(:,:,k) = tf(:,:,k)*tf(:,:,k)'; % assume noise to be I, i.e. the tf to swallow the amplitudes + end + + % scale the Nyquist and DC bins + c(:,:,1) = real(c(:,:,1)./2); + c(:,:,end) = real(c(:,:,end)./2); + + % create a freq-structure + freq = []; + freq.crsspctrm = c; + freq.label = label; + freq.freq = foi; + freq.dimord = 'chan_chan_freq'; + + % estimate the transfer-matrix non-parametrically + tmpcfg = []; + tmpcfg.method = 'transfer'; + tmpcfg.granger.stabilityfix = true; + t = ft_connectivityanalysis(tmpcfg, freq); + + % estimate the ar-model coefficients + a = transfer2coeffs(t.transfer,t.freq); + + % recursively call this function to generate the data, this is + % somewhate tricky with respect to keeping the provenance info. Here, + % it is solved by removing from the cfg the original user-specified + % fields + cfgorig = cfg; + cfg = removefields(cfgorig, {'coupling' 'ampl' 'delay' 'bpfreq'}); + cfg.method = 'ar'; + cfg.params = a; + cfg.noisecov = diag(diag(t.noisecov.*cfg.fsample./2)); + simulated = ft_connectivitysimulation(cfg); + cfg.previous = keepfields(cfgorig, {'coupling' 'ampl' 'delay' 'bpfreq'}); + otherwise - error('unknown method'); + ft_error('unknown method'); end -% create the output data -simulated = []; -simulated.trial = trial; -simulated.time = time; -simulated.fsample = cfg.fsample; -simulated.label = label; % do the general cleanup and bookkeeping at the end of the function ft_postamble debug @@ -291,3 +451,180 @@ ft_postamble provenance ft_postamble history simulated ft_postamble savevar simulated + + +%%%%%% +% helper function +function A = transfer2coeffs(H, freq, labelcmb, maxlag) + +% TRANSFER2COEFFS converts a spectral transfer matrix into the time domain +% equivalent multivariate autoregressive coefficients up to a specified +% lag, starting from lag 1. + +if nargin<3 + labelcmb = []; +end +if nargin<4 + maxlag = []; +end + +% do a check on the input data +siz = size(H); +if numel(siz)==3 && siz(1)==siz(2) + % assume chan_chan_freq + isfull = true; +elseif numel(siz)==2 + % assume chancmb_freq + isfull = false; + %assert(~isempty(labelcmb), 'input data appears to be chancmb_freq, but labelcmb is missing'); +else + ft_error('dimensionality of input data is not supported'); +end + +dfreq = round(diff(freq)*1e5)./1e5; % allow for some numeric issues +if ~all(dfreq==dfreq(1)) + ft_error('the frequency axis is not evenly spaced'); +end + +if freq(1)~=0 + ft_warning('when converting the transfer function to coefficients, the frequency axis should ideally start at 0, zero padding the spectral density'); + dfreq = mean(dfreq); + npad = freq(1)./dfreq; + + % update the freq axis and keep track of the frequency bins that are + % expected in the output + selfreq = (1:numel(freq)) + npad; + freq = [(0:(npad-1))./dfreq freq]; + if isfull + H = cat(3, zeros(siz(1),siz(2),npad), H); + else + H = cat(2, zeros(siz(1),npad), H); + end +else + selfreq = 1:numel(freq); +end + +% ensure H to be double precision +H = double(H); + +% deal with the two different types of input +if isfull + % check whether the last frequency bin is strictly real-valued. + % if that's the case, then it is assumed to be the Nyquist frequency + % and the two-sided spectral density will have an even number of + % frequency bins. if not, in order to preserve hermitian symmetry, + % the number of frequency bins needs to be odd. + Hend = H(:,:,end); + N = numel(freq); + m = size(H,1); + if all(imag(Hend(:)) size(cfg.chanscale,1) cfg.chanscale = cfg.chanscale'; @@ -236,11 +240,11 @@ end if ~isempty(cfg.mychanscale) && ~isfield(cfg, 'mychan') - warning('ignoring cfg.mychanscale; no channels specified in cfg.mychan'); + ft_warning('ignoring cfg.mychanscale; no channels specified in cfg.mychan'); cfg.mychanscale = []; end -if ~isfield(cfg, 'channel'), +if ~isfield(cfg, 'channel') if hascomp if size(data.topo,2)>9 cfg.channel = 1:10; @@ -255,13 +259,13 @@ if strcmp(cfg.viewmode, 'component') % read or create the layout that will be used for the topoplots - + if ~isempty(cfg.layout) tmpcfg = []; tmpcfg.layout = cfg.layout; cfg.layout = ft_prepare_layout(tmpcfg); else - warning('No layout specified - will try to construct one using sensor positions'); + ft_warning('No layout specified - will try to construct one using sensor positions'); tmpcfg = []; try, tmpcfg.elec = cfg.elec; end try, tmpcfg.grad = cfg.grad; end @@ -282,15 +286,15 @@ if hasdata % save whether data came from a timelock structure istimelock = strcmp(ft_datatype(data), 'timelock'); - + % check if the input data is valid for this function data = ft_checkdata(data, 'datatype', {'raw+comp', 'raw'}, 'feedback', 'yes', 'hassampleinfo', 'yes'); % fetch the header from the data structure in memory hdr = ft_fetch_header(data); - + if isfield(data, 'cfg') && ~isempty(ft_findcfg(data.cfg, 'origfs')) % don't use the events in case the data has been resampled - warning('the data has been resampled, not showing the events'); + ft_warning('the data has been resampled, not showing the events'); event = []; elseif isfield(data, 'cfg') && isfield(data.cfg, 'event') % use the event structure from the data as per bug #2501 @@ -303,11 +307,11 @@ %event = ft_fetch_event(data); event = []; end - + cfg.channel = ft_channelselection(cfg.channel, hdr.label); chansel = match_str(data.label, cfg.channel); Nchans = length(chansel); - + if isempty(cfg.continuous) if numel(data.trial) == 1 && ~istimelock cfg.continuous = 'yes'; @@ -316,20 +320,20 @@ end else if strcmp(cfg.continuous, 'yes') && (numel(data.trial) > 1) - warning('interpreting trial-based data as continous, time-axis is no longer appropriate. t(0) now corresponds to the first sample of the first trial, and t(end) to the last sample of the last trial') + ft_warning('interpreting trial-based data as continous, time-axis is no longer appropriate. t(0) now corresponds to the first sample of the first trial, and t(end) to the last sample of the last trial') end end - + % this is how the input data is segmented trlorg = zeros(numel(data.trial), 3); trlorg(:, [1 2]) = data.sampleinfo; - + % recreate offset vector (databrowser depends on this for visualisation) for ntrl = 1:numel(data.trial) trlorg(ntrl,3) = time2offset(data.time{ntrl}, data.fsample); end Ntrials = size(trlorg, 1); - + else % check if the input cfg is valid for this function cfg = ft_checkconfig(cfg, 'dataset2files', 'yes'); @@ -338,7 +342,7 @@ cfg = ft_checkconfig(cfg, 'renamedval', {'continuous', 'continuous', 'yes'}); % read the header from file hdr = ft_read_header(cfg.headerfile, 'headerformat', cfg.headerformat); - + if isempty(cfg.continuous) if hdr.nTrials==1 cfg.continuous = 'yes'; @@ -346,7 +350,7 @@ cfg.continuous = 'no'; end end - + if ~isempty(cfg.event) % use the events that the user passed in the configuration event = cfg.event; @@ -354,20 +358,20 @@ % read the events from file event = ft_read_event(cfg.dataset); end - + cfg.channel = ft_channelselection(cfg.channel, hdr.label); chansel = match_str(hdr.label, cfg.channel); Nchans = length(chansel); - + if strcmp(cfg.continuous, 'yes') Ntrials = 1; else Ntrials = hdr.nTrials; end - + % FIXME in case of continuous=yes the trl should be [1 hdr.nSamples*nTrials 0] % and a scrollbar should be used - + % construct trl-matrix for data from file on disk trlorg = zeros(Ntrials,3); if strcmp(cfg.continuous, 'yes') @@ -389,11 +393,11 @@ % FIXME make a check for the consistency of cfg.continous, cfg.blocksize, cfg.trl and the data header if Nchans == 0 - error('no channels to display'); + ft_error('no channels to display'); end if Ntrials == 0 - error('no trials to display'); + ft_error('no trials to display'); end if ischar(cfg.selectfeature) @@ -412,8 +416,12 @@ % determine the vertical scaling if ischar(cfg.ylim) if hasdata + sel = 1; + while all(isnan(reshape(data.trial{sel}(chansel,:),[],1))) + sel = sel+1; + end % the first trial is used to determine the vertical scaling - dat = data.trial{1}(chansel,:); + dat = data.trial{sel}(chansel,:); else % one second of data is read from file to determine the vertical scaling dat = ft_read_data(cfg.datafile, 'header', hdr, 'begsample', 1, 'endsample', round(hdr.Fs), 'chanindx', chansel, 'checkboundary', strcmp(cfg.continuous, 'no'), 'dataformat', cfg.dataformat, 'headerformat', cfg.headerformat); @@ -442,7 +450,7 @@ end cfg.ylim = [minval maxval]; otherwise - error('unsupported value for cfg.ylim'); + ft_error('unsupported value for cfg.ylim'); end % switch ylim % zoom in a bit when viemode is vertical if strcmp(cfg.viewmode, 'vertical') @@ -450,7 +458,7 @@ end else if (numel(cfg.ylim) ~= 2) || ~isnumeric(cfg.ylim) - error('cfg.ylim needs to be a 1x2 vector [ymin ymax], describing the upper and lower limits') + ft_error('cfg.ylim needs to be a 1x2 vector [ymin ymax], describing the upper and lower limits') end end @@ -461,22 +469,22 @@ labels_all= hdr.label; end if size(cfg.channelcolormap,2) ~= 3 - error('cfg.channelcolormap is not valid, size should be Nx3') + ft_error('cfg.channelcolormap is not valid, size should be Nx3') end if isnumeric(cfg.colorgroups) % groups defined by user if length(labels_all) ~= length(cfg.colorgroups) - error('length(cfg.colorgroups) should be length(data/hdr.label)') + ft_error('length(cfg.colorgroups) should be length(data/hdr.label)') end R = cfg.channelcolormap(:,1); G = cfg.channelcolormap(:,2); B = cfg.channelcolormap(:,3); chancolors = [R(cfg.colorgroups(:)) G(cfg.colorgroups(:)) B(cfg.colorgroups(:))]; - + elseif strcmp(cfg.colorgroups, 'allblack') chancolors = zeros(length(labels_all),3); - + elseif strcmp(cfg.colorgroups, 'chantype') type = ft_chantype(labels_all); [tmp1 tmp2 cfg.colorgroups] = unique(type); @@ -485,7 +493,7 @@ G = cfg.channelcolormap(:,2); B = cfg.channelcolormap(:,3); chancolors = [R(cfg.colorgroups(:)) G(cfg.colorgroups(:)) B(cfg.colorgroups(:))]; - + elseif strcmp(cfg.colorgroups(1:9), 'labelchar') % groups determined by xth letter of label labelchar_num = str2double(cfg.colorgroups(10)); @@ -499,13 +507,13 @@ G = cfg.channelcolormap(:,2); B = cfg.channelcolormap(:,3); chancolors = [R(cfg.colorgroups(:)) G(cfg.colorgroups(:)) B(cfg.colorgroups(:))]; - + elseif strcmp(cfg.colorgroups, 'sequential') % no grouping chancolors = lines(length(labels_all)); - + else - error('do not understand cfg.colorgroups') + ft_error('do not understand cfg.colorgroups') end % collect the artifacts that have been detected from cfg.artfctdef.xxx.artifact @@ -525,7 +533,7 @@ artlabel = artlabel(sel==1); if length(artlabel) > 9 - error('only up to 9 artifacts groups supported') + ft_error('only up to 9 artifacts groups supported') end % make artdata representing all artifacts in a "raw data" format @@ -590,7 +598,7 @@ defselcfg{6}.videofile = ft_getopt(cfg, 'videofile'); defselcfg{6}.anonimize = ft_getopt(cfg, 'anonimize'); defselfun{6} = 'audiovideo'; - + cfg.selfun = defselfun; cfg.selcfg = defselcfg; end @@ -663,7 +671,7 @@ end % set interruptible to off, see bug 3123 -set(h,'Interruptible','off','BusyAction', 'queue'); % enforce busyaction to queue to be sure +set(h, 'Interruptible', 'off', 'BusyAction', 'queue'); % enforce busyaction to queue to be sure % enable custom data cursor text dcm = datacursormode(h); @@ -732,10 +740,10 @@ uicontrol('tag', 'artifactui', 'parent', h, 'units', 'normalized', 'style', 'pushbutton', 'string', '>', 'userdata', ['control+' num2str(iArt)], 'position', [0.96, 0.855 - ((iArt-1)*0.09), 0.03, 0.04], 'backgroundcolor', opt.artcolors(iArt,:)) end if length(artlabel)>1 % highlight the first one as active - arth = findobj(h,'tag','artifactui'); + arth = findobj(h, 'tag', 'artifactui'); arth = arth(end:-1:1); % order is reversed so reverse it again hsel = [1 2 3] + (opt.ftsel-1) .*3; - set(arth(hsel),'fontweight','bold') + set(arth(hsel), 'fontweight', 'bold') end if true % strcmp(cfg.viewmode, 'butterfly') @@ -799,7 +807,7 @@ if nargout % wait until the user interface is closed, get the user data with the updated artifact details set(h, 'CloseRequestFcn', @cleanup_cb); - + while ishandle(h) uiwait(h); opt = getappdata(h, 'opt'); @@ -807,27 +815,27 @@ delete(h); end end - + % add the updated artifact definitions to the output cfg for i=1:length(opt.artdata.label) cfg.artfctdef.(opt.artdata.label{i}).artifact = convert_event(opt.artdata.trial{1}(i,:), 'artifact'); end - + % add the updated preproc to the output try browsecfg = getappdata(h, 'cfg'); cfg.preproc = browsecfg.preproc; end - + % add the update event to the output cfg cfg.event = opt.event; - + % do the general cleanup and bookkeeping at the end of the function ft_postamble debug ft_postamble trackconfig ft_postamble previous data ft_postamble provenance - + end % if nargout end % main function @@ -850,7 +858,7 @@ function definetrial_cb(h, eventdata) opt = getappdata(h, 'opt'); cfg = getappdata(h, 'cfg'); if strcmp(cfg.continuous, 'no') - + % when zooming in, lock the trial! one can only go to the next trial when horizontal scaling doesn't segment the data - from ft-meeting: this might be relaxed later on - roevdmei if isempty(opt.trllock) opt.trllock = opt.trlop; @@ -860,7 +868,7 @@ function definetrial_cb(h, eventdata) if (abs(locktrllen-cfg.blocksize) / locktrllen) < 0.1 cfg.blocksize = locktrllen; end - + %%%%%%%%% % trial is locked, change subdivision of trial if cfg.blocksize < locktrllen @@ -889,7 +897,7 @@ function definetrial_cb(h, eventdata) trllen = (trlvis(:,2) - trlvis(:,1)+1); sizediff = smpperseg - trllen; opt.nanpaddata = sizediff; - + if isfield(opt, 'trlvis') % update the current trial counter and try to keep the current sample the same opt.trlop = nearest(begsamples, thissegbeg); @@ -899,8 +907,8 @@ function definetrial_cb(h, eventdata) % update button set(findobj(get(h, 'children'), 'string', 'trial'), 'string', 'segment'); %%%%%%%%% - - + + %%%%%%%%% % trial is not locked, go to original trial division and zoom out elseif cfg.blocksize >= locktrllen @@ -914,17 +922,17 @@ function definetrial_cb(h, eventdata) trllen = (trlvis(:,2) - trlvis(:,1)+1); sizediff = smpperseg - trllen; opt.nanpaddata = sizediff; - + % update trialviewtype opt.trialviewtype = 'trial'; % update button set(findobj(get(h, 'children'), 'string', 'trialsegment'), 'string',opt.trialviewtype); - + % release trial lock opt.trllock = []; %%%%%%%%% end - + % save trlvis opt.trlvis = trlvis; else @@ -953,14 +961,14 @@ function definetrial_cb(h, eventdata) offset = begsamples - repmat(begsamples(1), [1 numel(begsamples)]); trlvis(:,3) = offset; end - + if isfield(opt, 'trlvis') % update the current trial counter and try to keep the current sample the same % opt.trlop = nearest(round((begsamples+endsamples)/2), thissample); opt.trlop = nearest(begsamples, thistrlbeg); end opt.trlvis = trlvis; - + % NaN-padding when horizontal scaling is bigger than the data % two possible situations, 1) zoomed out so far that all data is one segment, or 2) multiple segments but last segment is smaller than the rest sizediff = smpperseg-(endsamples-begsamples+1); @@ -1025,7 +1033,7 @@ function select_range_cb(h, range, cmenulab) %range 1X4 in sec relative to curre % mark or execute selfun if isempty(cmenulab) % the left button was clicked INSIDE a selected range, update the artifact definition or event - + if strcmp(cfg.selectmode, 'markartifact') % mark or unmark artifacts artval = opt.artdata.trial{1}(opt.ftsel, begsel:endsel); @@ -1037,7 +1045,7 @@ function select_range_cb(h, range, cmenulab) %range 1X4 in sec relative to curre fprintf('there is no overlap with the active artifact (%s), marking this as a new artifact\n',opt.artdata.label{opt.ftsel}); opt.artdata.trial{1}(opt.ftsel, begsel:endsel) = 1; end - + % redraw only when marking (so the focus doesn't go back to the databrowser after calling selfuns setappdata(h, 'opt', opt); setappdata(h, 'cfg', cfg); @@ -1055,7 +1063,7 @@ function select_range_cb(h, range, cmenulab) %range 1X4 in sec relative to curre % check if only 1 chan, other wise not clear max in which channel. % % ingnie: would be cool to add the option to select the channel when multiple channels if size(opt.curdata.trial{1},1) > 1 - error('cfg.selectmode = ''markpeakevent'' and ''marktroughevent'' only supported with 1 channel in the data') + ft_error('cfg.selectmode = ''markpeakevent'' and ''marktroughevent'' only supported with 1 channel in the data') end if strcmp(cfg.selectmode, 'markpeakevent') [dum ind_minmax] = max(opt.curdata.trial{1}(begsel-begsample+1:endsel-begsample+1)); @@ -1096,27 +1104,27 @@ function select_range_cb(h, range, cmenulab) %range 1X4 in sec relative to curre setappdata(h, 'cfg', cfg); redraw_cb(h); end - + else % the right button was used to activate the context menu and the user made a selection from that menu % execute the corresponding function - + % get index into cfgs selfunind = strcmp(cfg.selfun, cmenulab); - + % cut out the requested data segment switch cfg.seldat case 'current' - seldata = keepfields(opt.curdata, {'label', 'grad', 'elec', 'hdr'}); + seldata = keepfields(opt.curdata, {'label', 'grad', 'elec', 'opto', 'hdr'}); seldata.trial{1} = ft_fetch_data(opt.curdata, 'begsample', begsel, 'endsample', endsel); case 'all' - seldata = keepfields(opt.org, {'label', 'grad', 'elec', 'hdr'}); + seldata = keepfields(opt.org, {'label', 'grad', 'elec', 'opto', 'hdr'}); seldata.trial{1} = ft_fetch_data(opt.orgdata, 'begsample', begsel, 'endsample', endsel); end seldata.time{1} = offset2time(offset+begsel-begsample, opt.fsample, endsel-begsel+1); seldata.fsample = opt.fsample; seldata.sampleinfo = [begsel endsel offset]; - + % prepare input funhandle = ft_getuserfun(cmenulab, 'browse'); funcfg = cfg.selcfg{selfunind}; @@ -1218,7 +1226,7 @@ function preproc_cfg2_cb(h,eventdata) for icomm = 1:numel(code) eval([code{icomm} ';']); end - + % check for cfg and output into the original appdata-window if ~exist('cfg', 'var') cfg = []; @@ -1266,12 +1274,12 @@ function keyboard_cb(h, eventdata) fprintf('data has no artifact type %i \n', opt.ftsel) else % bold the active one - arth = findobj(h,'tag','artifactui'); + arth = findobj(h, 'tag', 'artifactui'); arth = arth(end:-1:1); % order is reversed so reverse it again hsel = [1 2 3] + (opt.ftsel-1) .*3 ; - set(arth(hsel),'fontweight','bold') + set(arth(hsel), 'fontweight', 'bold') % unbold the passive ones - set(arth(setdiff(1:numel(arth),hsel)),'fontweight','normal') + set(arth(setdiff(1:numel(arth),hsel)), 'fontweight', 'normal') % redraw setappdata(h, 'opt', opt); setappdata(h, 'cfg', cfg); @@ -1289,7 +1297,7 @@ function keyboard_cb(h, eventdata) % 1) artifacts can cross trial boundaries % 2) artifacts might not occur inside a trial boundary (when data is segmented differently than during artifact detection) % fetch trl representation of current artifact type - arttrl = convert_event(opt.artdata.trial{1}(opt.ftsel,:),'trl'); + arttrl = convert_event(opt.artdata.trial{1}(opt.ftsel,:), 'trl'); % discard artifacts in the future curvisend = opt.trlvis(opt.trlop,2); arttrl(arttrl(:,1) > curvisend,:) = []; @@ -1309,12 +1317,12 @@ function keyboard_cb(h, eventdata) fprintf('going to previous %s with "%s" artifact\n', opt.trialviewtype, opt.artdata.label{opt.ftsel}); opt.trlop = newtrlop; % other artifact type potentially selected, bold the active one - arth = findobj(h,'tag','artifactui'); + arth = findobj(h, 'tag', 'artifactui'); arth = arth(end:-1:1); % order is reversed so reverse it again hsel = [1 2 3] + (opt.ftsel-1) .*3 ; - set(arth(hsel),'fontweight','bold') + set(arth(hsel), 'fontweight', 'bold') % unbold the passive ones - set(arth(setdiff(1:numel(arth),hsel)),'fontweight','normal') + set(arth(setdiff(1:numel(arth),hsel)), 'fontweight', 'normal') % export into fig and continue setappdata(h, 'opt', opt); setappdata(h, 'cfg', cfg); @@ -1332,7 +1340,7 @@ function keyboard_cb(h, eventdata) % 1) artifacts can cross trial boundaries % 2) artifacts might not occur inside a trial boundary (when data is segmented differently than during artifact detection) % fetch trl representation of current artifact type - arttrl = convert_event(opt.artdata.trial{1}(opt.ftsel,:),'trl'); + arttrl = convert_event(opt.artdata.trial{1}(opt.ftsel,:), 'trl'); % discard artifacts in the past curvisbeg = opt.trlvis(opt.trlop,1); arttrl(arttrl(:,2) < curvisbeg,:) = []; @@ -1352,12 +1360,12 @@ function keyboard_cb(h, eventdata) fprintf('going to next %s with "%s" artifact\n', opt.trialviewtype, opt.artdata.label{opt.ftsel}); opt.trlop = newtrlop; % other artifact type potentially selected, bold the active one - arth = findobj(h,'tag','artifactui'); + arth = findobj(h, 'tag', 'artifactui'); arth = arth(end:-1:1); % order is reversed so reverse it again hsel = [1 2 3] + (opt.ftsel-1) .*3 ; - set(arth(hsel),'fontweight','bold') + set(arth(hsel), 'fontweight', 'bold') % unbold the passive ones - set(arth(setdiff(1:numel(arth),hsel)),'fontweight','normal') + set(arth(setdiff(1:numel(arth),hsel)), 'fontweight', 'normal') % export into fig and continue setappdata(h, 'opt', opt); setappdata(h, 'cfg', cfg); @@ -1474,7 +1482,7 @@ function keyboard_cb(h, eventdata) if numel(tmp)==2 cfg.ylim = tmp; else - warning('incorrect specification of cfg.ylim, not changing the limits for the vertical axes') + ft_warning('incorrect specification of cfg.ylim, not changing the limits for the vertical axes') end end setappdata(h, 'opt', opt); @@ -1510,11 +1518,11 @@ function keyboard_cb(h, eventdata) case 'vertical' % find channel identity by extracting timecourse objects and finding the time course closest to the cursor % this is a lot easier than the reverse, determining the y value of each time course scaled by the layout and vlim - tcobj = findobj(h,'tag','timecourse'); - tmpydat = get(tcobj,'ydata'); + tcobj = findobj(h, 'tag', 'timecourse'); + tmpydat = get(tcobj, 'ydata'); tmpydat = cat(1,tmpydat{:}); tmpydat = tmpydat(end:-1:1,:); % order of timecourse objects is reverse of channel order - tmpxdat = get(tcobj(1),'xdata'); + tmpxdat = get(tcobj(1), 'xdata'); % first find closest sample on x xsmp = nearest(tmpxdat,val(1)); % then find closes y sample, being the channel number @@ -1525,7 +1533,7 @@ function keyboard_cb(h, eventdata) end fprintf('channel name: %s\n',channame); redraw_cb(h, eventdata); - if strcmp(cfg.viewmode,'vertical') + if strcmp(cfg.viewmode, 'vertical') ypos = opt.laytime.pos(chanposind,2)+opt.laytime.height(chanposind)*3; if ypos>.9 % don't let label fall on plot boundary ypos = opt.laytime.pos(chanposind,2)-opt.laytime.height(chanposind)*3; @@ -1533,7 +1541,7 @@ function keyboard_cb(h, eventdata) else ypos = .9; end - ft_plot_text(pos, ypos, channame, 'FontSize', cfg.fontsize, 'FontUnits', cfg.fontunits, 'tag', 'identify', 'interpreter', 'none', 'FontSize', cfg.fontsize, 'FontUnits', cfg.fontunits); + ft_plot_text(pos, ypos, channame, 'FontSize', cfg.fontsize, 'FontUnits', cfg.fontunits, 'tag', 'identify', 'FontSize', cfg.fontsize, 'FontUnits', cfg.fontunits); if ~ishold hold on ft_plot_vector(opt.curdata.time{1}, opt.curdata.trial{1}(channb,:), 'box', false, 'tag', 'identify', 'hpos', opt.laytime.pos(chanposind,1), 'vpos', opt.laytime.pos(chanposind,2), 'width', opt.laytime.width(chanposind), 'height', opt.laytime.height(chanposind), 'hlim', opt.hlim, 'vlim', opt.vlim, 'color', 'k', 'linewidth', 2); @@ -1542,7 +1550,7 @@ function keyboard_cb(h, eventdata) ft_plot_vector(opt.curdata.time{1}, opt.curdata.trial{1}(channb,:), 'box', false, 'tag', 'identify', 'hpos', opt.laytime.pos(chanposind,1), 'vpos', opt.laytime.pos(chanposind,2), 'width', opt.laytime.width(chanposind), 'height', opt.laytime.height(chanposind), 'hlim', opt.hlim, 'vlim', opt.vlim, 'color', 'k', 'linewidth', 2); end else - warning('only supported with cfg.viewmode=''butterfly/vertical'''); + ft_warning('only supported with cfg.viewmode=''butterfly/vertical'''); end case 's' % toggle between selectmode options: switch from 'markartifact', to 'markpeakevent' to 'marktroughevent' and back with on screen feedback @@ -1610,6 +1618,24 @@ function redraw_cb(h, eventdata) %fprintf('redrawing with viewmode %s\n', cfg.viewmode); +cfg.channelclamped = ft_getopt(cfg, 'channelclamped'); + +% temporarily store the originally selected list of channels +userchan = cfg.channel; + +% add the clamped channels (cfg.channelclamped) at the end of the list +cfg.channel = setdiff(cfg.channel, cfg.channelclamped); +cfg.channel = union(cfg.channel, cfg.channelclamped); + +% if the number of channels changes, includes past channels +if numel(cfg.channel)19 @@ -1971,23 +1997,23 @@ function redraw_cb(h, eventdata) end yTickLabel = repmat(yTickLabel, 1, length(chanindx)); set(gca, 'yTick', yTick, 'yTickLabel', yTickLabel); - + else % the following is implemented for 2column, 3column, etcetera. % it also works for topographic layouts, such as CTF151 - + % determine channel indices into data outside of loop laysels = match_str(opt.laytime.label, opt.hdr.label); - + for i = 1:length(chanindx) color = opt.chancolors(chanindx(i),:); datsel = i; laysel = laysels(i); - + if ~isempty(datsel) && ~isempty(laysel) - + lh = ft_plot_vector(tim, dat(datsel, :), 'box', false, 'color', color, 'tag', 'timecourse', 'hpos', opt.laytime.pos(laysel,1), 'vpos', opt.laytime.pos(laysel,2), 'width', opt.laytime.width(laysel), 'height', opt.laytime.height(laysel), 'hlim', opt.hlim, 'vlim', opt.vlim, 'linewidth', cfg.linewidth); - + % store this data in the line object so that it can be displayed in the % data cursor (see subfunction datacursortext below) setappdata(lh, 'ft_databrowser_linetype', 'channel'); @@ -1996,13 +2022,13 @@ function redraw_cb(h, eventdata) setappdata(lh, 'ft_databrowser_yaxis', dat(datsel,:)); end end - + % ticks are not supported with such a layout yTick = []; yTickLabel = []; yTickLabel = repmat(yTickLabel, 1, length(chanindx)); set(gca, 'yTick', yTick, 'yTickLabel', yTickLabel); - + end % if strcmp viewmode if any(strcmp(cfg.viewmode, {'butterfly', 'component', 'vertical'})) @@ -2020,35 +2046,35 @@ function redraw_cb(h, eventdata) end if strcmp(cfg.viewmode, 'component') - + % determine the position of each of the original channels for the topgraphy laychan = opt.layorg; - + % determine the position of each of the topographies laytopo.pos(:,1) = opt.laytime.pos(:,1) - opt.laytime.width/2 - opt.laytime.height; laytopo.pos(:,2) = opt.laytime.pos(:,2) + opt.laytime.height/2; laytopo.width = opt.laytime.height; laytopo.height = opt.laytime.height; laytopo.label = opt.laytime.label; - + if ~isequal(opt.chanindx, chanindx) opt.chanindx = chanindx; - + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % fprintf('plotting component topographies...\n'); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% delete(findobj(h, 'tag', 'topography')); - + [sel1, sel2] = match_str(opt.orgdata.topolabel, laychan.label); chanx = laychan.pos(sel2,1); chany = laychan.pos(sel2,2); - + if strcmp(cfg.compscale, 'global') for i=1:length(chanindx) % loop through all components to get max and min zmin(i) = min(opt.orgdata.topo(sel1,chanindx(i))); zmax(i) = max(opt.orgdata.topo(sel1,chanindx(i))); end - + if strcmp(cfg.zlim, 'maxmin') zmin = min(zmin); zmax = max(zmax); @@ -2056,15 +2082,15 @@ function redraw_cb(h, eventdata) zmax = max([abs(zmin) abs(zmax)]); zmin = -zmax; else - error('configuration option for component scaling could not be recognized'); + ft_error('configuration option for component scaling could not be recognized'); end end - + for i=1:length(chanindx) % plot the topography of this component laysel = match_str(opt.laytime.label, opt.hdr.label(chanindx(i))); chanz = opt.orgdata.topo(sel1,chanindx(i)); - + if strcmp(cfg.compscale, 'local') % compute scaling factors here if strcmp(cfg.zlim, 'maxmin') @@ -2075,25 +2101,25 @@ function redraw_cb(h, eventdata) zmin = -zmax; end end - + % scaling chanz = (chanz - zmin) ./ (zmax- zmin); - + % laychan is the actual topo layout, in pixel units for .mat files % laytopo is a vertical layout determining where to plot each topo, with one entry per component - + ft_plot_topo(chanx, chany, chanz, 'mask', laychan.mask, 'interplim', 'mask', 'outline', laychan.outline, 'tag', 'topography', 'hpos', laytopo.pos(laysel,1)-laytopo.width(laysel)/2, 'vpos', laytopo.pos(laysel,2)-laytopo.height(laysel)/2, 'width', laytopo.width(laysel), 'height', laytopo.height(laysel), 'gridscale', 45); - + %axis equal %drawnow end - + caxis([0 1]); - + end % if redraw_topo - + set(gca, 'yTick', []) - + ax(1) = min(laytopo.pos(:,1) - laytopo.width); ax(2) = max(opt.laytime.pos(:,1) + opt.laytime.width/2); ax(3) = min(opt.laytime.pos(:,2) - opt.laytime.height/2); @@ -2101,7 +2127,7 @@ function redraw_cb(h, eventdata) % add white space to bottom and top so channels are not out-of-axis for the majority % NOTE: there is another spot above with the same code, which should be kept the same as this % determine amount of vertical padding using cfg.verticalpadding - if ~isnumeric(cfg.verticalpadding) && strcmp(cfg.verticalpadding,'auto') + if ~isnumeric(cfg.verticalpadding) && strcmp(cfg.verticalpadding, 'auto') % determine amount of padding using the number of channels if numel(cfg.channel)<=6 wsfac = 0; @@ -2135,6 +2161,10 @@ function redraw_cb(h, eventdata) % possibly adds some responsiveness if the 'thing' is clogged drawnow +% restore the originally selected list of channels, in case a set of +% additional fixed channels was selected +cfg.channel = userchan; + setappdata(h, 'opt', opt); setappdata(h, 'cfg', cfg); end % function redraw_cb @@ -2173,7 +2203,7 @@ function redraw_cb(h, eventdata) % SUBFUNCTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function cursortext = datacursortext(obj, event_obj) -pos = get(event_obj, 'position'); +pos = get(event_obj, 'Position'); linetype = getappdata(event_obj.Target, 'ft_databrowser_linetype'); @@ -2202,15 +2232,13 @@ function redraw_cb(h, eventdata) end % function datacursortext - - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % SUBFUNCTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function winresize_cb(h,eventdata) % check whether the current figure is the browser -if get(0,'currentFigure') ~= h +if get(0, 'currentFigure') ~= h return end @@ -2222,4 +2250,3 @@ function winresize_cb(h,eventdata) redraw_cb(h,eventdata); end % function datacursortext - diff --git a/external/fieldtrip/ft_defacemesh.m b/external/fieldtrip/ft_defacemesh.m index 203138f1..47444519 100644 --- a/external/fieldtrip/ft_defacemesh.m +++ b/external/fieldtrip/ft_defacemesh.m @@ -1,11 +1,10 @@ function mesh = ft_defacemesh(cfg, mesh) -% FT_DEFACEVOLUME allows you to de-identify a head -% surface mesh by erasing specific regions, such as the face and ears. The graphical -% user interface allows you to position a box over the anatomical data inside which -% all vertices will be removed. You might have to call this -% function multiple times when both face and ears need to be removed. Following -% defacing, you should check the result with FT_PLOT_MESH . +% FT_DEFACEMESH allows you to de-identify a scalp surface mesh by erasing specific +% regions, such as the face and ears. The graphical user interface allows you to +% position a box over the anatomical data inside which all vertices will be removed. +% You might have to call this function multiple times when both face and ears need to +% be removed. Following defacing, you should check the result with FT_PLOT_MESH. % % Use as % mesh = ft_defacevolume(cfg, mesh) diff --git a/external/fieldtrip/ft_defacevolume.m b/external/fieldtrip/ft_defacevolume.m index cea13080..c4dcc06d 100644 --- a/external/fieldtrip/ft_defacevolume.m +++ b/external/fieldtrip/ft_defacevolume.m @@ -1,10 +1,11 @@ function mri = ft_defacevolume(cfg, mri) -% FT_DEFACEVOLUME allows you to de-identify an anatomical MRI by erasing specific regions, such as the face and ears. The graphical -% user interface allows you to position a box over the anatomical data inside which -% all anatomical voxel values will be replaced by zero. You might have to call this -% function multiple times when both face and ears need to be removed. Following -% defacing, you should check the result with FT_SOURCEPLOT. +% FT_DEFACEVOLUME allows you to de-identify an anatomical MRI by erasing specific +% regions, such as the face and ears. The graphical user interface allows you to +% position a box over the anatomical data inside which all anatomical voxel values will +% be replaced by zero. You might have to call this function multiple times when both +% face and ears need to be removed. Following defacing, you should check the result +% with FT_SOURCEPLOT. % % Use as % mri = ft_defacevolume(cfg, mri) @@ -91,7 +92,7 @@ axmax = 0.15; rbol = 0.005; otherwise - error('unknown units (%s)', unit); + ft_error('unknown units (%s)', unit); end figHandle = figure; @@ -117,7 +118,11 @@ ft_plot_ortho(anatomy, 'transform', mri.transform, 'unit', mri.unit, 'resolution', resolution, 'style', 'intersect'); elseif ismesh - ft_plot_mesh(mri); + if isfield(mri, 'hex') + ft_plot_mesh(mri, 'surfaceonly', 'yes'); + else + ft_plot_mesh(mri); + end end axis vis3d @@ -258,10 +263,10 @@ dimtok = tokenize(dimord{i}, '_'); % do some sanity checks if any(strcmp(dimtok, '{pos}')) - error('not supported'); + ft_error('not supported'); end if numel(dimtok)>5 - error('too many dimensions'); + ft_error('too many dimensions'); end % remove the same positions from each matching dimension if numel(dimtok)>0 && strcmp(dimtok{1}, 'pos') diff --git a/external/fieldtrip/ft_defaults.m b/external/fieldtrip/ft_defaults.m index 38e58647..c3c1af36 100644 --- a/external/fieldtrip/ft_defaults.m +++ b/external/fieldtrip/ft_defaults.m @@ -1,8 +1,9 @@ function ft_defaults % FT_DEFAULTS (ending with "s") sets some general settings in the global variable -% ft_default (without the "s") and takes care of the required path settings. This -% function is called at the begin of all FieldTrip functions. +% ft_default (without the "s") and takes care of the required path settings. You can +% call this function in your startup.m script. This function is also called at the +% begin of all FieldTrip functions. % % The configuration defaults are stored in the global "ft_default" structure. % The ft_checkconfig function that is called by many FieldTrip functions will @@ -10,16 +11,25 @@ % the FieldTrip function that you are calling. % % The global options and their default values are -% ft_default.trackdatainfo = string, can be 'yes' or 'no' (default = 'no') -% ft_default.trackconfig = string, can be 'cleanup', 'report', 'off' (default = 'off') % ft_default.showcallinfo = string, can be 'yes' or 'no' (default = 'yes') % ft_default.checkconfig = string, can be 'pedantic', 'loose', 'silent' (default = 'loose') % ft_default.checksize = number in bytes, can be inf (default = 1e5) +% ft_default.trackconfig = string, can be 'cleanup', 'report', 'off' (default = 'off') +% ft_default.trackusage = false, or string with salt for one-way encryption of identifying information (by default this is enabled and an automatic salt is created) +% ft_default.trackdatainfo = string, can be 'yes' or 'no' (default = 'no') +% ft_default.trackcallinfo = string, can be 'yes' or 'no' (default = 'yes') % ft_default.outputfilepresent = string, can be 'keep', 'overwrite', 'error' (default = 'overwrite') % ft_default.debug = string, can be 'display', 'displayonerror', 'displayonsuccess', 'save', 'saveonerror', saveonsuccess' or 'no' (default = 'no') -% ft_default.trackusage = false, or string with salt for one-way encryption of identifying information (by default this is enabled and an automatic salt is created) +% ft_default.toolbox.signal = string, can be 'compat' or 'matlab' (default = 'compat') +% ft_default.toolbox.stats = string, can be 'compat' or 'matlab' (default = 'compat') +% ft_default.toolbox.images = string, can be 'compat' or 'matlab' (default = 'compat') +% +% The toolbox option for signal, stats and images allows you to specify whether you +% want to use a compatible drop-in to be used for these MathWorks toolboxes, or the +% original version from MathWorks. The default is 'compat', which has the advantage +% that you do not need a license for these toolboxes. % -% See also FT_HASTOOLBOX, FT_CHECKCONFIG +% See also FT_HASTOOLBOX, FT_CHECKCONFIG, FT_TRACKUSAGE % undocumented options % ft_default.siunits = 'yes' or 'no' @@ -51,6 +61,11 @@ initialized = false; end +% ft_warning is located in fieldtrip/utilities, which may not be on the path yet +if ~exist('ft_warning', 'file') + ft_warning = @warning; +end + % locate the file that contains the persistent FieldTrip preferences fieldtripprefs = fullfile(prefdir, 'fieldtripprefs.mat'); if exist(fieldtripprefs, 'file') @@ -69,10 +84,16 @@ if ~isfield(ft_default, 'debug'), ft_default.debug = 'no'; end % no, save, saveonerror, display, displayonerror, this is used in ft_pre/postamble_debug if ~isfield(ft_default, 'outputfilepresent'), ft_default.outputfilepresent = 'overwrite'; end % can be keep, overwrite, error -% these options allow to disable parts of the provenance +% These options allow to disable parts of the provenance if ~isfield(ft_default, 'trackcallinfo'), ft_default.trackcallinfo = 'yes'; end % yes or no if ~isfield(ft_default, 'trackdatainfo'), ft_default.trackdatainfo = 'no'; end % yes or no +% These options allow to prefer the MATLAB toolbox implementations ('matlab') over the drop-in replacements ('compat'). +if ~isfield(ft_default, 'toolbox'), ft_default.toolbox = []; end +if ~isfield(ft_default.toolbox, 'images'), ft_default.toolbox.images = 'compat'; end % matlab or compat +if ~isfield(ft_default.toolbox, 'stats') , ft_default.toolbox.stats = 'compat'; end % matlab or compat +if ~isfield(ft_default.toolbox, 'signal'), ft_default.toolbox.signal = 'compat'; end % matlab or compat + % Check whether this ft_defaults function has already been executed. Note that we % should not use ft_default itself directly, because the user might have set stuff % in that struct already prior to ft_defaults being called for the first time. @@ -85,7 +106,7 @@ ftPath = fileparts(mfilename('fullpath')); % get the full path to this function, strip away 'ft_defaults' ftPath = strrep(ftPath, '\', '\\'); if isempty(regexp(path, [ftPath pathsep '|' ftPath '$'], 'once')) - warning('FieldTrip is not yet on your MATLAB path, adding %s', strrep(ftPath, '\\', '\')); + ft_warning('FieldTrip is not yet on your MATLAB path, adding %s', strrep(ftPath, '\\', '\')); addpath(ftPath); end @@ -131,19 +152,23 @@ try % external/signal contains alternative implementations of some signal processing functions - addpath(fullfile(fileparts(which('ft_defaults')), 'external', 'signal')); + if ~ft_platform_supports('signal') || ~ft_hastoolbox('signal') || ~strcmp(ft_default.toolbox.signal, 'matlab') + addpath(fullfile(fileparts(which('ft_defaults')), 'external', 'signal')); + end end try - % some alternative implementations of statistics functions - if ~ft_platform_supports('stats') + % external/stats contains alternative implementations of some statistics functions + if ~ft_platform_supports('stats') || ~ft_hastoolbox('stats') || ~strcmp(ft_default.toolbox.stats, 'matlab') addpath(fullfile(fileparts(which('ft_defaults')), 'external', 'stats')); end end try % external/images contains alternative implementations of some image processing functions - addpath(fullfile(fileparts(which('ft_defaults')), 'external', 'images')); + if ~ft_platform_supports('images') || ~ft_hastoolbox('images') || ~strcmp(ft_default.toolbox.images, 'matlab') + addpath(fullfile(fileparts(which('ft_defaults')), 'external', 'images')); + end end try @@ -151,11 +176,6 @@ ft_hastoolbox('fileexchange', 3, 1); % not required end - try - % this directory contains the backward compatibility wrappers for the ft_xxx function name change - ft_hastoolbox('compat', 3, 1); % not required - end - try % these directories deal with compatibility with older MATLAB versions if ft_platform_supports('matlabversion', -inf, '2008a'), ft_hastoolbox('compat/matlablt2008b', 3, 1); end @@ -267,16 +287,23 @@ % SUBFUNCTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function checkMultipleToolbox(toolbox, keyfile) + +persistent warned +if isempty(warned) + warned = false; +end + if ~ft_platform_supports('which-all') return; end list = which(keyfile, '-all'); if length(list)>1 - [ws, warned] = ft_warning(sprintf('Multiple versions of %s on your path will confuse FieldTrip', toolbox)); - if warned % only throw the warning once + ft_warning('Multiple versions of %s on your path will confuse FieldTrip', toolbox); + if ~warned % only throw the following warnings once + warned = true; for i=1:length(list) - warning('one version of %s is found here: %s', toolbox, list{i}); + ft_warning('one version of %s is found here: %s', toolbox, list{i}); end end ft_warning('You probably used addpath(genpath(''path_to_fieldtrip'')), this can lead to unexpected behaviour. See http://www.fieldtriptoolbox.org/faq/should_i_add_fieldtrip_with_all_subdirectories_to_my_matlab_path'); diff --git a/external/fieldtrip/ft_definetrial.m b/external/fieldtrip/ft_definetrial.m index bf6187b0..a970423c 100644 --- a/external/fieldtrip/ft_definetrial.m +++ b/external/fieldtrip/ft_definetrial.m @@ -132,19 +132,19 @@ if ~isfield(cfg, 'trl') && (~isfield(cfg, 'trialfun') || isempty(cfg.trialfun)) % there used to be other system specific trialfuns in previous versions - % of fieldtrip, but they are deprecated and not included in recent + % of FieldTrip, but they are deprecated and not included in recent % versions any more cfg.trialfun = 'ft_trialfun_general'; - warning('no trialfun was specified, using ft_trialfun_general'); + ft_warning('no trialfun was specified, using ft_trialfun_general'); end % create the trial definition for this dataset and condition if isfield(cfg, 'trl') % the trial definition is already part of the configuration - fprintf('retaining existing trial definition\n'); + ft_info('retaining existing trial definition\n'); trl = cfg.trl; if isfield(cfg, 'event') - fprintf('retaining existing event information\n'); + ft_info('retaining existing event information\n'); event = cfg.event; else event = []; @@ -152,12 +152,13 @@ elseif isfield(cfg, 'trialfun') + trialfunSpecified = cfg.trialfun; cfg.trialfun = ft_getuserfun(cfg.trialfun, 'trialfun'); if isempty(cfg.trialfun) - error('the specified trialfun ''%s'' was not found', func2str(cfg.trialfun)); + ft_error('the specified trialfun ''%s'' was not found', trialfunSpecified); else - fprintf('evaluating trialfunction ''%s''\n', func2str(cfg.trialfun)); + ft_info('evaluating trialfunction ''%s''\n', func2str(cfg.trialfun)); end % determine the number of outpout arguments of the user-supplied trial function @@ -177,20 +178,20 @@ [trl, event] = feval(cfg.trialfun, cfg); end else - error('no trialfunction specified, see FT_DEFINETRIAL for help'); + ft_error('no trialfunction specified, see FT_DEFINETRIAL for help'); end if isfield(cfg, 'trialdef') && isfield(cfg.trialdef, 'eventtype') && isequal(cfg.trialdef.eventtype, '?') % give a gentle message instead of an error - fprintf('no trials have been defined yet, see FT_DEFINETRIAL for further help\n'); + ft_info('no trials have been defined yet, see FT_DEFINETRIAL for further help\n'); elseif size(trl,1)<1 - error('no trials were defined, see FT_DEFINETRIAL for help'); + ft_error('no trials were defined, see FT_DEFINETRIAL for help'); end % add the new trials and events to the output configuration -fprintf('found %d events\n', length(event)); +ft_info('found %d events\n', length(event)); cfg.event = event; -fprintf('created %d trials\n', size(trl,1)); +ft_info('created %d trials\n', size(trl,1)); cfg.trl = trl; % do the general cleanup and bookkeeping at the end of the function diff --git a/external/fieldtrip/ft_denoise_pca.m b/external/fieldtrip/ft_denoise_pca.m index 926c31b5..80b9906f 100644 --- a/external/fieldtrip/ft_denoise_pca.m +++ b/external/fieldtrip/ft_denoise_pca.m @@ -19,13 +19,14 @@ % The output structure dataout contains the denoised data in a format that is % consistent with the output of FT_PREPROCESSING. % -% The configuration should be according to +% The configuration should contain % cfg.refchannel = the channels used as reference signal (default = 'MEGREF') % cfg.channel = the channels to be denoised (default = 'MEG') % cfg.truncate = optional truncation of the singular value spectrum (default = 'no') % cfg.zscore = standardise reference data prior to PCA (default = 'no') % cfg.pertrial = 'no' (default) or 'yes'. Regress out the references on a per trial basis % cfg.trials = list of trials that are used (default = 'all') +% cfg.updatesens = 'no' or 'yes' (default = 'yes') % % if cfg.truncate is integer n > 1, n will be the number of singular values kept. % if 0 < cfg.truncate < 1, the singular value spectrum will be thresholded at the @@ -88,19 +89,21 @@ cfg.trials = ft_getopt(cfg, 'trials', 'all', 1); cfg.pertrial = ft_getopt(cfg, 'pertrial', 'no'); cfg.feedback = ft_getopt(cfg, 'feedback', 'none'); +cfg.updatesens = ft_getopt(cfg, 'updatesens', 'yes'); -if strcmp(cfg.pertrial, 'yes'), + +if strcmp(cfg.pertrial, 'yes') %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % iterate over trials %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - tmpcfg = keepfields(cfg, 'trials'); + tmpcfg = keepfields(cfg, {'trials', 'showcallinfo'}); % select trials of interest for i=1:numel(varargin) varargin{i} = ft_selectdata(tmpcfg, varargin{i}); [cfg, varargin{i}] = rollback_provenance(cfg, varargin{i}); end - + tmp = cell(numel(varargin{1}.trial),1); tmpcfg = cfg; tmpcfg.pertrial = 'no'; @@ -119,7 +122,7 @@ computeweights = ~isfield(cfg, 'pca'); - if length(varargin)==1, + if length(varargin)==1 % channel data and reference channel data are in 1 data structure data = varargin{1}; megchan = ft_channelselection(cfg.channel, data.label); @@ -152,7 +155,7 @@ end % select trials of interest - tmpcfg = keepfields(cfg, 'trials'); + tmpcfg = keepfields(cfg, {'trials', 'showcallinfo'}); data = ft_selectdata(tmpcfg, data); refdata = ft_selectdata(tmpcfg, refdata); % restore the provenance information @@ -170,7 +173,7 @@ if ischar(cfg.truncate) && strcmp(cfg.truncate, 'no') cfg.truncate = length(refindx); elseif ischar(cfg.truncate) || (cfg.truncate>1 && cfg.truncate/round(cfg.truncate)~=1) || cfg.truncate>length(refindx) - error('cfg.truncate should be either ''no'', an integer number <= the number of references, or a number between 0 and 1'); + ft_error('cfg.truncate should be either ''no'', an integer number <= the number of references, or a number between 0 and 1'); % FIXME the default truncation applied by 4D is 1x10^-8 end @@ -184,10 +187,10 @@ % compute std of data before the regression stdpre = cellstd(data.trial, 2); - if computeweights, + if computeweights % zscore - if strcmp(cfg.zscore, 'yes'), + if strcmp(cfg.zscore, 'yes') fprintf('zscoring the reference channel data\n'); [refdata.trial, sdref] = cellzscore(refdata.trial, 2, 0); %forced demeaned already else @@ -241,8 +244,8 @@ [i1,i2] = match_str(refchan, cfg.pca.reflabel); [i3,i4] = match_str(megchan, cfg.pca.label); - if length(i2)~=length(cfg.pca.reflabel), - error('you specified fewer references to use as there are in the precomputed weight table'); + if length(i2)~=length(cfg.pca.reflabel) + ft_error('you specified fewer references to use as there are in the precomputed weight table'); end refindx = refindx(i1); @@ -250,7 +253,7 @@ cfg.pca.w = cfg.pca.w(i4,i2); cfg.pca.label = cfg.pca.label(i4); cfg.pca.reflabel= cfg.pca.reflabel(i2); - if isfield(cfg.pca, 'rotmat'), + if isfield(cfg.pca, 'rotmat') cfg.pca = rmfield(cfg.pca, 'rotmat'); % dont know end @@ -268,44 +271,56 @@ m = cellmean(data.trial, 2); data.trial = cellvecadd(data.trial, -m); - % apply weights to the gradiometer-array if isfield(data, 'grad') - fprintf('applying the weights to the gradiometer balancing matrix\n'); - montage = []; - labelnew = pca.label; - nlabelnew = length(labelnew); - - % add columns of refchannels not yet present in labelnew - % [id, i1] = setdiff(pca.reflabel, labelnew); - % labelorg = [labelnew; pca.reflabel(sort(i1))]; - labelorg = data.grad.label; - nlabelorg = length(labelorg); - - % start with identity - montage.tra = eye(nlabelorg); - - % subtract weights - [i1, i2] = match_str(labelorg, pca.reflabel); - [i3, i4] = match_str(labelorg, pca.label); - montage.tra(i3,i1) = montage.tra(i3,i1) - pca.w(i4,i2); - montage.labelorg = labelorg; - montage.labelnew = labelorg; - - data.grad = ft_apply_montage(data.grad, montage, 'keepunused', 'yes', 'balancename', 'pca'); - - % order the fields - fnames = fieldnames(data.grad.balance); - tmp = false(1,numel(fnames)); - for k = 1:numel(fnames) - tmp(k) = isstruct(data.grad.balance.(fnames{k})); - end - [tmp, ix] = sort(tmp,'descend'); - data.grad.balance = orderfields(data.grad.balance, fnames(ix)); - + sensfield = 'grad'; + elseif isfield(data, 'elec') + sensfield = 'elec'; + elseif isfield(data, 'opto') + sensfield = 'opto'; else - warning('fieldtrip:ft_denoise_pca:WeightsNotAppliedToSensors', 'weights have been applied to the data only, not to the sensors'); + sensfield = []; end + % apply the linear projection also to the sensor description + if ~isempty(sensfield) + if strcmp(cfg.updatesens, 'yes') + fprintf('also applying the weights to the %s structure\n', sensfield); + + montage = []; + labelnew = pca.label; + + % add columns of refchannels not yet present in labelnew + % [id, i1] = setdiff(pca.reflabel, labelnew); + % labelold = [labelnew; pca.reflabel(sort(i1))]; + labelold = data.grad.label; + nlabelold = length(labelold); + + % start with identity + montage.tra = eye(nlabelold); + + % subtract weights + [i1, i2] = match_str(labelold, pca.reflabel); + [i3, i4] = match_str(labelold, pca.label); + montage.tra(i3,i1) = montage.tra(i3,i1) - pca.w(i4,i2); + montage.labelold = labelold; + montage.labelnew = labelold; + + data.(sensfield) = ft_apply_montage(data.(sensfield), montage, 'keepunused', 'yes', 'balancename', 'pca'); + + % order the fields + fnames = fieldnames(data.(sensfield).balance); + tmp = false(1,numel(fnames)); + for k = 1:numel(fnames) + tmp(k) = isstruct(data.(sensfield).balance.(fnames{k})); + end + [tmp, ix] = sort(tmp, 'descend'); + data.grad.balance = orderfields(data.(sensfield).balance, fnames(ix)); + + else + fprintf('not applying the weights to the %s structure\n', sensfield); + end + end % if sensfield + end % if pertrial % do the general cleanup and bookkeeping at the end of the function @@ -330,32 +345,32 @@ % X (and Y) should be linear cell-array(s) of matrices for which the size in at % least one of the dimensions should be the same for all cells -if nargin==2, +if nargin==2 flag = 1; dim = y; y = []; -elseif nargin==3, +elseif nargin==3 flag = 1; end nx = size(x); -if ~iscell(x) || length(nx)>2 || all(nx>1), - error('incorrect input for cellmean'); +if ~iscell(x) || length(nx)>2 || all(nx>1) + ft_error('incorrect input for cellmean'); end -if nargin==1, +if nargin==1 scx1 = cellfun('size', x, 1); scx2 = cellfun('size', x, 2); if all(scx2==scx2(1)), dim = 2; %let second dimension prevail elseif all(scx1==scx1(1)), dim = 1; - else error('no dimension to compute covariance for'); + else ft_error('no dimension to compute covariance for'); end end -if flag, +if flag mx = cellmean(x, 2); x = cellvecadd(x, -mx); - if ~isempty(y), + if ~isempty(y) my = cellmean(y, 2); y = cellvecadd(y, -my); end @@ -363,7 +378,7 @@ nx = max(nx); nsmp = cellfun('size', x, dim); -if isempty(y), +if isempty(y) csmp = cellfun(@covc, x, repmat({dim},1,nx), 'UniformOutput', 0); else csmp = cellfun(@covc, x, y, repmat({dim},1,nx), 'UniformOutput', 0); @@ -373,14 +388,14 @@ function [c] = covc(x, y, dim) -if nargin==2, +if nargin==2 dim = y; y = x; end -if dim==1, +if dim==1 c = x'*y; -elseif dim==2, +elseif dim==2 c = x*y'; end @@ -394,16 +409,16 @@ % least one of the dimensions should be the same for all cells nx = size(x); -if ~iscell(x) || length(nx)>2 || all(nx>1), - error('incorrect input for cellmean'); +if ~iscell(x) || length(nx)>2 || all(nx>1) + ft_error('incorrect input for cellmean'); end -if nargin==1, +if nargin==1 scx1 = cellfun('size', x, 1); scx2 = cellfun('size', x, 2); if all(scx2==scx2(1)), dim = 2; %let second dimension prevail elseif all(scx1==scx1(1)), dim = 1; - else error('no dimension to compute mean for'); + else ft_error('no dimension to compute mean for'); end end @@ -424,22 +439,22 @@ % can be set to 0). nx = size(x); -if ~iscell(x) || length(nx)>2 || all(nx>1), - error('incorrect input for cellstd'); +if ~iscell(x) || length(nx)>2 || all(nx>1) + ft_error('incorrect input for cellstd'); end -if nargin<2, +if nargin<2 scx1 = cellfun('size', x, 1); scx2 = cellfun('size', x, 2); if all(scx2==scx2(1)), dim = 2; %let second dimension prevail elseif all(scx1==scx1(1)), dim = 1; - else error('no dimension to compute mean for'); + else ft_error('no dimension to compute mean for'); end -elseif nargin==2, +elseif nargin==2 flag = 1; end -if flag, +if flag m = cellmean(x, dim); x = cellvecadd(x, -m); end @@ -461,19 +476,19 @@ % check once and for all to save time persistent bsxfun_exists; -if isempty(bsxfun_exists); - bsxfun_exists=exist('bsxfun','builtin'); - if ~bsxfun_exists; - error('bsxfun not found.'); +if isempty(bsxfun_exists) + bsxfun_exists=exist('bsxfun', 'builtin'); + if ~bsxfun_exists + ft_error('bsxfun not found.'); end end nx = size(x); -if ~iscell(x) || length(nx)>2 || all(nx>1), - error('incorrect input for cellmean'); +if ~iscell(x) || length(nx)>2 || all(nx>1) + ft_error('incorrect input for cellmean'); end -if ~iscell(v), +if ~iscell(v) v = repmat({v}, nx); end @@ -488,19 +503,19 @@ % check once and for all to save time persistent bsxfun_exists; -if isempty(bsxfun_exists); - bsxfun_exists=exist('bsxfun','builtin'); - if ~bsxfun_exists; - error('bsxfun not found.'); +if isempty(bsxfun_exists) + bsxfun_exists=exist('bsxfun', 'builtin'); + if ~bsxfun_exists + ft_error('bsxfun not found.'); end end nx = size(x); -if ~iscell(x) || length(nx)>2 || all(nx>1), - error('incorrect input for cellmean'); +if ~iscell(x) || length(nx)>2 || all(nx>1) + ft_error('incorrect input for cellmean'); end -if ~iscell(v), +if ~iscell(v) v = repmat({v}, nx); end @@ -508,10 +523,10 @@ sx2 = cellfun('size', x, 2); sv1 = cellfun('size', v, 1); sv2 = cellfun('size', v, 2); -if all(sx1==sv1) && all(sv2==1), -elseif all(sx2==sv2) && all(sv1==1), -elseif all(sv1==1) && all(sv2==1), -else error('inconsistent input'); +if all(sx1==sv1) && all(sv2==1) +elseif all(sx2==sv2) && all(sv1==1) +elseif all(sv1==1) && all(sv2==1) +else ft_error('inconsistent input'); end y = cellfun(@bsxfun, repmat({@times}, nx), x, v, 'UniformOutput', 0); @@ -528,22 +543,22 @@ % can be set to 0). SD is a vector containing the standard deviations, used for the normalisation. nx = size(x); -if ~iscell(x) || length(nx)>2 || all(nx>1), - error('incorrect input for cellstd'); +if ~iscell(x) || length(nx)>2 || all(nx>1) + ft_error('incorrect input for cellstd'); end -if nargin<2, +if nargin<2 scx1 = cellfun('size', x, 1); scx2 = cellfun('size', x, 2); - if all(scx2==scx2(1)), dim = 2; %let second dimension prevail + if all(scx2==scx2(1)), dim = 2; % let second dimension prevail elseif all(scx1==scx1(1)), dim = 1; - else error('no dimension to compute mean for'); + else ft_error('no dimension to compute mean for'); end -elseif nargin==2, +elseif nargin==2 flag = 1; end -if flag, +if flag m = cellmean(x, dim); x = cellvecadd(x, -m); end diff --git a/external/fieldtrip/ft_denoise_synthetic.m b/external/fieldtrip/ft_denoise_synthetic.m index 23e67812..b242d1d9 100644 --- a/external/fieldtrip/ft_denoise_synthetic.m +++ b/external/fieldtrip/ft_denoise_synthetic.m @@ -74,23 +74,23 @@ % check whether it is CTF data if ~ft_senstype(data, 'ctf') - error('synthetic gradients can only be computed for CTF data'); + ft_error('synthetic gradients can only be computed for CTF data'); end % check whether there are reference channels in the input data hasref = ~isempty(ft_channelselection('MEGREF', data.label)); if ~hasref - error('ft_denoise_synthetic:nohasref', 'synthetic gradients can only be computed when the input data contains reference channels'); + ft_error('synthetic gradients can only be computed when the input data contains reference channels'); end % select trials of interest -tmpcfg = keepfields(cfg, 'trials'); +tmpcfg = keepfields(cfg, {'trials', 'showcallinfo'}); data = ft_selectdata(tmpcfg, data); % restore the provenance information [cfg, data] = rollback_provenance(cfg, data); % remember the original channel ordering -labelorg = data.label; +labelold = data.label; % apply the balancing to the MEG data and to the gradiometer definition current = data.grad.balance.current; @@ -99,38 +99,37 @@ if ~strcmp(current, 'none') % first undo/invert the previously applied balancing try - current_montage = getfield(data.grad.balance, current); + current_montage = data.grad.balance.(current); catch - error('unknown balancing for input data'); + ft_error('unknown balancing for input data'); end fprintf('converting from "%s" to "none"\n', current); data.grad = ft_apply_montage(data.grad, current_montage, 'keepunused', 'yes', 'inverse', 'yes'); data = ft_apply_montage(data , current_montage, 'keepunused', 'yes', 'inverse', 'yes'); data.grad.balance.current = 'none'; -end % if +end % if current if ~strcmp(desired, 'none') % then apply the desired balancing try - desired_montage = getfield(data.grad.balance, desired); + desired_montage = data.grad.balance.(desired); catch - error('unknown balancing for input data'); + ft_error('unknown balancing for input data'); end fprintf('converting from "none" to "%s"\n', desired); data.grad = ft_apply_montage(data.grad, desired_montage, 'keepunused', 'yes', 'balancename', desired); data = ft_apply_montage(data , desired_montage, 'keepunused', 'yes', 'balancename', desired); - %data.grad.balance.current = desired; -end % if +end % if desired % reorder the channels to stay close to the original ordering -[selorg, selnew] = match_str(labelorg, data.label); -if numel(selnew)==numel(labelorg) +[selold, selnew] = match_str(labelold, data.label); +if numel(selnew)==numel(labelold) for i=1:numel(data.trial) data.trial{i} = data.trial{i}(selnew,:); end data.label = data.label(selnew); else - warning('channel ordering might have changed'); + ft_warning('channel ordering might have changed'); end % convert back to input type if necessary diff --git a/external/fieldtrip/ft_detect_movement.m b/external/fieldtrip/ft_detect_movement.m index b5c79225..9a2712e4 100644 --- a/external/fieldtrip/ft_detect_movement.m +++ b/external/fieldtrip/ft_detect_movement.m @@ -79,8 +79,8 @@ % read from an old *.mat file data = ft_checkdata(data, 'datatype', {'raw'}, 'feedback', 'yes', 'hassampleinfo', 'yes'); -if isfield(data,'fsample'); - fsample = getsubfield(data,'fsample'); +if isfield(data, 'fsample'); + fsample = getsubfield(data, 'fsample'); else fsample = 1./(mean(diff(data.time{1}))); end @@ -100,15 +100,15 @@ if ~isfield(cfg.velocity2D, 'mindur'), cfg.velocity2D.mindur = 3; end % minimum microsaccade duration in samples if ~isfield(cfg.velocity2D, 'velthres'), cfg.velocity2D.velthres = 6; end case 'clustering' - error('not implemented yet'); + ft_error('not implemented yet'); % Otero-Millan J, Castro JLA, Macknik SL, Martinez-Conde S (2014) % Unsupervised clustering method to detect microsaccades. J Vis 14. otherwise - error('unsupported option for cfg.method'); + ft_error('unsupported option for cfg.method'); end % select channels and trials of interest, by default this will select all channels and trials -tmpcfg = keepfields(cfg, {'trials', 'channel'}); +tmpcfg = keepfields(cfg, {'trials', 'channel', 'showcallinfo'}); data = ft_selectdata(tmpcfg, data); [cfg, data] = rollback_provenance(cfg, data); @@ -135,7 +135,7 @@ case 'velocity2D' % demean horizontal and vertical time courses - if strcmp(cfg.velocity2D.demean,'yes'); + if strcmp(cfg.velocity2D.demean, 'yes'); dat = ft_preproc_polyremoval(dat, 0, 1, ndatsample); end diff --git a/external/fieldtrip/ft_dipolefitting.m b/external/fieldtrip/ft_dipolefitting.m index be8a292e..cc434052 100644 --- a/external/fieldtrip/ft_dipolefitting.m +++ b/external/fieldtrip/ft_dipolefitting.m @@ -171,7 +171,7 @@ cfg = ft_checkconfig(cfg, 'createsubcfg', {'grid'}); % the default for this depends on the data type -if ~isfield(cfg, 'model'), +if ~isfield(cfg, 'model') if ~isempty(cfg.component) % each component is fitted independently cfg.model = 'moving'; @@ -195,7 +195,7 @@ % set up the symmetry constraints if ~isempty(cfg.symmetry) if cfg.numdipoles~=2 - error('symmetry constraints are only supported for two-dipole models'); + ft_error('symmetry constraints are only supported for two-dipole models'); elseif strcmp(cfg.symmetry, 'x') % this structure is passed onto the low-level ft_dipole_fit function cfg.dipfit.constr.reduce = [1 2 3]; % select the parameters [x1 y1 z1] @@ -212,7 +212,7 @@ cfg.dipfit.constr.expand = [1 2 3 1 2 3]; % repeat them as [x1 y1 z1 x1 y1 z1] cfg.dipfit.constr.mirror = [1 1 1 1 1 -1]; % multiply each of them with 1 or -1, resulting in [x1 y1 z1 x1 y1 -z1] else - error('unrecognized symmetry constraint'); + ft_error('unrecognized symmetry constraint'); end elseif ~isfield(cfg, 'dipfit') || ~isfield(cfg.dipfit, 'constr') % no symmetry constraints have been specified @@ -220,7 +220,7 @@ end if ft_getopt(cfg.dipfit.constr, 'sequential', false) && strcmp(cfg.model, 'moving') - error('the moving dipole model does not combine with the sequential constraint') + ft_error('the moving dipole model does not combine with the sequential constraint') % see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=3119 end @@ -257,10 +257,10 @@ end end -% select the desired channels, the order should be the same as in the sensor structure -[selcfg, seldata] = match_str(cfg.channel, data.label); -% take the selected channels -Vdata = data.avg(selcfg, :); +% select the desired channels, ordered according to the sensor structure +[selsens, seldata] = match_str(sens.label, data.label); +% take the selected channels from the data structure +Vdata = data.avg(seldata, :); % sphere the date using the noise covariance matrix supplied, if any % this affects both the gridsearch and the nonlinear optimization @@ -307,17 +307,17 @@ fprintf('selected %d topographies\n', ntime); if nchans0.001) - warning('the EEG data is not average referenced, correcting this'); + ft_warning('the EEG data is not average referenced, correcting this'); end Vdata = avgref(Vdata); end @@ -340,7 +340,7 @@ % check the specified dipole model if numel(cfg.dip.pos)~=cfg.numdipoles*3 || numel(cfg.dip.mom)~=cfg.numdipoles*3 - error('inconsistent number of dipoles in configuration') + ft_error('inconsistent number of dipoles in configuration') end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -355,31 +355,31 @@ elseif isfield(cfg.grid, 'pos') && size(cfg.grid.pos,2)==cfg.numdipoles*3 % this is also ok else - error('dipole scanning is only possible for a single dipole or a symmetric dipole pair'); + ft_error('dipole scanning is only possible for a single dipole or a symmetric dipole pair'); end - + % copy all options that are potentially used in ft_prepare_sourcemodel - tmpcfg = keepfields(cfg, {'grid' 'mri' 'headshape' 'symmetry' 'smooth' 'threshold' 'spheremesh' 'inwardshift'}); + tmpcfg = keepfields(cfg, {'grid' 'mri' 'headshape' 'symmetry' 'smooth' 'threshold' 'spheremesh' 'inwardshift', 'showcallinfo'}); tmpcfg.headmodel = headmodel; if ft_senstype(sens, 'eeg') tmpcfg.elec = sens; - else + elseif ft_senstype(sens, 'meg') tmpcfg.grad = sens; end % construct the dipole grid on which the gridsearch will be done grid = ft_prepare_sourcemodel(tmpcfg); - + ngrid = size(grid.pos,1); - + switch cfg.model case 'regional' grid.error = nan(ngrid, 1); case 'moving' grid.error = nan(ngrid, ntime); otherwise - error('unsupported cfg.model'); + ft_error('unsupported cfg.model'); end - + insideindx = find(grid.inside); ft_progress('init', cfg.feedback, 'scanning grid'); for i=1:length(insideindx) @@ -395,9 +395,9 @@ % dipole moment this makes the model potential U=lf*pinv(lf)*V and the % model error is norm(V-U) = norm(V-lf*pinv(lf)*V) = norm((eye-lf*pinv(lf))*V) if any(isnan(lf(:))) - % this might happen if one of the dipole locations of the grid is - % outside the brain compartment - lf(:) = 0; + % this might happen if one of the dipole locations of the grid is + % outside the brain compartment + lf(:) = 0; end switch cfg.model case 'regional' @@ -407,11 +407,11 @@ % remember the error for each latency independently grid.error(thisindx,:) = sum(((eye(nchans)-lf*pinv(lf))*Vdata).^2); otherwise - error('unsupported cfg.model'); + ft_error('unsupported cfg.model'); end % switch model end % looping over the grid ft_progress('close'); - + switch cfg.model case 'regional' % find the grid point(s) with the minimum error @@ -424,7 +424,7 @@ elseif cfg.numdipoles==2 fprintf('found minimum after scanning on grid point [%g %g %g; %g %g %g]\n', dip.pos(1), dip.pos(2), dip.pos(3), dip.pos(4), dip.pos(5), dip.pos(6)); end - + case 'moving' for t=1:ntime % find the grid point(s) with the minimum error @@ -438,11 +438,11 @@ fprintf('found minimum after scanning for topography %d on grid point [%g %g %g; %g %g %g]\n', t, dip(t).pos(1), dip(t).pos(2), dip(t).pos(3), dip(t).pos(4), dip(t).pos(5), dip(t).pos(6)); end end - + otherwise - error('unsupported cfg.model'); + ft_error('unsupported cfg.model'); end % switch model - + elseif strcmp(cfg.gridsearch, 'no') % use the initial guess supplied in the configuration for the remainder switch cfg.model @@ -453,9 +453,9 @@ dip(t) = struct(cfg.dip); % ensure that it is a struct, not a config object end otherwise - error('unsupported cfg.model'); + ft_error('unsupported cfg.model'); end % switch model - + end % if gridsearch yes/no % multiple dipoles can be represented either as a 1x(N*3) vector or as a Nx3 matrix, % i.e. [x1 y1 z1 x2 y2 z2] or [x1 y1 z1; x2 y2 z2] @@ -467,7 +467,7 @@ dip(t) = fixdipole(dip(t)); end otherwise - error('unsupported cfg.model'); + ft_error('unsupported cfg.model'); end % switch model if isfield(cfg, 'dipfit') @@ -504,7 +504,7 @@ success = 0; disp(lasterr); end - + case 'moving' % perform the non-linear dipole fit for each latency independently % instead of using dip(t) = dipole_fit(dip(t),...), I am using temporary variables dipin and dipout @@ -531,7 +531,7 @@ dip = dipout; clear dipin dipout otherwise - error('unsupported cfg.model'); + ft_error('unsupported cfg.model'); end % switch model end % if nonlinear @@ -544,8 +544,8 @@ case 'moving' success = ones(1,ntime); otherwise - error('unsupported cfg.model'); - + ft_error('unsupported cfg.model'); + end % switch model end @@ -581,7 +581,7 @@ end end otherwise - error('unsupported cfg.model'); + ft_error('unsupported cfg.model'); end % switch model switch cfg.model @@ -599,10 +599,10 @@ case 'moving' if isfreq % although this is technically possible so far, it does not make any sense - warning('a moving dipole model in the frequency domain is not supported'); + ft_warning('a moving dipole model in the frequency domain is not supported'); end otherwise - error('unsupported cfg.model'); + ft_error('unsupported cfg.model'); end % switch model %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/external/fieldtrip/ft_dipolesimulation.m b/external/fieldtrip/ft_dipolesimulation.m index 3d26f2b1..872d371c 100644 --- a/external/fieldtrip/ft_dipolesimulation.m +++ b/external/fieldtrip/ft_dipolesimulation.m @@ -92,16 +92,16 @@ cfg = ft_checkconfig(cfg, 'renamed', {'vol', 'headmodel'}); % set the defaults -if ~isfield(cfg, 'dip'), cfg.dip = []; end -if ~isfield(cfg.dip, 'pos'), cfg.dip.pos = [-5 0 15]; end -if ~isfield(cfg.dip, 'mom'), cfg.dip.mom = [1 0 0]'; end -if ~isfield(cfg, 'fsample'), cfg.fsample = 250; end -if ~isfield(cfg, 'relnoise'), cfg.relnoise = 0; end -if ~isfield(cfg, 'absnoise'), cfg.absnoise = 0; end -if ~isfield(cfg, 'feedback'), cfg.feedback = 'text'; end -if ~isfield(cfg, 'channel'), cfg.channel = 'all'; end -if ~isfield(cfg, 'dipoleunit'), cfg.dipoleunit = 'nA*m'; end -if ~isfield(cfg, 'chanunit'), cfg.chanunit = {}; end +cfg.dip = ft_getopt(cfg, 'dip', []); +cfg.dip.pos = ft_getopt(cfg.dip, 'pos', [-5 0 15]); +cfg.dip.mom = ft_getopt(cfg.dip, 'mom', [1 0 0]'); +cfg.fsample = ft_getopt(cfg, 'fsample', 250); +cfg.relnoise = ft_getopt(cfg, 'relnoise', 0); +cfg.absnoise = ft_getopt(cfg, 'absnoise', 0); +cfg.feedback = ft_getopt(cfg, 'feedback', 'text'); +cfg.channel = ft_getopt(cfg, 'channel', 'all'); +cfg.dipoleunit = ft_getopt(cfg, 'dipoleunit', 'nA*m'); +cfg.chanunit = ft_getopt(cfg, 'chanunit', {}); cfg.dip = fixdipole(cfg.dip); Ndipoles = size(cfg.dip.pos,1); @@ -185,13 +185,13 @@ if length(dippos)==1 dippos = repmat(dippos, 1, Ntrials); elseif length(dippos)~=Ntrials - error('incorrect number of trials specified in the dipole position'); + ft_error('incorrect number of trials specified in the dipole position'); end if length(dipmom)==1 dipmom = repmat(dipmom, 1, Ntrials); elseif length(dipmom)~=Ntrials - error('incorrect number of trials specified in the dipole moment'); + ft_error('incorrect number of trials specified in the dipole moment'); end simulated.trial = {}; @@ -207,7 +207,7 @@ nsamples = size(dipsignal{trial},2); nchannels = size(lf,1); simulated.trial{trial} = zeros(nchannels,nsamples); - for i = 1:3, + for i = 1:3 simulated.trial{trial} = simulated.trial{trial} + lf(:,i:3:end) * ... (repmat(dipmom{trial}(i:3:end),1,nsamples) .* dipsignal{trial}); end diff --git a/external/fieldtrip/ft_electrodeplacement.m b/external/fieldtrip/ft_electrodeplacement.m index deb3a357..dd81586a 100644 --- a/external/fieldtrip/ft_electrodeplacement.m +++ b/external/fieldtrip/ft_electrodeplacement.m @@ -1,49 +1,69 @@ function [elec] = ft_electrodeplacement(cfg, varargin) -% FT_ELECTRODEPLACEMENT allows placing electrodes on a volume or headshape. -% The different methods are described in detail below. +% FT_ELECTRODEPLACEMENT allows manual placement of electrodes on a MRI scan, CT scan +% or on a triangulated surface of the head. This function supports different methods. % -% VOLUME - Navigate an orthographic display of a volume (e.g. CT or -% MR scan), and assign an electrode label to the current crosshair location -% by clicking on a label in the eletrode list. You can undo the selection by -% clicking on the same label again. The electrode labels shown in the list -% can be prespecified using cfg.channel when calling ft_electrodeplacement. -% The zoom slider allows zooming in at the location of the crosshair. -% The intensity sliders allow thresholding the image's low and high values. -% The magnet feature transports the crosshair to the nearest peak intensity -% voxel, within a certain voxel radius of the selected location. -% The labels feature displays the labels of the selected electrodes within -% the orthoplot. The global feature allows toggling the view between all -% and near-crosshair markers. +% VOLUME - Navigate an orthographic display of a volume (e.g. CT or MRI scan), and +% assign an electrode label to the current crosshair location by clicking on a label +% in the eletrode list. You can undo the selection by clicking on the same label +% again. The electrode labels shown in the list can be prespecified using cfg.channel +% when calling ft_electrodeplacement. The zoom slider allows zooming in at the +% location of the crosshair. The intensity sliders allow thresholding the image's low +% and high values. The magnet feature transports the crosshair to the nearest peak +% intensity voxel, within a certain voxel radius of the selected location. The labels +% feature displays the labels of the selected electrodes within the orthoplot. The +% global feature allows toggling the view between all and near-crosshair +% markers. The scan feature allows toggling between scans when another scan +% is given as input. % -% HEADSHAPE - Navigate a triangulated head/brain surface, and assign -% an electrode location by clicking on the brain. The electrode -% is placed on the triangulation itself. FIXME: this needs updating +% HEADSHAPE - Navigate a triangulated scalp (for EEG) or brain (for ECoG) surface, +% and assign an electrode location by clicking on the surface. The electrode is +% placed on the triangulation itself. +% +% 1020 - Starting from a triangulated scalp surface and the nasion, inion, left and +% right pre-auricular points, this automatically constructs and follows contours over +% the surface according to the 5% system. Electrodes are placed at certain relative +% distances along these countours. This is an extension of the 10-20 standard +% electrode placement system and includes the 20%, 10% and 5% locations. See +% "Oostenveld R, Praamstra P. The five percent electrode system for high-resolution +% EEG and ERP measurements. Clin Neurophysiol. 2001 Apr;112(4):713-9" for details. % % Use as -% [elec] = ft_electrodeplacement(cfg, mri) -% where the input mri should be an anatomical CT or MRI volume -% Use as +% [elec] = ft_electrodeplacement(cfg, ct) +% [elec] = ft_electrodeplacement(cfg, ct, mri) +% where the input mri should be an anatomical CT or MRI volume, or % [elec] = ft_electrodeplacement(cfg, headshape) -% where the input headshape should be a surface triangulation +% where the input headshape should be a surface triangulation. % % The configuration can contain the following options -% cfg.method = string representing the method for aligning or placing the electrodes -% 'mri' place electrodes in a brain volume -% 'headshape' place electrodes on the head surface +% cfg.method = string representing the method for placing the electrodes +% 'mri' interactively locate electrodes in a MRI or CT scan +% 'headshape' interactively locate electrodes on a head surface +% '1020' automatically place electrodes on a head surface +% +% The following options apply to the mri method % cfg.parameter = string, field in data (default = 'anatomy' if present in data) -% cfg.channel = Nx1 cell-array with selection of channels (default = '1','2', ...) +% cfg.channel = Nx1 cell-array with selection of channels (default = {'1' '2' ...}) % cfg.elec = struct containing previously placed electrodes (this overwrites cfg.channel) % cfg.clim = color range of the data (default = [0 1], i.e. the full range) % cfg.magtype = string representing the 'magnet' type used for placing the electrodes +% 'peakweighted' place electrodes at weighted peak intensity voxel (default) +% 'troughweighted' place electrodes at weighted trough intensity voxel % 'peak' place electrodes at peak intensity voxel (default) % 'trough' place electrodes at trough intensity voxel % 'weighted' place electrodes at center-of-mass -% cfg.magradius = number representing the radius for the cfg.magtype based search (default = 2) +% cfg.magradius = number representing the radius for the cfg.magtype based search (default = 3) +% +% The following options apply to the 1020 method +% cfg.fiducial.nas = 1x3 vector with coordinates +% cfg.fiducial.ini = 1x3 vector with coordinates +% cfg.fiducial.lpa = 1x3 vector with coordinates +% cfg.fiducial.rpa = 1x3 vector with coordinates +% cfg.feedback = string, can be 'yes' or 'no' for detailled feedback (default = 'yes') % -% See also FT_ELECTRODEREALIGN, FT_VOLUMEREALIGN +% See also FT_ELECTRODEREALIGN, FT_VOLUMEREALIGN, FT_VOLUMESEGMENT, FT_PREPARE_MESH -% Copyright (C) 2015, Arjen Stolk & Robert Oostenveld +% Copyright (C) 2015-2017, Arjen Stolk, Sandon Griffin & Robert Oostenveld % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -84,23 +104,24 @@ % ensure that old and unsupported options are not being relied on by the end-user's script % see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2837 cfg = ft_checkconfig(cfg, 'renamed', {'viewdim', 'axisratio'}); +cfg = ft_checkconfig(cfg, 'renamedval', {'method', 'mri', 'volume'}); % set the defaults -cfg.method = ft_getopt(cfg, 'method'); % volume, headshape +cfg.method = ft_getopt(cfg, 'method'); % volume, headshape, 1020 +cfg.feedback = ft_getopt(cfg, 'feedback', 'yes'); cfg.parameter = ft_getopt(cfg, 'parameter', 'anatomy'); cfg.channel = ft_getopt(cfg, 'channel', []); % default will be determined further down {'1', '2', ...} cfg.elec = ft_getopt(cfg, 'elec', []); % use previously placed electrodes cfg.renderer = ft_getopt(cfg, 'renderer', 'opengl'); % view options cfg.clim = ft_getopt(cfg, 'clim', [0 1]); % initial volume intensity limit voxels -cfg.markerdist = ft_getopt(cfg, 'markerdist', 5); % marker-slice distance for including in the view +cfg.markerdist = ft_getopt(cfg, 'markerdist', 5); % marker-slice distance view when ~global % magnet options -cfg.magtype = ft_getopt(cfg, 'magtype', 'peak'); % detect peaks or troughs or center-of-mass -cfg.magradius = ft_getopt(cfg, 'magradius', 2); % specify the physical unit radius +cfg.magtype = ft_getopt(cfg, 'magtype', 'peakweighted'); % detect weighted peaks or troughs +cfg.magradius = ft_getopt(cfg, 'magradius', 3); % specify the physical unit radius cfg.voxelratio = ft_getopt(cfg, 'voxelratio', 'data'); % display size of the voxel, 'data' or 'square' cfg.axisratio = ft_getopt(cfg, 'axisratio', 'data'); % size of the axes of the three orthoplots, 'square', 'voxel', or 'data' - if isempty(cfg.method) && ~isempty(varargin) % the default determines on the input data switch ft_datatype(varargin{1}) @@ -114,14 +135,17 @@ % check if the input data is valid for this function switch cfg.method case 'volume' - mri = ft_checkdata(varargin{1}, 'datatype', 'volume', 'feedback', 'yes'); - case {'headshape'} + for v = 1:numel(varargin) + mri{v} = ft_checkdata(varargin{v}, 'datatype', 'volume', 'feedback', 'yes', 'hascoordsys', 'yes', 'hasunit', 'yes'); + end + case {'headshape', '1020'} headshape = fixpos(varargin{1}); - headshape = ft_determine_coordsys(headshape); + headshape = ft_checkdata(headshape, 'hascoordsys', 'yes'); end switch cfg.method case 'headshape' + % give the user instructions disp('Use the mouse to click on the desired electrode positions'); disp('Afterwards you may have to update the electrode labels'); @@ -138,7 +162,7 @@ ft_plot_mesh(headshape); else skin = [255 213 119]/255; - ft_plot_mesh(headshape,'facecolor', skin,'EdgeColor','none','facealpha',1); + ft_plot_mesh(headshape, 'facecolor', skin, 'EdgeColor', 'none', 'facealpha',1); lighting gouraud material shiny camlight @@ -147,7 +171,7 @@ % rotate3d on xyz = ft_select_point3d(headshape, 'nearest', false, 'multiple', true, 'marker', '*'); numelec = size(xyz, 1); - + % construct the output electrode structure elec = keepfields(headshape, {'unit', 'coordsys'}); elec.elecpos = xyz; @@ -158,7 +182,7 @@ elec.label{i} = sprintf('%d', i); end end - + case 'volume' % start building the figure @@ -173,92 +197,98 @@ set(h, 'windowkeypressfcn', @cb_keyboard); set(h, 'CloseRequestFcn', @cb_cleanup); set(h, 'renderer', cfg.renderer); - - % axes settings - if strcmp(cfg.axisratio, 'voxel') - % determine the number of voxels to be plotted along each axis - axlen1 = mri.dim(1); - axlen2 = mri.dim(2); - axlen3 = mri.dim(3); - elseif strcmp(cfg.axisratio, 'data') - % determine the length of the edges along each axis - [cp_voxel, cp_head] = cornerpoints(mri.dim, mri.transform); - axlen1 = norm(cp_head(2,:)-cp_head(1,:)); - axlen2 = norm(cp_head(4,:)-cp_head(1,:)); - axlen3 = norm(cp_head(5,:)-cp_head(1,:)); - elseif strcmp(cfg.axisratio, 'square') - % the length of the axes should be equal - axlen1 = 1; - axlen2 = 1; - axlen3 = 1; - end - - % this is the size reserved for subplot h1, h2 and h3 - h1size(1) = 0.82*axlen1/(axlen1 + axlen2); - h1size(2) = 0.82*axlen3/(axlen2 + axlen3); - h2size(1) = 0.82*axlen2/(axlen1 + axlen2); - h2size(2) = 0.82*axlen3/(axlen2 + axlen3); - h3size(1) = 0.82*axlen1/(axlen1 + axlen2); - h3size(2) = 0.82*axlen2/(axlen2 + axlen3); - - if strcmp(cfg.voxelratio, 'square') - voxlen1 = 1; - voxlen2 = 1; - voxlen3 = 1; - elseif strcmp(cfg.voxelratio, 'data') - % the size of the voxel is scaled with the data - [cp_voxel, cp_head] = cornerpoints(mri.dim, mri.transform); - voxlen1 = norm(cp_head(2,:)-cp_head(1,:))/norm(cp_voxel(2,:)-cp_voxel(1,:)); - voxlen2 = norm(cp_head(4,:)-cp_head(1,:))/norm(cp_voxel(4,:)-cp_voxel(1,:)); - voxlen3 = norm(cp_head(5,:)-cp_head(1,:))/norm(cp_voxel(5,:)-cp_voxel(1,:)); + + % volume-dependent axis settings + for v = 1:numel(mri) + if strcmp(cfg.axisratio, 'voxel') + % determine the number of voxels to be plotted along each axis + axlen1 = mri{v}.dim(1); + axlen2 = mri{v}.dim(2); + axlen3 = mri{v}.dim(3); + elseif strcmp(cfg.axisratio, 'data') + % determine the length of the edges along each axis + [cp_voxel, cp_head] = cornerpoints(mri{v}.dim, mri{v}.transform); + axlen1 = norm(cp_head(2,:)-cp_head(1,:)); + axlen2 = norm(cp_head(4,:)-cp_head(1,:)); + axlen3 = norm(cp_head(5,:)-cp_head(1,:)); + elseif strcmp(cfg.axisratio, 'square') + % the length of the axes should be equal + axlen1 = 1; + axlen2 = 1; + axlen3 = 1; + end + + % this is the size reserved for subplot h1, h2 and h3 + h1size(1) = 0.92*axlen1/(axlen1 + axlen2); % x + h1size(2) = 0.92*axlen3/(axlen2 + axlen3); % z + h2size(1) = 0.92*axlen2/(axlen1 + axlen2); % y + h2size(2) = 0.92*axlen3/(axlen2 + axlen3); % z + h3size(1) = 0.92*axlen1/(axlen1 + axlen2); % x + h3size(2) = 0.92*axlen2/(axlen2 + axlen3); % y + + % axis handles will hold the anatomical functional if present, along with labels etc. + h1 = axes('position', [0.02 0.02+0.04+h3size(2) h1size(1) h1size(2)]); % x z + h2 = axes('position', [0.02+0.04+h1size(1) 0.02+0.04+h3size(2) h2size(1) h2size(2)]); % y z + h3 = axes('position', [0.02 0.02 h3size(1) h3size(2)]); % x y + + set(h1, 'Tag', 'ik', 'Visible', 'off', 'XAxisLocation', 'top'); axis(h1, 'equal'); + set(h2, 'Tag', 'jk', 'Visible', 'off', 'YAxisLocation', 'right'); axis(h2, 'equal'); % after rotating in ft_plot_ortho this becomes top + set(h3, 'Tag', 'ij', 'Visible', 'off'); axis(h3, 'equal'); + + if strcmp(cfg.voxelratio, 'square') + voxlen1 = 1; + voxlen2 = 1; + voxlen3 = 1; + elseif strcmp(cfg.voxelratio, 'data') + % the size of the voxel is scaled with the data + [cp_voxel, cp_head] = cornerpoints(mri{v}.dim, mri{v}.transform); + voxlen1 = norm(cp_head(2,:)-cp_head(1,:))/norm(cp_voxel(2,:)-cp_voxel(1,:)); + voxlen2 = norm(cp_head(4,:)-cp_head(1,:))/norm(cp_voxel(4,:)-cp_voxel(1,:)); + voxlen3 = norm(cp_head(5,:)-cp_head(1,:))/norm(cp_voxel(5,:)-cp_voxel(1,:)); + end + + %set(h1, 'DataAspectRatio', 1./[voxlen1 voxlen2 voxlen3]); % FIXME: this no longer works when using mri.transform with ft_plot_ortho (instead of eye(4)); + %set(h2, 'DataAspectRatio', 1./[voxlen1 voxlen2 voxlen3]); + %set(h3, 'DataAspectRatio', 1./[voxlen1 voxlen2 voxlen3]); + + mri{v}.axes = [h1 h2 h3]; + mri{v}.h1size = h1size; + mri{v}.h2size = h2size; + mri{v}.h3size = h3size; + mri{v}.clim = cfg.clim; + mri{v}.slim = [.9 1]; % 90% - maximum + + dat = double(mri{v}.(cfg.parameter)); + dmin = min(dat(:)); + dmax = max(dat(:)); + mri{v}.dat = (dat-dmin)./(dmax-dmin); % range between 0 and 1 + clear dat dmin dmax end - - % axis handles will hold the anatomical functional if present, along with labels etc. - h1 = axes('position',[0.06 0.06+0.06+h3size(2) h1size(1) h1size(2)]); - h2 = axes('position',[0.06+0.06+h1size(1) 0.06+0.06+h3size(2) h2size(1) h2size(2)]); - h3 = axes('position',[0.06 0.06 h3size(1) h3size(2)]); - - set(h1, 'Tag', 'ik', 'Visible', 'off', 'XAxisLocation', 'top'); - set(h2, 'Tag', 'jk', 'Visible', 'off', 'YAxisLocation', 'right'); % after rotating in ft_plot_ortho this becomes top - set(h3, 'Tag', 'ij', 'Visible', 'off'); - - set(h1, 'DataAspectRatio', 1./[voxlen1 voxlen2 voxlen3]); - set(h2, 'DataAspectRatio', 1./[voxlen1 voxlen2 voxlen3]); - set(h3, 'DataAspectRatio', 1./[voxlen1 voxlen2 voxlen3]); - - xc = round(mri.dim(1)/2); % start with center view - yc = round(mri.dim(2)/2); - zc = round(mri.dim(3)/2); - - dat = double(mri.(cfg.parameter)); - dmin = min(dat(:)); - dmax = max(dat(:)); - dat = (dat-dmin)./(dmax-dmin); % range between 0 and 1 - + % intensity range sliders h45text = uicontrol('Style', 'text',... - 'String','Intensity',... + 'String', 'Intensity',... 'Units', 'normalized', ... - 'Position',[2*h1size(1)+0.03 h3size(2)+0.03 h1size(1)/4 0.04],... + 'Position', [2*mri{1}.h1size(1)-0.02 mri{1}.h3size(2)-0.02 mri{1}.h1size(1)/4 0.04],... 'BackgroundColor', [1 1 1], ... - 'HandleVisibility','on'); - + 'HandleVisibility', 'on'); + h4 = uicontrol('Style', 'slider', ... 'Parent', h, ... 'Min', 0, 'Max', 1, ... 'Value', cfg.clim(1), ... 'Units', 'normalized', ... - 'Position', [2*h1size(1)+0.02 0.15+h3size(2)/3 0.05 h3size(2)/2-0.05], ... + 'Position', [2*mri{1}.h1size(1)-0.03 0.10+mri{1}.h3size(2)/3 0.05 mri{1}.h3size(2)/2-0.05], ... 'Callback', @cb_minslider); - + h5 = uicontrol('Style', 'slider', ... 'Parent', h, ... 'Min', 0, 'Max', 1, ... 'Value', cfg.clim(2), ... 'Units', 'normalized', ... - 'Position', [2*h1size(1)+0.07 0.15+h3size(2)/3 0.05 h3size(2)/2-0.05], ... + 'Position', [2*mri{1}.h1size(1)+0.02 0.10+mri{1}.h3size(2)/3 0.05 mri{1}.h3size(2)/2-0.05], ... 'Callback', @cb_maxslider); - + % java intensity range slider (dual-knob slider): the java component gives issues when wanting to % access the opt structure % [jRangeSlider] = com.jidesoft.swing.RangeSlider(0,1,cfg.clim(1),cfg.clim(2)); % min,max,low,high @@ -266,174 +296,227 @@ % set(h4, 'Units', 'normalized', 'Position', [0.05+h1size(1) 0.07 0.07 h3size(2)], 'Parent', h); % set(jRangeSlider, 'Orientation', 1, 'PaintTicks', true, 'PaintLabels', true, ... % 'Background', java.awt.Color.white, 'StateChangedCallback', @cb_intensityslider); - + % electrode listbox + chanlabel = {}; chanstring = {}; + markerlab = {}; markerpos = {}; if ~isempty(cfg.elec) % re-use previously placed (cfg.elec) electrodes - cfg.channel = []; % ensure cfg.channel is empty, for filling it up for e = 1:numel(cfg.elec.label) - cfg.channel{e,1} = cfg.elec.label{e}; - chanstring{e} = ['' cfg.channel{e,1} '']; % hmtl'ize - - markerlab{e,1} = cfg.elec.label{e}; - markerpos{e,1} = cfg.elec.elecpos(e,:); + chanlabel{end+1,1} = cfg.elec.label{e}; + chanstring{end+1} = ['' cfg.elec.label{e} '']; % hmtl'ize + + markerlab{end+1,1} = cfg.elec.label{e}; + markerpos{end+1,1} = cfg.elec.elecpos(e,:); end - else % otherwise use standard / prespecified (cfg.channel) electrode labels - if isempty(cfg.channel) - for c = 1:150 - cfg.channel{c,1} = sprintf('%d', c); + end + if ~isempty(cfg.channel) % use prespecified (cfg.channel) electrode labels + for c = 1:numel(cfg.channel) + if ~ismember(cfg.channel{c}, chanlabel) % avoid overlap between cfg.channel and elec.label + chanlabel{end+1,1} = cfg.channel{c}; + chanstring{end+1} = ['' cfg.channel{c} '']; % hmtl'ize + + markerlab{end+1,1} = {}; + markerpos{end+1,1} = zeros(0,3); end end - for c = 1:numel(cfg.channel) - chanstring{c} = ['' cfg.channel{c,1} '']; % hmtl'ize - - markerlab{c,1} = {}; - markerpos{c,1} = zeros(0,3); + end + if isempty(cfg.elec) && isempty(cfg.channel) % create electrode labels on-the-fly + for c = 1:150 + chanlabel{end+1,1} = sprintf('%d', c); + chanstring{end+1} = ['' sprintf('%d', c) '']; % hmtl'ize + + markerlab{end+1,1} = {}; + markerpos{end+1,1} = zeros(0,3); end end - + h6 = uicontrol('Style', 'listbox', ... 'Parent', h, ... 'Value', [], 'Min', 0, 'Max', numel(chanstring), ... 'Units', 'normalized', ... - 'Position', [0.07+h1size(1)+0.05 0.07 h1size(1)/2 h3size(2)], ... + 'FontSize', 12, ... + 'Position', [mri{1}.h1size(1)+0.07 0.02 mri{1}.h2size(1)/2.5 mri{1}.h3size(2)], ... 'Callback', @cb_eleclistbox, ... 'String', chanstring); - + % switches / radio buttons - h7 = uicontrol('Style', 'radiobutton',... + h7text = uicontrol('Style', 'text',... + 'String', 'Magnet',... + 'Units', 'normalized', ... + 'Position', [2*mri{1}.h1size(1)-0.047 0.18 mri{1}.h1size(1)/3 0.04],... + 'BackgroundColor', [1 1 1], ... + 'HandleVisibility', 'on'); + + h7 = uicontrol('Style', 'popupmenu',... 'Parent', h, ... - 'Value', 1, ... - 'String','Magnet',... + 'Value', 4, ... % corresponding to magradius = 3 (see String) + 'String', {'0', '1', '2', '3', '4', '5'}, ... 'Units', 'normalized', ... - 'Position',[2*h1size(1) 0.22 h1size(1)/3 0.05],... + 'Position', [2*mri{1}.h1size(1)-0.103 0.18 mri{1}.h1size(1)/4.25 0.04],... 'BackgroundColor', [1 1 1], ... - 'HandleVisibility','on', ... + 'HandleVisibility', 'on', ... 'Callback', @cb_magnetbutton); - - h8 = uicontrol('Style', 'radiobutton',... + radii = get(h7, 'String'); + if ~ismember(num2str(cfg.magradius), radii) % add user-specified radius to the list + set(h7, 'String', [radii(:); num2str(cfg.magradius)]); + set(h7, 'Value', numel(radii)+1); + end + + h8 = uicontrol('Style', 'checkbox',... 'Parent', h, ... 'Value', 0, ... - 'String','Labels',... + 'String', 'Labels',... 'Units', 'normalized', ... - 'Position',[2*h1size(1) 0.17 h1size(1)/3 0.05],... + 'Position', [2*mri{1}.h1size(1)-0.05 0.14 mri{1}.h1size(1)/3 0.04],... 'BackgroundColor', [1 1 1], ... - 'HandleVisibility','on', ... + 'HandleVisibility', 'on', ... 'Callback', @cb_labelsbutton); - - h9 = uicontrol('Style', 'radiobutton',... + + h9 = uicontrol('Style', 'checkbox',... 'Parent', h, ... 'Value', 0, ... - 'String','Global',... + 'String', 'Global',... 'Units', 'normalized', ... - 'Position',[2*h1size(1) 0.12 h1size(1)/3 0.05],... + 'Position', [2*mri{1}.h1size(1)-0.05 0.10 mri{1}.h1size(1)/3 0.04],... 'BackgroundColor', [1 1 1], ... - 'HandleVisibility','on', ... + 'HandleVisibility', 'on', ... 'Callback', @cb_globalbutton); - - hscatter = uicontrol('Style', 'radiobutton',... + + hscatter = uicontrol('Style', 'checkbox',... 'Parent', h, ... 'Value', 0, ... - 'String','Scatter',... + 'String', 'Scatter',... 'Units', 'normalized', ... - 'Position',[2*h1size(1) 0.07 h1size(1)/3 0.05],... + 'Position', [2*mri{1}.h1size(1)-0.05 0.06 mri{1}.h1size(1)/3 0.04],... 'BackgroundColor', [1 1 1], ... - 'HandleVisibility','on', ... + 'HandleVisibility', 'on', ... 'Callback', @cb_scatterbutton); + hscan = uicontrol('Style', 'checkbox',... + 'Parent', h, ... + 'Value', 0, ... + 'String', 'CT/MRI',... + 'Units', 'normalized', ... + 'Position', [2*mri{1}.h1size(1)-0.05 0.02 mri{1}.h1size(1)/3 0.04],... + 'BackgroundColor', [1 1 1], ... + 'HandleVisibility', 'on', ... + 'Visible', 'off', ... + 'Callback', @cb_scanbutton); + if numel(mri)>1; set(hscan, 'Visible', 'on'); end % only when two scans are given as input + % zoom slider h10text = uicontrol('Style', 'text',... - 'String','Zoom',... + 'String', 'Zoom',... 'Units', 'normalized', ... - 'Position',[1.8*h1size(1)+0.01 h3size(2)+0.03 h1size(1)/4 0.04],... + 'Position', [1.8*mri{1}.h1size(1)-0.04 mri{1}.h3size(2)-0.02 mri{1}.h1size(1)/4 0.04],... 'BackgroundColor', [1 1 1], ... - 'HandleVisibility','on'); - + 'HandleVisibility', 'on'); + h10 = uicontrol('Style', 'slider', ... 'Parent', h, ... 'Min', 0, 'Max', 0.9, ... 'Value', 0, ... 'Units', 'normalized', ... - 'Position', [1.8*h1size(1)+0.02 0.15+h3size(2)/3 0.05 h3size(2)/2-0.05], ... + 'Position', [1.8*mri{1}.h1size(1)-0.03 0.10+mri{1}.h3size(2)/3 0.05 mri{1}.h3size(2)/2-0.05], ... 'SliderStep', [.1 .1], ... 'Callback', @cb_zoomslider); - + % instructions to the user fprintf(strcat(... - '1. Viewing options:\n',... + '1. Orthoplot viewing options:\n',... ' a. use the left mouse button to navigate the image, or\n',... ' b. use the arrow keys to increase or decrease the slice number by one\n',... - '2. Placement options:\n',... - ' a. click an electrode label in the list to assign the crosshair location, or\n',... + '2. Orthoplot placement options:\n',... + ' a. click an electrode label in the list to assign it to the crosshair location, or\n',... ' b. doubleclick a previously assigned electrode label to remove its marker\n',... - '3. To finalize, close the window or press q on the keyboard\n')); - + '3. To finalize, close the window or press q on the keyboard\n', ... + '4. See Stolk, Griffin et al. (2017) for further electrode processing options\n')); + % create structure to be passed to gui opt = []; - opt.dim = mri.dim; - opt.ijk = [xc yc zc]; - opt.h1size = h1size; - opt.h2size = h2size; - opt.h3size = h3size; - opt.handlesaxes = [h1 h2 h3 h4 h5 h6 h7 h8 h9 h10 hscatter]; - opt.handlesfigure = h; - opt.handlesmarker = []; + opt.label = chanlabel; + opt.axes = [mri{1}.axes(1) mri{1}.axes(2) mri{1}.axes(3) h4 h5 h6 h7 h8 h9 h10 hscatter hscan]; + opt.mainfig = h; opt.quit = false; - opt.ana = dat; opt.update = [1 1 1]; opt.init = true; opt.tag = 'ik'; + opt.ana = mri{1}.dat; % the plotted anatomy opt.mri = mri; opt.showcrosshair = true; - opt.vox = [opt.ijk]; % voxel coordinates (physical units) - opt.pos = ft_warp_apply(mri.transform, opt.ijk); % head coordinates (e.g. mm) - opt.showlabels = 0; - opt.label = cfg.channel; + opt.pos = [0 0 0]; % middle of the scan, head coordinates + opt.showlabels = false; opt.magnet = get(h7, 'Value'); opt.magradius = cfg.magradius; opt.magtype = cfg.magtype; opt.showmarkers = true; opt.global = get(h9, 'Value'); % show all markers in the current slices opt.scatter = get(hscatter, 'Value'); % additional scatterplot - opt.slim = [.8 1]; % 80% - maximum + opt.scan = get(hscan, 'Value'); % switch scans + opt.slim = [.9 1]; % 90% - maximum opt.markerlab = markerlab; opt.markerpos = markerpos; opt.markerdist = cfg.markerdist; % hidden option opt.clim = cfg.clim; opt.zoom = 0; - if isfield(mri, 'unit') && ~strcmp(mri.unit, 'unknown') - opt.unit = mri.unit; % this is shown in the feedback on screen - else - opt.unit = ''; % this is not shown - end - + setappdata(h, 'opt', opt); cb_redraw(h); - + while(opt.quit==0) uiwait(h); opt = getappdata(h, 'opt'); end delete(h); - + % collect the results - elec.label = {}; - elec.elecpos = []; - elec.chanpos = []; - elec.tra = []; + elec = keepfields(mri{1}, {'unit', 'coordsys'}); + elec.label = {}; + elec.elecpos = []; for i=1:length(opt.markerlab) if ~isempty(opt.markerlab{i,1}) elec.label = [elec.label; opt.markerlab{i,1}]; elec.elecpos = [elec.elecpos; opt.markerpos{i,1}]; end end - elec.chanpos = elec.elecpos; % identicial to elecpos + elec.chanpos = elec.elecpos; elec.tra = eye(size(elec.elecpos,1)); - if isfield(mri, 'unit') - elec.unit = mri.unit; + + case '1020' + + % the placement procedure fails if the fiducials coincide with vertices + dist = @(x, y) sqrt(sum(bsxfun(@minus, x, y).^2,2)); + tolerance = 0.1 * ft_scalingfactor('mm', headshape.unit); % 0.1 mm + nas = cfg.fiducial.nas; + ini = cfg.fiducial.ini; + lpa = cfg.fiducial.lpa; + rpa = cfg.fiducial.rpa; + if any(dist(headshape.pos, nas) mri.dim) || any([xi yi zi] <= 0) - return; -end - -opt.ijk = [xi yi zi 1]'; -opt.ijk = opt.ijk(1:3)'; - -% construct a string with user feedback -str1 = sprintf('voxel %d, index [%d %d %d]', sub2ind(mri.dim(1:3), xi, yi, zi), opt.ijk); +h1 = opt.axes(1); +h2 = opt.axes(2); +h3 = opt.axes(3); if opt.init - ft_plot_ortho(opt.ana, 'transform', eye(4), 'location', opt.ijk, 'style', 'subplot', 'parents', [h1 h2 h3], 'update', opt.update, 'doscale', false,'clim', opt.clim); - - opt.anahandles = findobj(opt.handlesfigure, 'type', 'surface')'; - parenttag = get(opt.anahandles,'parent'); + delete(findobj(opt.mainfig, 'Type', 'Surface')); % get rid of old orthos (to facilitate switching scans) + ft_plot_ortho(opt.ana, 'transform', opt.mri{1}.transform, 'location', opt.pos, 'style', 'subplot', 'parents', [h1 h2 h3], 'update', opt.update, 'doscale', false, 'clim', opt.clim, 'unit', opt.mri{1}.unit); + + opt.anahandles = findobj(opt.mainfig, 'Type', 'Surface')'; + parenttag = get(opt.anahandles, 'parent'); parenttag{1} = get(parenttag{1}, 'tag'); parenttag{2} = get(parenttag{2}, 'tag'); parenttag{3} = get(parenttag{3}, 'tag'); @@ -489,169 +557,164 @@ function cb_redraw(h, eventdata) opt.anahandles = opt.anahandles(i3(i2)); % seems like swapping the order opt.anahandles = opt.anahandles(:)'; set(opt.anahandles, 'tag', 'ana'); - + % for zooming purposes opt.axis = zeros(1,6); - opt.axis([1 3 5]) = 0.5; - opt.axis([2 4 6]) = size(opt.ana) + 0.5; + opt.axis = [opt.axes(1).XLim opt.axes(1).YLim opt.axes(1).ZLim]; else - ft_plot_ortho(opt.ana, 'transform', eye(4), 'location', opt.ijk, 'style', 'subplot', 'surfhandle', opt.anahandles, 'update', opt.update, 'doscale', false,'clim', opt.clim); - - if all(round([xi yi zi])<=mri.dim) && all(round([xi yi zi])>0) - fprintf('==================================================================================\n'); - str = sprintf('voxel %d, index [%d %d %d]', sub2ind(mri.dim(1:3), round(xi), round(yi), round(zi)), round([xi yi zi])); - - lab = 'crosshair'; - opt.vox = [xi yi zi]; - ind = sub2ind(mri.dim(1:3), round(opt.vox(1)), round(opt.vox(2)), round(opt.vox(3))); - opt.pos = ft_warp_apply(mri.transform, opt.vox); - switch opt.unit - case 'mm' - fprintf('%10s: voxel %9d, index = [%3d %3d %3d], head = [%.1f %.1f %.1f] %s\n', lab, ind, opt.vox, opt.pos, opt.unit); - case 'cm' - fprintf('%10s: voxel %9d, index = [%3d %3d %3d], head = [%.2f %.2f %.2f] %s\n', lab, ind, opt.vox, opt.pos, opt.unit); - case 'm' - fprintf('%10s: voxel %9d, index = [%3d %3d %3d], head = [%.4f %.4f %.4f] %s\n', lab, ind, opt.vox, opt.pos, opt.unit); - otherwise - fprintf('%10s: voxel %9d, index = [%3d %3d %3d], head = [%f %f %f] %s\n', lab, ind, opt.vox, opt.pos, opt.unit); - end + ft_plot_ortho(opt.ana, 'transform', opt.mri{1}.transform, 'location', opt.pos, 'style', 'subplot', 'surfhandle', opt.anahandles, 'update', opt.update, 'doscale', false, 'clim', opt.clim, 'unit', opt.mri{1}.unit); + + fprintf('==================================================================================\n'); + lab = 'crosshair'; + switch opt.mri{1}.unit + case 'mm' + fprintf('%10s at [%.1f %.1f %.1f] %s\n', lab, opt.pos, opt.mri{1}.unit); + case 'cm' + fprintf('%10s at [%.2f %.2f %.2f] %s\n', lab, opt.pos, opt.mri{1}.unit); + case 'm' + fprintf('%10s at [%.4f %.4f %.4f] %s\n', lab, opt.pos, opt.mri{1}.unit); + otherwise + fprintf('%10s at [%f %f %f] %s\n', lab, opt.pos, opt.mri{1}.unit); end - end % make the last current axes current again -sel = findobj('type','axes','tag',tag); +sel = findobj('type', 'axes', 'tag',tag); if ~isempty(sel) - set(opt.handlesfigure, 'currentaxes', sel(1)); + set(opt.mainfig, 'currentaxes', sel(1)); end % zoom -xloadj = round((xi-opt.axis(1))-(xi-opt.axis(1))*opt.zoom); -xhiadj = round((opt.axis(2)-xi)-(opt.axis(2)-xi)*opt.zoom); -yloadj = round((yi-opt.axis(3))-(yi-opt.axis(3))*opt.zoom); -yhiadj = round((opt.axis(4)-yi)-(opt.axis(4)-yi)*opt.zoom); -zloadj = round((zi-opt.axis(5))-(zi-opt.axis(5))*opt.zoom); -zhiadj = round((opt.axis(6)-zi)-(opt.axis(6)-zi)*opt.zoom); +xi = opt.pos(1); +yi = opt.pos(2); +zi = opt.pos(3); +xloadj = ((xi-opt.axis(1))-(xi-opt.axis(1))*opt.zoom); +xhiadj = ((opt.axis(2)-xi)-(opt.axis(2)-xi)*opt.zoom); +yloadj = ((yi-opt.axis(3))-(yi-opt.axis(3))*opt.zoom); +yhiadj = ((opt.axis(4)-yi)-(opt.axis(4)-yi)*opt.zoom); +zloadj = ((zi-opt.axis(5))-(zi-opt.axis(5))*opt.zoom); +zhiadj = ((opt.axis(6)-zi)-(opt.axis(6)-zi)*opt.zoom); axis(h1, [xi-xloadj xi+xhiadj yi-yloadj yi+yhiadj zi-zloadj zi+zhiadj]); axis(h2, [xi-xloadj xi+xhiadj yi-yloadj yi+yhiadj zi-zloadj zi+zhiadj]); axis(h3, [xi-xloadj xi+xhiadj yi-yloadj yi+yhiadj]); if opt.init % draw the crosshairs for the first time - hch1 = crosshair([xi yi-yloadj zi], 'parent', h1, 'color', 'yellow'); % was [xi 1 zi], now corrected for zoom - hch2 = crosshair([xi+xhiadj yi zi], 'parent', h2, 'color', 'yellow'); % was [opt.dim(1) yi zi], now corrected for zoom - hch3 = crosshair([xi yi zi], 'parent', h3, 'color', 'yellow'); % was [xi yi opt.dim(3)], now corrected for zoom + delete(findobj(opt.mainfig, 'Type', 'Line')); % get rid of old crosshairs (to facilitate switching scans) + hch1 = ft_plot_crosshair([xi yi-yloadj zi], 'parent', h1, 'color', 'yellow'); % was [xi 1 zi], now corrected for zoom + hch2 = ft_plot_crosshair([xi+xhiadj yi zi], 'parent', h2, 'color', 'yellow'); % was [opt.dim(1) yi zi], now corrected for zoom + hch3 = ft_plot_crosshair([xi yi zi], 'parent', h3, 'color', 'yellow'); % was [xi yi opt.dim(3)], now corrected for zoom opt.handlescross = [hch1(:)';hch2(:)';hch3(:)']; - opt.handlesmarker = []; + opt.redrawmarker = 1; else % update the existing crosshairs, don't change the handles - crosshair([xi yi-yloadj zi], 'handle', opt.handlescross(1, :)); - crosshair([xi+xhiadj yi zi], 'handle', opt.handlescross(2, :)); - crosshair([xi yi zi], 'handle', opt.handlescross(3, :)); + ft_plot_crosshair([xi yi-yloadj zi], 'handle', opt.handlescross(1, :)); + ft_plot_crosshair([xi+xhiadj yi zi], 'handle', opt.handlescross(2, :)); + ft_plot_crosshair([xi yi zi], 'handle', opt.handlescross(3, :)); end if opt.showcrosshair - set(opt.handlescross,'Visible','on'); + set(opt.handlescross, 'Visible', 'on'); else - set(opt.handlescross,'Visible','off'); + set(opt.handlescross, 'Visible', 'off'); end -delete(opt.handlesmarker(opt.handlesmarker(:)>0)); -opt.handlesmarker = []; - % draw markers -idx = find(~cellfun(@isempty,opt.markerlab)); % non-empty markers -if ~isempty(idx) - for i=1:numel(idx) - markerlab{i,1} = opt.markerlab{idx(i),1}; - markerpos(i,:) = opt.markerpos{idx(i),1}; - end - - opt.vox2 = round(ft_warp_apply(inv(mri.transform), markerpos)); % head to vox - tmp1 = opt.vox2(:,1); - tmp2 = opt.vox2(:,2); - tmp3 = opt.vox2(:,3); - - subplot(h1); - if ~opt.global % filter markers distant to the current slice (N units and further) - posj_idx = find( abs(tmp2 - repmat(yi,size(tmp2))) < opt.markerdist); - posi = tmp1(posj_idx); - posj = tmp2(posj_idx); - posk = tmp3(posj_idx); - else % plot all markers on the current slice - posj_idx = 1:numel(tmp1); - posi = tmp1; - posj = tmp2; - posk = tmp3; - end - if ~isempty(posi) - hold on - opt.handlesmarker(:,1) = plot3(posi, repmat(yi-yloadj,size(posj)), posk, 'marker', '+', 'linestyle', 'none', 'color', 'r'); % [xi yi-yloadj zi] - if opt.showlabels - for i=1:numel(posj_idx) - opt.handlesmarker(i,4) = text(posi(i), yi-yloadj, posk(i), markerlab{posj_idx(i),1}, 'color', 'b'); +delete(findobj(h, 'Type', 'Line', 'Marker', '+')); % remove previous markers +delete(findobj(h, 'Type', 'text')); % remove previous labels +if opt.showmarkers + idx = find(~cellfun(@isempty,opt.markerlab)); % non-empty markers + if ~isempty(idx) + for i=1:numel(idx) + opt.markerlab_sel{i,1} = opt.markerlab{idx(i),1}; + opt.markerpos_sel(i,:) = opt.markerpos{idx(i),1}; + end + + tmp1 = opt.markerpos_sel(:,1); + tmp2 = opt.markerpos_sel(:,2); + tmp3 = opt.markerpos_sel(:,3); + + subplot(h1); + if ~opt.global % filter markers distant to the current slice (N units and further) + posj_idx = find( abs(tmp2 - repmat(yi,size(tmp2))) < opt.markerdist); + posi = tmp1(posj_idx); + posj = tmp2(posj_idx); + posk = tmp3(posj_idx); + else % plot all markers on the current slice + posj_idx = 1:numel(tmp1); + posi = tmp1; + posj = tmp2; + posk = tmp3; + end + if ~isempty(posi) + hold on + plot3(posi, repmat(yi-yloadj,size(posj)), posk, 'marker', '+', 'linestyle', 'none', 'color', 'r'); % [xi yi-yloadj zi] + if opt.showlabels + for i=1:numel(posj_idx) + text(posi(i), yi-yloadj, posk(i), opt.markerlab_sel{posj_idx(i),1}, 'color', [1 .5 0]); + end end + hold off end - hold off - end - - subplot(h2); - if ~opt.global % filter markers distant to the current slice (N units and further) - posi_idx = find( abs(tmp1 - repmat(xi,size(tmp1))) < opt.markerdist); - posi = tmp1(posi_idx); - posj = tmp2(posi_idx); - posk = tmp3(posi_idx); - else % plot all markers on the current slice - posi_idx = 1:numel(tmp1); - posi = tmp1; - posj = tmp2; - posk = tmp3; - end - if ~isempty(posj) - hold on - opt.handlesmarker(:,2) = plot3(repmat(xi+xhiadj,size(posi)), posj, posk, 'marker', '+', 'linestyle', 'none', 'color', 'r'); % [xi+xhiadj yi zi] - if opt.showlabels - for i=1:numel(posi_idx) - opt.handlesmarker(i,5) = text(posi(i)+xhiadj, posj(i), posk(i), markerlab{posi_idx(i),1}, 'color', 'b'); + + subplot(h2); + if ~opt.global % filter markers distant to the current slice (N units and further) + posi_idx = find( abs(tmp1 - repmat(xi,size(tmp1))) < opt.markerdist); + posi = tmp1(posi_idx); + posj = tmp2(posi_idx); + posk = tmp3(posi_idx); + else % plot all markers on the current slice + posi_idx = 1:numel(tmp1); + posi = tmp1; + posj = tmp2; + posk = tmp3; + end + if ~isempty(posj) + hold on + plot3(repmat(xi+xhiadj,size(posi)), posj, posk, 'marker', '+', 'linestyle', 'none', 'color', 'r'); % [xi+xhiadj yi zi] + if opt.showlabels + for i=1:numel(posi_idx) + text(posi(i)+xhiadj, posj(i), posk(i), opt.markerlab_sel{posi_idx(i),1}, 'color', [1 .5 0]); + end end + hold off end - hold off - end - - subplot(h3); - if ~opt.global % filter markers distant to the current slice (N units and further) - posk_idx = find( abs(tmp3 - repmat(zi,size(tmp3))) < opt.markerdist); - posi = tmp1(posk_idx); - posj = tmp2(posk_idx); - posk = tmp3(posk_idx); - else % plot all markers on the current slice - posk_idx = 1:numel(tmp1); - posi = tmp1; - posj = tmp2; - posk = tmp3; - end - if ~isempty(posk) - hold on - opt.handlesmarker(:,3) = plot3(posi, posj, repmat(zi,size(posk)), 'marker', '+', 'linestyle', 'none', 'color', 'r'); % [xi yi zi] - if opt.showlabels - for i=1:numel(posk_idx) - opt.handlesmarker(i,6) = text(posi(i), posj(i), zi, markerlab{posk_idx(i),1}, 'color', 'b'); + + subplot(h3); + if ~opt.global % filter markers distant to the current slice (N units and further) + posk_idx = find( abs(tmp3 - repmat(zi,size(tmp3))) < opt.markerdist); + posi = tmp1(posk_idx); + posj = tmp2(posk_idx); + posk = tmp3(posk_idx); + else % plot all markers on the current slice + posk_idx = 1:numel(tmp1); + posi = tmp1; + posj = tmp2; + posk = tmp3; + end + if ~isempty(posk) + hold on + plot3(posi, posj, repmat(zi,size(posk)), 'marker', '+', 'linestyle', 'none', 'color', 'r'); % [xi yi zi] + if opt.showlabels + for i=1:numel(posk_idx) + text(posi(i), posj(i), zi, opt.markerlab_sel{posk_idx(i),1}, 'color', [1 .5 0]); + end end + hold off end - hold off - end -end % for all markers - -if isfield(opt, 'scatterfig') - cb_scatterredraw(h); % also update the appendix - figure(h); % FIXME: ugly as it switches forth and back to mainfig -end + end % for all markers +end % if showmarkers % do not initialize on the next call opt.init = false; setappdata(h, 'opt', opt); set(h, 'currentaxes', curr_ax); -toc + +% also update the appendix +if isfield(opt, 'scatterfig') + cb_scatterredraw(h); + figure(h); % this switches back to mainfig +end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % SUBFUNCTION @@ -669,18 +732,18 @@ function cb_scatterredraw(h, eventdata) 'Color', [1 1 1], ... 'Visible', 'on'); set(opt.scatterfig, 'CloseRequestFcn', @cb_scattercleanup); - opt.scatterfig_h1 = axes('position',[0.06 0.06 0.74 0.88]); - set(opt.scatterfig_h1, 'DataAspectRatio', get(opt.handlesaxes(1), 'DataAspectRatio')); - axis image; + opt.scatterfig_h1 = axes('position', [0.02 0.02 0.96 0.96]); + set(opt.scatterfig_h1, 'DataAspectRatio', get(opt.axes(1), 'DataAspectRatio')); + axis square; axis tight; axis off; view([0 0]); xlabel('x'); ylabel('y'); zlabel('z'); % scatter range sliders opt.scatterfig_h23text = uicontrol('Style', 'text',... - 'String','Treshold',... + 'String', 'Intensity',... 'Units', 'normalized', ... - 'Position',[.85+0.03 .26 .1 0.04],... + 'Position', [.85+0.03 .26 .1 0.04],... 'BackgroundColor', [1 1 1], ... - 'HandleVisibility','on'); + 'HandleVisibility', 'on'); opt.scatterfig_h2 = uicontrol('Style', 'slider', ... 'Parent', opt.scatterfig, ... @@ -698,35 +761,74 @@ function cb_scatterredraw(h, eventdata) 'Position', [.85+.07 .06 .05 .2], ... 'Callback', @cb_scattermaxslider); - msize = round(2500/opt.mri.dim(3)); % headsize (25 cm) / z slices + hskullstrip = uicontrol('Style', 'togglebutton', ... + 'Parent', opt.scatterfig, ... + 'String', 'Skullstrip', ... + 'Value', 0, ... + 'Units', 'normalized', ... + 'Position', [.88 .88 .1 .1], ... + 'HandleVisibility', 'on', ... + 'Callback', @cb_skullstrip); + + % datacursor mode options + opt.scatterfig_dcm = datacursormode(opt.scatterfig); + set(opt.scatterfig_dcm, ... + 'DisplayStyle', 'datatip', ... + 'SnapToDataVertex', 'off', ... + 'Enable', 'off', ... + 'UpdateFcn', @cb_scatter_dcm); + + % draw the crosshair for the first time + opt.handlescross2 = ft_plot_crosshair(opt.pos, 'parent', opt.scatterfig_h1, 'color', 'blue'); + + % instructions to the user + fprintf(strcat(... + '5. Scatterplot viewing options:\n',... + ' a. use the Data Cursor, Rotate 3D, Pan, and Zoom tools to navigate to electrodes in 3D space\n')); + + opt.redrawscatter = 1; + opt.redrawmarker = 1; + end + + figure(opt.scatterfig); % make current figure + + if opt.redrawscatter + delete(findobj('type', 'scatter')); % remove previous scatters + msize = round(2000/opt.mri{1}.dim(3)); % headsize (20 cm) / z slices inc = abs(opt.slim(2)-opt.slim(1))/4; % color increments for r = 1:4 % 4 color layers to encode peaks lim1 = opt.slim(1) + r*inc - inc; lim2 = opt.slim(1) + r*inc; voxind = find(opt.ana>lim1 & opt.ana0 pnt(end,:) = []; end - + if l1=='i' && l2=='j' updatepanel = [1 2 3]; elseif l1=='i' && l2=='k' @@ -902,10 +1008,10 @@ function cb_keyboard(h, eventdata) elseif l1=='j' && l2=='k' updatepanel = [3 1 2]; end - + otherwise % do nothing - + end % switch key %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -949,58 +1055,26 @@ function cb_getposition(h, eventdata) h = getparent(h); opt = getappdata(h, 'opt'); curr_ax = get(h, 'currentaxes'); -pos = mean(get(curr_ax, 'currentpoint')); tag = get(curr_ax, 'tag'); if ~isempty(tag) && ~opt.init + pos = mean(get(curr_ax, 'currentpoint')); if strcmp(tag, 'ik') - opt.ijk([1 3]) = round(pos([1 3])); + opt.pos([1 3]) = pos([1 3]); opt.update = [1 1 1]; elseif strcmp(tag, 'ij') - opt.ijk([1 2]) = round(pos([1 2])); + opt.pos([1 2]) = pos([1 2]); opt.update = [1 1 1]; elseif strcmp(tag, 'jk') - opt.ijk([2 3]) = round(pos([2 3])); + opt.pos([2 3]) = pos([2 3]); opt.update = [1 1 1]; end + opt.pos = min(opt.pos(:)', opt.axis([2 4 6])); % avoid out-of-bounds + opt.pos = max(opt.pos(:)', opt.axis([1 3 5])); +end + +if opt.magradius>0 % magnetize + opt = magnetize(opt); end -opt.ijk = min(opt.ijk(:)', opt.dim); -opt.ijk = max(opt.ijk(:)', [1 1 1]); - -if opt.magnet % magnetize - try - center = opt.ijk; - radius = opt.magradius; - % FIXME here it would be possible to adjust the selection at the edges of the volume - xsel = center(1)+(-radius:radius); - ysel = center(2)+(-radius:radius); - zsel = center(3)+(-radius:radius); - cubic = opt.ana(xsel, ysel, zsel); - if strcmp(opt.magtype, 'peak') - % find the peak intensity voxel within the cube - [val, idx] = max(cubic(:)); - [ix, iy, iz] = ind2sub(size(cubic), idx); - elseif strcmp(opt.magtype, 'trough') - % find the trough intensity voxel within the cube - [val, idx] = min(cubic(:)); - [ix, iy, iz] = ind2sub(size(cubic), idx); - elseif strcmp(opt.magtype, 'weighted') - % find the weighted center of mass in the cube - dim = size(cubic); - [X, Y, Z] = ndgrid(1:dim(1), 1:dim(2), 1:dim(3)); - cubic = cubic./sum(cubic(:)); - ix = round(X(:)' * cubic(:)); - iy = round(Y(:)' * cubic(:)); - iz = round(Z(:)' * cubic(:)); - end - % adjust the indices for the selection - opt.ijk = [ix, iy, iz] + center - radius - 1; - fprintf('==================================================================================\n'); - fprintf(' clicked at [%d %d %d], %s magnetized adjustment [%d %d %d]\n', center, opt.magtype, opt.ijk-center); - catch - % this fails if the selection is at the edge of the volume - warning('cannot magnetize at the edge of the volume'); - end -end % if magnetize setappdata(h, 'opt', opt); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1106,32 +1180,33 @@ function cb_eleclistbox(h6, eventdata) end eleclis = cellstr(get(h6, 'String')); % all labels eleclab = eleclis{elecidx}; % this elec's label - + h = getparent(h6); opt = getappdata(h, 'opt'); - + % toggle electrode status and assign markers if strfind(eleclab, 'silver') % not yet, check fprintf('assigning marker %s\n', opt.label{elecidx,1}); - eleclab = regexprep(eleclab, '"silver"','"black"'); % replace font color + eleclab = regexprep(eleclab, '"silver"', '"black"'); % replace font color opt.markerlab{elecidx,1} = opt.label(elecidx,1); % assign marker label opt.markerpos{elecidx,1} = opt.pos; % assign marker position elseif strfind(eleclab, 'black') % already chosen before, move cusor to marker or uncheck - if strcmp(get(h,'SelectionType'),'normal') % single click to move cursor to + if strcmp(get(h, 'SelectionType'), 'normal') % single click to move cursor to fprintf('moving cursor to marker %s\n', opt.label{elecidx,1}); - opt.ijk = ft_warp_apply(inv(opt.mri.transform), opt.markerpos{elecidx,1}); % move cursor to marker position - elseif strcmp(get(h,'SelectionType'),'open') % double click to uncheck + opt.pos = opt.markerpos{elecidx,1}; % move cursor to marker position + elseif strcmp(get(h, 'SelectionType'), 'open') % double click to uncheck fprintf('removing marker %s\n', opt.label{elecidx,1}); - eleclab = regexprep(eleclab, '"black"','"silver"'); % replace font color + eleclab = regexprep(eleclab, '"black"', '"silver"'); % replace font color opt.markerlab{elecidx,1} = {}; % assign marker label - opt.markerpos{elecidx,1} = zeros(0,3); % assign marker position + opt.markerpos{elecidx,1} = []; % assign marker position end end - + % update plot eleclis{elecidx} = eleclab; set(h6, 'String', eleclis); set(h6, 'ListboxTop', listtopidx); % ensure listbox does not move upon label selec + opt.redrawmarker = 1; setappdata(h, 'opt', opt); cb_redraw(h); end @@ -1143,9 +1218,80 @@ function cb_magnetbutton(h7, eventdata) h = getparent(h7); opt = getappdata(h, 'opt'); -opt.magnet = get(h7, 'value'); +radii = get(h7, 'String'); +opt.magradius = str2double(radii{get(h7, 'value')}); +fprintf(' changed magnet radius to %.1f %s\n', opt.magradius, opt.mri{1}.unit); setappdata(h, 'opt', opt); +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function opt = magnetize(opt) + +try + pos = opt.pos; + vox = round(ft_warp_apply(inv(opt.mri{1}.transform), pos)); % head to vox coord (for indexing within anatomy) + xsel = vox(1)+(-opt.magradius:opt.magradius); + ysel = vox(2)+(-opt.magradius:opt.magradius); + zsel = vox(3)+(-opt.magradius:opt.magradius); + cubic = opt.ana(xsel, ysel, zsel); + if strcmp(opt.magtype, 'peak') + % find the peak intensity voxel within the cube + [val, idx] = max(cubic(:)); + [ix, iy, iz] = ind2sub(size(cubic), idx); + elseif strcmp(opt.magtype, 'trough') + % find the trough intensity voxel within the cube + [val, idx] = min(cubic(:)); + [ix, iy, iz] = ind2sub(size(cubic), idx); + elseif strcmp(opt.magtype, 'weighted') + % find the weighted center of mass in the cube + dim = size(cubic); + [X, Y, Z] = ndgrid(1:dim(1), 1:dim(2), 1:dim(3)); + cubic = cubic./sum(cubic(:)); + ix = (X(:)' * cubic(:)); + iy = (Y(:)' * cubic(:)); + iz = (Z(:)' * cubic(:)); + elseif strcmp(opt.magtype, 'peakweighted') + % find the peak intensity voxel and then the center of mass + [val, idx] = max(cubic(:)); + [ix, iy, iz] = ind2sub(size(cubic), idx); + vox = [ix, iy, iz] + vox - opt.magradius - 1; % move cursor to peak + xsel = vox(1)+(-opt.magradius:opt.magradius); + ysel = vox(2)+(-opt.magradius:opt.magradius); + zsel = vox(3)+(-opt.magradius:opt.magradius); + cubic = opt.ana(xsel, ysel, zsel); + dim = size(cubic); + [X, Y, Z] = ndgrid(1:dim(1), 1:dim(2), 1:dim(3)); + cubic = cubic./sum(cubic(:)); + ix = (X(:)' * cubic(:)); + iy = (Y(:)' * cubic(:)); + iz = (Z(:)' * cubic(:)); + elseif strcmp(opt.magtype, 'troughweighted') + % find the peak intensity voxel and then the center of mass + [val, idx] = min(cubic(:)); + [ix, iy, iz] = ind2sub(size(cubic), idx); + vox = [ix, iy, iz] + vox - opt.magradius - 1; % move cursor to trough + xsel = vox(1)+(-opt.magradius:opt.magradius); + ysel = vox(2)+(-opt.magradius:opt.magradius); + zsel = vox(3)+(-opt.magradius:opt.magradius); + cubic = opt.ana(xsel, ysel, zsel); + dim = size(cubic); + [X, Y, Z] = ndgrid(1:dim(1), 1:dim(2), 1:dim(3)); + cubic = 1-cubic; + cubic = cubic./(sum(cubic(:))); + ix = (X(:)' * cubic(:)); + iy = (Y(:)' * cubic(:)); + iz = (Z(:)' * cubic(:)); + end + % adjust the indices for the selection + voxadj = [ix, iy, iz] + vox - opt.magradius - 1; + opt.pos = ft_warp_apply(opt.mri{1}.transform, voxadj); + fprintf('==================================================================================\n'); + fprintf(' clicked at [%.1f %.1f %.1f], %s magnetized adjustment [%.1f %.1f %.1f] %s\n', pos, opt.magtype, opt.pos-pos, opt.mri{1}.unit); +catch + % this fails if the selection is at the edge of the volume +end + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % SUBFUNCTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1154,6 +1300,7 @@ function cb_labelsbutton(h8, eventdata) h = getparent(h8); opt = getappdata(h, 'opt'); opt.showlabels = get(h8, 'value'); +opt.redrawmarker = 1; setappdata(h, 'opt', opt); cb_redraw(h); @@ -1200,10 +1347,10 @@ function cb_scatterbutton(hscatter, eventdata) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function cb_scattercleanup(hObject, eventdata) -h = findobj('type','figure','name',mfilename); +h = findobj('type', 'figure', 'name',mfilename); opt = getappdata(h, 'opt'); opt.scatter = 0; -set(opt.handlesaxes(11), 'Value', 0); +set(opt.axes(11), 'Value', 0); opt = rmfield(opt, 'scatterfig'); setappdata(h, 'opt', opt); delete(hObject); @@ -1213,22 +1360,12 @@ function cb_scattercleanup(hObject, eventdata) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function cb_scatterminslider(h2, eventdata) -h = findobj('type','figure','name',mfilename); +h = findobj('type', 'figure', 'name',mfilename); opt = getappdata(h, 'opt'); opt.slim(1) = get(h2, 'value'); fprintf('scatter limits updated to [%.03f %.03f]\n', opt.slim); +opt.redrawscatter = 1; setappdata(h, 'opt', opt); - -delete(findobj('type','scatter')); % remove previous scatters -msize = round(2500/opt.mri.dim(3)); % headsize (25 cm) / z slices -inc = abs(opt.slim(2)-opt.slim(1))/4; % color increments -for r = 1:4 % 4 color layers to encode peaks - lim1 = opt.slim(1) + r*inc - inc; - lim2 = opt.slim(1) + r*inc; - voxind = find(opt.ana>lim1 & opt.ana0 % magnetize + opt = magnetize(opt); +end +dcm_txt = ['']; % ['index = [' num2str(opt.pos) ']']; + +if strcmp(get(opt.scatterfig_dcm, 'Enable'), 'on') % update appl and figures + setappdata(h, 'opt', opt); + figure(h); + cb_redraw(h); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function cb_skullstrip(hObject, eventdata) -delete(findobj('type','scatter')); % remove previous scatters -msize = round(2500/opt.mri.dim(3)); % headsize (25 cm) / z slices -inc = abs(opt.slim(2)-opt.slim(1))/4; % color increments -for r = 1:4 % 4 color layers to encode peaks - lim1 = opt.slim(1) + r*inc - inc; - lim2 = opt.slim(1) + r*inc; - voxind = find(opt.ana>lim1 & opt.ana) +% cfg.fshome = string, path to freesurfer +% +% See also FT_READ_SENS, FT_VOLUMEREALIGN, FT_INTERACTIVEREALIGN, +% FT_DETERMINE_COORDSYS, FT_PREPARE_MESH % Copyright (C) 2005-2015, Robert Oostenveld % @@ -156,12 +172,18 @@ % set the defaults cfg.warp = ft_getopt(cfg, 'warp', 'rigidbody'); cfg.channel = ft_getopt(cfg, 'channel', 'all'); +cfg.keepchannel = ft_getopt(cfg, 'keepchannel', 'no'); cfg.feedback = ft_getopt(cfg, 'feedback', 'no'); cfg.casesensitive = ft_getopt(cfg, 'casesensitive', 'no'); cfg.headshape = ft_getopt(cfg, 'headshape', []); % for triangulated head surface, without labels cfg.target = ft_getopt(cfg, 'target', []); % for electrodes or fiducials, always with labels cfg.coordsys = ft_getopt(cfg, 'coordsys'); % this allows for automatic template fiducial placement +if isempty(cfg.target) + % remove the field, otherwise ft_checkconfig will complain + cfg = rmfield(cfg, 'target'); +end + if ~isempty(cfg.coordsys) && isempty(cfg.target) % set the template fiducial locations according to the coordinate system switch lower(cfg.coordsys) @@ -175,7 +197,7 @@ cfg.target.label{2} = 'LPA'; cfg.target.label{3} = 'RPA'; otherwise - error('the %s coordinate system is not automatically supported, please specify fiducial details in cfg.target') + ft_error('the %s coordinate system is not automatically supported, please specify fiducial details in cfg.target') end end @@ -187,14 +209,12 @@ cfg = ft_checkconfig(cfg, 'required', 'headshape', 'forbidden', 'target'); case 'fiducial' % realign using the NAS, LPA and RPA fiducials cfg = ft_checkconfig(cfg, 'required', 'target', 'forbidden', 'headshape'); + case 'moveinward' % moves eletrodes inward + cfg = ft_checkconfig(cfg, 'required', 'moveinward'); end % switch cfg.method if strcmp(cfg.method, 'fiducial') && isfield(cfg, 'warp') && ~isequal(cfg.warp, 'rigidbody') - warning('The method ''fiducial'' implies a rigid body tramsformation. See also http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=1722'); - cfg.warp = 'rigidbody'; -end -if strcmp(cfg.method, 'fiducial') && isfield(cfg, 'warp') && ~isequal(cfg.warp, 'rigidbody') - warning('The method ''interactive'' implies a rigid body tramsformation. See also http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=1722'); + ft_warning('The method ''fiducial'' implies a rigid body tramsformation. See also http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=1722'); cfg.warp = 'rigidbody'; end @@ -209,7 +229,7 @@ end % the data can be passed as input arguments or can be read from disk -hasdata = exist('data', 'var'); +hasdata = exist('elec_original', 'var'); % get the electrode definition that should be warped if ~hasdata @@ -220,13 +240,13 @@ end % ensure that the units are specified -elec_original = ft_convert_units(elec_original); +elec_original = ft_determine_units(elec_original); % ensure up-to-date sensor description (Oct 2011) elec_original = ft_datatype_sens(elec_original); % ensure that channel and electrode positions are the same -assert(isequaln(elec_original.elecpos, elec_original.chanpos), 'this function requires same electrode and channel positions.'); +assert(isequaln(elec_original.elecpos, elec_original.chanpos), 'this function requires same electrode and channel positions'); % remember the original electrode locations and labels and do all the work with a % temporary copy, this involves channel selection and changing to lower case @@ -253,7 +273,7 @@ if isstruct(cfg.target{i}) target(i) = cfg.target{i}; else - target(i) = ft_read_sens(cfg.target{i}); + target(i) = ft_read_sens(cfg.target{i}, 'senstype', 'eeg'); end end clear tmp @@ -286,7 +306,7 @@ % read the headshape from file headshape = ft_read_headshape(cfg.headshape); else - error('cfg.headshape is not specified correctly') + ft_error('cfg.headshape is not specified correctly') end if ~isfield(headshape, 'tri') && ~isfield(headshape, 'poly') % generate a closed triangulation from the surface points @@ -297,11 +317,10 @@ end % convert all labels to lower case for string comparisons -% this has to be done AFTER keeping the original labels and positions +cfg.channel = ft_channelselection(cfg.channel, elec.label); if strcmp(cfg.casesensitive, 'no') - for i=1:length(elec.label) - elec.label{i} = lower(elec.label{i}); - end + elec.label = lower(elec.label); + cfg.channel = lower(cfg.channel); if usetarget for j=1:length(target) for i=1:length(target(j).label) @@ -310,6 +329,9 @@ end end end +[cfgsel, datsel] = match_str(cfg.channel, elec.label); +% keep the original channel labels +label_original = elec_original.label(datsel); % start with an empty structure, this will be returned at the end norm = []; @@ -375,15 +397,38 @@ % determine electrode selection and overlapping subset for warping cfg.channel = ft_channelselection(cfg.channel, elec.label); - - % make subselection of electrodes [cfgsel, datsel] = match_str(cfg.channel, elec.label); elec.label = elec.label(datsel); elec.elecpos = elec.elecpos(datsel,:); norm.label = elec.label; - if strcmp(lower(cfg.warp), 'dykstra2012') - norm.elecpos = ft_warp_dykstra2012(elec.elecpos, headshape, cfg.feedback); + if strcmp(cfg.warp, 'dykstra2012') + norm.elecpos = warp_dykstra2012(cfg, elec, headshape); + elseif strcmp(cfg.warp, 'fsaverage') + subj_pial = ft_read_headshape(cfg.headshape); + [PATHSTR, NAME] = fileparts(cfg.headshape); % lh or rh + subj_reg = ft_read_headshape([PATHSTR filesep NAME '.sphere.reg']); + if ~isdir([cfg.fshome filesep 'subjects' filesep 'fsaverage' filesep 'surf']) + ft_error(['freesurfer dir ' cfg.fshome filesep 'subjects' filesep 'fsaverage' filesep 'surf cannot be found']) + end + fsavg_pial = ft_read_headshape([cfg.fshome filesep 'subjects' filesep 'fsaverage' filesep 'surf' filesep NAME '.pial']); + fsavg_reg = ft_read_headshape([cfg.fshome filesep 'subjects' filesep 'fsaverage' filesep 'surf' filesep NAME '.sphere.reg']); + + for e = 1:numel(elec.label) + % subject space (3D surface): electrode pos -> vertex index + dist = sqrt(sum(((subj_pial.pos - repmat(elec.elecpos(e,:), size(subj_pial.pos,1), 1)).^2),2)); + [~, minidx] = min(dist); + + % intersubject space (2D sphere): vertex index -> vertex pos -> template vertex index + dist2 = sqrt(sum(((fsavg_reg.pos - repmat(subj_reg.pos(minidx,:), size(fsavg_reg.pos,1), 1)).^2),2)); + [~, minidx2] = min(dist2); + clear minidx + + % template space (3D surface): template vertex index -> template electrode pos + norm.elecpos(e,:) = fsavg_pial.pos(minidx2,:); + clear minidx2 + end + clear subj_pial subj_reg fsavg_pial fsavg_reg else fprintf('warping electrodes to skin surface... '); % the newline comes later [norm.elecpos, norm.m] = ft_warp_optim(elec.elecpos, headshape, cfg.warp); @@ -421,7 +466,7 @@ elseif length(match_str(label, option6))==3 cfg.fiducial = option6; else - error('could not determine consistent fiducials in the input and the target, please specify cfg.fiducial or cfg.coordsys') + ft_error('could not determine consistent fiducials in the input and the target, please specify cfg.fiducial or cfg.coordsys') end end fprintf('matching fiducials {''%s'', ''%s'', ''%s''}\n', cfg.fiducial{1}, cfg.fiducial{2}, cfg.fiducial{3}); @@ -433,7 +478,7 @@ elec.elecpos = elec.elecpos(datsel,:); if length(cfg.fiducial)~=3 - error('you must specify exaclty three fiducials'); + ft_error('you must specify exactly three fiducials'); end % do case-insensitive search for fiducial locations @@ -441,7 +486,7 @@ lpa_indx = match_str(lower(elec.label), lower(cfg.fiducial{2})); rpa_indx = match_str(lower(elec.label), lower(cfg.fiducial{3})); if length(nas_indx)~=1 || length(lpa_indx)~=1 || length(rpa_indx)~=1 - error('not all fiducials were found in the electrode set'); + ft_error('not all fiducials were found in the electrode set'); end elec_nas = elec.elecpos(nas_indx,:); elec_lpa = elec.elecpos(lpa_indx,:); @@ -460,7 +505,7 @@ lpa_indx = match_str(lower(target(i).label), lower(cfg.fiducial{2})); rpa_indx = match_str(lower(target(i).label), lower(cfg.fiducial{3})); if length(nas_indx)~=1 || length(lpa_indx)~=1 || length(rpa_indx)~=1 - error(sprintf('not all fiducials were found in template %d', i)); + ft_error('not all fiducials were found in template %d', i); end tmpl_nas(i,:) = target(i).elecpos(nas_indx,:); tmpl_lpa(i,:) = target(i).elecpos(lpa_indx,:); @@ -533,43 +578,59 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% elseif strcmp(cfg.method, 'interactive') %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - % give the user instructions - disp('Use the mouse to rotate the head and the electrodes around, and click "redisplay"'); - disp('Close the figure when you are done'); - % open a figure - fig = figure; - % add the data to the figure - set(fig, 'CloseRequestFcn', @cb_close); - setappdata(fig, 'elec', elec); - setappdata(fig, 'transform', eye(4)); - if useheadshape - setappdata(fig, 'headshape', headshape); + + tmpcfg = []; + tmpcfg.individual.elec = elec; + if isfield(cfg, 'headshape') && ~isempty(cfg.headshape) + tmpcfg.template.headshape = cfg.headshape; end - if usetarget - % FIXME interactive realigning to template electrodes is not yet supported - % this requires a consistent handling of channel selection etc. - setappdata(fig, 'target', target); + if isfield(cfg, 'target') && ~isempty(cfg.target) + if iscell(cfg.target) + if numel(cfg.target)>1 + ft_notice('computing the average electrode positions'); + tmpcfg.template.elec = ft_average_sens(cfg.target); + else + tmpcfg.template.elec = cfg.target{1}; + end + elseif isstruct(cfg.target) + tmpcfg.template.elec = cfg.target; + end + tmpcfg.template.elecstyle = {'facecolor', 'blue'}; + ft_info('plotting the target electrodes in blue'); end - % add the GUI elements - cb_creategui(gca); - cb_redraw(gca); - rotate3d on - waitfor(fig); - % get the data from the figure that was left behind as global variable - tmp = norm; - clear global norm - norm = tmp; - clear tmp + + % use the more generic ft_interactiverealign for the actual work + tmpcfg = ft_interactiverealign(tmpcfg); + % only keep the transformation, it will be applied to the electrodes further down + norm.m = tmpcfg.m; + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% elseif strcmp(cfg.method, 'project') %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - [dum, prj] = project_elec(elec.elecpos, headshape.pos, headshape.tri); - % replace the electrodes with the projected version - elec.elecpos = prj; + % determine electrode selection + cfg.channel = ft_channelselection(cfg.channel, elec.label); + [cfgsel, datsel] = match_str(cfg.channel, elec.label); + elec.label = elec.label(datsel); + elec.elecpos = elec.elecpos(datsel,:); + + norm.label = elec.label; + [dum, norm.elecpos] = project_elec(elec.elecpos, headshape.pos, headshape.tri); + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +elseif strcmp(cfg.method, 'moveinward') + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % determine electrode selection + cfg.channel = ft_channelselection(cfg.channel, elec.label); + [cfgsel, datsel] = match_str(cfg.channel, elec.label); + elec.label = elec.label(datsel); + elec.elecpos = elec.elecpos(datsel,:); + + norm.label = elec.label; + norm.elecpos = moveinward(elec.elecpos, cfg.moveinward); else - error('unknown method'); + ft_error('unknown method'); end % if method @@ -577,10 +638,9 @@ % electrode labels by their case-sensitive original values switch cfg.method case {'template', 'headshape'} - if strcmp(lower(cfg.warp), 'dykstra2012') + if strcmpi(cfg.warp, 'dykstra2012') || strcmpi(cfg.warp, 'fsaverage') elec_realigned = norm; - elec_realigned.unit = elec_original.unit; - + elec_realigned.label = label_original; else % the transformation is a linear or non-linear warp, i.e. a vector try @@ -589,12 +649,13 @@ elec_realigned = ft_transform_sens(feval(cfg.warp, norm.m), elec_original); catch % the previous section will fail for nonlinear transformations - elec_realigned.label = elec_original.label; - try, elec_realigned.elecpos = ft_warp_apply(norm.m, elec_original.elecpos, cfg.warp); end + elec_realigned.label = label_original; + try + elec_realigned.elecpos = ft_warp_apply(norm.m, elec_original.elecpos, cfg.warp); + end % FIXME why is an error here not dealt with? end % remember the transformation elec_realigned.(cfg.warp) = norm.m; - end case {'fiducial' 'interactive'} @@ -604,12 +665,13 @@ % remember the transformation elec_realigned.homogeneous = norm.m; - case 'project' + case {'project', 'moveinward'} % nothing to be done - elec_realigned = elec; + elec_realigned = norm; + elec_realigned.label = label_original; otherwise - error('unknown method'); + ft_error('unknown method'); end % the coordinate system is in general not defined after transformation @@ -627,24 +689,50 @@ if isfield(headshape, 'coordsys') elec_realigned.coordsys = headshape.coordsys; end + if isfield(elec_original, 'coordsys') + if strcmp(cfg.warp, 'dykstra2012') % this warp simply moves the electrodes in the same coordinate space + elec_realigned.coordsys = elec_original.coordsys; + elseif strcmp(cfg.warp, 'fsaverage') + elec_realigned.coordsys = 'fsaverage'; + end + end case 'fiducial' if isfield(target, 'coordsys') elec_realigned.coordsys = target.coordsys; end case 'interactive' % the coordinate system is not known - case 'project' + case {'project', 'moveinward'} % the coordinate system remains the same if isfield(elec_original, 'coordsys') elec_realigned.coordsys = elec_original.coordsys; end otherwise - error('unknown method'); + ft_error('unknown method'); +end + +if istrue(cfg.keepchannel) + % append the channels that are not realigned + [~, idx] = setdiff(elec_original.label, elec_realigned.label); + idx = sort(idx); + elec_realigned.label = [elec_realigned.label; elec_original.label(idx)]; + elec_realigned.elecpos = [elec_realigned.elecpos; elec_original.elecpos(idx,:)]; end % channel positions are identical to the electrode positions (this was checked at the start) elec_realigned.chanpos = elec_realigned.elecpos; +% copy over unit, chantype, and chanunit information in case this was not already done +if ~isfield(elec_realigned, 'unit') && isfield(elec_original, 'unit') + elec_realigned.unit = elec_original.unit; +end +if ~isfield(elec_realigned, 'chantype') && isfield(elec_original, 'chantype') + elec_realigned.chantype = elec_original.chantype; +end +if ~isfield(elec_realigned, 'chanunit') && isfield(elec_original, 'chanunit') + elec_realigned.chanunit = elec_original.chanunit; +end + % update it to the latest version elec_realigned = ft_datatype_sens(elec_realigned); @@ -666,169 +754,3 @@ function my_line3(xyzB, xyzE, varargin) for i=1:size(xyzB,1) line([xyzB(i,1) xyzE(i,1)], [xyzB(i,2) xyzE(i,2)], [xyzB(i,3) xyzE(i,3)], varargin{:}) end - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -function cb_creategui(hObject, eventdata, handles) -% % define the position of each GUI element -fig = get(hObject, 'parent'); -% constants -CONTROL_WIDTH = 0.05; -CONTROL_HEIGHT = 0.06; -CONTROL_HOFFSET = 0.7; -CONTROL_VOFFSET = 0.5; -% rotateui -uicontrol('tag', 'rotateui', 'parent', fig, 'units', 'normalized', 'style', 'text', 'string', 'rotate', 'callback', []) -uicontrol('tag', 'rx', 'parent', fig, 'units', 'normalized', 'style', 'edit', 'string', '0', 'callback', @cb_redraw) -uicontrol('tag', 'ry', 'parent', fig, 'units', 'normalized', 'style', 'edit', 'string', '0', 'callback', @cb_redraw) -uicontrol('tag', 'rz', 'parent', fig, 'units', 'normalized', 'style', 'edit', 'string', '0', 'callback', @cb_redraw) -ft_uilayout(fig, 'tag', 'rotateui', 'BackgroundColor', [0.8 0.8 0.8], 'width', 2*CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'hpos', CONTROL_HOFFSET, 'vpos', CONTROL_VOFFSET); -ft_uilayout(fig, 'tag', 'rx', 'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'hpos', CONTROL_HOFFSET+3*CONTROL_WIDTH, 'vpos', CONTROL_VOFFSET); -ft_uilayout(fig, 'tag', 'ry', 'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'hpos', CONTROL_HOFFSET+4*CONTROL_WIDTH, 'vpos', CONTROL_VOFFSET); -ft_uilayout(fig, 'tag', 'rz', 'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'hpos', CONTROL_HOFFSET+5*CONTROL_WIDTH, 'vpos', CONTROL_VOFFSET); - -% scaleui -uicontrol('tag', 'scaleui', 'parent', fig, 'units', 'normalized', 'style', 'text', 'string', 'scale', 'callback', []) -uicontrol('tag', 'sx', 'parent', fig, 'units', 'normalized', 'style', 'edit', 'string', '1', 'callback', @cb_redraw) -uicontrol('tag', 'sy', 'parent', fig, 'units', 'normalized', 'style', 'edit', 'string', '1', 'callback', @cb_redraw) -uicontrol('tag', 'sz', 'parent', fig, 'units', 'normalized', 'style', 'edit', 'string', '1', 'callback', @cb_redraw) -ft_uilayout(fig, 'tag', 'scaleui', 'BackgroundColor', [0.8 0.8 0.8], 'width', 2*CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'hpos', CONTROL_HOFFSET, 'vpos', CONTROL_VOFFSET-CONTROL_HEIGHT); -ft_uilayout(fig, 'tag', 'sx', 'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'hpos', CONTROL_HOFFSET+3*CONTROL_WIDTH, 'vpos', CONTROL_VOFFSET-CONTROL_HEIGHT); -ft_uilayout(fig, 'tag', 'sy', 'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'hpos', CONTROL_HOFFSET+4*CONTROL_WIDTH, 'vpos', CONTROL_VOFFSET-CONTROL_HEIGHT); -ft_uilayout(fig, 'tag', 'sz', 'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'hpos', CONTROL_HOFFSET+5*CONTROL_WIDTH, 'vpos', CONTROL_VOFFSET-CONTROL_HEIGHT); - -% translateui -uicontrol('tag', 'translateui', 'parent', fig, 'units', 'normalized', 'style', 'text', 'string', 'translate', 'callback', []) -uicontrol('tag', 'tx', 'parent', fig, 'units', 'normalized', 'style', 'edit', 'string', '0', 'callback', @cb_redraw) -uicontrol('tag', 'ty', 'parent', fig, 'units', 'normalized', 'style', 'edit', 'string', '0', 'callback', @cb_redraw) -uicontrol('tag', 'tz', 'parent', fig, 'units', 'normalized', 'style', 'edit', 'string', '0', 'callback', @cb_redraw) -ft_uilayout(fig, 'tag', 'translateui', 'BackgroundColor', [0.8 0.8 0.8], 'width', 2*CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'hpos', CONTROL_HOFFSET, 'vpos', CONTROL_VOFFSET-2*CONTROL_HEIGHT); -ft_uilayout(fig, 'tag', 'tx', 'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'hpos', CONTROL_HOFFSET+3*CONTROL_WIDTH, 'vpos', CONTROL_VOFFSET-2*CONTROL_HEIGHT); -ft_uilayout(fig, 'tag', 'ty', 'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'hpos', CONTROL_HOFFSET+4*CONTROL_WIDTH, 'vpos', CONTROL_VOFFSET-2*CONTROL_HEIGHT); -ft_uilayout(fig, 'tag', 'tz', 'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'hpos', CONTROL_HOFFSET+5*CONTROL_WIDTH, 'vpos', CONTROL_VOFFSET-2*CONTROL_HEIGHT); - -% control buttons -uicontrol('tag', 'redisplaybtn', 'parent', fig, 'units', 'normalized', 'style', 'pushbutton', 'string', 'redisplay', 'value', [], 'callback', @cb_redraw); -uicontrol('tag', 'applybtn', 'parent', fig, 'units', 'normalized', 'style', 'pushbutton', 'string', 'apply', 'value', [], 'callback', @cb_apply); -uicontrol('tag', 'toggle labels', 'parent', fig, 'units', 'normalized', 'style', 'pushbutton', 'string', 'toggle label', 'value', 0, 'callback', @cb_redraw); -uicontrol('tag', 'toggle axes', 'parent', fig, 'units', 'normalized', 'style', 'pushbutton', 'string', 'toggle axes', 'value', 0, 'callback', @cb_redraw); -ft_uilayout(fig, 'tag', 'redisplaybtn', 'BackgroundColor', [0.8 0.8 0.8], 'width', 6*CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'vpos', CONTROL_VOFFSET-3*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET); -ft_uilayout(fig, 'tag', 'applybtn', 'BackgroundColor', [0.8 0.8 0.8], 'width', 6*CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'vpos', CONTROL_VOFFSET-4*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET); -ft_uilayout(fig, 'tag', 'toggle labels', 'BackgroundColor', [0.8 0.8 0.8], 'width', 6*CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'vpos', CONTROL_VOFFSET-5*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET); -ft_uilayout(fig, 'tag', 'toggle axes', 'BackgroundColor', [0.8 0.8 0.8], 'width', 6*CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'vpos', CONTROL_VOFFSET-6*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET); - -% alpha ui (somehow not implemented, facealpha is fixed at 0.7 -uicontrol('tag', 'alphaui', 'parent', fig, 'units', 'normalized', 'style', 'text', 'string', 'alpha', 'value', [], 'callback', []); -uicontrol('tag', 'alpha', 'parent', fig, 'units', 'normalized', 'style', 'edit', 'string', '0.7', 'value', [], 'callback', @cb_redraw); -ft_uilayout(fig, 'tag', 'alphaui', 'BackgroundColor', [0.8 0.8 0.8], 'width', 3*CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'vpos', CONTROL_VOFFSET-7*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET); -ft_uilayout(fig, 'tag', 'alpha', 'BackgroundColor', [0.8 0.8 0.8], 'width', 3*CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'vpos', CONTROL_VOFFSET-7*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET+3*CONTROL_WIDTH); - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -function cb_redraw(hObject, eventdata, handles) -fig = get(hObject, 'parent'); -headshape = getappdata(fig, 'headshape'); -elec = getappdata(fig, 'elec'); -target = getappdata(fig, 'target'); -% get the transformation details -rx = str2num(get(findobj(fig, 'tag', 'rx'), 'string')); -ry = str2num(get(findobj(fig, 'tag', 'ry'), 'string')); -rz = str2num(get(findobj(fig, 'tag', 'rz'), 'string')); -tx = str2num(get(findobj(fig, 'tag', 'tx'), 'string')); -ty = str2num(get(findobj(fig, 'tag', 'ty'), 'string')); -tz = str2num(get(findobj(fig, 'tag', 'tz'), 'string')); -sx = str2num(get(findobj(fig, 'tag', 'sx'), 'string')); -sy = str2num(get(findobj(fig, 'tag', 'sy'), 'string')); -sz = str2num(get(findobj(fig, 'tag', 'sz'), 'string')); -R = rotate ([rx ry rz]); -T = translate([tx ty tz]); -S = scale ([sx sy sz]); -H = S * T * R; -elec = ft_transform_sens(H, elec); -axis vis3d; cla -xlabel('x') -ylabel('y') -zlabel('z') - -if ~isempty(target) - disp('Plotting the target electrodes in blue'); - if size(target.elecpos, 2)==2 - hs = plot(target.elecpos(:,1), target.elecpos(:,2), 'b.', 'MarkerSize', 20); - else - hs = plot3(target.elecpos(:,1), target.elecpos(:,2), target.elecpos(:,3), 'b.', 'MarkerSize', 20); - end -end - -if ~isempty(headshape) - % plot the faces of the 2D or 3D triangulation - skin = [255 213 119]/255; - ft_plot_mesh(headshape,'facecolor', skin,'EdgeColor','none','facealpha',0.7); - lighting gouraud - material shiny - camlight -end - -if isfield(elec, 'fid') && ~isempty(elec.fid.pos) - disp('Plotting the fiducials in red'); - ft_plot_sens(elec.fid,'style', 'r*'); -end - -if get(findobj(fig, 'tag', 'toggle axes'), 'value') - axis on - grid on -else - axis off - grid on -end - -hold on -if get(findobj(fig, 'tag', 'toggle labels'), 'value') - ft_plot_sens(elec,'label', 'on'); -else - ft_plot_sens(elec,'label', 'off'); -end - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -function cb_apply(hObject, eventdata, handles) -fig = get(hObject, 'parent'); -elec = getappdata(fig, 'elec'); -transform = getappdata(fig, 'transform'); -% get the transformation details -rx = str2num(get(findobj(fig, 'tag', 'rx'), 'string')); -ry = str2num(get(findobj(fig, 'tag', 'ry'), 'string')); -rz = str2num(get(findobj(fig, 'tag', 'rz'), 'string')); -tx = str2num(get(findobj(fig, 'tag', 'tx'), 'string')); -ty = str2num(get(findobj(fig, 'tag', 'ty'), 'string')); -tz = str2num(get(findobj(fig, 'tag', 'tz'), 'string')); -sx = str2num(get(findobj(fig, 'tag', 'sx'), 'string')); -sy = str2num(get(findobj(fig, 'tag', 'sy'), 'string')); -sz = str2num(get(findobj(fig, 'tag', 'sz'), 'string')); -R = rotate ([rx ry rz]); -T = translate([tx ty tz]); -S = scale ([sx sy sz]); -H = S * T * R; -elec = ft_transform_headshape(H, elec); -transform = H * transform; -set(findobj(fig, 'tag', 'rx'), 'string', 0); -set(findobj(fig, 'tag', 'ry'), 'string', 0); -set(findobj(fig, 'tag', 'rz'), 'string', 0); -set(findobj(fig, 'tag', 'tx'), 'string', 0); -set(findobj(fig, 'tag', 'ty'), 'string', 0); -set(findobj(fig, 'tag', 'tz'), 'string', 0); -set(findobj(fig, 'tag', 'sx'), 'string', 1); -set(findobj(fig, 'tag', 'sy'), 'string', 1); -set(findobj(fig, 'tag', 'sz'), 'string', 1); -setappdata(fig, 'elec', elec); -setappdata(fig, 'transform', transform); -cb_redraw(hObject); - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -function cb_close(hObject, eventdata, handles) -% make the current transformation permanent and subsequently allow deleting the figure -cb_apply(gca); -% get the updated electrode from the figure -fig = hObject; -% hmmm, this is ugly -global norm -norm = getappdata(fig, 'elec'); -norm.m = getappdata(fig, 'transform'); -set(fig, 'CloseRequestFcn', @delete); -delete(fig); diff --git a/external/fieldtrip/ft_freqanalysis.m b/external/fieldtrip/ft_freqanalysis.m index e3dc2d5c..e346969d 100644 --- a/external/fieldtrip/ft_freqanalysis.m +++ b/external/fieldtrip/ft_freqanalysis.m @@ -11,99 +11,96 @@ % depends on the type of computation that you want to perform. % % The configuration should contain: -% cfg.method = different methods of calculating the spectra -% 'mtmfft', analyses an entire spectrum for the entire data -% length, implements multitaper frequency transformation -% 'mtmconvol', implements multitaper time-frequency -% transformation based on multiplication in the -% frequency domain. -% 'wavelet', implements wavelet time frequency -% transformation (using Morlet wavelets) based on -% multiplication in the frequency domain. -% 'tfr', implements wavelet time frequency -% transformation (using Morlet wavelets) based on -% convolution in the time domain. -% 'mvar', does a fourier transform on the coefficients -% of an estimated multivariate autoregressive model, -% obtained with FT_MVARANALYSIS. In this case, the -% output will contain a spectral transfer matrix, -% the cross-spectral density matrix, and the -% covariance matrix of the innovatio noise. -% cfg.output = 'pow' return the power-spectra -% 'powandcsd' return the power and the cross-spectra -% 'fourier' return the complex Fourier-spectra -% cfg.channel = Nx1 cell-array with selection of channels (default = 'all'), -% see FT_CHANNELSELECTION for details -% cfg.channelcmb = Mx2 cell-array with selection of channel pairs (default = {'all' 'all'}), -% see FT_CHANNELCOMBINATION for details -% cfg.trials = 'all' or a selection given as a 1xN vector (default = 'all') -% cfg.keeptrials = 'yes' or 'no', return individual trials or average (default = 'no') -% cfg.keeptapers = 'yes' or 'no', return individual tapers or average (default = 'no') -% cfg.pad = number, 'nextpow2', or 'maxperlen' (default), length -% in seconds to which the data can be padded out. The -% padding will determine your spectral resolution. If you -% want to compare spectra from data pieces of different -% lengths, you should use the same cfg.pad for both, in -% order to spectrally interpolate them to the same -% spectral resolution. The new option 'nextpow2' rounds -% the maximum trial length up to the next power of 2. By -% using that amount of padding, the FFT can be computed -% more efficiently in case 'maxperlen' has a large prime -% factor sum. +% cfg.method = different methods of calculating the spectra +% 'mtmfft', analyses an entire spectrum for the entire data +% length, implements multitaper frequency transformation +% 'mtmconvol', implements multitaper time-frequency +% transformation based on multiplication in the +% frequency domain. +% 'wavelet', implements wavelet time frequency +% transformation (using Morlet wavelets) based on +% multiplication in the frequency domain. +% 'tfr', implements wavelet time frequency +% transformation (using Morlet wavelets) based on +% convolution in the time domain. +% 'mvar', does a fourier transform on the coefficients +% of an estimated multivariate autoregressive model, +% obtained with FT_MVARANALYSIS. In this case, the +% output will contain a spectral transfer matrix, +% the cross-spectral density matrix, and the +% covariance matrix of the innovatio noise. +% cfg.output = 'pow' return the power-spectra +% 'powandcsd' return the power and the cross-spectra +% 'fourier' return the complex Fourier-spectra +% cfg.channel = Nx1 cell-array with selection of channels (default = 'all'), +% see FT_CHANNELSELECTION for details +% cfg.channelcmb = Mx2 cell-array with selection of channel pairs (default = {'all' 'all'}), +% see FT_CHANNELCOMBINATION for details +% cfg.trials = 'all' or a selection given as a 1xN vector (default = 'all') +% cfg.keeptrials = 'yes' or 'no', return individual trials or average (default = 'no') +% cfg.keeptapers = 'yes' or 'no', return individual tapers or average (default = 'no') +% cfg.pad = number, 'nextpow2', or 'maxperlen' (default), length +% in seconds to which the data can be padded out. The +% padding will determine your spectral resolution. If you +% want to compare spectra from data pieces of different +% lengths, you should use the same cfg.pad for both, in +% order to spectrally interpolate them to the same +% spectral resolution. The new option 'nextpow2' rounds +% the maximum trial length up to the next power of 2. By +% using that amount of padding, the FFT can be computed +% more efficiently in case 'maxperlen' has a large prime +% factor sum. % cfg.padtype = string, type of padding (default 'zero', see % ft_preproc_padding) % cfg.polyremoval = number (default = 0), specifying the order of the -% polynome which is fitted and subtracted from the time -% domain data prior to the spectral analysis. For -% example, a value of 1 corresponds to a linear trend. -% The default is a mean subtraction, thus a value of 0. -% If no removal is requested, specify -1. +% polynome which is fitted and subtracted from the time +% domain data prior to the spectral analysis. For +% example, a value of 1 corresponds to a linear trend. +% The default is a mean subtraction, thus a value of 0. +% If no removal is requested, specify -1. % see FT_PREPROC_POLYREMOVAL for details % % -% METHOD SPECIFIC OPTIONS AND DESCRIPTIONS +% METHOD SPECIFIC OPTIONS AND DESCRIPTIONS % -% MTMFFT -% MTMFFT performs frequency analysis on any time series -% trial data using the 'multitaper method' (MTM) based on discrete -% prolate spheroidal sequences (Slepian sequences) as tapers. -% Alternatively, you can use conventional tapers (e.g. Hanning). +% MTMFFT performs frequency analysis on any time series trial data using a +% conventional single taper (e.g. Hanning) or using the multiple tapers based on +% discrete prolate spheroidal sequences (DPSS), also known as the Slepian +% sequence. +% cfg.taper = 'dpss', 'hanning' or many others, see WINDOW (default = 'dpss') +% For cfg.output='powandcsd', you should specify the channel combinations +% between which to compute the cross-spectra as cfg.channelcmb. Otherwise +% you should specify only the channels in cfg.channel. % cfg.foilim = [begin end], frequency band of interest % OR % cfg.foi = vector 1 x numfoi, frequencies of interest % cfg.tapsmofrq = number, the amount of spectral smoothing through % multi-tapering. Note that 4 Hz smoothing means % plus-minus 4 Hz, i.e. a 8 Hz smoothing box. -% cfg.taper = 'dpss', 'hanning' or many others, see WINDOW (default = 'dpss') -% For cfg.output='powandcsd', you should specify the channel combinations -% between which to compute the cross-spectra as cfg.channelcmb. Otherwise -% you should specify only the channels in cfg.channel. % -% MTMCONVOL -% MTMCONVOL performs time-frequency analysis on any time series trial -% data using the 'multitaper method' (MTM) based on Slepian sequences as -% tapers. Alternatively, you can use conventional tapers (e.g. Hanning). +% MTMCONVOL performs time-frequency analysis on any time series trial data using +% the 'multitaper method' (MTM) based on Slepian sequences as tapers. +% Alternatively, you can use conventional tapers (e.g. Hanning). % cfg.tapsmofrq = vector 1 x numfoi, the amount of spectral smoothing -% through multi-tapering. Note that 4 Hz smoothing means -% plus-minus 4 Hz, i.e. a 8 Hz smoothing box. -% cfg.foi = vector 1 x numfoi, frequencies of interest -% cfg.taper = 'dpss', 'hanning' or many others, see WINDOW (default = 'dpss') -% For cfg.output='powandcsd', you should specify the channel combinations -% between which to compute the cross-spectra as cfg.channelcmb. Otherwise -% you should specify only the channels in cfg.channel. -% cfg.t_ftimwin = vector 1 x numfoi, length of time window (in seconds) -% cfg.toi = vector 1 x numtoi, the times on which the analysis -% windows should be centered (in seconds), or a string -% such as '50%' or 'all' (default). Both string options -% use all timepoints available in the data, but 'all' -% centers a spectral estimate on each sample, whereas -% the percentage specifies the degree of overlap between -% the shortest time windows from cfg.t_ftimwin. +% through multi-tapering. Note that 4 Hz smoothing means +% plus-minus 4 Hz, i.e. a 8 Hz smoothing box. +% cfg.foi = vector 1 x numfoi, frequencies of interest +% cfg.taper = 'dpss', 'hanning' or many others, see WINDOW (default = 'dpss') +% For cfg.output='powandcsd', you should specify the channel combinations +% between which to compute the cross-spectra as cfg.channelcmb. Otherwise +% you should specify only the channels in cfg.channel. +% cfg.t_ftimwin = vector 1 x numfoi, length of time window (in seconds) +% cfg.toi = vector 1 x numtoi, the times on which the analysis +% windows should be centered (in seconds), or a string +% such as '50%' or 'all' (default). Both string options +% use all timepoints available in the data, but 'all' +% centers a spectral estimate on each sample, whereas +% the percentage specifies the degree of overlap between +% the shortest time windows from cfg.t_ftimwin. % -% WAVELET -% WAVELET performs time-frequency analysis on any time series trial data -% using the 'wavelet method' based on Morlet wavelets. Using mulitplication -% in the frequency domain instead of convolution in the time domain. +% WAVELET performs time-frequency analysis on any time series trial data using the +% 'wavelet method' based on Morlet wavelets. Using mulitplication in the frequency +% domain instead of convolution in the time domain. % cfg.foi = vector 1 x numfoi, frequencies of interest % OR % cfg.foilim = [begin end], frequency band of interest @@ -120,10 +117,9 @@ % defined as: st = 1/(2*pi*sf) % % -% TFR -% TFR performs time-frequency analysis on any time series trial data -% using the 'wavelet method' based on Morlet wavelets. Using convolution -% in the time domain instead of multiplication in the frequency domain. +% TFR performs time-frequency analysis on any time series trial data using the +% 'wavelet method' based on Morlet wavelets. Using convolution in the time domain +% instead of multiplication in the frequency domain. % cfg.foi = vector 1 x numfoi, frequencies of interest % OR % cfg.foilim = [begin end], frequency band of interest @@ -133,7 +129,6 @@ % be choosen >= 3; (default = 3) % % -% % To facilitate data-handling and distributed computing you can use % cfg.inputfile = ... % cfg.outputfile = ... @@ -142,7 +137,7 @@ % file. These mat files should contain only a single variable, % corresponding with the input/output structure. % -% See also +% See also FT_FREQSTATISTICS, FT_FREQDESCRIPTIVES, FT_CONNECTIVITYANALYSIS % Guidelines for use in an analysis pipeline: % after FT_FREQANALYSIS you will have frequency or time-frequency @@ -227,41 +222,39 @@ cfg = ft_checkconfig(cfg, 'forbidden', {'latency'}); % see bug 1376 and 1076 cfg = ft_checkconfig(cfg, 'renamedval', {'method', 'wltconvol', 'wavelet'}); -% select trials of interest -tmpcfg = []; -tmpcfg.trials = cfg.trials; -tmpcfg.channel = cfg.channel; +% select channels and trials of interest, by default this will select all channels and trials +tmpcfg = keepfields(cfg, {'trials', 'channel', 'showcallinfo'}); data = ft_selectdata(tmpcfg, data); % restore the provenance information [cfg, data] = rollback_provenance(cfg, data); % some proper error handling if isfield(data, 'trial') && numel(data.trial)==0 - error('no trials were selected'); % this does not apply for MVAR data + ft_error('no trials were selected'); % this does not apply for MVAR data end if numel(data.label)==0 - error('no channels were selected'); + ft_error('no channels were selected'); end % switch over method and do some of the method specfic checks and defaulting switch cfg.method - + case 'mtmconvol' cfg.taper = ft_getopt(cfg, 'taper', 'dpss'); if isequal(cfg.taper, 'dpss') && ~isfield(cfg, 'tapsmofrq') - error('you must specify a smoothing parameter with taper = dpss'); + ft_error('you must specify a smoothing parameter with taper = dpss'); end % check for foi above Nyquist - if isfield(cfg,'foi') + if isfield(cfg, 'foi') if any(cfg.foi > (data.fsample/2)) - error('frequencies in cfg.foi are above Nyquist') + ft_error('frequencies in cfg.foi are above Nyquist') end if isequal(cfg.taper, 'dpss') && not(isfield(cfg, 'tapsmofrq')) - error('you must specify a smoothing parameter with taper = dpss'); + ft_error('you must specify a smoothing parameter with taper = dpss'); end end - cfg = ft_checkconfig(cfg, 'required', {'toi','t_ftimwin'}); + cfg = ft_checkconfig(cfg, 'required', {'toi', 't_ftimwin'}); if ischar(cfg.toi) begtim = min(cellfun(@min,data.time)); endtim = max(cellfun(@max,data.time)); @@ -273,42 +266,42 @@ cfg.toi = linspace(begtim, endtim, round((endtim-begtim) ./ ... (overlap * min(cfg.t_ftimwin))) + 1); else - error('cfg.toi should be either a numeric vector or a string: can be ''all'' or a percentage (e.g., ''50%'')'); + ft_error('cfg.toi should be either a numeric vector or a string: can be ''all'' or a percentage (e.g., ''50%'')'); end end - + case 'mtmfft' cfg.taper = ft_getopt(cfg, 'taper', 'dpss'); if isequal(cfg.taper, 'dpss') && not(isfield(cfg, 'tapsmofrq')) - error('you must specify a smoothing parameter with taper = dpss'); + ft_error('you must specify a smoothing parameter with taper = dpss'); end % check for foi above Nyquist - if isfield(cfg,'foi') + if isfield(cfg, 'foi') if any(cfg.foi > (data.fsample/2)) - error('frequencies in cfg.foi are above Nyquist') + ft_error('frequencies in cfg.foi are above Nyquist') end end if isequal(cfg.taper, 'dpss') && not(isfield(cfg, 'tapsmofrq')) - error('you must specify a smoothing parameter with taper = dpss'); + ft_error('you must specify a smoothing parameter with taper = dpss'); end - + case 'wavelet' cfg.width = ft_getopt(cfg, 'width', 7); cfg.gwidth = ft_getopt(cfg, 'gwidth', 3); - + case 'tfr' cfg = ft_checkconfig(cfg, 'renamed', {'waveletwidth', 'width'}); cfg = ft_checkconfig(cfg, 'unused', {'downsample'}); cfg.width = ft_getopt(cfg, 'width', 7); cfg.gwidth = ft_getopt(cfg, 'gwidth', 3); - + case 'hilbert' - warning('method = hilbert requires user action to deal with filtering-artifacts') + ft_warning('method = hilbert requires user action to deal with filtering-artifacts') if ~isfield(cfg, 'filttype'), cfg.filttype = 'but'; end if ~isfield(cfg, 'filtorder'), cfg.filtorder = 4; end if ~isfield(cfg, 'filtdir'), cfg.filtdir = 'twopass'; end if ~isfield(cfg, 'width'), cfg.width = 1; end - + case 'mvar' if isfield(cfg, 'inputfile') freq = feval(@ft_freqanalysis_mvar,cfg); @@ -316,16 +309,18 @@ freq = feval(@ft_freqanalysis_mvar,cfg,data); end return - + + case 'neuvar' + cfg.order = ft_getopt(cfg, 'order', 1); % order of differentiation + otherwise - error('specified cfg.method is not supported') + ft_error('specified cfg.method is not supported') end % set all the defaults cfg.pad = ft_getopt(cfg, 'pad', []); if isempty(cfg.pad) - warning('Default cfg.pad = ''maxperlen'' can run slowly.') - disp('Consider using cfg.pad = ''nextpow2'' for more efficient FFT computation.') + ft_notice('Default cfg.pad=''maxperlen'' can run slowly. Consider using cfg.pad=''nextpow2'' for more efficient FFT computation.') cfg.pad = 'maxperlen'; end cfg.padtype = ft_getopt(cfg, 'padtype', 'zero'); @@ -343,8 +338,8 @@ if strcmp(cfg.output, 'fourier') cfg.keeptrials = ft_getopt(cfg, 'keeptrials', 'yes'); cfg.keeptapers = ft_getopt(cfg, 'keeptapers', 'yes'); - if strcmp(cfg.keeptrials, 'no') || strcmp(cfg.keeptapers, 'no'), - error('cfg.output = ''fourier'' requires cfg.keeptrials = ''yes'' and cfg.keeptapers = ''yes'''); + if strcmp(cfg.keeptrials, 'no') || strcmp(cfg.keeptapers, 'no') + ft_error('cfg.output = ''fourier'' requires cfg.keeptrials = ''yes'' and cfg.keeptapers = ''yes'''); end else cfg.keeptrials = ft_getopt(cfg, 'keeptrials', 'no'); @@ -352,36 +347,36 @@ end % set flags for keeping trials and/or tapers -if strcmp(cfg.keeptrials,'no') && strcmp(cfg.keeptapers,'no') +if strcmp(cfg.keeptrials, 'no') && strcmp(cfg.keeptapers, 'no') keeprpt = 1; -elseif strcmp(cfg.keeptrials,'yes') && strcmp(cfg.keeptapers,'no') +elseif strcmp(cfg.keeptrials, 'yes') && strcmp(cfg.keeptapers, 'no') keeprpt = 2; -elseif strcmp(cfg.keeptrials,'no') && strcmp(cfg.keeptapers,'yes') - error('There is currently no support for keeping tapers WITHOUT KEEPING TRIALS.'); -elseif strcmp(cfg.keeptrials,'yes') && strcmp(cfg.keeptapers,'yes') +elseif strcmp(cfg.keeptrials, 'no') && strcmp(cfg.keeptapers, 'yes') + ft_error('There is currently no support for keeping tapers WITHOUT KEEPING TRIALS.'); +elseif strcmp(cfg.keeptrials, 'yes') && strcmp(cfg.keeptapers, 'yes') keeprpt = 4; end -if strcmp(cfg.keeptrials,'yes') && strcmp(cfg.keeptapers,'yes') - if ~strcmp(cfg.output, 'fourier'), - error('Keeping trials AND tapers is only possible with fourier as the output.'); +if strcmp(cfg.keeptrials, 'yes') && strcmp(cfg.keeptapers, 'yes') + if ~strcmp(cfg.output, 'fourier') + ft_error('Keeping trials AND tapers is only possible with fourier as the output.'); end end % Set flags for output -if strcmp(cfg.output,'pow') +if strcmp(cfg.output, 'pow') powflg = 1; csdflg = 0; fftflg = 0; -elseif strcmp(cfg.output,'powandcsd') +elseif strcmp(cfg.output, 'powandcsd') powflg = 1; csdflg = 1; fftflg = 0; -elseif strcmp(cfg.output,'fourier') +elseif strcmp(cfg.output, 'fourier') powflg = 0; csdflg = 0; fftflg = 1; else - error('Unrecognized output required'); + ft_error('Unrecognized output required'); end % prepare channel(cmb) @@ -406,7 +401,7 @@ % determine the corresponding indices of all channel combinations [dummy,chancmbind(:,1)] = match_str(cfg.channelcmb(:,1), data.label); [dummy,chancmbind(:,2)] = match_str(cfg.channelcmb(:,2), data.label); - + nchancmb = size(chancmbind,1); chanind = unique([chanind(:); chancmbind(:)]); nchan = length(chanind); @@ -431,13 +426,13 @@ else padding = cfg.pad*data.fsample; if padding= baseline(1) & timeVec <= baseline(2)); +baselineTimes = false(size(baseline,1),numel(timeVec)); +for k = 1:size(baseline,1) + baselineTimes(k,:) = (timeVec >= baseline(k,1) & timeVec <= baseline(k,2)); +end -if length(size(data)) ~= 3, - error('time-frequency matrix should have three dimensions (chan,freq,time)'); +if length(size(data)) ~= 3 + ft_error('time-frequency matrix should have three dimensions (chan,freq,time)'); end % compute mean of time/frequency quantity in the baseline interval, % ignoring NaNs, and replicate this over time dimension -meanVals = repmat(nanmean(data(:,:,baselineTimes), 3), [1 1 size(data, 3)]); +if size(baselineTimes,1)==size(data,2) + % do frequency specific baseline + meanVals = nan+zeros(size(data)); + for k = 1:size(baselineTimes,1) + meanVals(:,k,:) = repmat(nanmean(data(:,k,baselineTimes(k,:)), 3), [1 1 size(data, 3)]); + end +else + meanVals = repmat(nanmean(data(:,:,baselineTimes), 3), [1 1 size(data, 3)]); +end if (strcmp(baselinetype, 'absolute')) data = data - meanVals; @@ -188,5 +206,5 @@ elseif (strcmp(baselinetype, 'db')) data = 10*log10(data ./ meanVals); else - error('unsupported method for baseline normalization: %s', baselinetype); + ft_error('unsupported method for baseline normalization: %s', baselinetype); end diff --git a/external/fieldtrip/ft_freqcomparison.m b/external/fieldtrip/ft_freqcomparison.m deleted file mode 100644 index 2695ae1f..00000000 --- a/external/fieldtrip/ft_freqcomparison.m +++ /dev/null @@ -1,137 +0,0 @@ -function [freq] = ft_freqcomparison(cfg, varargin) - -% FT_FREQCOMPARISON is deprecated, please use FT_MATH instead. -% -% See also FT_MATH, FT_FREQBASELINE - -% Copyright (C) 2010-2011, Arjen Stolk, DCCN, Donders Institute -% -% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org -% for the documentation and details. -% -% FieldTrip is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. -% -% FieldTrip is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with FieldTrip. If not, see . -% -% $Id$ - -% DEPRECATED by roboos on 30 July 2013 -% see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2222 for more details -% support for this functionality can be removed at the end of 2013 -warning('FT_FREQCOMPARISON is deprecated, please use FT_MATH instead.') - -% these are used by the ft_preamble/ft_postamble function and scripts -ft_revision = '$Id$'; -ft_nargin = nargin; -ft_nargout = nargout; - -% do the general setup of the function -ft_defaults -ft_preamble init -ft_preamble debug -ft_preamble provenance varargin -ft_preamble trackconfig - -% the ft_abort variable is set to true or false in ft_preamble_init -if ft_abort - return -end - -% nargin check -if length(varargin)~=2 - error('two conditions required as input'); -end - -% check if the input data is valid for this function -varargin{1} = ft_checkdata(varargin{1}, 'datatype', 'freq', 'feedback', 'yes'); -varargin{2} = ft_checkdata(varargin{2}, 'datatype', 'freq', 'feedback', 'yes'); - -% set the defaults -if ~isfield(cfg, 'comparisontype'), cfg.comparisontype = 'absolute'; end - -% we have to ensure that we don't end up with an inconsistent dataset -% remove cross-spectral densities since coherence cannot be computed any more -if isfield(varargin{1}, 'crsspctrm') - varargin{1} = rmfield(varargin{1}, 'crsspctrm'); -end -if isfield(varargin{1}, 'cohspctrmsem') - varargin{1} = rmfield(varargin{1}, 'cohspctrmsem'); -end -if isfield(varargin{1}, 'powspctrmsem') - varargin{1} = rmfield(varargin{1}, 'powspctrmsem'); -end -if isfield(varargin{2}, 'crsspctrm') - varargin{2} = rmfield(varargin{2}, 'crsspctrm'); -end -if isfield(varargin{2}, 'cohspctrmsem') - varargin{2} = rmfield(varargin{2}, 'cohspctrmsem'); -end -if isfield(varargin{2}, 'powspctrmsem') - varargin{2} = rmfield(varargin{2}, 'powspctrmsem'); -end - -% initiate output variable -freq = varargin{1}; - -if strcmp(varargin{1}.dimord, 'rpt_chan_freq') || strcmp(varargin{1}.dimord, 'subj_chan_freq') - % frequency comparison for multiple trials/subjects - - if size(varargin{1}.powspctrm,3) ~= size(varargin{2}.powspctrm,3) - error('input conditions have different sizes'); - end - - if strcmp(cfg.comparisontype, 'absolute') - for j = 1:size(varargin{2}.powspctrm,1) - freq.powspctrm(j,:,:) = varargin{2}.powspctrm(j,:,:) - mean(varargin{1}.powspctrm,1); - end - elseif strcmp(cfg.comparisontype, 'relchange') - for j = 1:size(varargin{2}.powspctrm,1) - freq.powspctrm(j,:,:) = (varargin{2}.powspctrm(j,:,:) - mean(varargin{1}.powspctrm,1)) ./ mean(varargin{1}.powspctrm,1); - end - elseif strcmp(cfg.comparisontype, 'relative') - for j = 1:size(varargin{2}.powspctrm,1) - freq.powspctrm(j,:,:) = varargin{2}.powspctrm(j,:,:) ./ mean(varargin{1}.powspctrm,1); - end - else - error('unsupported comparisontype'); - end - -elseif strcmp(varargin{1}.dimord, 'chan_freq') || strcmp(varargin{1}.dimord, 'chan_freq_time') - % frequency comparison for averages - - if size(varargin{1}.powspctrm,2) ~= size(varargin{2}.powspctrm,2) - error('input conditions have different sizes'); - end - - if strcmp(cfg.comparisontype, 'absolute') - freq.powspctrm = varargin{2}.powspctrm - varargin{1}.powspctrm; - elseif strcmp(cfg.comparisontype, 'relchange') - freq.powspctrm = (varargin{2}.powspctrm - varargin{1}.powspctrm) ./ varargin{1}.powspctrm; - elseif strcmp(cfg.comparisontype, 'relative') - freq.powspctrm = varargin{2}.powspctrm ./ varargin{1}.powspctrm; - else - error('unsupported comparisontype'); - end - -else - error('unsupported dimord') -end - -% user update -fprintf('performing %s comparison \n', cfg.comparisontype); - -% do the general cleanup and bookkeeping at the end of the function -ft_postamble debug -ft_postamble trackconfig -ft_postamble previous varargin -ft_postamble provenance freq -ft_postamble history freq diff --git a/external/fieldtrip/ft_freqdescriptives.m b/external/fieldtrip/ft_freqdescriptives.m index c0ce1fe2..edd555c9 100644 --- a/external/fieldtrip/ft_freqdescriptives.m +++ b/external/fieldtrip/ft_freqdescriptives.m @@ -45,8 +45,8 @@ % cfg.previous % cfg.version -% Copyright (C) 2004-2006, Pascal Fries & Jan-Mathijs Schoffelen, F.C. Donders Centre -% Copyright (C) 2010, Jan-Mathijs Schoffelen, F.C. Donders Centre +% Copyright (C) 2004-2006, Pascal Fries & Jan-Mathijs Schoffelen +% Copyright (C) 2010, Jan-Mathijs Schoffelen % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -109,7 +109,7 @@ cfg.keeptrials = ft_getopt(cfg, 'keeptrials', 'no'); % check if the input data is valid for this function -freq = ft_checkdata(freq, 'datatype', {'freq', 'freqmvar'}, 'feedback', 'yes'); +freq = ft_checkdata(freq, 'datatype', {'freq', 'freqmvar'}, 'feedback', cfg.feedback); % get data in the correct representation, it should only have power freq = ft_checkdata(freq, 'cmbrepresentation', 'sparsewithpow', 'channelcmb', {}); @@ -122,18 +122,18 @@ keepflg = strcmp(cfg.keeptrials, 'yes'); % check sensibility of configuration -if sum([varflg keepflg]>1), error('you should specify only one of cfg.keeptrials or cfg.variance'); end -if ~hasrpt && (varflg || keepflg), error('a variance-estimate or a single trial estimate without repeated observations in the input is not possible'); end -if ~hasrpt && ~strcmp(cfg.trials, 'all'), error('trial selection requires input data with repeated observations'); end +if sum([varflg keepflg]>1), ft_error('you should specify only one of cfg.keeptrials or cfg.variance'); end +if ~hasrpt && (varflg || keepflg), ft_error('a variance-estimate or a single trial estimate without repeated observations in the input is not possible'); end +if ~hasrpt && ~strcmp(cfg.trials, 'all'), ft_error('trial selection requires input data with repeated observations'); end if ~varflg && jckflg, varflg = 1; end % select data of interest -tmpcfg = keepfields(cfg, {'trials', 'channel', 'latency', 'frequency'}); +tmpcfg = keepfields(cfg, {'trials', 'channel', 'latency', 'frequency', 'showcallinfo'}); freq = ft_selectdata(tmpcfg, freq); % restore the provenance information [cfg, freq] = rollback_provenance(cfg, freq); -if jckflg, +if jckflg % the data is 'sparsewithpow', so it contains a powspctrm and optionally a crsspctrm % the checking of a 'rpt' is handled above, so it can be assumed that the 'rpt' is the % first dimension @@ -148,7 +148,7 @@ end end -if varflg, +if varflg siz = [size(freq.powspctrm) 1]; outsum = zeros(siz(2:end)); outssq = zeros(siz(2:end)); @@ -164,7 +164,7 @@ end ft_progress('close'); - if jckflg, + if jckflg bias = (n-1).^2; else bias = 1; @@ -184,7 +184,7 @@ powspctrm = freq.powspctrm; end -if hasrpt && ~keepflg, +if hasrpt && ~keepflg dimtok = tokenize(freq.dimord, '_'); newdimord = dimtok{2}; for k = 3:numel(dimtok) @@ -199,12 +199,12 @@ output.dimord = newdimord; output.freq = freq.freq; output.label = freq.label; -if isfield(freq, 'time'), output.time = freq.time; end; -if isfield(freq, 'grad'), output.grad = freq.grad; end; -if isfield(freq, 'cumtapcnt'), output.cumtapcnt = freq.cumtapcnt; end; -if isfield(freq, 'cumsumcnt'), output.cumsumcnt = freq.cumsumcnt; end; output.powspctrm = powspctrm; -if exist('powspctrmsem', 'var'), output.powspctrmsem = powspctrmsem; end; +if isfield(freq, 'time'), output.time = freq.time; end +if isfield(freq, 'grad'), output.grad = freq.grad; end +if isfield(freq, 'cumtapcnt'), output.cumtapcnt = freq.cumtapcnt; end +if isfield(freq, 'cumsumcnt'), output.cumsumcnt = freq.cumsumcnt; end +if exist('powspctrmsem', 'var'), output.powspctrmsem = powspctrmsem; end % remember the trialinfo if strcmp(cfg.keeptrials, 'yes') && isfield(freq, 'trialinfo') diff --git a/external/fieldtrip/ft_freqgrandaverage.m b/external/fieldtrip/ft_freqgrandaverage.m index 33f8510d..c1534405 100644 --- a/external/fieldtrip/ft_freqgrandaverage.m +++ b/external/fieldtrip/ft_freqgrandaverage.m @@ -85,7 +85,7 @@ if isempty(cfg.parameter) && isfield(varargin{1}, 'powspctrm') cfg.parameter = 'powspctrm'; elseif isempty(cfg.parameter) - error('you should specify a valid parameter to average'); + ft_error('you should specify a valid parameter to average'); end if ischar(cfg.parameter) @@ -101,10 +101,10 @@ % check whether the input data is suitable if hasrpt - error('the input data of each subject should be an average, use FT_FREQDESCRIPTIVES first'); + ft_error('the input data of each subject should be an average, use FT_FREQDESCRIPTIVES first'); end if hastap - error('multiple tapers in the input are not supported'); + ft_error('multiple tapers in the input are not supported'); end if ischar(cfg.foilim) && strcmp(cfg.foilim, 'all') @@ -144,7 +144,7 @@ % pick the selections for i=1:Nsubj if ~isfield(varargin{i}, cfg.parameter{k}) - error('the field %s is not present in data structure %d', cfg.parameter{k}, i); + ft_error('the field %s is not present in data structure %d', cfg.parameter{k}, i); end [dum, chansel] = match_str(cfg.channel, varargin{i}.label); varargin{i}.label = varargin{i}.label(chansel); @@ -168,7 +168,7 @@ case {'rpt_chan_freq_time' 'rpttap_chan_freq_time' 'subj_chan_freq_time'} varargin{i}.(cfg.parameter{k}) = varargin{i}.(cfg.parameter{k})(:,chansel,freqsel,timesel); otherwise - error('unsupported dimord'); + ft_error('unsupported dimord'); end end % for i = subject end % for k = parameter @@ -182,11 +182,11 @@ % give some feedback on the screen if strcmp(cfg.keepindividual, 'no') for k=1:numel(cfg.parameter) - fprintf('computing average %s over %d subjects\n', cfg.parameter{k}, Nsubj); + ft_info('computing average %s over %d subjects\n', cfg.parameter{k}, Nsubj); end else for k=1:numel(cfg.parameter) - fprintf('not computing average, but keeping individual %s for %d subjects\n', cfg.parameter{k}, Nsubj); + ft_info('not computing average, but keeping individual %s for %d subjects\n', cfg.parameter{k}, Nsubj); end end @@ -217,10 +217,10 @@ grandavg.labelcmb = varargin{1}.labelcmb; end if isfield(varargin{1}, 'grad') - warning('discarding gradiometer information because it cannot be averaged'); + ft_warning('discarding gradiometer information because it cannot be averaged'); end if isfield(varargin{1}, 'elec') - warning('discarding electrode information because it cannot be averaged'); + ft_warning('discarding electrode information because it cannot be averaged'); end if strcmp(cfg.keepindividual, 'yes') grandavg.dimord = ['subj_',varargin{1}.dimord]; diff --git a/external/fieldtrip/ft_freqinterpolate.m b/external/fieldtrip/ft_freqinterpolate.m index 0efa22a7..ea3037ef 100644 --- a/external/fieldtrip/ft_freqinterpolate.m +++ b/external/fieldtrip/ft_freqinterpolate.m @@ -62,9 +62,10 @@ % check if the input data is valid for this function freq = ft_checkdata(freq, 'datatype', 'freq', 'feedback', 'yes'); -% set the default values -if ~isfield(cfg, 'method'), cfg.method = 'nan'; end -if ~isfield(cfg, 'foilim'), cfg.foilim = [49 51; 99 101; 149 151]; end +% set the defaults +cfg.method = ft_getopt(cfg, 'method', 'nan'); +cfg.foilim = ft_getopt(cfg, 'foilim', [49 51; 99 101; 149 151]); + for i = 1:size(cfg.foilim,1) % determine the exact frequency bins to interpolate @@ -85,14 +86,14 @@ case 'rpt_chan_freq_time' freq.powspctrm(:,:,peakbeg:peakend,:) = nan; otherwise - error('unsupported dimord'); + ft_error('unsupported dimord'); end % switch elseif strcmp(cfg.method, 'linear') - error('not yet implemented'); + ft_error('not yet implemented'); else - error('unsupported method'); + ft_error('unsupported method'); end end % for each frequency range diff --git a/external/fieldtrip/ft_freqsimulation.m b/external/fieldtrip/ft_freqsimulation.m index 3ff5e785..65488f24 100644 --- a/external/fieldtrip/ft_freqsimulation.m +++ b/external/fieldtrip/ft_freqsimulation.m @@ -132,7 +132,7 @@ % See also FT_FREQANALYSIS, FT_TIMELOCKSIMULATION, FT_DIPOLESIMULATION, % FT_CONNECTIVITYSIMULATION -% Copyright (C) 2007-2008, Ingrid Nieuwenhuis & Robert Oostenveld, F.C. Donders Centre +% Copyright (C) 2007-2008, Ingrid Nieuwenhuis & Robert Oostenveld % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -190,7 +190,7 @@ cfg.numtrl = length(cfg.time); end -if strcmp(cfg.method,'superimposed') +if strcmp(cfg.method, 'superimposed') if ~isfield(cfg, 's1'), cfg.s1 = []; end if ~isfield(cfg.s1, 'freq'), cfg.s1.freq = 10; end if ~isfield(cfg.s1, 'phase'), cfg.s1.phase = 0; end @@ -205,7 +205,7 @@ if ~isfield(cfg.s3, 'ampl'), cfg.s3.ampl = 0; end end -if strcmp(cfg.method,'broadband') +if strcmp(cfg.method, 'broadband') if ~isfield(cfg, 'n1'), cfg.n1 = []; end if ~isfield(cfg.n1, 'ampl'), cfg.n1.ampl = 1; end if ~isfield(cfg.n1, 'bpfreq'), cfg.n1.bpfreq = [30 50]; end @@ -214,7 +214,7 @@ if ~isfield(cfg.n2, 'bpfreq'), cfg.n2.bpfreq = [80 120]; end end -if strcmp(cfg.method,'phalow_amphigh') +if strcmp(cfg.method, 'phalow_amphigh') if ~isfield(cfg, 's1'), cfg.s1 = []; end if ~isfield(cfg.s1, 'freq'), cfg.s1.freq = 3; end if ~isfield(cfg.s1, 'phase'), cfg.s1.phase = -1*pi; end @@ -229,7 +229,7 @@ if ~isfield(cfg.s3, 'ampl'), cfg.s3.ampl = cfg.s1.ampl; end end -if strcmp(cfg.method,'amplow_amphigh') +if strcmp(cfg.method, 'amplow_amphigh') if ~isfield(cfg, 's1'), cfg.s1 = []; end if ~isfield(cfg.s1, 'freq'), cfg.s1.freq = 6; end if ~isfield(cfg.s1, 'phase'), cfg.s1.phase = 0; end @@ -248,7 +248,7 @@ if ~isfield(cfg.s3, 'ampl'), cfg.s3.ampl = cfg.s4.ampl; end end -if strcmp(cfg.method,'phalow_freqhigh') +if strcmp(cfg.method, 'phalow_freqhigh') if ~isfield(cfg, 's1'), cfg.s1 = []; end if ~isfield(cfg.s1, 'freq'), cfg.s1.freq = 20; end if ~isfield(cfg.s1, 'phase'), cfg.s1.phase = 0; end @@ -259,7 +259,7 @@ if ~isfield(cfg.s2, 'ampl'), cfg.s2.ampl = pi; end end -if strcmp(cfg.method,'asymmetric') +if strcmp(cfg.method, 'asymmetric') if ~isfield(cfg, 's1'), cfg.s1 = []; end if ~isfield(cfg.s1, 'freq'), cfg.s1.freq = 6; end if ~isfield(cfg.s1, 'phase'), cfg.s1.phase = 0; end @@ -271,7 +271,6 @@ if ~isfield(cfg, 'noise'), cfg.noise = []; end if ~isfield(cfg.noise, 'ampl'), cfg.noise.ampl = 1; end - if ~isempty(cfg.time) % use the user-supplied time vectors timevec = cfg.time; @@ -282,24 +281,29 @@ end end +% give the user some feedback +ft_info('simulating data using %s method', cfg.method); +ft_debug('using %f as samping frequency', cfg.fsample); +ft_debug('using %d trials of %f seconds long', cfg.numtrl, cfg.trllen); -%%%%%%% SUPERIMPOSED, SIMPLY ADD THE SIGNALS %%%%%%%%% -if strcmp(cfg.method,'superimposed') +%%%%%%% SUPERIMPOSED, SIMPLY ADD THE SIGNALS %%%%%%%%% +if strcmp(cfg.method, 'superimposed') + % make data for iTr = 1 : length(timevec) if ischar(cfg.s1.phase); phase_s1 = rand * 2 *pi; else phase_s1 = cfg.s1.phase; end if ischar(cfg.s2.phase); phase_s2 = rand * 2 *pi; else phase_s2 = cfg.s2.phase; end if ischar(cfg.s3.phase); phase_s3 = rand * 2 *pi; else phase_s3 = cfg.s3.phase; end - + s1 = cfg.s1.ampl*cos(2*pi*cfg.s1.freq*timevec{iTr} + phase_s1); s2 = cfg.s2.ampl*cos(2*pi*cfg.s2.freq*timevec{iTr} + phase_s2); s3 = cfg.s3.ampl*cos(2*pi*cfg.s3.freq*timevec{iTr} + phase_s3); noise = cfg.noise.ampl*randn(size(timevec{iTr})); mix = s1 + s2 + s3 + noise; - + data.trial{iTr}(1,:) = mix; - if strcmp(cfg.output,'all') + if strcmp(cfg.output, 'all') data.trial{iTr}(2,:) = s1; data.trial{iTr}(3,:) = s2; data.trial{iTr}(4,:) = s3; @@ -307,63 +311,63 @@ end data.time{iTr} = timevec{iTr}; end % for iTr - + data.label{1} = 'mix'; - if strcmp(cfg.output,'all') + if strcmp(cfg.output, 'all') data.label{2} = 's1'; data.label{3} = 's2'; data.label{4} = 's3'; data.label{5} = 'noise'; end data.fsample = cfg.fsample; - + %%%%%%% SUPERIMPOSED BROADBAND SIGNAL %%%%%%%%% -elseif strcmp(cfg.method,'broadband') - +elseif strcmp(cfg.method, 'broadband') + % make data for iTr = 1 : length(timevec) n1 = ft_preproc_bandpassfilter(cfg.n1.ampl*randn(size(timevec{iTr})), cfg.fsample, cfg.n1.bpfreq); n2 = ft_preproc_bandpassfilter(cfg.n2.ampl*randn(size(timevec{iTr})), cfg.fsample, cfg.n2.bpfreq); noise = cfg.noise.ampl*randn(size(timevec{iTr})); mix = n1 + n2 + noise; - + data.trial{iTr}(1,:) = mix; - if strcmp(cfg.output,'all') + if strcmp(cfg.output, 'all') data.trial{iTr}(2,:) = n1; data.trial{iTr}(3,:) = n2; data.trial{iTr}(4,:) = noise; end data.time{iTr} = timevec{iTr}; end % for iTr - + data.label{1} = 'mix'; - if strcmp(cfg.output,'all') + if strcmp(cfg.output, 'all') data.label{2} = 'n1'; data.label{3} = 'n2'; data.label{4} = 'noise'; end data.fsample = cfg.fsample; - + %%%%%%% PHASE TO AMPLITUDE CORRELATION %%%%%%%%% -elseif strcmp(cfg.method,'phalow_amphigh') - +elseif strcmp(cfg.method, 'phalow_amphigh') + % sanity checks if cfg.s2.freq < cfg.s1.freq - error('with method is phalow_amphigh freq s2 should be higher than freq s1') + ft_error('with method is phalow_amphigh freq s2 should be higher than freq s1') end if cfg.s2.freq > cfg.fsample/2 - error('you cannot have a frequency higher than the sample frequency/2') + ft_error('you cannot have a frequency higher than the sample frequency/2') end if cfg.s3.freq ~= 0 || cfg.s3.phase ~= 0 - warning('for method phalow_amphigh s3 is DC and therefore expect freq and phase to be zero but they are not') + ft_warning('for method phalow_amphigh s3 is DC and therefore expect freq and phase to be zero but they are not') end if cfg.s3.ampl < cfg.s1.ampl - warning('expect amplitude s3 (=DC) not to be smaller than amplitude s1 (=low frequency)') + ft_warning('expect amplitude s3 (=DC) not to be smaller than amplitude s1 (=low frequency)') end - + % make data for iTr = 1 : length(timevec) - + if ischar(cfg.s1.phase); phase_AM = rand * 2 *pi; else phase_AM = cfg.s1.phase; end if ischar(cfg.s2.phase); phase_high = rand * 2 *pi; else phase_high = cfg.s2.phase; end if ischar(cfg.s3.phase); phase_DC = rand * 2 *pi; else phase_DC = cfg.s3.phase; end @@ -372,9 +376,9 @@ DC = cfg.s3.ampl*cos(2*pi*0*timevec{iTr} + phase_DC); noise = cfg.noise.ampl*randn(size(timevec{iTr})); mix = ((AM + DC) .* high) + noise; - + data.trial{iTr}(1,:) = mix; - if strcmp(cfg.output,'all') + if strcmp(cfg.output, 'all') data.trial{iTr}(2,:) = AM; data.trial{iTr}(3,:) = high; data.trial{iTr}(4,:) = DC; @@ -382,36 +386,36 @@ end data.time{iTr} = timevec{iTr}; end % for iTr - + data.label{1} = 'mix'; - if strcmp(cfg.output,'all') + if strcmp(cfg.output, 'all') data.label{2} = 's1 (AM)'; data.label{3} = 's2 (high)'; data.label{4} = 's3 (DC)'; data.label{5} = 'noise'; end data.fsample = cfg.fsample; - + %%%%%%% POWER TO POWER CORRELATION %%%%%%%%% -elseif strcmp(cfg.method,'amplow_amphigh') - +elseif strcmp(cfg.method, 'amplow_amphigh') + % sanity checks if cfg.s2.freq < cfg.s1.freq || cfg.s1.freq < cfg.s4.freq - error('with method is powlow_powhigh freq s4 < s1 < s2') + ft_error('with method is powlow_powhigh freq s4 < s1 < s2') end if cfg.s2.freq > cfg.fsample/2 - error('you cannot have a frequency higher than the sample frequency/2') + ft_error('you cannot have a frequency higher than the sample frequency/2') end if cfg.s3.freq ~= 0 || cfg.s3.phase ~= 0 - warning('for method powlow_powhigh s3 is DC and therefore expect freq and phase to be zero but they are not') + ft_warning('for method powlow_powhigh s3 is DC and therefore expect freq and phase to be zero but they are not') end if cfg.s3.ampl < cfg.s4.ampl - warning('expect amplitude s3 (=DC) not to be smaller than amplitude s4 (= AM frequency)') + ft_warning('expect amplitude s3 (=DC) not to be smaller than amplitude s4 (= AM frequency)') end - + % make data for iTr = 1 : length(timevec) - + if ischar(cfg.s1.phase); phase_low = rand * 2 *pi; else phase_low = cfg.s1.phase; end if ischar(cfg.s2.phase); phase_high = rand * 2 *pi; else phase_high = cfg.s2.phase; end if ischar(cfg.s3.phase); phase_DC = rand * 2 *pi; else phase_DC = cfg.s3.phase; end @@ -424,9 +428,9 @@ lowmix = ((AM + DC) .* low); highmix = ((AM + DC) .* high); mix = lowmix + highmix + noise; - + data.trial{iTr}(1,:) = mix; - if strcmp(cfg.output,'all') + if strcmp(cfg.output, 'all') data.trial{iTr}(2,:) = low; data.trial{iTr}(3,:) = high; data.trial{iTr}(4,:) = DC; @@ -437,9 +441,9 @@ end data.time{iTr} = timevec{iTr}; end % for iTr - + data.label{1} = 'mix'; - if strcmp(cfg.output,'all') + if strcmp(cfg.output, 'all') data.label{2} = 's1 (low)'; data.label{3} = 's2 (high)'; data.label{4} = 's3 (DC)'; @@ -449,18 +453,18 @@ data.label{8} = 'mixhigh'; end data.fsample = cfg.fsample; - + %%%%%%% PHASE TO FREQUENCY CORRELATION %%%%%%%%% -elseif strcmp(cfg.method,'phalow_freqhigh') - +elseif strcmp(cfg.method, 'phalow_freqhigh') + % sanity checks if cfg.s1.freq > cfg.fsample/2 || cfg.s2.freq > cfg.fsample/2 - error('you cannot have a frequency higher than the sample frequency/2') + ft_error('you cannot have a frequency higher than the sample frequency/2') end - + % make data for iTr = 1 : length(timevec) - + if ischar(cfg.s1.phase); phase_s1 = rand * 2 *pi; else phase_s1 = cfg.s1.phase; end if ischar(cfg.s2.phase); phase_s2 = rand * 2 *pi; else phase_s2= cfg.s2.phase; end s1 = cfg.s1.ampl .* cos(2*pi*cfg.s1.freq * timevec{iTr} + phase_s1); % to be modulated signal @@ -470,9 +474,9 @@ inst_pha = inst_pha_base + inst_pha_mod; noise = cfg.noise.ampl*randn(size(timevec{iTr})); mix = cfg.s1.ampl .* cos(inst_pha) + noise; - + data.trial{iTr}(1,:) = mix; - if strcmp(cfg.output,'all') + if strcmp(cfg.output, 'all') data.trial{iTr}(2,:) = s1; data.trial{iTr}(3,:) = s2; data.trial{iTr}(4,:) = noise; @@ -482,9 +486,9 @@ end data.time{iTr} = timevec{iTr}; end % for iTr - + data.label{1} = 'mix'; - if strcmp(cfg.output,'all') + if strcmp(cfg.output, 'all') data.label{2} = 's1'; data.label{3} = 's2'; data.label{4} = 'noise'; @@ -493,14 +497,14 @@ data.label{7} = 'inst phase'; end data.fsample = cfg.fsample; - + %%%%%%% ASYMETRIC POSITIVE AND NEGATIVE PEAKS %%%%%%%%% -elseif strcmp(cfg.method,'asymmetric') - +elseif strcmp(cfg.method, 'asymmetric') + % make data for iTr = 1 : length(timevec) if ischar(cfg.s1.phase); phase_s1 = rand * 2 *pi; else phase_s1 = cfg.s1.phase; end - + s1 = cfg.s1.ampl*cos(2*pi*cfg.s1.freq*timevec{iTr} + phase_s1); tmp = cos(2*pi*cfg.s1.freq*timevec{iTr} + phase_s1); % same signal but with unit amplitude tmp = (tmp+1)/2; % scaled and shifted between 0 and 1 @@ -509,26 +513,26 @@ s2 = tmp; noise = cfg.noise.ampl*randn(size(timevec{iTr})); mix = s2 + noise; - + data.trial{iTr}(1,:) = mix; - if strcmp(cfg.output,'all') + if strcmp(cfg.output, 'all') data.trial{iTr}(2,:) = s1; data.trial{iTr}(3,:) = s2; data.trial{iTr}(4,:) = noise; end data.time{iTr} = timevec{iTr}; end % for iTr - + data.label{1} = 'mix'; - if strcmp(cfg.output,'all') + if strcmp(cfg.output, 'all') data.label{2} = 's1'; data.label{3} = 's2'; data.label{4} = 'noise'; end data.fsample = cfg.fsample; - + else - error('unknown method specified') + ft_error('unknown method specified') end % do the general cleanup and bookkeeping at the end of the function diff --git a/external/fieldtrip/ft_freqstatistics.m b/external/fieldtrip/ft_freqstatistics.m index a00608ca..41c91445 100644 --- a/external/fieldtrip/ft_freqstatistics.m +++ b/external/fieldtrip/ft_freqstatistics.m @@ -113,7 +113,7 @@ end % ensure that the data in all inputs has the same channels, time-axis, etc. -tmpcfg = keepfields(cfg, {'frequency', 'avgoverfreq', 'latency', 'avgovertime', 'channel', 'avgoverchan', 'parameter'}); +tmpcfg = keepfields(cfg, {'frequency', 'avgoverfreq', 'latency', 'avgovertime', 'channel', 'avgoverchan', 'parameter', 'showcallinfo'}); [varargin{:}] = ft_selectdata(tmpcfg, varargin{:}); % restore the provenance information [cfg, varargin{:}] = rollback_provenance(cfg, varargin{:}); @@ -168,13 +168,13 @@ if exist(['ft_statistics_' cfg.method], 'file') statmethod = str2func(['ft_statistics_' cfg.method]); else - error('could not find the corresponding function for cfg.method="%s"\n', cfg.method); + ft_error('could not find the corresponding function for cfg.method="%s"\n', cfg.method); end fprintf('using "%s" for the statistical testing\n', func2str(statmethod)); % check that the design completely describes the data if size(dat,2) ~= size(cfg.design,2) - error('the length of the design matrix (%d) does not match the number of observations in the data (%d)', size(cfg.design,2), size(dat,2)); + ft_error('the length of the design matrix (%d) does not match the number of observations in the data (%d)', size(cfg.design,2), size(dat,2)); end % determine the number of output arguments diff --git a/external/fieldtrip/ft_globalmeanfield.m b/external/fieldtrip/ft_globalmeanfield.m index e1a8f340..610d16b6 100644 --- a/external/fieldtrip/ft_globalmeanfield.m +++ b/external/fieldtrip/ft_globalmeanfield.m @@ -3,13 +3,13 @@ % FT_GLOBALMEANFIELD calculates global mean field amplitude or power of input data % % Use as -% [gmf] = ft_globalmeanfield(cfg, indata) +% [gmf] = ft_globalmeanfield(cfg, data) % % The data should be organised in a structure as obtained from the % FT_TIMELOCKANALYSIS function. The configuration should be according to % FT_PREPROCESSING function. The configuration should be according to % -% cfg.methods = string, whether the amplitude or power should be calculated (see below, default is 'amplitude') +% cfg.method = string, determines whether the amplitude or power should be calculated (see below, default is 'amplitude', can be 'power') % cfg.channel = Nx1 cell-array with selection of channels (default = 'all'), % see FT_CHANNELSELECTION for details % @@ -33,8 +33,8 @@ % % See also FT_TIMELOCKANALYSIS -% Copyright (C) 2014, Jim Herring -% Copyright (C) 2014, Robert Oostenveld +% Copyright (C) 2017, Jan-Mathijs Schoffelen +% Copyright (C) 2014, Jim Herring, Robert Oostenveld % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -54,10 +54,6 @@ % % $Id$ -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% the initial part deals with parsing the input options and data -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - % these are used by the ft_preamble/ft_postamble function and scripts ft_revision = '$Id$'; ft_nargin = nargin; @@ -78,8 +74,9 @@ end % select channels and trials of interest, by default this will select all channels and trials -tmpcfg = keepfields(cfg, {'trials', 'channel'}); +tmpcfg = keepfields(cfg, {'trials', 'channel', 'showcallinfo'}); datain = ft_selectdata(tmpcfg, datain); +% restore the provenance information [cfg, datain] = rollback_provenance(cfg, datain); % ensure that the input data is valid for this function, this will also do @@ -93,14 +90,6 @@ % ensure that the options are valid cfg = ft_checkopt(cfg, 'method', 'char', {'amplitude', 'power'}); -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% the actual computation is done in the middle part -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - - -% do your stuff... -dataout = []; dataout = keepfields(datain,{'avg','time','label','dimord','cfg'}); switch cfg.method @@ -115,10 +104,6 @@ % this might involve more active checking of whether the input options % are consistent with the data and with each other -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% deal with the output -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - % do the general cleanup and bookkeeping at the end of the function ft_postamble debug ft_postamble trackconfig diff --git a/external/fieldtrip/ft_headmovement.m b/external/fieldtrip/ft_headmovement.m index f3685d63..479dd0e5 100644 --- a/external/fieldtrip/ft_headmovement.m +++ b/external/fieldtrip/ft_headmovement.m @@ -16,7 +16,7 @@ % % See also FT_REGRESSCONFOUND FT_REALTIME_HEADLOCALIZER -% Copyright (C) 2008-2010, Jan-Mathijs Schoffelen +% Copyright (C) 2008-2017, Jan-Mathijs Schoffelen, Robert Oostenveld % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -57,10 +57,12 @@ cfg = ft_checkconfig(cfg, 'dataset2files', 'yes'); % set the defaults -if ~isfield(cfg, 'numclusters'), cfg.numclusters = 12; end +cfg.numclusters = ft_getopt(cfg, 'numclusters', 12); +cfg.feedback = ft_getopt(cfg, 'feedback', 'yes'); % read the header information hdr = ft_read_header(cfg.headerfile); +assert(numel(intersect(hdr.label, {'HLC0011' 'HLC0012' 'HLC0013' 'HLC0021' 'HLC0022' 'HLC0023' 'HLC0031' 'HLC0032' 'HLC0033'}))==9, 'the data does not contain the expected head localizer channels'); % work with gradiometers in dewar coordinates, since HLCs are also % in dewar coords. at present I did not find the nas, lpa, rpa channels, @@ -81,49 +83,23 @@ tmpcfg = []; tmpcfg.dataset = cfg.dataset; tmpcfg.trl = cfg.trl; -tmpcfg.channel = {'HLC0011' 'HLC0012' 'HLC0013'... - 'HLC0021' 'HLC0022' 'HLC0023'... - 'HLC0031' 'HLC0032' 'HLC0033'}; +tmpcfg.channel = {'HLC0011' 'HLC0012' 'HLC0013' 'HLC0021' 'HLC0022' 'HLC0023' 'HLC0031' 'HLC0032' 'HLC0033'}; tmpcfg.continuous = 'yes'; data = ft_preprocessing(tmpcfg); -%resample doesn't work, because data will be demeaned -%tmpcfg = []; -%tmpcfg.resamplefs = 100; -%data = resampledata(tmpcfg, data); - -dat = zeros(length(data.label), 0); -wdat = zeros(1, 0); -for k = 1:length(data.trial) - tmpdat = data.trial{k}; - utmpdat = unique(tmpdat','rows')'; - dat = [dat utmpdat]; - - wtmpdat = zeros(1,size(utmpdat,2)); - for m = 1:size(utmpdat,2) - wtmpdat(1,m) = sum(sum(tmpdat-utmpdat(:,m)*ones(1,size(tmpdat,2))==0,1)==9); - end - wdat = [wdat wtmpdat]; -end -dat(:, wdat<100) = []; -wdat(wdat<100) = []; - -switch grad.unit - case 'm' - %do nothing - case 'cm' - dat = dat.*100; - case 'mm' - dat = dat.*1000; - otherwise - keyboard -end +dat = cat(2, data.trial{:}); +dat = dat * ft_scalingfactor('m', grad.unit); % scale in units of the gradiometer definition + +[tmpdata, dum, ic] = unique(dat', 'rows'); +dat = tmpdata'; -nhcoils = size(dat,1); -nsmp = size(dat,2); +% counthow often each position occurs +[wdat, dum] = hist(ic, unique(ic)); +% compute the cluster means [bin, cluster] = kmeans(dat', cfg.numclusters); +% find the three channels for each fiducial selnas = strmatch('HLC001', data.label); sellpa = strmatch('HLC002', data.label); selrpa = strmatch('HLC003', data.label); @@ -136,33 +112,22 @@ numperbin(k) = sum(wdat(bin==ubin(k))); end -if 1, +if istrue(cfg.feedback) hc = read_ctf_hc([cfg.datafile(1:end-4),'hc']); - trf = hc.homogenous; - xdir = trf(1,1:3); - ydir = trf(2,1:3); - zdir = trf(3,1:3); - - trf2 = inv(hc.homogenous); - origin = trf2(1:3,4)'; - - xaxis = [repmat(origin, [15 1]) + [0:14]'*xdir]; - yaxis = [repmat(origin, [9 1]) + [0:8]'*ydir; ... - repmat(origin, [9 1]) - [0:8]'*ydir]; - zaxis = [repmat(origin, [10 1]) + [0:9]'*zdir; ... - repmat(origin, [3 1]) - [0:2]'*zdir]; - + % plot some stuff figure; hold on; - plot3(xaxis(:,1),xaxis(:,2),xaxis(:,3),'k.-'); - plot3(yaxis(:,1),yaxis(:,2),yaxis(:,3),'k.-'); - plot3(zaxis(:,1),zaxis(:,2),zaxis(:,3),'k.-'); + title(sprintf('%s coordinates (%s)', grad_dewar.coordsys, grad_dewar.unit)); + ft_plot_axes(grad_dewar); + ft_plot_sens(grad_dewar); + fiducials = [nas;lpa;rpa]; - h = plot3(fiducials(:,1), fiducials(:,2), fiducials(:,3), 'b.'); + plot3(fiducials(:,1), fiducials(:,2), fiducials(:,3), 'b.'); plot3(hc.dewar.nas(1), hc.dewar.nas(2), hc.dewar.nas(3), 'ro'); plot3(hc.dewar.lpa(1), hc.dewar.lpa(2), hc.dewar.lpa(3), 'ro'); plot3(hc.dewar.rpa(1), hc.dewar.rpa(2), hc.dewar.rpa(3), 'ro'); axis vis3d; axis off + end % compute transformation matrix from dewar to head coordinates @@ -179,7 +144,7 @@ gradnew.tra = repmat(grad.tra, [1 npos]); for m = 1:npos tmptransform = transform(:,:,m); - gradnew.coilpos((m-1)*ncoils+1:(m*ncoils), :) = ft_warp_apply(tmptransform, grad.coilpos); % back to head-crd + gradnew.coilpos((m-1)*ncoils+1:(m*ncoils), :) = ft_warp_apply(tmptransform, grad.coilpos); % back to head coordinates tmptransform(1:3, 4) = 0; % keep rotation only gradnew.coilori((m-1)*ncoils+1:(m*ncoils), :) = ft_warp_apply(tmptransform, grad.coilori); gradnew.tra(:, (m-1)*ncoils+1:(m*ncoils)) = grad.tra.*(numperbin(m)./sum(numperbin)); diff --git a/external/fieldtrip/ft_interactiverealign.m b/external/fieldtrip/ft_interactiverealign.m index 497b782e..32388337 100644 --- a/external/fieldtrip/ft_interactiverealign.m +++ b/external/fieldtrip/ft_interactiverealign.m @@ -1,31 +1,40 @@ -function cfg = ft_interactiverealign(cfg) +function [cfg] = ft_interactiverealign(cfg) -% FT_INTERACTIVEREALIGN interactively rotates, scales and translates -% electrode positions to template electrode positions or towards -% the head surface. +% FT_INTERACTIVEREALIGN allows the user to interactively translate, rotate and scale an +% individual geometrical object to a template geometrical object. It can for example be used +% to align EEG electrodes to a model of the scalp surface. % % Use as % [cfg] = ft_interactiverealign(cfg) % -% The configuration structure should contain the individuals geometrical -% objects that have to be realigned as -% cfg.individual.elec = structure -% cfg.individual.grad = structure -% cfg.individual.headmodel = structure, see FT_PREPARE_HEADMODEL -% cfg.individual.headmodelstyle = 'edge', 'surface' or 'both' (default = 'edge') -% cfg.individual.headshape = structure, see FT_READ_HEADSHAPE -% cfg.individual.headshapestyle = 'vertex', 'surface' or 'both' (default = 'vertex') +% The configuration structure should contain the individuals geometrical object that +% has to be realigned +% cfg.individual.elec = structure +% cfg.individual.grad = structure +% cfg.individual.headmodel = structure, see FT_PREPARE_HEADMODEL +% cfg.individual.headshape = structure, see FT_READ_HEADSHAPE +% cfg.individual.mri = structure, see FT_READ_MRI +% You can specify the style with which the objects are displayed using +% cfg.individual.headmodelstyle = 'vertex', 'edge', 'surface' or 'both' (default = 'edge') +% cfg.individual.headshapestyle = 'vertex', 'edge', 'surface' or 'both' (default = 'vertex') % -% The configuration structure should also contain the geometrical -% objects of a template that serves as target -% cfg.template.elec = structure -% cfg.template.grad = structure -% cfg.template.headmodel = structure, see FT_PREPARE_HEADMODEL -% cfg.template.headmodelstyle = 'edge', 'surface' or 'both' (default = 'edge') -% cfg.template.headshape = structure, see FT_READ_HEADSHAPE -% cfg.template.headshapestyle = 'vertex', 'surface' or 'both' (default = 'vertex') +% The configuration structure should also contain the geometrical object of a +% template that serves as target +% cfg.template.axes = string, 'yes' or 'no (default = 'no') +% cfg.template.elec = structure +% cfg.template.grad = structure +% cfg.template.headmodel = structure, see FT_PREPARE_HEADMODEL +% cfg.template.headshape = structure, see FT_READ_HEADSHAPE +% cfg.template.mri = structure, see FT_READ_MRI +% You can specify the style with which the objects are displayed using +% cfg.template.headmodelstyle = 'vertex', 'edge', 'surface' or 'both' (default = 'edge') +% cfg.template.headshapestyle = 'vertex', 'edge', 'surface' or 'both' (default = 'vertex') % -% See also FT_VOLUMEREALIGN, FT_ELECTRODEREALIGN, FT_READ_SENS, FT_READ_VOL, FT_READ_HEADSHAPE +% You can specify one or multiple individual objects which will all be realigned and +% one or multiple template objects. +% +% See also FT_VOLUMEREALIGN, FT_ELECTRODEREALIGN, FT_DETERMINE_COORDSYS, +% FT_READ_SENS, FT_READ_VOL, FT_READ_HEADSHAPE % Copyright (C) 2008, Vladimir Litvak % @@ -72,22 +81,41 @@ cfg.template = ft_checkconfig(cfg.template, 'renamed', {'volstyle', 'headmodelstyle'}); cfg.individual.elec = ft_getopt(cfg.individual, 'elec', []); +cfg.individual.elecstyle = ft_getopt(cfg.individual, 'elecstyle', {}); % key-value pairs cfg.individual.grad = ft_getopt(cfg.individual, 'grad', []); +cfg.individual.gradstyle = ft_getopt(cfg.individual, 'gradstyle', {}); % key-value pairs cfg.individual.headshape = ft_getopt(cfg.individual, 'headshape', []); -cfg.individual.headshapestyle = ft_getopt(cfg.individual, 'headshapestyle', 'vertex'); +if ~isempty(cfg.individual.headshape) && isfield(cfg.individual.headshape, 'tri') + cfg.individual.headshapestyle = ft_getopt(cfg.individual, 'headshapestyle', 'surface'); +else + cfg.individual.headshapestyle = ft_getopt(cfg.individual, 'headshapestyle', 'vertex'); +end cfg.individual.headmodel = ft_getopt(cfg.individual, 'headmodel', []); cfg.individual.headmodelstyle = ft_getopt(cfg.individual, 'headmodelstyle', 'edge'); cfg.individual.mri = ft_getopt(cfg.individual, 'mri', []); -cfg.individual.mristyle = ft_getopt(cfg.individual, 'mristyle', 'intersect'); +cfg.individual.mristyle = ft_getopt(cfg.individual, 'mristyle', {}); +cfg.template.axes = ft_getopt(cfg.template, 'axes', 'no'); cfg.template.elec = ft_getopt(cfg.template, 'elec', []); +cfg.template.elecstyle = ft_getopt(cfg.template, 'elecstyle', {}); % key-value pairs cfg.template.grad = ft_getopt(cfg.template, 'grad', []); +cfg.template.gradstyle = ft_getopt(cfg.template, 'gradstyle', {}); % key-value pairs cfg.template.headshape = ft_getopt(cfg.template, 'headshape', []); -cfg.template.headshapestyle = ft_getopt(cfg.template, 'headshapestyle', 'vertex'); +if ~isempty(cfg.template.headshape) && isfield(cfg.template.headshape, 'tri') + cfg.template.headshapestyle = ft_getopt(cfg.template, 'headshapestyle', 'surface'); +else + cfg.template.headshapestyle = ft_getopt(cfg.template, 'headshapestyle', 'vertex'); +end cfg.template.headmodel = ft_getopt(cfg.template, 'headmodel', []); cfg.template.headmodelstyle = ft_getopt(cfg.template, 'headmodelstyle', 'edge'); cfg.template.mri = ft_getopt(cfg.template, 'mri', []); -cfg.template.mristyle = ft_getopt(cfg.template, 'mristyle', 'intersect'); +cfg.template.mristyle = ft_getopt(cfg.template, 'mristyle', {}); + +% convert the string that describes the style to a cell-array +cfg.template.headshapestyle = updatestyle(cfg.template.headshapestyle); +cfg.individual.headshapestyle = updatestyle(cfg.individual.headshapestyle); +cfg.template.headmodelstyle = updatestyle(cfg.template.headmodelstyle); +cfg.individual.headmodelstyle = updatestyle(cfg.individual.headmodelstyle); template = struct(cfg.template); individual = struct(cfg.individual); @@ -108,17 +136,41 @@ % convert the coordinates of all geometrical objects into mm fn = {'elec', 'grad', 'headshape', 'headmodel', 'mri'}; +hasindividual = false(size(fn)); +originalunit = cell(size(fn)); for i=1:length(fn) if ~isempty(individual.(fn{i})) - individual.(fn{i}) = ft_convert_units(individual.(fn{i}), 'mm'); + hasindividual(i) = true; + individual.(fn{i}) = ft_determine_units(individual.(fn{i})); % ensure that it has units + originalunit{i} = individual.(fn{i}).unit; + individual.(fn{i}) = ft_convert_units(individual.(fn{i}), 'mm'); % ensure that the units are all in mm + end +end +hastemplate = false(size(fn)); +for i=1:length(fn) + if ~isempty(template.(fn{i})) + template.(fn{i}) = ft_determine_units(template.(fn{i})); % ensure that it has units + hastemplate(i) = true; + template.(fn{i}) = ft_convert_units(template.(fn{i}), 'mm'); % ensure that the units are all in mm end end + +% determine the coordinate system of the template objects +coordsys = []; for i=1:length(fn) if ~isempty(template.(fn{i})) - template.(fn{i}) = ft_convert_units(template.(fn{i}), 'mm'); + if isfield(template.(fn{i}), 'coordsys') + if isempty(coordsys) + % remember the first coordinate system + coordsys = template.(fn{i}).coordsys; + end + % ensure that all template objects have the same coordinate system as the first one + assert(isequal(coordsys, template.(fn{i}).coordsys)); + end end end +% ensure that the headshape surface is triangulated if ~isempty(template.headshape) if ~isfield(template.headshape, 'tri') || isempty(template.headshape.tri) template.headshape.tri = projecttri(template.headshape.pos); @@ -131,6 +183,9 @@ end end +ft_info('Use the mouse to rotate the geometry, and click "redisplay" to update the light.'); +ft_info('Close the figure when you are done.'); + % open a figure fig = figure; set(gca, 'position', [0.05 0.15 0.75 0.75]); @@ -142,15 +197,27 @@ setappdata(fig, 'template', template); setappdata(fig, 'transform', eye(4)); setappdata(fig, 'cleanup', false); +setappdata(fig, 'coordsys', coordsys); % can be unknown setappdata(fig, 'toggle_axes', 1); setappdata(fig, 'toggle_grid', 1); % add the GUI elements -cb_creategui(gca); -cb_redraw(gca); +cb_creategui(gcf); +cb_redraw(gcf); rotate3d on +if isempty(coordsys) || strcmp(coordsys, 'unknown') + ft_notice('the template coordinate system is unknown, selecting the viewpoint is not possible'); + ft_uilayout(gcf, 'tag', 'viewpointbtn', 'Visible', 'off'); +else + [labelx, labely, labelz] = coordsys2label(coordsys, 2, 0); + ft_notice('the template coordinate system is "%s"', coordsys); + ft_info('the positive X-axis is pointing to %s', labelx); + ft_info('the positive Y-axis is pointing to %s', labely); + ft_info('the positive Z-axis is pointing to %s', labelz); +end + cleanup = false; while ~cleanup uiwait(fig); @@ -212,14 +279,14 @@ function cb_creategui(h, eventdata, handles) ft_uilayout(fig, 'tag', 'tz', 'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET+5*CONTROL_WIDTH, 'vpos', CONTROL_VOFFSET-1*CONTROL_HEIGHT); % control buttons -uicontrol('tag', 'viewbtn', 'parent', fig, 'units', 'normalized', 'style', 'popup', 'string', 'top|bottom|left|right|front|back', 'value', 1, 'callback', @cb_view); +uicontrol('tag', 'viewpointbtn', 'parent', fig, 'units', 'normalized', 'style', 'popup', 'string', 'top|bottom|left|right|front|back', 'value', 1, 'callback', @cb_viewpoint); uicontrol('tag', 'redisplaybtn', 'parent', fig, 'units', 'normalized', 'style', 'pushbutton', 'string', 'redisplay', 'value', [], 'callback', @cb_redraw); uicontrol('tag', 'applybtn', 'parent', fig, 'units', 'normalized', 'style', 'pushbutton', 'string', 'apply', 'value', [], 'callback', @cb_apply); uicontrol('tag', 'toggle labels', 'parent', fig, 'units', 'normalized', 'style', 'pushbutton', 'string', 'toggle label', 'value', 0, 'callback', @cb_redraw); uicontrol('tag', 'toggle axes', 'parent', fig, 'units', 'normalized', 'style', 'pushbutton', 'string', 'toggle axes', 'value', getappdata(fig, 'toggle_axes'), 'callback', @cb_redraw); uicontrol('tag', 'toggle grid', 'parent', fig, 'units', 'normalized', 'style', 'pushbutton', 'string', 'toggle grid', 'value', getappdata(fig, 'toggle_grid'), 'callback', @cb_redraw); uicontrol('tag', 'quitbtn', 'parent', fig, 'units', 'normalized', 'style', 'pushbutton', 'string', 'quit', 'value', 1, 'callback', @cb_quit); -ft_uilayout(fig, 'tag', 'viewbtn', 'BackgroundColor', [0.8 0.8 0.8], 'width', 6*CONTROL_WIDTH, 'height', CONTROL_HEIGHT, 'vpos', CONTROL_VOFFSET-2*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET); +ft_uilayout(fig, 'tag', 'viewpointbtn', 'BackgroundColor', [0.8 0.8 0.8], 'width', 6*CONTROL_WIDTH, 'height', CONTROL_HEIGHT, 'vpos', CONTROL_VOFFSET-2*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET); ft_uilayout(fig, 'tag', 'redisplaybtn', 'BackgroundColor', [0.8 0.8 0.8], 'width', 6*CONTROL_WIDTH, 'height', CONTROL_HEIGHT, 'vpos', CONTROL_VOFFSET-4*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET); ft_uilayout(fig, 'tag', 'applybtn', 'BackgroundColor', [0.8 0.8 0.8], 'width', 6*CONTROL_WIDTH, 'height', CONTROL_HEIGHT, 'vpos', CONTROL_VOFFSET-5*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET); ft_uilayout(fig, 'tag', 'toggle labels', 'BackgroundColor', [0.8 0.8 0.8], 'width', 6*CONTROL_WIDTH, 'height', CONTROL_HEIGHT, 'vpos', CONTROL_VOFFSET-6*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET); @@ -240,7 +307,7 @@ function cb_redraw(h, eventdata, handles) individual = getappdata(fig, 'individual'); template = getappdata(fig, 'template'); transform = getappdata(fig, 'transform'); - +coordsys = getappdata(fig, 'coordsys'); % get the transformation details rx = str2double(get(findobj(fig, 'tag', 'rx'), 'string')); @@ -261,157 +328,91 @@ function cb_redraw(h, eventdata, handles) transform = H * transform; axis vis3d; cla -xlabel('x') -ylabel('y') -zlabel('z') +xlabel('x (mm)') +ylabel('y (mm)') +zlabel('z (mm)') hold on % the "individual" struct is a local copy, so it is safe to change it here if ~isempty(individual.headmodel) - individual.headmodel = ft_transform_vol(transform, individual.headmodel); + individual.headmodel = ft_transform_geometry(transform, individual.headmodel); end if ~isempty(individual.elec) - individual.elec = ft_transform_sens(transform, individual.elec); + individual.elec = ft_transform_geometry(transform, individual.elec); end if ~isempty(individual.grad) - individual.grad = ft_transform_sens(transform, individual.grad); + individual.grad = ft_transform_geometry(transform, individual.grad); end if ~isempty(individual.headshape) - individual.headshape = ft_transform_headshape(transform, individual.headshape); + individual.headshape = ft_transform_geometry(transform, individual.headshape); end if ~isempty(individual.mri) - individual.mri.transform = transform * individual.mri.transform; + individual.mri = ft_transform_geometry(transform, individual.mri); end if ~isempty(template.mri) - if strcmp(template.mristyle, 'intersect') - ft_plot_ortho(template.mri.anatomy, 'transform', template.mri.transform, 'style', 'intersect', 'intersectmesh', individual.headshape); - elseif strcmp(template.mristyle, 'montage') - ft_plot_montage(template.mri.anatomy, 'transform', template.mri.transform, 'style', 'intersect', 'intersectmesh', individual.headshape); - end + ft_plot_ortho(template.mri.anatomy, 'transform', template.mri.transform, 'style', 'intersect', 'intersectmesh', individual.headshape, cfg.individual.mristyle{:}); end if ~isempty(individual.mri) - if strcmp(individual.mristyle, 'intersect') - ft_plot_ortho(individual.mri.anatomy, 'transform', individual.mri.transform, 'style', 'intersect', 'intersectmesh', template.headshape); - elseif strcmp(individual.mristyle, 'montage') - ft_plot_montage(individual.mri.anatomy, 'transform', individual.mri.transform, 'style', 'intersect', 'intersectmesh', template.headshape); - end + ft_plot_ortho(individual.mri.anatomy, 'transform', individual.mri.transform, 'style', 'intersect', 'intersectmesh', template.headshape, cfg.template.mristyle{:}); +end + +if istrue(template.axes) + ft_plot_axes([], 'unit', 'mm', 'coordsys', coordsys); end if ~isempty(template.elec) - % FIXME use ft_plot_sens if isfield(template.elec, 'line') tmpbnd = []; tmpbnd.pos = template.elec.chanpos; tmpbnd.tri = template.elec.line; - ft_plot_mesh(tmpbnd,'vertexcolor', 'b', 'facecolor', 'none', 'edgecolor', 'b', 'vertexsize',10) + ft_plot_mesh(tmpbnd, 'vertexcolor', 'b', 'facecolor', 'none', 'edgecolor', 'b', 'vertexsize', 10) else - ft_plot_mesh(template.elec.chanpos,'vertexcolor', 'b', 'vertexsize',10); + ft_plot_sens(template.elec, template.elecstyle{:}); end end if ~isempty(individual.elec) - % FIXME use ft_plot_sens if isfield(individual.elec, 'line') tmpbnd = []; tmpbnd.pos = individual.elec.chanpos; tmpbnd.tri = individual.elec.line; - ft_plot_mesh(tmpbnd,'vertexcolor', 'r', 'facecolor', 'none', 'edgecolor', 'r', 'vertexsize',10) + ft_plot_mesh(tmpbnd, 'vertexcolor', 'r', 'facecolor', 'none', 'edgecolor', 'r', 'vertexsize', 10) else - ft_plot_mesh(individual.elec.chanpos,'vertexcolor', 'r', 'vertexsize',10); + ft_plot_sens(individual.elec, individual.elecstyle{:}); end end if ~isempty(template.grad) - % FIXME use ft_plot_sens - ft_plot_mesh(template.grad.chanpos,'vertexcolor', 'b', 'vertexsize',10); - % FIXME also plot lines? + ft_plot_sens(template.grad, template.gradstyle{:}); end if ~isempty(individual.grad) - % FIXME use ft_plot_sens - ft_plot_mesh(individual.grad.chanpos,'vertexcolor', 'r', 'vertexsize',10); - % FIXME also plot lines? -end - -if ~isempty(template.headmodel) - % FIXME this only works for boundary element models - if strcmp(template.headmodelstyle, 'edge') - vertexcolor = 'none'; - edgecolor = 'k'; - facecolor = 'none'; - elseif strcmp(template.headmodelstyle, 'surface') - vertexcolor = 'none'; - edgecolor = 'none'; - facecolor = 'skin'; - elseif strcmp(template.headmodelstyle, 'both') - vertexcolor = 'none'; - edgecolor = 'k'; - facecolor = 'skin'; - end + ft_plot_sens(individual.grad, individual.gradstyle{:}); +end + +% FIXME this only works for boundary element models +if isstruct(template.headmodel) && isfield(template.headmodel, 'bnd') for i = 1:numel(template.headmodel.bnd) - ft_plot_mesh(template.headmodel.bnd(i), 'facecolor', facecolor, 'vertexcolor', vertexcolor, 'edgecolor', edgecolor) + ft_plot_mesh(template.headmodel.bnd(i), template.headmodelstyle{:}); end end -if ~isempty(individual.headmodel) - % FIXME this only works for boundary element models - if strcmp(individual.headmodelstyle, 'edge') - vertexcolor = 'none'; - edgecolor = 'k'; - facecolor = 'none'; - elseif strcmp(individual.headmodelstyle, 'surface') - vertexcolor = 'none'; - edgecolor = 'none'; - facecolor = 'skin'; - elseif strcmp(individual.headmodelstyle, 'both') - vertexcolor = 'none'; - edgecolor = 'k'; - facecolor = 'skin'; - end +% FIXME this only works for boundary element models +if isstruct(individual.headmodel) && isfield(individual.headmodel, 'bnd') for i = 1:numel(individual.headmodel.bnd) - ft_plot_mesh(individual.headmodel.bnd(i), 'facecolor', facecolor, 'vertexcolor', vertexcolor, 'edgecolor', edgecolor) + ft_plot_mesh(individual.headmodel.bnd(i), individual.headmodelstyle{:}); end end -if ~isempty(template.headshape) - if isfield(template.headshape, 'pos') && ~isempty(template.headshape.pos) - if strcmp(template.headshapestyle, 'edge') - vertexcolor = 'none'; - edgecolor = 'k'; - facecolor = 'none'; - elseif strcmp(template.headshapestyle, 'surface') - vertexcolor = 'none'; - edgecolor = 'none'; - facecolor = 'skin'; - elseif strcmp(template.headshapestyle, 'both') - vertexcolor = 'none'; - edgecolor = 'k'; - facecolor = 'skin'; - end - ft_plot_headshape(template.headshape, 'facecolor', facecolor, 'vertexcolor', vertexcolor, 'edgecolor', edgecolor) - end +if isstruct(template.headshape) && isfield(template.headshape, 'pos') && ~isempty(template.headshape.pos) + ft_plot_headshape(template.headshape, template.headshapestyle{:}); end -if ~isempty(individual.headshape) - if isfield(individual.headshape, 'pos') && ~isempty(individual.headshape.pos) - if strcmp(individual.headshapestyle, 'edge') - vertexcolor = 'none'; - edgecolor = 'k'; - facecolor = 'none'; - elseif strcmp(individual.headshapestyle, 'surface') - vertexcolor = 'none'; - edgecolor = 'none'; - facecolor = 'skin'; - elseif strcmp(individual.headshapestyle, 'both') - vertexcolor = 'none'; - edgecolor = 'k'; - facecolor = 'skin'; - end - ft_plot_headshape(individual.headshape, 'facecolor', facecolor, 'vertexcolor', vertexcolor, 'edgecolor', edgecolor) - end +if isstruct(individual.headshape) && isfield(individual.headshape, 'pos') && ~isempty(individual.headshape.pos) + ft_plot_headshape(individual.headshape, individual.headshapestyle{:}) end alpha(str2double(get(findobj(fig, 'tag', 'alpha'), 'string'))); @@ -480,25 +481,17 @@ function cb_apply(h, eventdata, handles) end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -function cb_view(h, eventdata) +function cb_viewpoint(h, eventdata) -% FIXME this is hardcoded for a particular (probably MNI/SPM) coordinate system +fig = getparent(h); +coordsys = getappdata(fig, 'coordsys'); + +% get the index of the option that was selected val = get(h, 'value'); -switch val - case 1 - view([90 90]); - case 2 - view([90 -90]); - case 3 - view([-90 0]); - case 4 - view([90 0]); - case 5 - view([-180 0]); - case 6 - view([0 0]); - otherwise -end + +viewpoint = {'top', 'bottom', 'left', 'right', 'front', 'back'}; +setviewpoint(gca, coordsys, viewpoint{val}); + uiresume; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -519,3 +512,20 @@ function cb_quit(h, eventdata) h = p; p = get(h, 'parent'); end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function style = updatestyle(style) +if ischar(style) + switch style + case 'vertex' + style = {'vertexcolor', 'k', 'edgecolor', 'none', 'facecolor', 'none'}; + case 'edge' + style = {'vertexcolor', 'none', 'edgecolor', 'k', 'facecolor', 'none'}; + case 'surface' + style = {'vertexcolor', 'none', 'edgecolor', 'none', 'facecolor', 'skin'}; + case 'both' + style = {'vertexcolor', 'none', 'edgecolor', 'k', 'facecolor', 'skin'}; + otherwise + ft_error('unsupported style "%s"', style); + end % switch +end % if diff --git a/external/fieldtrip/ft_interpolatenan.m b/external/fieldtrip/ft_interpolatenan.m index 14b2d21e..78fb7d22 100644 --- a/external/fieldtrip/ft_interpolatenan.m +++ b/external/fieldtrip/ft_interpolatenan.m @@ -1,19 +1,22 @@ function dataout = ft_interpolatenan(cfg, datain) -% FT_INTERPOLATENAN interpolates data that contains segments of nans -% obtained by replacing artifactual data with nans using, for example, FT_REJECTARTIFACT, -% or by redefining trials with FT_REDEFINETRIAL resulting in trials with -% gaps. +% FT_INTERPOLATENAN interpolates time series that contains segments of nans obtained +% by replacing artifactual data with nans using, for example, FT_REJECTARTIFACT, or +% by redefining trials with FT_REDEFINETRIAL resulting in trials with gaps. % % Use as -% outdata = ft_interpolatenan(cfg, indata) -% where indata is data as obtained from FT_PREPROCESSING -% and cfg is a configuratioun structure that should contain +% outdata = ft_interpolatenan(cfg, indata) +% where cfg is a configuration structure and the input data is obtained from FT_PREPROCESSING. % -% cfg.method = string, interpolation method, see HELP INTERP1 (default = 'linear') -% cfg.prewindow = value, length of data prior to interpolation window, in seconds (default = 1) -% cfg.postwindow = value, length of data after interpolation window, in seconds (default = 1) +% The configuration should contain +% cfg.method = string, interpolation method, see HELP INTERP1 (default = 'linear') +% cfg.prewindow = value, length of data prior to interpolation window, in seconds (default = 1) +% cfg.postwindow = value, length of data after interpolation window, in seconds (default = 1) +% cfg.feedback = string, 'no', 'text', 'textbar', 'gui' (default = 'text') % +% This function only interpolates over time, not over space. If you want to +% interpolate using spatial information, e.g. using neighbouring channels, you should +% use FT_CHANNELREPAIR. % % To facilitate data-handling and distributed computing with the peer-to-peer % module, this function has the following options: @@ -24,7 +27,7 @@ % files should contain only a single variable, corresponding with the % input/output structure. % -% See also FT_REJECTARTIFACT, FT_REDEFINETRIAL +% See also FT_REJECTARTIFACT, FT_REDEFINETRIAL, FT_CHANNELREPAIR % Copyright (C) 2003-2011, Jan-Mathijs Schoffelen & Robert Oostenveld % @@ -59,7 +62,7 @@ ft_defaults ft_preamble init ft_preamble debug -ft_preamble loadvar datain +ft_preamble loadvar datain ft_preamble provenance datain ft_preamble trackconfig @@ -72,57 +75,58 @@ datain = ft_checkdata(datain, 'datatype', {'raw+comp', 'raw'}, 'feedback', 'yes', 'hassampleinfo', 'yes'); % check if the input is valid -cfg = ft_checkconfig(cfg, 'allowedval',{'method','nearest','linear','spline','pchip','cubic','v5cubic'}); +cfg = ft_checkconfig(cfg, 'allowedval', {'method', 'nearest', 'linear', 'spline', 'pchip', 'cubic', 'v5cubic'}); cfg = ft_checkopt(cfg, 'prewindow', 'numericscalar'); cfg = ft_checkopt(cfg, 'postwindow', 'numericscalar'); % get the options -method = ft_getopt(cfg, 'method', 'linear'); % default is linear -prewindow = ft_getopt(cfg, 'prewindow', 1); % default is 1 second -postwindow = ft_getopt(cfg, 'postwindow', 1); % default is 1 seconds +cfg.method = ft_getopt(cfg, 'method', 'linear'); % default is linear +cfg.prewindow = ft_getopt(cfg, 'prewindow', 1); % default is 1 second +cfg.postwindow = ft_getopt(cfg, 'postwindow', 1); % default is 1 seconds +cfg.feedback = ft_getopt(cfg, 'feedback', 'etf'); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % the actual computation is done in the middle part %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +prewindow = round(cfg.prewindow * datain.fsample); % Express window in samples +postwindow = round(cfg.postwindow * datain.fsample); % Express window in samples + +% Start with a copy of the input data dataout = datain; -ntrl = numel(datain.trial); -prewindow = round(prewindow * datain.fsample); % Express window in samples -postwindow = round(postwindow * datain.fsample); % Express window in samples -% Let users know that the interpolation will start and initialize the -% progress indicator -fprintf('Initializing %s interpolation of %d trials\n',method,ntrl); -ft_progress('init', 'etf'); +% Let users know that the interpolation will start and initialize the progress indicator +ntrl = numel(datain.trial); +fprintf('Initializing %s interpolation of %d trials\n', cfg.method, ntrl); +ft_progress('init', cfg.feedback, 'Processing trial...'); for i=1:ntrl - ft_progress(i/ntrl, 'Processing trial %d out of %d',i,ntrl); - nchan = size(datain.trial{i},1); + ft_progress(i/ntrl, 'Processing trial %d from %d', i, ntrl); replace = isnan(datain.trial{i}); % Find samples that have been replaced by nans if any(replace(:)) % Check whether any values should be interpolated - [idx_start_r, idx_start_c] = find(diff(replace,[],2)==1); % Determine onset of nan-chunk - [dum, idx_end_c] = find(diff(replace,[],2)==-1); % Determine offset of nan-chunk - idx_start_c = idx_start_c + 1; % correct for shift due to using diff - + [idx_start_r, idx_start_c] = find(diff(replace, [], 2)==1); % Determine onset of nan-chunk + [dum, idx_end_c] = find(diff(replace, [], 2)==-1); % Determine offset of nan-chunk + idx_start_c = idx_start_c + 1; % Correct for shift due to using diff + % Loop across found nan-chunks - for j=1:size(idx_start_c,1) - sample_window = [idx_start_c(j)-prewindow:idx_start_c(j)-1 idx_end_c(j)+1:idx_end_c(j)+postwindow]; % Indices of time-points used for interpolation - if any(sample_window<1) || any(sample_window>size(datain.trial{i},2)) % Check whether sampling window falls within data range - ft_warning('Sample window partially outside of data-range, using less samples'); - sample_window(sample_window<1|sample_window>size(datain.trial{i},2))=[]; - elseif any(isnan(datain.trial{i}(idx_start_r(j),sample_window))) % Check whether sampling window overlaps with other chunk of nans - error('Sample window overlaps with other chunk of nans'); - end; - fill_window = idx_start_c(j):idx_end_c(j); % Indices of time-points that will be interpolated - fill = interp1(sample_window, datain.trial{i}(idx_start_r(j),sample_window),fill_window,method); % Interpolation - dataout.trial{i}(idx_start_r(j),fill_window)=fill; % Add interpolated segments to dataout - end; - end; -end; % i=1:ntrl + for j=1:size(idx_start_c, 1) + sample_window = [idx_start_c(j)-prewindow:idx_start_c(j)-1 idx_end_c(j)+1:idx_end_c(j)+postwindow]; % Indices of time-points used for interpolation + if any(sample_window<1) || any(sample_window>size(datain.trial{i}, 2)) % Check whether sampling window falls within data range + ft_warning('Sample window partially outside of data-range, using less samples'); + sample_window(sample_window<1|sample_window>size(datain.trial{i}, 2))=[]; + elseif any(isnan(datain.trial{i}(idx_start_r(j), sample_window))) % Check whether sampling window overlaps with other chunk of nans + ft_error('Sample window overlaps with other chunk of nans'); + end + fill_window = idx_start_c(j):idx_end_c(j); % Indices of time-points that will be interpolated + fill = interp1(sample_window, datain.trial{i}(idx_start_r(j), sample_window), fill_window, cfg.method); % Interpolation + dataout.trial{i}(idx_start_r(j), fill_window)=fill; % Add interpolated segments to dataout + end + end +end % for all trials ft_progress('close'); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% Cleanup +% cleanup %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ft_postamble debug diff --git a/external/fieldtrip/ft_lateralizedpotential.m b/external/fieldtrip/ft_lateralizedpotential.m index 8cfea9a3..7efe8253 100644 --- a/external/fieldtrip/ft_lateralizedpotential.m +++ b/external/fieldtrip/ft_lateralizedpotential.m @@ -91,7 +91,7 @@ avgR = ft_checkdata(avgR, 'datatype', 'timelock'); % set the defaults -if ~isfield(cfg, 'channelcmb'), +if ~isfield(cfg, 'channelcmb') cfg.channelcmb = { 'Fp1' 'Fp2' 'F7' 'F8' @@ -105,7 +105,7 @@ end if ~isequal(avgL.time, avgR.time) - error('the time axes are not the same'); + ft_error('the time axes are not the same'); end % start with an empty output structure @@ -117,12 +117,12 @@ % add timelock signature if isfield(avgL, 'dimord') && isfield(avgR, 'dimord') if ~strcmp(avgL.dimord, avgR.dimord) - error('The input data are of different dimord types'); + ft_error('The input data are of different dimord types'); else lrp.dimord = avgL.dimord; end else - error('''dimord'' not found. The function expects timelock data'); + ft_error('''dimord'' not found. The function expects timelock data'); end % compute the lateralized potentials diff --git a/external/fieldtrip/ft_layoutplot.m b/external/fieldtrip/ft_layoutplot.m index b7aa9b21..d47ebb78 100644 --- a/external/fieldtrip/ft_layoutplot.m +++ b/external/fieldtrip/ft_layoutplot.m @@ -31,6 +31,9 @@ % cfg.output = filename to which the layout will be written (default = []) % cfg.montage = 'no' or a montage structure (default = 'no') % cfg.image = filename, use an image to construct a layout (e.g. usefull for ECoG grids) +% cfg.visible = string, 'yes' or 'no' whether figure will be visible (default = 'yes') +% cfg.box = string, 'yes' or 'no' whether box should be plotted around electrode (default = 'yes') +% cfg.mask = string, 'yes' or 'no' whether the mask should be plotted (default = 'yes') % % Alternatively the layout can be constructed from either % data.elec structure with electrode positions @@ -90,8 +93,19 @@ return end +% the data can be passed as input argument or can be read from disk hasdata = exist('data', 'var'); +if hasdata + % check if the input data is valid for this function + data = ft_checkdata(data); +end + +% set the defaults +cfg.visible = ft_getopt(cfg, 'visible', 'yes'); +cfg.box = ft_getopt(cfg, 'box', 'yes'); +cfg.mask = ft_getopt(cfg, 'mask', 'yes'); + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % extract/generate layout information %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -119,7 +133,11 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % plot all details pertaining to the layout in one figure %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -figure; +if istrue(cfg.visible) + f = figure('visible', 'on'); +else + f = figure('visible', 'off'); +end % set the figure window title funcname = mfilename(); @@ -145,9 +163,9 @@ fprintf('reading background image from %s\n', cfg.image); img = imread(cfg.image); img = flipdim(img, 1); % in combination with "axis xy" - + bw = 1; - + if bw % convert to greyscale image img = mean(img, 3); @@ -162,7 +180,7 @@ axis xy end -ft_plot_lay(lay, 'point', true, 'box', true, 'label', true, 'mask', true, 'outline', true); +ft_plot_lay(lay, 'point', true, 'box', istrue(cfg.box), 'label', true, 'mask', istrue(cfg.mask), 'outline', true); % the following code can be used to verify a bipolar montage, given the % layout of the monopolar channels @@ -178,19 +196,19 @@ continue end % find the position of the begin and end of the arrow - beglab = cfg.montage.labelorg{begindx}; - endlab = cfg.montage.labelorg{endindx}; + beglab = cfg.montage.labelold{begindx}; + endlab = cfg.montage.labelold{endindx}; begindx = find(strcmp(lay.label, beglab)); % the index in the layout endindx = find(strcmp(lay.label, endlab)); % the index in the layout if ~numel(begindx)==1 || ~numel(endindx)==1 % one of the channels in the bipolar pair does not seem to be in the layout continue end - + begpos = lay.pos(begindx,:); endpos = lay.pos(endindx,:); arrow(begpos, endpos, 'Length', 5) - + end % for all re-referenced channels end % if montage diff --git a/external/fieldtrip/ft_math.m b/external/fieldtrip/ft_math.m index dda02bb2..38dc0d10 100644 --- a/external/fieldtrip/ft_math.m +++ b/external/fieldtrip/ft_math.m @@ -123,6 +123,12 @@ cfg.parameter = {cfg.parameter}; end +if ft_datatype(varargin{1}, 'raw+comp') + if length(varargin)>1 + ft_error('ft_math does not support more than one input argument if the input data is of type "raw" or "comp"') + end +end + % this function only works for the upcoming (not yet standard) source representation without sub-structures if ft_datatype(varargin{1}, 'source') % update the old-style beamformer source reconstruction @@ -142,7 +148,7 @@ for p=1:length(cfg.parameter) if ~issubfield(varargin{1}, cfg.parameter{p}) - error('the requested parameter is not present in the data'); + ft_error('the requested parameter is not present in the data'); end end @@ -158,53 +164,35 @@ for p = 1:length(cfg.parameter) dimordtmp{p} = getdimord(varargin{1}, cfg.parameter{p}); if p>1 && ~strcmp(dimordtmp{1}, dimordtmp{p}) - error('the dimord of multiple parameters must be the same'); + ft_error('the dimord of multiple parameters must be the same'); end end -dimord = dimordtmp{1}; clear dimordtmp -dimtok = tokenize(dimord, '_'); - -% this determines which descriptive fields will get copied over -haschan = any(strcmp(dimtok, 'chan')); -haschancmb = any(strcmp(dimtok, 'chancmb')); -hasfreq = any(strcmp(dimtok, 'freq')); -hastime = any(strcmp(dimtok, 'time')); -haspos = any(strcmp(dimtok, 'pos')); - -% construct the output data structure -data = []; -if haschan - data.label = varargin{1}.label; -end -if haschancmb - data.labelcmb = varargin{1}.labelcmb; -end -if hasfreq - data.freq = varargin{1}.freq; -end -if hastime - data.time = varargin{1}.time; -end -if haspos - if isfield(varargin{1}, 'pos') - data.pos = varargin{1}.pos; - end - if isfield(varargin{1}, 'dim') - data.dim = varargin{1}.dim; - end - if isfield(varargin{1}, 'transform') - data.transform = varargin{1}.transform; - end +clear dimordtmp + +% construct the output data structure; make sure descriptive fields will get copied over +% some ugly things need to be done in order to get the correct xxxdimord +% fields in the output +fn = fieldnames(varargin{1}); +dimordfields = fn(~cellfun(@isempty, strfind(fn, 'dimord')))'; +if numel(dimordfields)==1 && strcmp(dimordfields{1},'dimord') + % this is OK and counts for most data structures +else + % this is in the case of one or more xxxdimord fields, in which case + % only the requested parameters' xxxdimord fields should be returned in + % the output + ok = false(1,numel(dimordfields)); + for p = 1:length(cfg.parameter) + ok(p) = any(~cellfun(@isempty, strfind(dimordfields, cfg.parameter{p}))); + end + dimordfields = dimordfields(ok); end - -% use an anonymous function -assign = @(var, val) assignin('caller', var, val); +data = keepfields(varargin{1}, [dimordfields {'label', 'labelcmb', 'freq', 'time', 'pos', 'dim', 'transform'}]); for p = 1:length(cfg.parameter) fprintf('selecting %s from the first input argument\n', cfg.parameter{p}); % create the local variables x1, x2, ... for i=1:length(varargin) - assign(sprintf('x%i', i), getsubfield(varargin{i}, cfg.parameter{p})); + assign_var(sprintf('x%i', i), getsubfield(varargin{i}, cfg.parameter{p})); end % create the local variables s and m @@ -212,20 +200,20 @@ m = ft_getopt(cfg, 'matrix'); % check the dimensionality of m against the input data - if ~isempty(m), + if ~isempty(m) for i=1:length(varargin) ok = isequal(size(getsubfield(varargin{i}, cfg.parameter{p})),size(m)); if ~ok, break; end end - if ~ok, - error('the dimensions of cfg.matrix do not allow for element-wise operations'); + if ~ok + ft_error('the dimensions of cfg.matrix do not allow for element-wise operations'); end end % only one of these can be defined at the moment (i.e. not allowing for % operations such as (x1+m)^s for now - if ~isempty(m) && ~isempty(s), - error('you can either specify a cfg.matrix or a cfg.scalar, not both'); + if ~isempty(m) && ~isempty(s) + ft_error('you can either specify a cfg.matrix or a cfg.scalar, not both'); end % touch it to keep track of it in the output cfg @@ -233,14 +221,14 @@ if ~isempty(m), cfg.matrix; end % replace s with m, so that the code below is more transparent - if ~isempty(m), + if ~isempty(m) s = m; clear m; end if length(varargin)==1 switch cfg.operation case 'add' - if isscalar(s), + if isscalar(s) fprintf('adding %f to the %s\n', s, cfg.parameter{p}); else fprintf('adding the contents of cfg.matrix to the %s\n', cfg.parameter{p}); @@ -252,7 +240,7 @@ end case 'subtract' - if isscalar(s), + if isscalar(s) fprintf('subtracting %f from the %s\n', s, cfg.parameter{p}); else fprintf('subtracting the contents of cfg.matrix from the %s\n', cfg.parameter{p}); @@ -264,7 +252,7 @@ end case 'multiply' - if isscalar(s), + if isscalar(s) fprintf('multiplying %s with %f\n', cfg.parameter{p}, s); else fprintf('multiplying %s with the content of cfg.matrix\n', cfg.parameter{p}); @@ -277,7 +265,7 @@ end case 'divide' - if isscalar(s), + if isscalar(s) fprintf('dividing %s by %f\n', cfg.parameter{p}, s); else fprintf('dividing %s by the content of cfg.matrix\n', cfg.parameter{p}); @@ -328,7 +316,7 @@ for j=1:length(varargin) % rather than working with x1 and x2, we need to work on its elements % xx1 is one element of the x1 cell-array - assign(sprintf('xx%d', j), eval(sprintf('x%d{%d}', j, i))) + assign_var(sprintf('xx%d', j), eval(sprintf('x%d{%d}', j, i))) end % gather xx1, xx2, ... into a cell-array @@ -371,7 +359,7 @@ case 'subtract' if length(varargin)>2 - error('the operation "%s" requires exactly 2 input arguments', cfg.operation); + ft_error('the operation "%s" requires exactly 2 input arguments', cfg.operation); end fprintf('subtracting the 2nd input argument from the 1st\n'); if iscell(x1) @@ -382,7 +370,7 @@ case 'divide' if length(varargin)>2 - error('the operation "%s" requires exactly 2 input arguments', cfg.operation); + ft_error('the operation "%s" requires exactly 2 input arguments', cfg.operation); end fprintf('dividing the 1st input argument by the 2nd\n'); if iscell(x1) @@ -393,7 +381,7 @@ case 'log10' if length(varargin)>2 - error('the operation "%s" requires exactly 2 input arguments', cfg.operation); + ft_error('the operation "%s" requires exactly 2 input arguments', cfg.operation); end fprintf('taking the log difference between the 2nd input argument and the 1st\n'); y = log10(x1 ./ varargin{2}.(cfg.parameter{p})); @@ -426,7 +414,7 @@ for j=1:length(varargin) % rather than working with x1 and x2, we need to work on its elements % xx1 is one element of the x1 cell-array - assign(sprintf('xx%d', j), eval(sprintf('x%d{%d}', j, i))) + assign_var(sprintf('xx%d', j), eval(sprintf('x%d{%d}', j, i))) end % gather xx1, xx2, ... into a cell-array @@ -447,13 +435,12 @@ % store the result of the operation in the output structure data = setsubfield(data, cfg.parameter{p}, y); end % p over length(cfg.parameter) -data.dimord = dimord; % certain fields should remain in the output, but only if they are identical in all inputs -keepfield = {'grad', 'elec', 'inside', 'trialinfo', 'sampleinfo'}; +keepfield = {'grad', 'elec', 'opto', 'inside', 'trialinfo', 'sampleinfo', 'tri'}; for j=1:numel(keepfield) if isfield(varargin{1}, keepfield{j}) - tmp = varargin{i}.(keepfield{j}); + tmp = varargin{1}.(keepfield{j}); keep = true; else keep = false; @@ -480,6 +467,17 @@ ft_postamble history data ft_postamble savevar data + +function assign_var(var, val) +% Note: using an anonymous function as follows does not work in Octave: +% +% ** assign_var = @(var, val) assignin('caller', var, val); +% +% Also using the name 'assign' does not seem to work, hence 'assign_var' + + assignin('caller', var, val); + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % SUBFUNCTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/external/fieldtrip/ft_megplanar.m b/external/fieldtrip/ft_megplanar.m index d308b55b..ed66d1a6 100644 --- a/external/fieldtrip/ft_megplanar.m +++ b/external/fieldtrip/ft_megplanar.m @@ -103,8 +103,8 @@ israw = true; end -if isfreq, - if ~isfield(data, 'fourierspctrm'), error('freq data should contain Fourier spectra'); end +if isfreq + if ~isfield(data, 'fourierspctrm'), ft_error('freq data should contain Fourier spectra'); end end cfg = ft_checkconfig(cfg, 'renamed', {'hdmfile', 'headmodel'}); @@ -139,9 +139,7 @@ cfg = ft_checkconfig(cfg, 'createsubcfg', {'grid'}); % select trials of interest -tmpcfg = []; -tmpcfg.trials = cfg.trials; -tmpcfg.channel = cfg.channel; +tmpcfg = keepfields(cfg, {'trials', 'channel', 'showcallinfo'}); data = ft_selectdata(tmpcfg, data); % restore the provenance information [cfg, data] = rollback_provenance(cfg, data); @@ -160,7 +158,7 @@ cfg.spheremesh = ft_getopt(cfg, 'spheremesh', 642); if isfreq - error('the method ''sourceproject'' is not supported for frequency data as input'); + ft_error('the method ''sourceproject'' is not supported for frequency data as input'); end Nchan = length(data.label); @@ -187,7 +185,7 @@ % read the headshape from file headshape = ft_read_headshape(cfg.headshape); else - error('cfg.headshape is not specified correctly') + ft_error('cfg.headshape is not specified correctly') end if ~isfield(headshape, 'tri') % generate a closed triangulation from the surface points @@ -213,20 +211,21 @@ planarmontage = []; planarmontage.tra = transform; - planarmontage.labelorg = axial.grad.label; + planarmontage.labelold = axial.grad.label; planarmontage.labelnew = planar.grad.label; % apply the linear transformation to the data interp = ft_apply_montage(data, planarmontage, 'keepunused', 'yes'); + % also apply the linear transformation to the gradiometer definition interp.grad = ft_apply_montage(data.grad, planarmontage, 'balancename', 'planar', 'keepunused', 'yes'); % ensure there is a type string describing the gradiometer definition if ~isfield(interp.grad, 'type') - % put the original gradiometer type in (will get _planar appended) - interp.grad.type = ft_senstype(data.grad); + interp.grad.type = [ft_senstype(data.grad) '_planar']; + else + interp.grad.type = [interp.grad.type '_planar']; end - interp.grad.type = [interp.grad.type '_planar']; % % interpolate the data towards the planar gradiometers % for i=1:Ntrials @@ -249,17 +248,17 @@ % else - sens = ft_convert_units(data.grad); + sens = ft_determine_units(data.grad); chanposnans = any(isnan(sens.chanpos(:))) || any(isnan(sens.chanori(:))); if chanposnans - if isfield(sens, 'chanposorg') + if isfield(sens, 'chanposold') % temporarily replace chanpos and chanorig with the original values - sens.chanpos = sens.chanposorg; - sens.chanori = sens.chanoriorg; - sens.label = sens.labelorg; - sens = rmfield(sens, {'chanposorg', 'chanoriorg', 'labelorg'}); + sens.chanpos = sens.chanposold; + sens.chanori = sens.chanoriold; + sens.label = sens.labelold; + sens = rmfield(sens, {'chanposold', 'chanoriold', 'labelold'}); else - error('The channel positions (and/or orientations) contain NaNs; this prohibits correct behavior of the function. Please replace the input channel definition with one that contains valid channel positions'); + ft_error('The channel positions (and/or orientations) contain NaNs; this prohibits correct behavior of the function. Please replace the input channel definition with one that contains valid channel positions'); end end cfg.channel = ft_channelselection(cfg.channel, sens.label); @@ -296,7 +295,7 @@ % % generically call megplanar_orig megplanar_sincos or megplanar_fitplane %fun = ['megplanar_' cfg.planarmethod]; %if ~exist(fun, 'file') - % error('unknown method for computation of planar gradient'); + % ft_error('unknown method for computation of planar gradient'); %end %planarmontage = eval([fun '(cfg, data.grad)']); @@ -313,7 +312,7 @@ otherwise fun = ['megplanar_' cfg.planarmethod]; if ~exist(fun, 'file') - error('unknown method for computation of planar gradient'); + ft_error('unknown method for computation of planar gradient'); end planarmontage = eval([fun '(cfg, data.grad)']); end @@ -342,13 +341,13 @@ interp.grad.chanpos(ix,:) = sens.chanpos(iy,:); % if the original chanpos contained nans, make sure to put nans in the - % updated one as well, and move the updated chanpos values to chanposorg + % updated one as well, and move the updated chanpos values to chanposold if chanposnans - interp.grad.chanposorg = sens.chanpos; - interp.grad.chanoriorg = sens.chanori; - interp.grad.labelorg = sens.label; - interp.grad.chanpos = nan(size(interp.grad.chanpos)); - interp.grad.chanori = nan(size(interp.grad.chanori)); + interp.grad.chanposold = sens.chanpos; + interp.grad.chanoriold = sens.chanori; + interp.grad.labelold = sens.label; + interp.grad.chanpos = nan(size(interp.grad.chanpos)); + interp.grad.chanori = nan(size(interp.grad.chanori)); end end diff --git a/external/fieldtrip/ft_megrealign.m b/external/fieldtrip/ft_megrealign.m index 74cf9b94..3f98d7f9 100644 --- a/external/fieldtrip/ft_megrealign.m +++ b/external/fieldtrip/ft_megrealign.m @@ -185,16 +185,16 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% template = struct([]); % initialize as empty structure for i=1:length(cfg.template) - if ischar(cfg.template{i}), + if ischar(cfg.template{i}) fprintf('reading template sensor position from %s\n', cfg.template{i}); - tmp = ft_read_sens(cfg.template{i}); - elseif isstruct(cfg.template{i}) && isfield(cfg.template{i}, 'coilpos') && isfield(cfg.template{i}, 'coilori') && isfield(cfg.template{i}, 'tra'), + tmp = ft_read_sens(cfg.template{i}, 'senstype', 'meg'); + elseif isstruct(cfg.template{i}) && isfield(cfg.template{i}, 'coilpos') && isfield(cfg.template{i}, 'coilori') && isfield(cfg.template{i}, 'tra') tmp = cfg.template{i}; - elseif isstruct(cfg.template{i}) && isfield(cfg.template{i}, 'pnt') && isfield(cfg.template{i}, 'ori') && isfield(cfg.template{i}, 'tra'), + elseif isstruct(cfg.template{i}) && isfield(cfg.template{i}, 'pnt') && isfield(cfg.template{i}, 'ori') && isfield(cfg.template{i}, 'tra') % it seems to be a pre-2011v1 type gradiometer structure, update it tmp = ft_datatype_sens(cfg.template{i}); else - error('unrecognized template input'); + ft_error('unrecognized template input'); end % prevent "Subscripted assignment between dissimilar structures" error template = appendstruct(template, tmp); clear tmp @@ -242,7 +242,7 @@ end % copy all options that are potentially used in ft_prepare_sourcemodel -tmpcfg = keepfields(cfg, {'grid' 'mri' 'headshape' 'symmetry' 'smooth' 'threshold' 'spheremesh' 'inwardshift'}); +tmpcfg = keepfields(cfg, {'grid', 'mri', 'headshape', 'symmetry', 'smooth', 'threshold', 'spheremesh', 'inwardshift', 'showcallinfo'}); tmpcfg.headmodel = volold; tmpcfg.grad = data.grad; % create the dipole grid on which the data will be projected @@ -257,7 +257,7 @@ % compute the forward model for the new gradiometer positions fprintf('computing forward model for %d dipoles\n', size(pos,1)); lfnew = ft_compute_leadfield(pos, template.grad, volnew); -if ~pertrial, +if ~pertrial %this needs to be done only once lfold = ft_compute_leadfield(pos, data.grad, volold); [realign, noalign, bkalign] = computeprojection(lfold, lfnew, cfg.pruneratio, cfg.verify); @@ -265,20 +265,20 @@ %the forward model and realignment matrices have to be computed for each trial %this also goes for the singleshell volume conductor model %x = which('rigidbodyJM'); %this function is needed - %if isempty(x), - % error('you are trying out experimental code for which you need some extra functionality which is currently not in the release version of fieldtrip. if you are interested in trying it out, contact jan-mathijs'); + %if isempty(x) + % ft_error('you are trying out experimental code for which you need some extra functionality which is currently not in the release version of FieldTrip. if you are interested in trying it out, contact Jan-Mathijs'); %end end % interpolate the data towards the template gradiometers for i=1:Ntrials fprintf('realigning trial %d\n', i); - if pertrial, + if pertrial %warp the gradiometer array according to the motiontracking data sel = match_str(rest.label, {'nasX';'nasY';'nasZ';'lpaX';'lpaY';'lpaZ';'rpaX';'rpaY';'rpaZ'}); hmdat = rest.trial{i}(sel,:); if ~all(hmdat==repmat(hmdat(:,1),[1 size(hmdat,2)])) - error('only one position per trial is at present allowed'); + ft_error('only one position per trial is at present allowed'); else %M = rigidbodyJM(hmdat(:,1)) M = ft_headcoordinates(hmdat(1:3,1),hmdat(4:6,1),hmdat(7:9,1)); @@ -311,7 +311,7 @@ % plot the topography before and after the realignment if strcmp(cfg.feedback, 'yes') - warning('showing MEG topography (RMS value over time) in the first trial only'); + ft_warning('showing MEG topography (RMS value over time) in the first trial only'); Nchan = length(data.grad.label); [id,it] = match_str(data.grad.label, template.grad.label); pos1 = data.grad.chanpos(id,:); @@ -327,7 +327,7 @@ [u, s, v] = svd(data.trial{1}(id,:)); p1 = u(:,1); [u, s, v] = svd(data.realign{1}(it,:)); p2 = u(:,1); otherwise - error('unsupported cfg.topoparam'); + ft_error('unsupported cfg.topoparam'); end X = [pos1(:,1) pos2(:,1)]'; @@ -447,7 +447,7 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function [lfi] = prunedinv(lf, r) [u, s, v] = svd(lf); -if r<1, +if r<1 % treat r as a ratio p = find(s<(s(1,1)*r) & s~=0); else diff --git a/external/fieldtrip/ft_meshrealign.m b/external/fieldtrip/ft_meshrealign.m new file mode 100644 index 00000000..2e7ac6d9 --- /dev/null +++ b/external/fieldtrip/ft_meshrealign.m @@ -0,0 +1,961 @@ +function mesh_realigned = ft_meshrealign(cfg, mesh) + +% FT_MESHREALIGN rotates, translates and optionally scales electrode positions. The +% different methods are described in detail below. +% +% INTERACTIVE - You can display the mesh surface together with axis coordinate +% system, and manually (using the graphical user interface) adjust the rotation, +% translation and scaling parameters. +% +% FIDUCIAL - The coordinate system is updated according to the definition of the +% coordinates of anatomical landmarks or fiducials that are specified in the +% configuration. If the fiducials are not specified in the configurartion, you will +% have to click them in an interactive display of the mesh surface. +% +% Use as +% mesh = ft_meshrealign(cfg, mesh) +% where the mesh input argument comes from FT_READ_HEADSHAPE or FT_PREPARE_MESH and +% cfg is a configuration structure that should contain +% +% cfg.method = string, can be 'interactive' or fiducial' (default = 'interactive') +% +% The configuration can furthermore contain +% cfg.coordsys = string, can be 'ctf', 'neuromag', '4d', 'bti', 'itab' +% cfg.fiducial.nas = [x y z], position of nasion +% cfg.fiducial.lpa = [x y z], position of LPA +% cfg.fiducial.rpa = [x y z], position of RPA +% +% The fiducials should be expressed in the coordinates and units of the input mesh. +% +% To facilitate data-handling and distributed computing you can use +% cfg.inputfile = ... +% cfg.outputfile = ... +% If you specify one of these (or both) the input data will be read from a *.mat +% file on disk and/or the output data will be written to a *.mat file. These mat +% files should contain only a single variable, corresponding with the +% input/output structure. +% +% See also FT_READ_HEADSHAPE, FT_PREPARE_MESH, FT_ELECTRODEREALIGN, FT_VOLUMEREALIGN + +% Copyrights (C) 2017, Robert Oostenveld +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% the initial part deals with parsing the input options and data +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% these are used by the ft_preamble/ft_postamble function and scripts +ft_revision = '$Id$'; +ft_nargin = nargin; +ft_nargout = nargout; + +% do the general setup of the function +ft_defaults +ft_preamble init +ft_preamble debug +ft_preamble loadvar mesh +ft_preamble provenance mesh +ft_preamble trackconfig + +% the ft_abort variable is set to true or false in ft_preamble_init +if ft_abort + % do not continue function execution in case the outputfile is present and the user indicated to keep it + return +end + +% ensure that the input data is valid for this function, this will also do +% backward-compatibility conversions of old data that for example was +% read from an old *.mat file +mesh = ft_checkdata(mesh, 'datatype', 'mesh', 'feedback', 'yes', 'hasunit', 'yes', 'hascoordsys', 'no'); + +% get the options +cfg.method = ft_getopt(cfg, 'method', 'interactive'); +cfg.coordsys = ft_getopt(cfg, 'coordsys'); +cfg.fiducial = ft_getopt(cfg, 'fiducial'); +cfg.fiducial.nas = ft_getopt(cfg.fiducial, 'nas'); +cfg.fiducial.lpa = ft_getopt(cfg.fiducial, 'lpa'); +cfg.fiducial.rpa = ft_getopt(cfg.fiducial, 'rpa'); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% the actual computation is done in the middle part +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% start with a copy +mesh_realigned = keepfields(mesh, {'pos', 'tri', 'tet', 'hex', 'unit', 'line', 'edge', 'color', 'curv', 'sulc'}); + +switch cfg.method + case 'interactive' + + tmpcfg = []; + tmpcfg.template.axes = 'yes'; + tmpcfg.template.headshape.pos = zeros(3,3); % three vertices + tmpcfg.template.headshape.tri = [1 2 3]; % one triangle + tmpcfg.template.headshape.unit = 'mm'; + tmpcfg.template.headshape.coordsys = cfg.coordsys; + tmpcfg.template.headshapestyle = {'vertexcolor', 'none', 'edgecolor', 'none', 'facecolor', 'none'}; + tmpcfg.individual.headshape = mesh_realigned; + tmpcfg = ft_interactiverealign(tmpcfg); + % keep the homogenous transformation + transform = tmpcfg.m; + + case 'fiducial' + % it must be present and it must be a string + ft_checkopt(cfg, 'coordsys', {'char'}); + + hasnas = ~isempty(cfg.fiducial.nas); + haslpa = ~isempty(cfg.fiducial.lpa); + hasrpa = ~isempty(cfg.fiducial.rpa); + + if ~hasnas || ~haslpa || ~hasrpa + % do something interactive to get them + % this is shared with ft_volumerealign + + cfg.fiducial.nas = [nan nan nan]; + cfg.fiducial.lpa = [nan nan nan]; + cfg.fiducial.rpa = [nan nan nan]; + cfg.fiducial.zpoint = [nan nan nan]; + + scalp = mesh; + mri = []; + + switch cfg.coordsys + case {'ctf' '4d' 'bti' 'yokogawa' 'asa' 'itab' 'neuromag'} + fidlabel = {'nas', 'lpa', 'rpa', 'zpoint'}; + fidletter = {'n', 'l', 'r', 'z'}; + fidexplanation1 = ' press n for nas, l for lpa, r for rpa\n'; + fidexplanation2 = ' press z for an extra control point that should have a positive z-value\n'; + case 'acpc' + fidlabel = {'ac', 'pc', 'xzpoint', 'right'}; + fidletter = {'a', 'p', 'z', 'r'}; + fidexplanation1 = ' press a for ac, p for pc, z for xzpoint\n'; + fidexplanation2 = ' press r for an extra control point that should be on the right side\n'; + case 'paxinos' + fidlabel = {'bregma', 'lambda', 'yzpoint'}; + fidletter = {'b', 'l', 'z'}; + fidexplanation1 = ' press b for bregma, l for lambda, z for yzpoint\n'; + fidexplanation2 = ''; + otherwise + ft_error('unknown coordinate system "%s"', cfg.coordsys); + end % switch coordsys + + fprintf('\n'); + fprintf(strcat(... + '1. To change the orientation of the head surface, use the\n',... + '"Rotate 3D" option in the figure toolbar\n',... + '2. To mark a fiducial position or anatomical landmark, do BOTH:\n',... + ' a. select the position by clicking on it with the left mouse button\n',... + ' b. specify it by pressing the letter corresponding to the fiducial/landmark:\n', fidexplanation1, fidexplanation2, ... + ' You can mark the fiducials multiple times, until you are satisfied with the positions.\n',... + '3. To finalize markers and quit interactive mode, press q on keyboard\n')); + + % start building the figure + h = figure; + set(h, 'color', [1 1 1]); + set(h, 'visible', 'on'); + % add callbacks + set(h, 'windowkeypressfcn', @cb_keyboard_surface); + set(h, 'CloseRequestFcn', @cb_cleanup); + + % create figure handles + h1 = axes; + + % create structure to be passed to gui + opt = []; + opt.viewresult = false; % flag to use for certain keyboard/redraw calls + opt.handlesfigure = h; + opt.handlesaxes = h1; + opt.handlesfigure = h; + opt.handlesmarker = []; + opt.camlighthandle = []; + opt.init = true; + opt.quit = false; + opt.scalp = scalp; + opt.showmarkers = false; + opt.mri = mri; + opt.fiducial = cfg.fiducial; + opt.fidlabel = fidlabel; + opt.fidletter = fidletter; + opt.fidexplanation1 = fidexplanation1; + if isfield(scalp, 'unit') && ~strcmp(scalp.unit, 'unknown') + opt.unit = scalp.unit; % this is shown in the feedback on screen + else + opt.unit = ''; % this is not shown + end + + setappdata(h, 'opt', opt); + cb_redraw_surface(h); + + while(opt.quit==0) + uiwait(h); + opt = getappdata(h, 'opt'); + end + delete(h); + + % store the interactively determined fiducials in the configuration + % the actual coordinate transformation will be done further down + cfg.fiducial = opt.fiducial; + + end + + % compute the homogenous transformation + transform = ft_headcoordinates(cfg.fiducial.nas, cfg.fiducial.lpa, cfg.fiducial.rpa, cfg.coordsys); + + + otherwise + ft_error('unsupported method "%s"', cfg.method); +end + +% update the positions +mesh_realigned = ft_transform_geometry(transform, mesh_realigned); + +% assign the coordinate system +if ~isempty(cfg.coordsys) + mesh_realigned.coordsys = cfg.coordsys; +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% deal with the output +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% do the general cleanup and bookkeeping at the end of the function + +ft_postamble debug +ft_postamble trackconfig +ft_postamble previous mesh +ft_postamble provenance mesh_realigned +ft_postamble history mesh_realigned +ft_postamble savevar mesh_realigned + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function cb_redraw_surface(h, eventdata) +h = getparent(h); +opt = getappdata(h, 'opt'); + +markercolor = {'r', 'g', 'b', 'y'}; + +if opt.init + ft_plot_mesh(opt.scalp, 'edgecolor', 'none', 'facecolor', 'skin') + hold on +end + +% recreate the camera lighting +delete(opt.camlighthandle); +opt.camlighthandle = camlight; + +% remove the previous fiducials +delete(opt.handlesmarker(opt.handlesmarker(:)>0)); +opt.handlesmarker = []; + +% redraw the fiducials +for i=1:length(opt.fidlabel) + lab = opt.fidlabel{i}; + pos = opt.fiducial.(lab); + if all(~isnan(pos)) + opt.handlesmarker(i,1) = plot3(pos(1), pos(2), pos(3), 'marker', 'o', 'color', markercolor{i}); + opt.handlesmarker(i,2) = text(pos(1), pos(2), pos(3), lab); + end +end + +opt.init = false; +setappdata(h, 'opt', opt); +uiresume + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function cb_keyboard_surface(h, eventdata) +h = getparent(h); +opt = getappdata(h, 'opt'); + +if isempty(eventdata) + % determine the key that corresponds to the uicontrol element that was activated + key = get(h, 'userdata'); +else + % determine the key that was pressed on the keyboard + key = parseKeyboardEvent(eventdata); +end + +% get the most recent surface position that was clicked with the mouse +pos = select3d(opt.handlesaxes); + +sel = find(strcmp(opt.fidletter, key)); +if ~isempty(sel) + % update the corresponding fiducial + opt.fiducial.(opt.fidlabel{sel}) = pos(:)'; +end + +fprintf('==================================================================================\n'); +for i=1:length(opt.fidlabel) + lab = opt.fidlabel{i}; + vox = opt.fiducial.(lab); + pos = vox; + ind = nan; + switch opt.unit + case 'mm' + fprintf('%10s: voxel %9d, index = [%3d %3d %3d], head = [%.1f %.1f %.1f] %s\n', lab, ind, round(vox), pos, opt.unit); + case 'cm' + fprintf('%10s: voxel %9d, index = [%3d %3d %3d], head = [%.2f %.2f %.2f] %s\n', lab, ind, round(vox), pos, opt.unit); + case 'm' + fprintf('%10s: voxel %9d, index = [%3d %3d %3d], head = [%.4f %.4f %.4f] %s\n', lab, ind, round(vox), pos, opt.unit); + otherwise + fprintf('%10s: voxel %9d, index = [%3d %3d %3d], head = [%f %f %f] %s\n', lab, ind, round(vox), pos, opt.unit); + end +end + +setappdata(h, 'opt', opt); + +if isequal(key, 'q') + cb_cleanup(h); +else + cb_redraw_surface(h); +end + +uiresume(h); + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function cb_redraw(h, eventdata) +h = getparent(h); +opt = getappdata(h, 'opt'); + +curr_ax = get(h, 'currentaxes'); +tag = get(curr_ax, 'tag'); + +mri = opt.mri; + +h1 = opt.handlesaxes(1); +h2 = opt.handlesaxes(2); +h3 = opt.handlesaxes(3); + +% extract to-be-plotted/clicked location and check whether inside figure +xi = opt.ijk(1); +yi = opt.ijk(2); +zi = opt.ijk(3); +if any([xi yi zi] > mri.dim) || any([xi yi zi] <= 0) + return; +end + +% transform here to coordinate system space instead of voxel space if viewing results +% the code were this transform will impact fiducial/etc coordinates is unaffected, as it is switched off +% (note: fiducial/etc coordinates are transformed into coordinate space in the code dealing with realignment) +if opt.viewresult + tmp = ft_warp_apply(mri.transform, [xi yi zi]); + xi = tmp(1); + yi = tmp(2); + zi = tmp(3); +end + +if opt.init + % create the initial figure + if ~opt.viewresult + % if realigning, plotting is done in voxel space + ft_plot_ortho(opt.ana, 'transform', eye(4), 'location', [xi yi zi], 'style', 'subplot', 'parents', [h1 h2 h3], 'update', opt.update, 'doscale', false, 'clim', opt.clim); + else + % if viewing result, plotting is done in head coordinate system space + if ~opt.twovol + % one vol case + ft_plot_ortho(opt.ana, 'transform', mri.transform, 'location', [xi yi zi], 'style', 'subplot', 'parents', [h1 h2 h3], 'update', opt.update, 'doscale', false, 'clim', opt.realignclim); + else + % two vol case + % base volume, with color red + hbase = []; % need the handle for the individual surfs + [hbase(1), hbase(2), hbase(3)] = ft_plot_ortho(opt.ana, 'transform', mri.transform, 'unit', mri.unit, 'location', [xi yi zi], 'style', 'subplot', 'parents', [h1 h2 h3], 'update', opt.update, 'doscale', false, 'clim', opt.targetclim, 'datmask',opt.targetmask, 'opacitylim', [0 1]); + for ih = 1:3 + col = get(hbase(ih), 'CData'); + col(:,:,2:3) = 0; + set(hbase(ih), 'CData',col); + end + % aligned volume, with color blue + hreal = []; % need the handle for the individual surfs + [hreal(1), hreal(2), hreal(3)] = ft_plot_ortho(opt.realignana, 'transform', opt.realignvol.transform, 'unit', opt.realignvol.unit, 'location', [xi yi zi], 'style', 'subplot', 'parents', [h1 h2 h3], 'update', opt.update, 'doscale', false, 'clim', opt.realignclim, 'datmask',opt.realignmask, 'opacitylim', [0 1]); + for ih = 1:3 + col = get(hreal(ih), 'CData'); + col(:,:,1:2) = 0; + set(hreal(ih), 'CData',col); + end + end + end % if ~opt.viewresult + + % fetch surf objects, set ana tag, and put in surfhandles + if ~opt.viewresult || (opt.viewresult && ~opt.twovol) + opt.anahandles = findobj(opt.handlesfigure, 'type', 'surface')'; + parenttag = get(opt.anahandles, 'parent'); + parenttag{1} = get(parenttag{1}, 'tag'); + parenttag{2} = get(parenttag{2}, 'tag'); + parenttag{3} = get(parenttag{3}, 'tag'); + [i1,i2,i3] = intersect(parenttag, {'ik';'jk';'ij'}); + opt.anahandles = opt.anahandles(i3(i2)); % seems like swapping the order + opt.anahandles = opt.anahandles(:)'; + set(opt.anahandles, 'tag', 'ana'); + else + % this should do the same as the above + set(hbase, 'tag', 'ana'); + set(hreal, 'tag', 'ana'); + opt.anahandles = {hbase, hreal}; + end +else + % update the existing figure + if ~opt.viewresult + % if realigning, plotting is done in voxel space + ft_plot_ortho(opt.ana, 'transform', eye(4), 'location', [xi yi zi], 'style', 'subplot', 'surfhandle', opt.anahandles, 'update', opt.update, 'doscale', false, 'clim', opt.clim); + else + % if viewing result, plotting is done in head coordinate system space + if ~opt.twovol + % one vol case + ft_plot_ortho(opt.ana, 'transform', mri.transform, 'unit', mri.unit, 'location', [xi yi zi], 'style', 'subplot', 'surfhandle', opt.anahandles, 'update', opt.update, 'doscale', false, 'clim', opt.realignclim); + else + % two vol case + % base volume, with color red + hbase = []; % need the handle for the individual surfs + [hbase(1), hbase(2), hbase(3)] = ft_plot_ortho(opt.ana, 'transform', mri.transform, 'unit', mri.unit, 'location', [xi yi zi], 'style', 'subplot', 'surfhandle', opt.anahandles{1}, 'update', opt.update, 'doscale', false, 'clim', opt.targetclim, 'datmask', opt.targetmask, 'opacitylim', [0 1]); + for ih = 1:3 + col = get(hbase(ih), 'CData'); + col(:,:,2:3) = 0; + set(hbase(ih), 'CData', col); + end + % aligned volume, with color blue + hreal = []; % need the handle for the individual surfs + [hreal(1), hreal(2), hreal(3)] = ft_plot_ortho(opt.realignana, 'transform', opt.realignvol.transform, 'unit', opt.realignvol.unit, 'location', [xi yi zi], 'style', 'subplot', 'surfhandle', opt.anahandles{2}, 'update', opt.update, 'doscale', false, 'clim', opt.realignclim, 'datmask', opt.realignmask, 'opacitylim', [0 1]); + for ih = 1:3 + col = get(hreal(ih), 'CData'); + col(:,:,1:2) = 0; + set(hreal(ih), 'CData', col); + end + end + end % if ~opt.viewresult + + % display current location + if ~opt.viewresult + % if realigning, plotting is done in voxel space + if all(round([xi yi zi])<=mri.dim) && all(round([xi yi zi])>0) + fprintf('==================================================================================\n'); + + lab = 'crosshair'; + vox = [xi yi zi]; + ind = sub2ind(mri.dim(1:3), round(vox(1)), round(vox(2)), round(vox(3))); + pos = ft_warp_apply(mri.transform, vox); + switch opt.unit + case 'mm' + fprintf('%10s: voxel %9d, index = [%3d %3d %3d], head = [%.1f %.1f %.1f] %s\n', lab, ind, vox, pos, opt.unit); + case 'cm' + fprintf('%10s: voxel %9d, index = [%3d %3d %3d], head = [%.2f %.2f %.2f] %s\n', lab, ind, vox, pos, opt.unit); + case 'm' + fprintf('%10s: voxel %9d, index = [%3d %3d %3d], head = [%.4f %.4f %.4f] %s\n', lab, ind, vox, pos, opt.unit); + otherwise + fprintf('%10s: voxel %9d, index = [%3d %3d %3d], head = [%f %f %f] %s\n', lab, ind, vox, pos, opt.unit); + end + end + + for i=1:length(opt.fidlabel) + lab = opt.fidlabel{i}; + vox = opt.fiducial.(lab); + ind = sub2ind(mri.dim(1:3), round(vox(1)), round(vox(2)), round(vox(3))); + pos = ft_warp_apply(mri.transform, vox); + switch opt.unit + case 'mm' + fprintf('%10s: voxel %9d, index = [%3d %3d %3d], head = [%.1f %.1f %.1f] %s\n', lab, ind, vox, pos, opt.unit); + case 'cm' + fprintf('%10s: voxel %9d, index = [%3d %3d %3d], head = [%.2f %.2f %.2f] %s\n', lab, ind, vox, pos, opt.unit); + case 'm' + fprintf('%10s: voxel %9d, index = [%3d %3d %3d], head = [%.4f %.4f %.4f] %s\n', lab, ind, vox, pos, opt.unit); + otherwise + fprintf('%10s: voxel %9d, index = [%3d %3d %3d], head = [%f %f %f] %s\n', lab, ind, vox, pos, opt.unit); + end + end + + else + % if viewing result, plotting is done in head coordinate system space + lab = 'crosshair'; + pos = [xi yi zi]; + switch opt.unit + case 'mm' + fprintf('%10s: head = [%.1f %.1f %.1f] %s\n', lab, pos, opt.unit); + case 'cm' + fprintf('%10s: head = [%.2f %.2f %.2f] %s\n', lab, pos, opt.unit); + case 'm' + fprintf('%10s: head = [%.4f %.4f %.4f] %s\n', lab, pos, opt.unit); + otherwise + fprintf('%10s: head = [%f %f %f] %s\n', lab, pos, opt.unit); + end + end % if ~opt.viewresult + +end % if opt.init + +set(opt.handlesaxes(1), 'Visible', 'on'); +set(opt.handlesaxes(2), 'Visible', 'on'); +set(opt.handlesaxes(3), 'Visible', 'on'); +if opt.viewresult + set(opt.handlesaxes(1), 'color', [.94 .94 .94]); + set(opt.handlesaxes(2), 'color', [.94 .94 .94]); + set(opt.handlesaxes(3), 'color', [.94 .94 .94]); +end + + +% make the last current axes current again +sel = findobj('type', 'axes', 'tag',tag); +if ~isempty(sel) + set(opt.handlesfigure, 'currentaxes', sel(1)); +end + +% set crosshair coordinates dependent on voxel/system coordinate space +% crosshair needs to be plotted 'towards' the viewing person, i.e. with a little offset +% i.e. this is the coordinate of the 'flat' axes with a little bit extra in the direction of the axis +% this offset cannot be higher than the to be plotted data, or it will not be visible (i.e. be outside of the visible axis) +if ~opt.viewresult + crossoffs = opt.dim; + crossoffs(2) = 1; % workaround to use the below +else + % because the orientation of the three slices are determined by eye(3) (no orientation is specified above), + % the direction of view is always: + % h1 -to+ + % h2 +to- + % h3 -to+ + % use this to create the offset for viewing the crosshair + mincoordstep = abs(ft_warp_apply(mri.transform, [1 1 1]) - ft_warp_apply(mri.transform, [2 2 2])); + crossoffs = [xi yi zi] + [1 -1 1].*mincoordstep; +end + +if opt.init + % draw the crosshairs for the first time + hch1 = ft_plot_crosshair([xi crossoffs(2) zi], 'parent', h1, 'color', 'yellow'); + hch2 = ft_plot_crosshair([crossoffs(1) yi zi], 'parent', h2, 'color', 'yellow'); + hch3 = ft_plot_crosshair([xi yi crossoffs(3)], 'parent', h3, 'color', 'yellow'); + opt.handlescross = [hch1(:)';hch2(:)';hch3(:)']; + opt.handlesmarker = []; +else + % update the existing crosshairs, don't change the handles + ft_plot_crosshair([xi crossoffs(2) zi], 'handle', opt.handlescross(1, :)); + ft_plot_crosshair([crossoffs(1) yi zi], 'handle', opt.handlescross(2, :)); + ft_plot_crosshair([xi yi crossoffs(3)], 'handle', opt.handlescross(3, :)); +end +% For some unknown god-awful reason, the line command 'disables' all transparency. +% The below command resets it. It was the only axes property that I (=roemei) could +% find that changed after adding the crosshair, and putting it back to 'childorder' +% instead of 'depth' fixes the problem. Lucky, the line command only 'disables' in +% the new graphics system introduced in 2014b (any version below is fine, and does +% not contain the sortmethod property --> crash) +if ~verLessThan('matlab', '8.4') % 8.4 = 2014b + set(h1, 'sortMethod', 'childorder') + set(h2, 'sortMethod', 'childorder') + set(h3, 'sortMethod', 'childorder') +end + +if opt.showcrosshair + set(opt.handlescross, 'Visible', 'on'); +else + set(opt.handlescross, 'Visible', 'off'); +end + +markercolor = {'r', 'g', 'b', 'y'}; + +delete(opt.handlesmarker(opt.handlesmarker(:)>0)); +opt.handlesmarker = []; + +if ~opt.viewresult + for i=1:length(opt.fidlabel) + pos = opt.fiducial.(opt.fidlabel{i}); + % if any(isnan(pos)) + % continue + % end + + posi = pos(1); + posj = pos(2); + posk = pos(3); + + subplot(h1); + hold on + opt.handlesmarker(i,1) = plot3(posi, 1, posk, 'marker', 'o', 'color', markercolor{i}); + hold off + + subplot(h2); + hold on + opt.handlesmarker(i,2) = plot3(opt.dim(1), posj, posk, 'marker', 'o', 'color', markercolor{i}); + hold off + + subplot(h3); + hold on + opt.handlesmarker(i,3) = plot3(posi, posj, opt.dim(3), 'marker', 'o', 'color', markercolor{i}); + hold off + end % for each fiducial +end + +if opt.showmarkers + set(opt.handlesmarker, 'Visible', 'on'); +else + set(opt.handlesmarker, 'Visible', 'off'); +end + +opt.init = false; +setappdata(h, 'opt', opt); +set(h, 'currentaxes', curr_ax); + +uiresume + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function cb_keyboard(h, eventdata) + +if isempty(eventdata) + % determine the key that corresponds to the uicontrol element that was activated + key = get(h, 'userdata'); +else + % determine the key that was pressed on the keyboard + key = parseKeyboardEvent(eventdata); +end +% get focus back to figure +if ~strcmp(get(h, 'type'), 'figure') + set(h, 'enable', 'off'); + drawnow; + set(h, 'enable', 'on'); +end + +h = getparent(h); +opt = getappdata(h, 'opt'); + +curr_ax = get(h, 'currentaxes'); +tag = get(curr_ax, 'tag'); + +if isempty(key) + % this happens if you press the apple key + key = ''; +end + +% the following code is largely shared with FT_SOURCEPLOT +switch key + case {'' 'shift+shift' 'alt-alt' 'control+control' 'command-0'} + % do nothing + + case '1' + subplot(opt.handlesaxes(1)); + + case '2' + subplot(opt.handlesaxes(2)); + + case '3' + subplot(opt.handlesaxes(3)); + + case opt.fidletter + if ~opt.viewresult + sel = strcmp(key, opt.fidletter); + fprintf('==================================================================================\n'); + fprintf('selected %s\n', opt.fidlabel{sel}); + opt.fiducial.(opt.fidlabel{sel}) = opt.ijk; + setappdata(h, 'opt', opt); + cb_redraw(h); + end + + case 'q' + setappdata(h, 'opt', opt); + cb_cleanup(h); + + case {'i' 'j' 'k' 'm' 28 29 30 31 'leftarrow' 'rightarrow' 'uparrow' 'downarrow'} % TODO FIXME use leftarrow rightarrow uparrow downarrow + % update the view to a new position + if strcmp(tag,'ik') && (strcmp(key,'i') || strcmp(key,'uparrow') || isequal(key, 30)), opt.ijk(3) = opt.ijk(3)+1; opt.update = [0 0 1]; + elseif strcmp(tag,'ik') && (strcmp(key,'j') || strcmp(key,'leftarrow') || isequal(key, 28)), opt.ijk(1) = opt.ijk(1)-1; opt.update = [0 1 0]; + elseif strcmp(tag,'ik') && (strcmp(key,'k') || strcmp(key,'rightarrow') || isequal(key, 29)), opt.ijk(1) = opt.ijk(1)+1; opt.update = [0 1 0]; + elseif strcmp(tag,'ik') && (strcmp(key,'m') || strcmp(key,'downarrow') || isequal(key, 31)), opt.ijk(3) = opt.ijk(3)-1; opt.update = [0 0 1]; + elseif strcmp(tag,'ij') && (strcmp(key,'i') || strcmp(key,'uparrow') || isequal(key, 30)), opt.ijk(2) = opt.ijk(2)+1; opt.update = [1 0 0]; + elseif strcmp(tag,'ij') && (strcmp(key,'j') || strcmp(key,'leftarrow') || isequal(key, 28)), opt.ijk(1) = opt.ijk(1)-1; opt.update = [0 1 0]; + elseif strcmp(tag,'ij') && (strcmp(key,'k') || strcmp(key,'rightarrow') || isequal(key, 29)), opt.ijk(1) = opt.ijk(1)+1; opt.update = [0 1 0]; + elseif strcmp(tag,'ij') && (strcmp(key,'m') || strcmp(key,'downarrow') || isequal(key, 31)), opt.ijk(2) = opt.ijk(2)-1; opt.update = [1 0 0]; + elseif strcmp(tag,'jk') && (strcmp(key,'i') || strcmp(key,'uparrow') || isequal(key, 30)), opt.ijk(3) = opt.ijk(3)+1; opt.update = [0 0 1]; + elseif strcmp(tag,'jk') && (strcmp(key,'j') || strcmp(key,'leftarrow') || isequal(key, 28)), opt.ijk(2) = opt.ijk(2)-1; opt.update = [1 0 0]; + elseif strcmp(tag,'jk') && (strcmp(key,'k') || strcmp(key,'rightarrow') || isequal(key, 29)), opt.ijk(2) = opt.ijk(2)+1; opt.update = [1 0 0]; + elseif strcmp(tag,'jk') && (strcmp(key,'m') || strcmp(key,'downarrow') || isequal(key, 31)), opt.ijk(3) = opt.ijk(3)-1; opt.update = [0 0 1]; + else + % do nothing + end + + setappdata(h, 'opt', opt); + cb_redraw(h); + + % contrast scaling + case {43 'shift+equal'} % numpad + + % disable if viewresult + if ~opt.viewresult + if isempty(opt.clim) + opt.clim = [min(opt.ana(:)) max(opt.ana(:))]; + end + % reduce color scale range by 10% + cscalefactor = (opt.clim(2)-opt.clim(1))/10; + %opt.clim(1) = opt.clim(1)+cscalefactor; + opt.clim(2) = opt.clim(2)-cscalefactor; + setappdata(h, 'opt', opt); + cb_redraw(h); + end + + case {45 'shift+hyphen'} % numpad - + % disable if viewresult + if ~opt.viewresult + if isempty(opt.clim) + opt.clim = [min(opt.ana(:)) max(opt.ana(:))]; + end + % increase color scale range by 10% + cscalefactor = (opt.clim(2)-opt.clim(1))/10; + %opt.clim(1) = opt.clim(1)-cscalefactor; + opt.clim(2) = opt.clim(2)+cscalefactor; + setappdata(h, 'opt', opt); + cb_redraw(h); + end + + case 99 % 'c' + opt.showcrosshair = ~opt.showcrosshair; + setappdata(h, 'opt', opt); + cb_redraw(h); + + case 102 % 'f' + if ~opt.viewresult + opt.showmarkers = ~opt.showmarkers; + setappdata(h, 'opt', opt); + cb_redraw(h); + end + + case 3 % right mouse click + % add point to a list + l1 = get(get(gca, 'xlabel'), 'string'); + l2 = get(get(gca, 'ylabel'), 'string'); + switch l1 + case 'i' + xc = d1; + case 'j' + yc = d1; + case 'k' + zc = d1; + end + switch l2 + case 'i' + xc = d2; + case 'j' + yc = d2; + case 'k' + zc = d2; + end + pnt = [pnt; xc yc zc]; + + case 2 % middle mouse click + l1 = get(get(gca, 'xlabel'), 'string'); + l2 = get(get(gca, 'ylabel'), 'string'); + + % remove the previous point + if size(pnt,1)>0 + pnt(end,:) = []; + end + + if l1=='i' && l2=='j' + updatepanel = [1 2 3]; + elseif l1=='i' && l2=='k' + updatepanel = [2 3 1]; + elseif l1=='j' && l2=='k' + updatepanel = [3 1 2]; + end + + otherwise + % do nothing + +end % switch key +if ~opt.viewresult + uiresume(h) +end +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function cb_buttonpress(h, eventdata) + +h = getparent(h); +cb_getposition(h); + +switch get(h, 'selectiontype') + case 'normal' + % just update to new position, nothing else to be done here + cb_redraw(h); + case 'alt' + set(h, 'windowbuttonmotionfcn', @cb_tracemouse); + cb_redraw(h); + otherwise +end + +uiresume + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function cb_buttonrelease(h, eventdata) + +set(h, 'windowbuttonmotionfcn', ''); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function cb_tracemouse(h, eventdata) + +h = getparent(h); +cb_getposition(h); +cb_redraw(h); +uiresume + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function cb_getposition(h, eventdata) + +h = getparent(h); +opt = getappdata(h, 'opt'); + +curr_ax = get(h, 'currentaxes'); +pos = mean(get(curr_ax, 'currentpoint')); + +tag = get(curr_ax, 'tag'); + +% transform pos from coordinate system space to voxel space if viewing results +if opt.viewresult + pos = ft_warp_apply(inv(opt.mri.transform),pos); % not sure under which circumstances the transformation matrix is not invertible... +end + +if ~isempty(tag) && ~opt.init + if strcmp(tag, 'ik') + opt.ijk([1 3]) = round(pos([1 3])); + opt.update = [1 1 1]; + elseif strcmp(tag, 'ij') + opt.ijk([1 2]) = round(pos([1 2])); + opt.update = [1 1 1]; + elseif strcmp(tag, 'jk') + opt.ijk([2 3]) = round(pos([2 3])); + opt.update = [1 1 1]; + end +end +opt.ijk = min(opt.ijk(:)', opt.dim); +opt.ijk = max(opt.ijk(:)', [1 1 1]); + +setappdata(h, 'opt', opt); +uiresume + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function cb_cleanup(h, eventdata) + +opt = getappdata(h, 'opt'); +if ~opt.viewresult + opt.quit = true; + setappdata(h, 'opt', opt); + uiresume +else + % not part of interactive process requiring output handling, quite immediately + delete(h); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function h = getparent(h) +p = h; +while p~=0 + h = p; + p = get(h, 'parent'); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function key = parseKeyboardEvent(eventdata) + +key = eventdata.Key; + +% handle possible numpad events (different for Windows and UNIX systems) +% NOTE: shift+numpad number does not work on UNIX, since the shift +% modifier is always sent for numpad events +if isunix() + shiftInd = match_str(eventdata.Modifier, 'shift'); + if ~isnan(str2double(eventdata.Character)) && ~isempty(shiftInd) + % now we now it was a numpad keystroke (numeric character sent AND + % shift modifier present) + key = eventdata.Character; + eventdata.Modifier(shiftInd) = []; % strip the shift modifier + end +elseif ispc() + if strfind(eventdata.Key, 'numpad') + key = eventdata.Character; + end +end + +if ~isempty(eventdata.Modifier) + key = [eventdata.Modifier{1} '+' key]; +end + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function cb_minslider(h4, eventdata) + +tag = get(h4, 'tag'); +newlim = get(h4, 'value'); +h = getparent(h4); +opt = getappdata(h, 'opt'); +if isempty(tag) + opt.clim(1) = newlim; +elseif strcmp(tag, 'rel') + opt.realignclim(1) = newlim; +elseif strcmp(tag, 'tar') + opt.targetclim(1) = newlim; +end +if isempty(tag) + fprintf('contrast limits updated to [%.03f %.03f]\n', opt.clim); +elseif strcmp(tag, 'rel') + fprintf('realigned contrast limits updated to [%.03f %.03f]\n', opt.realignclim); +elseif strcmp(tag, 'tar') + fprintf('target cfontrast limits updated to [%.03f %.03f]\n', opt.targetclim); +end +setappdata(h, 'opt', opt); +cb_redraw(h); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function cb_maxslider(h5, eventdata) + +tag = get(h5, 'tag'); +newlim = get(h5, 'value'); +h = getparent(h5); +opt = getappdata(h, 'opt'); +if isempty(tag) + opt.clim(2) = newlim; +elseif strcmp(tag, 'rel') + opt.realignclim(2) = newlim; +elseif strcmp(tag, 'tar') + opt.targetclim(2) = newlim; +end +if isempty(tag) + fprintf('contrast limits updated to [%.03f %.03f]\n', opt.clim); +elseif strcmp(tag, 'rel') + fprintf('realigned contrast limits updated to [%.03f %.03f]\n', opt.realignclim); +elseif strcmp(tag, 'tar') + fprintf('target contrast limits updated to [%.03f %.03f]\n', opt.targetclim); +end +setappdata(h, 'opt', opt); +cb_redraw(h); diff --git a/external/fieldtrip/ft_movieplotER.m b/external/fieldtrip/ft_movieplotER.m index 502f04af..f94b384f 100644 --- a/external/fieldtrip/ft_movieplotER.m +++ b/external/fieldtrip/ft_movieplotER.m @@ -36,6 +36,8 @@ % If you specify this option the input data will be read from a *.mat % file on disk. This mat files should contain only a single variable named 'data', % corresponding to the input structure. +% +% See also FT_MULTIPLOTER, FT_TOPOPLOTER, FT_SINGLEPLOTER, FT_MOVIEPLOTTFR, FT_SOURCEMOVIE % Copyright (C) 2009, Ingrid Nieuwenhuis % Copyright (C) 2011, Jan-Mathijs Schoffelen, Robert Oostenveld, Cristiano Micheli @@ -83,7 +85,7 @@ % apply optional baseline correction if ~strcmp(cfg.baseline, 'no') - tmpcfg = keepfields(cfg, {'baseline', 'baselinetype', 'parameter'}); + tmpcfg = keepfields(cfg, {'baseline', 'baselinetype', 'parameter', 'showcallinfo'}); data = ft_timelockbaseline(tmpcfg, data); [cfg, data] = rollback_provenance(cfg, data); % prevent the baseline correction from happening in ft_movieplotTFR diff --git a/external/fieldtrip/ft_movieplotTFR.m b/external/fieldtrip/ft_movieplotTFR.m index afe1e579..d67f6d49 100644 --- a/external/fieldtrip/ft_movieplotTFR.m +++ b/external/fieldtrip/ft_movieplotTFR.m @@ -42,27 +42,29 @@ % if you specify this option the input data will be read from a *.mat % file on disk. this mat files should contain only a single variable named 'data', % corresponding to the input structure. +% +% See also FT_MULTIPLOTTFR, FT_TOPOPLOTTFR, FT_SINGLEPLOTTFR, FT_MOVIEPLOTER, FT_SOURCEMOVIE % Copyright (c) 2009, Ingrid Nieuwenhuis -% Copyright (c) 2011, jan-Mathijs Schoffelen, Robert Oostenveld, Cristiano Micheli +% Copyright (c) 2011, Jan-Mathijs Schoffelen, Robert Oostenveld, Cristiano Micheli % -% this file is part of fieldtrip, see http://www.fieldtriptoolbox.org +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. % % FieldTrip is free software: you can redistribute it and/or modify -% it under the terms of the gnu general public license as published by -% the free software foundation, either version 3 of the license, or +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or % (at your option) any later version. % % FieldTrip is distributed in the hope that it will be useful, -% but without any warranty; without even the implied warranty of -% merchantability or fitness for a particular purpose. see the -% gnu general public license for more details. +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. % -% you should have received a copy of the gnu general public license -% along with fieldtrip. if not, see . +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . % -% $id: ft_movieploter.m 4354 2011-10-05 15:06:02z crimic $ +% $Id$ % these are used by the ft_preamble/ft_postamble function and scripts ft_revision = '$Id$'; @@ -118,7 +120,7 @@ % apply optional baseline correction if ~strcmp(cfg.baseline, 'no') - tmpcfg = keepfields(cfg, {'baseline', 'baselinetype', 'parameter'}); + tmpcfg = keepfields(cfg, {'baseline', 'baselinetype', 'parameter', 'showcallinfo'}); data = ft_freqbaseline(tmpcfg, data); [cfg, data] = rollback_provenance(cfg, data); end @@ -138,17 +140,17 @@ if isfield(data,'dimord') if strcmp(data.dimord,'chan_freq_time') if length(xvalues)~=size(parameter,3) - error('inconsistent size of "%s" compared to "%s"', cfg.parameter, xparam); + ft_error('inconsistent size of "%s" compared to "%s"', cfg.parameter, xparam); end if length(yvalues)~=size(parameter,2) - error('inconsistent size of "%s" compared to "%s"', cfg.parameter, yparam); + ft_error('inconsistent size of "%s" compared to "%s"', cfg.parameter, yparam); end elseif strcmp(data.dimord,'chan_time') if length(xvalues)~=size(parameter,2) - error('inconsistent size of "%s" compared to "%s"', cfg.parameter, xparam); + ft_error('inconsistent size of "%s" compared to "%s"', cfg.parameter, xparam); end else - error('input data is incompatible') + ft_error('input data is incompatible') end end @@ -188,7 +190,7 @@ % select the channels in the data that match with the layout: [seldat, sellay] = match_str(data.label, layout.label); if isempty(seldat) - error('labels in data and labels in layout do not match'); + ft_error('labels in data and labels in layout do not match'); end % make a subselection of the data @@ -368,7 +370,7 @@ F(iFrame) = getframe; end else - error('Either moviefreq or movietime should contain a bin number') + ft_error('Either moviefreq or movietime should contain a bin number') end else for iFrame = 1:floor(size(parameter, 2)/cfg.samperframe) diff --git a/external/fieldtrip/ft_multiplotCC.m b/external/fieldtrip/ft_multiplotCC.m index ee7558be..f44eddaa 100644 --- a/external/fieldtrip/ft_multiplotCC.m +++ b/external/fieldtrip/ft_multiplotCC.m @@ -57,19 +57,18 @@ data = ft_checkdata(data); % check if the input cfg is valid for this function -cfg = ft_checkconfig(cfg, 'renamed', {'zparam', 'parameter'}); +cfg = ft_checkconfig(cfg, 'renamed', {'zparam', 'parameter'}); cfg = ft_checkconfig(cfg, 'deprecated', {'xparam'}); -% if ~isfield(cfg, 'layout'), cfg.layout = 'CTF151.lay'; end; -%if ~isfield(cfg, 'xparam'), cfg.xparam = 'freq'; end; -if ~isfield(cfg, 'xlim'), cfg.xlim = 'all'; end; -if ~isfield(cfg, 'parameter'), cfg.parameter = 'avg.icohspctrm'; end; +% set the defaults +cfg.xlim = ft_getopt(cfg, 'xlim', 'all'); +cfg.parameter = ft_getopt(cfg, 'parameter', 'avg.icohspctrm'); -if strcmp(cfg.parameter, 'avg.icohspctrm') && ~issubfield(data, 'avg.icohspctrm'), +if strcmp(cfg.parameter, 'avg.icohspctrm') && ~issubfield(data, 'avg.icohspctrm') data.avg.icohspctrm = abs(imag(data.avg.cohspctrm)); end -if strcmp(data.dimord, 'chan_chan_freq'), +if strcmp(data.dimord, 'chan_chan_freq') % reshape input-data, such that ft_topoplotTFR will take it cnt = 1; siz = size(data.prob); @@ -88,16 +87,16 @@ scale = [0 max(dat(:))-0.2]; end -if isfield(cfg, 'xparam'), +if isfield(cfg, 'xparam') xparam = getsubfield(data, cfg.xparam); - if ~strcmp(cfg.xlim, 'all'), + if ~strcmp(cfg.xlim, 'all') fbin = [nearest(xparam, cfg.xlim(1)) nearest(xparam, cfg.xlim(2))]; else fbin = [xparam(1) xparam(end)]; end end -% R=read or create the layout that will be used for plotting +% read or create the layout that will be used for plotting lay = ft_prepare_layout(cfg);%, varargin{1}); cfg.layout = lay; ft_plot_lay(lay, 'box', false,'label','no','point','no'); @@ -113,7 +112,6 @@ xScaleFac = 1/(max(Width)+ max(X) - min(X)); yScaleFac = 1/(max(Height)+ max(Y) - min(Y)); - Xpos = xScaleFac*(X-min(X)); Ypos = 0.9*yScaleFac*(Y-min(Y)); @@ -129,7 +127,7 @@ config.refmarker = strmatch(Lbl(k), data.label); end config.interplimits = 'electrodes'; - if isfield(cfg, 'xparam'), + if isfield(cfg, 'xparam') config.xparam = cfg.xparam; config.xlim = xparam; else @@ -142,7 +140,7 @@ config.zlim = scale; config.grid_scale = 30; ft_topoplotTFR(config, data); - drawnow; + drawnow end end @@ -152,3 +150,4 @@ ft_postamble previous data ft_postamble history data ft_postamble provenance + diff --git a/external/fieldtrip/ft_multiplotER.m b/external/fieldtrip/ft_multiplotER.m index b5470135..642c9931 100644 --- a/external/fieldtrip/ft_multiplotER.m +++ b/external/fieldtrip/ft_multiplotER.m @@ -1,41 +1,44 @@ function [cfg] = ft_multiplotER(cfg, varargin) -% FT_MULTIPLOTER plots the event-related potentials, event-related fields -% or oscillatory activity (power or coherence) versus frequency. Multiple -% datasets can be overlayed. The plots are arranged according to their -% location specified in the layout. +% FT_MULTIPLOTER plots the event-related potentials or event-related fields verus +% time, or the oscillatory activity (power or coherence) versus frequency. Multiple +% datasets can be overlayed. The plots are arranged according to their location +% specified in the layout. % % Use as % ft_multiplotER(cfg, data) % or % ft_multiplotER(cfg, data, data2, ..., dataN) % -% The data can be an ERP/ERF produced by FT_TIMELOCKANALYSIS, a powerspectrum -% produced by FT_FREQANALYSIS or a coherencespectrum produced by FT_FREQDESCRIPTIVES. -% If you specify multiple datasets they must contain the same channels, etc. +% The data can be an event-related potential or field produced by +% FT_TIMELOCKANALYSIS, a power spectrum produced by FT_FREQANALYSIS or a coherence +% spectrum produced by FT_FREQDESCRIPTIVES. +% +% If you specify multiple datasets they should contain the same channels, etc. % % The configuration can have the following parameters: -% cfg.parameter = field to be plotted on y-axis (default depends on data.dimord) -% 'avg', 'powspctrm' or 'cohspctrm' +% cfg.parameter = field to be plotted on y-axis, for example 'avg', 'powspctrm' or 'cohspctrm' (default is automatic) % cfg.maskparameter = field in the first dataset to be used for marking significant data % cfg.maskstyle = style used for masking of data, 'box', 'thickness' or 'saturation' (default = 'box') % cfg.xlim = 'maxmin' or [xmin xmax] (default = 'maxmin') % cfg.ylim = 'maxmin', 'maxabs', 'zeromax', 'minzero', or [ymin ymax] (default = 'maxmin') +% cfg.gradscale = number, scaling to apply to the MEG gradiometer channels prior to display +% cfg.magscale = number, scaling to apply to the MEG magnetometer channels prior to display % cfg.channel = Nx1 cell-array with selection of channels (default = 'all'), see FT_CHANNELSELECTION for details % cfg.refchannel = name of reference channel for visualising connectivity, can be 'gui' % cfg.baseline = 'yes', 'no' or [time1 time2] (default = 'no'), see FT_TIMELOCKBASELINE or FT_FREQBASELINE -% cfg.baselinetype = 'absolute' or 'relative' (default = 'absolute') % cfg.trials = 'all' or a selection given as a 1xN vector (default = 'all') -% cfg.axes = 'yes', 'no' (default = 'yes') -% Draw x- and y-axes for each graph -% cfg.box = 'yes', 'no' (default = 'no') -% Draw a box around each graph -% cfg.comment = string of text (default = date + colors) +% cfg.axes = string, 'yes' or 'no' whether to draw x- and y-axes for each graph (default = 'yes') +% cfg.box = string, 'yes' or 'no' whether to draw a box around each graph (default = 'no') +% cfg.showlabels = 'yes' or 'no' (default = 'no') +% cfg.showoutline = 'yes' or 'no' (default = 'no') +% cfg.showscale = 'yes' or 'no' (default = 'yes') +% cfg.showcomment = 'yes' or 'no' (default = 'yes') +% cfg.comment = string of text (default = date + limits) % Add 'comment' to graph (according to COMNT in the layout) -% cfg.showlabels = 'yes', 'no' (default = 'no') -% cfg.showoutline = 'yes', 'no' (default = 'no') -% cfg.fontsize = font size of comment and labels (if present) (default = 8) -% cfg.interactive = Interactive plot 'yes' or 'no' (default = 'yes') +% cfg.limittext = add user-defined text instead of cfg.comment, (default = cfg.comment) +% cfg.fontsize = font size of comment and labels (default = 8) +% cfg.interactive = 'yes' or 'no', make the plot interactive (default = 'yes') % In a interactive plot you can select areas and produce a new % interactive plot when a selected area is clicked. Multiple areas % can be selected by holding down the SHIFT key. @@ -45,31 +48,26 @@ % cfg.linewidth = linewidth in points (default = 0.5) % cfg.graphcolor = color(s) used for plotting the dataset(s) (default = 'brgkywrgbkywrgbkywrgbkyw') % alternatively, colors can be specified as Nx3 matrix of RGB values -% cfg.directionality = '', 'inflow' or 'outflow' specifies for -% connectivity measures whether the inflow into a -% node, or the outflow from a node is plotted. The -% (default) behavior of this option depends on the dimor -% of the input data (see below). -% cfg.layout = specify the channel layout for plotting using one of -% the supported ways (see below). +% cfg.directionality = '', 'inflow' or 'outflow' specifies for connectivity measures whether the +% inflow into a node, or the outflow from a node is plotted. The (default) behavior +% of this option depends on the dimord of the input data (see below). +% cfg.layout = specify the channel layout for plotting using one of the supported ways (see below). % -% For the plotting of directional connectivity data the cfg.directionality -% option determines what is plotted. The default value and the supported -% functionality depend on the dimord of the input data. If the input data -% is of dimord 'chan_chan_XXX', the value of directionality determines -% whether, given the reference channel(s), the columns (inflow), or rows -% (outflow) are selected for plotting. In this situation the default is -% 'inflow'. Note that for undirected measures, inflow and outflow should -% give the same output. If the input data is of dimord 'chancmb_XXX', the -% value of directionality determines whether the rows in data.labelcmb are -% selected. With 'inflow' the rows are selected if the refchannel(s) occur in -% the right column, with 'outflow' the rows are selected if the -% refchannel(s) occur in the left column of the labelcmb-field. Default in -% this case is '', which means that all rows are selected in which the -% refchannel(s) occur. This is to robustly support linearly indexed -% undirected connectivity metrics. In the situation where undirected -% connectivity measures are linearly indexed, specifying 'inflow' or -% 'outflow' can result in unexpected behavior. +% For the plotting of directional connectivity data the cfg.directionality option +% determines what is plotted. The default value and the supported functionality +% depend on the dimord of the input data. If the input data is of dimord +% 'chan_chan_XXX', the value of directionality determines whether, given the +% reference channel(s), the columns (inflow), or rows (outflow) are selected for +% plotting. In this situation the default is 'inflow'. Note that for undirected +% measures, inflow and outflow should give the same output. If the input data is of +% dimord 'chancmb_XXX', the value of directionality determines whether the rows in +% data.labelcmb are selected. With 'inflow' the rows are selected if the +% refchannel(s) occur in the right column, with 'outflow' the rows are selected if +% the refchannel(s) occur in the left column of the labelcmb-field. Default in this +% case is '', which means that all rows are selected in which the refchannel(s) +% occur. This is to robustly support linearly indexed undirected connectivity +% metrics. In the situation where undirected connectivity measures are linearly +% indexed, specifying 'inflow' or 'outflow' can result in unexpected behavior. % % The layout defines how the channels are arranged and what the size of each % subplot is. You can specify the layout in a variety of ways: @@ -100,6 +98,8 @@ % Copyright (C) 2003-2006, Ole Jensen % Copyright (C) 2007-2011, Roemer van der Meij & Jan-Mathijs Schoffelen +% Copyright (C) 2012-2017, F.C. Donders Centre + % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -119,6 +119,17 @@ % % $Id$ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% DEVELOPERS NOTE: This code is organized in a similar fashion for multiplot/singleplot/topoplot +% and for ER/TFR and should remain consistent over those 6 functions. +% Section 1: general cfg handling that is independent from the data +% Section 2: data handling, this also includes converting bivariate (chan_chan and chancmb) into univariate data +% Section 3: select the data to be plotted and determine min/max range +% Section 4: do the actual plotting +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Section 1: general cfg handling that is independent from the data + % these are used by the ft_preamble/ft_postamble function and scripts ft_revision = '$Id$'; ft_nargin = nargin; @@ -137,34 +148,39 @@ return end -for i=1:length(varargin) +Ndata = length(varargin); +for i=1:Ndata % check if the input data is valid for this function varargin{i} = ft_checkdata(varargin{i}, 'datatype', {'timelock', 'freq'}); end % check if the input cfg is valid for this function -cfg = ft_checkconfig(cfg, 'renamedval', {'zlim', 'absmax', 'maxabs'}); -cfg = ft_checkconfig(cfg, 'renamedval', {'directionality', 'feedforward', 'outflow'}); -cfg = ft_checkconfig(cfg, 'renamedval', {'directionality', 'feedback', 'inflow'}); -cfg = ft_checkconfig(cfg, 'renamed', {'matrixside', 'directionality'}); cfg = ft_checkconfig(cfg, 'renamed', {'cohrefchannel', 'refchannel'}); -cfg = ft_checkconfig(cfg, 'renamed', {'zparam', 'parameter'}); cfg = ft_checkconfig(cfg, 'renamed', {'hlim', 'xlim'}); +cfg = ft_checkconfig(cfg, 'renamed', {'matrixside', 'directionality'}); cfg = ft_checkconfig(cfg, 'renamed', {'vlim', 'ylim'}); -cfg = ft_checkconfig(cfg, 'deprecated', {'xparam'}); +cfg = ft_checkconfig(cfg, 'renamed', {'zparam', 'parameter'}); +cfg = ft_checkconfig(cfg, 'renamedval', {'directionality', 'feedback', 'inflow'}); +cfg = ft_checkconfig(cfg, 'renamedval', {'directionality', 'feedforward', 'outflow'}); +cfg = ft_checkconfig(cfg, 'renamedval', {'zlim', 'absmax', 'maxabs'}); cfg = ft_checkconfig(cfg, 'unused', {'cohtargetchannel'}); +% cfg = ft_checkconfig(cfg, 'deprecated', {'xparam'}); % set the defaults cfg.baseline = ft_getopt(cfg, 'baseline', 'no'); cfg.trials = ft_getopt(cfg, 'trials', 'all', 1); cfg.xlim = ft_getopt(cfg, 'xlim', 'maxmin'); cfg.ylim = ft_getopt(cfg, 'ylim', 'maxmin'); -cfg.comment = ft_getopt(cfg, 'comment', strcat([date '\n'])); +cfg.comment = ft_getopt(cfg, 'comment', date); +cfg.limittext = ft_getopt(cfg, 'limittext', 'default'); cfg.axes = ft_getopt(cfg, 'axes', 'yes'); cfg.showlabels = ft_getopt(cfg, 'showlabels', 'no'); cfg.showoutline = ft_getopt(cfg, 'showoutline', 'no'); +cfg.showscale = ft_getopt(cfg, 'showscale', 'yes'); +cfg.showcomment = ft_getopt(cfg, 'showcomment', 'yes'); cfg.box = ft_getopt(cfg, 'box', 'no'); cfg.fontsize = ft_getopt(cfg, 'fontsize', 8); +cfg.fontweight = ft_getopt(cfg, 'fontweight'); cfg.graphcolor = ft_getopt(cfg, 'graphcolor', 'brgkywrgbkywrgbkywrgbkyw'); cfg.interactive = ft_getopt(cfg, 'interactive', 'yes'); cfg.renderer = ft_getopt(cfg, 'renderer'); % let MATLAB decide on default @@ -181,40 +197,10 @@ cfg.frequency = ft_getopt(cfg, 'frequency', 'all'); % needed for frequency selection with TFR data cfg.latency = ft_getopt(cfg, 'latency', 'all'); % needed for latency selection with TFR data, FIXME, probably not used -if numel(findobj(gcf, 'type', 'axes', '-not', 'tag', 'ft-colorbar')) > 1 && strcmp(cfg.interactive, 'yes') - warning('using cfg.interactive = ''yes'' in subplots is not supported, setting cfg.interactive = ''no''') - cfg.interactive = 'no'; -end - -Ndata = length(varargin); - -for i=1:Ndata - dtype{i} = ft_datatype(varargin{i}); - hastime(i) = ~isempty(strfind(varargin{i}.dimord, 'time')); - hasfreq(i) = ~isempty(strfind(varargin{i}.dimord, 'freq')); -end - -% check if the input has consistent datatypes -if ~all(strcmp(dtype, dtype{1})) || ~all(hastime==hastime(1)) || ~all(hasfreq==hasfreq(1)) - error('different datatypes are not allowed as input'); -end -dtype = dtype{1}; -hastime = hastime(1); -hasfreq = hasfreq(1); - -% ensure that all inputs are sufficiently consistent -if hastime && ~checktime(varargin{:}, 'identical', cfg.tolerance); - error('this function requires identical time axes for all input structures'); -end -if hasfreq && ~checkfreq(varargin{:}, 'identical', cfg.tolerance); - error('this function requires identical frequency axes for all input structures'); -end - -%FIXME rename directionality and refchannel in more meaningful options if ischar(cfg.graphcolor) - GRAPHCOLOR = ['k' cfg.graphcolor]; + graphcolor = cfg.graphcolor(1:Ndata); elseif isnumeric(cfg.graphcolor) - GRAPHCOLOR = [0 0 0; cfg.graphcolor]; + graphcolor = cfg.graphcolor(1:Ndata,:); end % check for linestyle being a cell-array, check it's length, and lengthen it if does not have enough styles in it @@ -224,7 +210,7 @@ if Ndata>1 if (length(cfg.linestyle) < Ndata ) && (length(cfg.linestyle) > 1) - error('either specify cfg.linestyle as a cell-array with one cell for each dataset, or only specify one linestyle') + ft_error('either specify cfg.linestyle as a cell-array with one cell for each dataset, or only specify one linestyle') elseif (length(cfg.linestyle) < Ndata ) && (length(cfg.linestyle) == 1) tmpstyle = cfg.linestyle{1}; cfg.linestyle = cell(Ndata , 1); @@ -234,355 +220,214 @@ end end -% % interactive plotting is not allowed with more than 1 input -% if numel(varargin)>1 && strcmp(cfg.interactive, 'yes') -% error('interactive plotting is not supported with more than 1 input data set'); -% end +% this is needed for the figure title and correct labeling of graphcolor later on +if nargin>1 + if isfield(cfg, 'dataname') + dataname = cfg.dataname; + else + dataname = cell(1,Ndata); + for i=1:Ndata + if ~isempty(inputname(i+1)) + dataname{i} = inputname(i+1); + else + dataname{i} = ['data' num2str(i,'%02d')]; + end + end + end +else % data provided through cfg.inputfile + dataname = cfg.inputfile; +end -dimord = varargin{1}.dimord; -dimtok = tokenize(dimord, '_'); -% ensure that the preproc specific options are located in the cfg.preproc -% substructure, but also ensure that the field 'refchannel' is present at the -% highest level in the structure. This is a little hack by JM because the field -% refchannel can also refer to the plotting of a connectivity metric. Also, -% the freq2raw conversion does not work at all in the call to ft_preprocessing. -% Therefore, for now, the preprocessing will not be done when there is freq -% data in the input. A more generic solution should be considered. +%% Section 2: data handling, this also includes converting bivariate (chan_chan and chancmb) into univariate data -if isfield(cfg, 'refchannel'), refchannelincfg = cfg.refchannel; end -if ~any(strcmp({'freq', 'freqmvar'}, dtype)), - cfg = ft_checkconfig(cfg, 'createsubcfg', {'preproc'}); -end -if exist('refchannelincfg', 'var'), cfg.refchannel = refchannelincfg; end - -if ~isempty(cfg.preproc) - % preprocess the data, i.e. apply filtering, baselinecorrection, etc. - fprintf('applying preprocessing options\n'); - if ~isfield(cfg.preproc, 'feedback') - cfg.preproc.feedback = cfg.interactive; - end - for i=1:Ndata - varargin{i} = ft_preprocessing(cfg.preproc, varargin{i}); - end +for i=1:Ndata + dtype{i} = ft_datatype(varargin{i}); + hastime(i) = isfield(varargin{i}, 'time'); + hasfreq(i) = isfield(varargin{i}, 'freq'); end -for i=1:Ndata - % this is needed for correct treatment of GRAPHCOLOR later on - if nargin>1, - if ~isempty(inputname(i+1)) - iname{i+1} = inputname(i+1); - else - iname{i+1} = ['input', num2str(i, '%02d')]; - end - else - iname{i+1} = cfg.inputfile{i}; - end +% check if the input has consistent datatypes +if ~all(strcmp(dtype, dtype{1})) || ~all(hastime==hastime(1)) || ~all(hasfreq==hasfreq(1)) + ft_error('different datatypes are not allowed as input'); end +dtype = dtype{1}; +hastime = hastime(1); +hasfreq = hasfreq(1); % Set x/y/parameter defaults according to datatype and dimord switch dtype case 'timelock' xparam = 'time'; - yparam = ''; - cfg.parameter = ft_getopt(cfg, 'parameter', 'avg'); + if isfield(varargin{1}, 'trial') + cfg.parameter = ft_getopt(cfg, 'parameter', 'trial'); + elseif isfield(varargin{1}, 'individual') + cfg.parameter = ft_getopt(cfg, 'parameter', 'individual'); + elseif isfield(varargin{1}, 'avg') + cfg.parameter = ft_getopt(cfg, 'parameter', 'avg'); + end case 'freq' - if any(ismember(dimtok, 'time')) - xparam = 'time'; - yparam = 'freq'; - cfg.parameter = ft_getopt(cfg, 'parameter', 'powspctrm'); + if hastime && hasfreq + xparam = 'time'; % further down the code will compute the average over selected frequencies else xparam = 'freq'; - yparam = ''; - cfg.parameter = ft_getopt(cfg, 'parameter', 'powspctrm'); end + cfg.parameter = ft_getopt(cfg, 'parameter', 'powspctrm'); case 'comp' % not supported otherwise % not supported end -% user specified own fields, but no yparam (which is not asked in help) -if exist('xparam', 'var') && isfield(cfg, 'parameter') && ~exist('yparam', 'var') - yparam = ''; +% check whether rpt/subj is present and remove if necessary +dimord = getdimord(varargin{1}, cfg.parameter); +dimtok = tokenize(dimord, '_'); +hasrpt = any(ismember(dimtok, {'rpt' 'subj'})); + +if ~hasrpt + assert(isequal(cfg.trials, 'all') || isequal(cfg.trials, 1), 'incorrect specification of cfg.trials for data without repetitions'); +else + assert(~isempty(cfg.trials), 'empty specification of cfg.trials for data with repetitions'); end +% parse cfg.channel if isfield(cfg, 'channel') && isfield(varargin{1}, 'label') cfg.channel = ft_channelselection(cfg.channel, varargin{1}.label); elseif isfield(cfg, 'channel') && isfield(varargin{1}, 'labelcmb') cfg.channel = ft_channelselection(cfg.channel, unique(varargin{1}.labelcmb(:))); end -% perform channel selection, unless in the other plotting functions this -% can always be done because ft_multiplotER is the entry point into the -% interactive stream, but will not be revisited -if isfield(varargin{1}, 'label') - % only do the channel selection when it can actually be done, - % i.e. when the data are bivariate ft_selectdata will crash, moreover - % the bivariate case is handled below - tmpcfg = keepfields(cfg, 'channel'); - tmpvar = varargin{1}; - [varargin{:}] = ft_selectdata(tmpcfg, varargin{:}); - % restore the provenance information - [cfg, varargin{:}] = rollback_provenance(cfg, varargin{:}); - - if isfield(tmpvar, cfg.maskparameter) && ~isfield(varargin{1}, cfg.maskparameter) - % the mask parameter is not present after ft_selectdata, because it is - % not included in all input arguments. Make the same selection and copy - % it over - tmpvar = ft_selectdata(tmpcfg, tmpvar); - varargin{1}.(cfg.maskparameter) = tmpvar.(cfg.maskparameter); - end - - clear tmpvar tmpcfg -end - -if isfield(varargin{1}, 'label') % && strcmp(cfg.interactive, 'no') - selchannel = ft_channelselection(cfg.channel, varargin{1}.label); -elseif isfield(varargin{1}, 'labelcmb') % && strcmp(cfg.interactive, 'no') - selchannel = ft_channelselection(cfg.channel, unique(varargin{1}.labelcmb(:))); -end - -% check whether rpt/subj is present and remove if necessary -% FIXME this should be implemented with avgoverpt in ft_selectdata -hasrpt = sum(ismember(dimtok, {'rpt' 'subj'})); -if strcmp(dtype, 'timelock') && hasrpt, - tmpcfg = []; - - % disable hashing of input data (speeds up things) - tmpcfg.trackcallinfo = 'no'; - - tmpcfg.trials = cfg.trials; +% Apply baseline correction +if ~strcmp(cfg.baseline, 'no') for i=1:Ndata - % save mask (timelockanalysis will remove it) + % keep mask-parameter if it is set if ~isempty(cfg.maskparameter) - tmpmask = varargin{i}.(cfg.maskparameter); + tempmask = varargin{i}.(cfg.maskparameter); end - varargin{i} = ft_timelockanalysis(tmpcfg, varargin{i}); - if ~strcmp(cfg.parameter, 'avg') - % rename avg back into its original parameter name - varargin{i}.(cfg.parameter) = varargin{i}.avg; - varargin{i} = rmfield(varargin{i}, 'avg'); + if strcmp(dtype, 'timelock') && strcmp(xparam, 'time') + varargin{i} = ft_timelockbaseline(cfg, varargin{i}); + elseif strcmp(dtype, 'freq') && strcmp(xparam, 'time') + varargin{i} = ft_freqbaseline(cfg, varargin{i}); + elseif strcmp(dtype, 'freq') && strcmp(xparam, 'freq') + ft_error('Baseline correction is not supported for spectra without a time dimension'); + else + ft_warning('Baseline correction not applied, please set xparam'); end - - % put back mask + % put mask-parameter back if it is set if ~isempty(cfg.maskparameter) - varargin{i}.(cfg.maskparameter) = tmpmask; + varargin{i}.(cfg.maskparameter) = tempmask; end end - dimord = varargin{1}.dimord; - dimtok = tokenize(dimord, '_'); +end -elseif strcmp(dtype, 'freq') && hasrpt, - % this also deals with fourier-spectra in the input - % or with multiple subjects in a frequency domain stat-structure - % on the fly computation of coherence spectrum is not supported - for i=1:Ndata - if isfield(varargin{i}, 'crsspctrm'), - varargin{i} = rmfield(varargin{i}, 'crsspctrm'); - end - end +% channels SHOULD be selected here, as no interactive action produces a new multiplot +tmpcfg = keepfields(cfg, {'channel', 'showcallinfo', 'trials'}); +if hasrpt + tmpcfg.avgoverrpt = 'yes'; +else + tmpcfg.avgoverrpt = 'no'; +end +if hastime && hasfreq + tmpcfg.avgoverfreq = 'yes'; % average over the selected frequencies + tmpcfg.frequency = cfg.frequency; % not to be confused with cfg.xlim or cfg.ylim + tmpcfg.keepfreqdim = 'no'; +else + tmpcfg.avgoverfreq = 'no'; +end +tmpvar = varargin{1}; +[varargin{:}] = ft_selectdata(tmpcfg, varargin{:}); +% restore the provenance information +[cfg, varargin{:}] = rollback_provenance(cfg, varargin{:}); - tmpcfg = []; - tmpcfg.trials = cfg.trials; - tmpcfg.jackknife = 'no'; - for i=1:Ndata - if isfield(cfg, 'parameter') && ~strcmp(cfg.parameter, 'powspctrm') - % freqdesctiptives will only work on the powspctrm field - % hence a temporary copy of the data is needed - tempdata.dimord = varargin{i}.dimord; - tempdata.freq = varargin{i}.freq; - tempdata.label = varargin{i}.label; - tempdata.powspctrm = varargin{i}.(cfg.parameter); - if isfield(varargin{i}, 'cfg') tempdata.cfg = varargin{i}.cfg; end - tempdata = ft_freqdescriptives(tmpcfg, tempdata); - varargin{i}.(cfg.parameter) = tempdata.powspctrm; - clear tempdata - else - varargin{i} = ft_freqdescriptives(tmpcfg, varargin{i}); - end - end - dimord = varargin{1}.dimord; - dimtok = tokenize(dimord, '_'); +if isfield(tmpvar, cfg.maskparameter) && ~isfield(varargin{1}, cfg.maskparameter) + % the mask parameter is not present after ft_selectdata, because it is + % not included in all input arguments. Make the same selection and copy + % it over + tmpvar = ft_selectdata(tmpcfg, tmpvar); + varargin{1}.(cfg.maskparameter) = tmpvar.(cfg.maskparameter); end -% % Read or create the layout that will be used for plotting -cla -lay = ft_prepare_layout(cfg, varargin{1}); -cfg.layout = lay; +clear tmpvar tmpcfg dimord dimtok hastime hasfreq hasrpt -% plot layout -boxflg = istrue(cfg.box); -labelflg = false; % channel labels are plotted further down using ft_plot_vector -outlineflg = istrue(cfg.showoutline); -ft_plot_lay(lay, 'box', boxflg, 'label', labelflg, 'outline', outlineflg, 'point', 'no', 'mask', 'no'); +% ensure that the preproc specific options are located in the cfg.preproc +% substructure, but also ensure that the field 'refchannel' remains at the +% highest level in the structure. This is a little hack by JM because the field +% refchannel can relate to connectivity or to an EEg reference. -% Apply baseline correction -if ~strcmp(cfg.baseline, 'no') +if isfield(cfg, 'refchannel'), refchannelincfg = cfg.refchannel; cfg = rmfield(cfg, 'refchannel'); end +cfg = ft_checkconfig(cfg, 'createsubcfg', {'preproc'}); +if exist('refchannelincfg', 'var'), cfg.refchannel = refchannelincfg; end + +if ~isempty(cfg.preproc) + % preprocess the data, i.e. apply filtering, baselinecorrection, etc. + fprintf('applying preprocessing options\n'); + if ~isfield(cfg.preproc, 'feedback') + cfg.preproc.feedback = cfg.interactive; + end for i=1:Ndata - if strcmp(dtype, 'timelock') && strcmp(xparam, 'time') - varargin{i} = ft_timelockbaseline(cfg, varargin{i}); - elseif strcmp(dtype, 'freq') && strcmp(xparam, 'time') - varargin{i} = ft_freqbaseline(cfg, varargin{i}); - elseif strcmp(dtype, 'freq') && strcmp(xparam, 'freq') - error('Baseline correction is not supported for spectra without a time dimension'); - else - warning('Baseline correction not applied, please set xparam'); - end + varargin{i} = ft_preprocessing(cfg.preproc, varargin{i}); end end % Handle the bivariate case +dimord = getdimord(varargin{1}, cfg.parameter); +if startsWith(dimord, 'chan_chan_') || startsWith(dimord, 'chancmb_') + % convert the bivariate data to univariate and call this plotting function with univariate input + cfg.originalfunction = 'ft_multiplotER'; + cfg.trials = 'all'; % trial selection has been taken care off + bivariate_common(cfg, varargin{:}); + return +end -% Check for bivariate metric with 'chan_chan' in the dimord -selchan = strmatch('chan', dimtok); -isfull = length(selchan)>1; +% Apply channel-type specific scaling +tmpcfg = keepfields(cfg, {'parameter', 'chanscale', 'ecgscale', 'eegscale', 'emgscale', 'eogscale', 'gradscale', 'magscale', 'megscale', 'mychan', 'mychanscale'}); +for i=1:Ndata + varargin{i} = chanscale_common(tmpcfg, varargin{i}); +end -% Check for bivariate metric with a labelcmb -haslabelcmb = isfield(varargin{1}, 'labelcmb'); -if (isfull || haslabelcmb) && (isfield(varargin{1}, cfg.parameter) && ~strcmp(cfg.parameter, 'powspctrm')) - % A reference channel is required: - if ~isfield(cfg, 'refchannel') - error('no reference channel is specified'); - end +%% Section 3: select the data to be plotted and determine min/max range - % check for refchannel being part of selection - if ~strcmp(cfg.refchannel, 'gui') - if haslabelcmb - cfg.refchannel = ft_channelselection(cfg.refchannel, unique(varargin{1}.labelcmb(:))); - else - cfg.refchannel = ft_channelselection(cfg.refchannel, varargin{1}.label); - end - if (isfull && ~any(ismember(varargin{1}.label, cfg.refchannel))) || ... - (haslabelcmb && ~any(ismember(varargin{1}.labelcmb(:), cfg.refchannel))) - error('cfg.refchannel is a not present in the (selected) channels)') - end - end +% Read or create the layout that will be used for plotting +tmpcfg = removefields(cfg, 'inputfile'); % ensure the inputfile field not to exist +cfg.layout = ft_prepare_layout(tmpcfg, varargin{1}); - % Interactively select the reference channel - if strcmp(cfg.refchannel, 'gui') - % Open a single figure with the channel layout, the user can click on a reference channel - h = clf; - ft_plot_lay(lay, 'box', false); - title('Select the reference channel by dragging a selection window, more than 1 channel can be selected...'); - % add the channel information to the figure - info = guidata(gcf); - info.x = lay.pos(:, 1); - info.y = lay.pos(:, 2); - info.label = lay.label; - guidata(h, info); - %set(gcf, 'WindowButtonUpFcn', {@ft_select_channel, 'callback', {@select_topoplotER, cfg, data}}); - set(gcf, 'WindowButtonUpFcn', {@ft_select_channel, 'multiple', true, 'callback', {@select_multiplotER, cfg, varargin{1}}, 'event', 'WindowButtonUpFcn'}); - set(gcf, 'WindowButtonDownFcn', {@ft_select_channel, 'multiple', true, 'callback', {@select_multiplotER, cfg, varargin{1}}, 'event', 'WindowButtonDownFcn'}); - set(gcf, 'WindowButtonMotionFcn', {@ft_select_channel, 'multiple', true, 'callback', {@select_multiplotER, cfg, varargin{1}}, 'event', 'WindowButtonMotionFcn'}); - return - end +% Take the subselection of channels that is contained in the layout, this is the same in all datasets +[selchan, sellay] = match_str(varargin{1}.label, cfg.layout.label); - for i=1:Ndata - if ~isfull, - % Convert 2-dimensional channel matrix to a single dimension: - if isempty(cfg.directionality) - sel1 = find(strcmp(cfg.refchannel, varargin{i}.labelcmb(:, 2))); - sel2 = find(strcmp(cfg.refchannel, varargin{i}.labelcmb(:, 1))); - elseif strcmp(cfg.directionality, 'outflow') - sel1 = []; - sel2 = find(strcmp(cfg.refchannel, varargin{i}.labelcmb(:, 1))); - elseif strcmp(cfg.directionality, 'inflow') - sel1 = find(strcmp(cfg.refchannel, varargin{i}.labelcmb(:, 2))); - sel2 = []; - end - fprintf('selected %d channels for %s\n', length(sel1)+length(sel2), cfg.parameter); - if length(sel1)+length(sel2)==0 - error('there are no channels selected for plotting: you may need to look at the specification of cfg.directionality'); - end - varargin{i}.(cfg.parameter) = varargin{i}.(cfg.parameter)([sel1;sel2], :, :); - varargin{i}.label = [varargin{i}.labelcmb(sel1, 1);varargin{i}.labelcmb(sel2, 2)]; - varargin{i}.labelcmb = varargin{i}.labelcmb([sel1;sel2], :); - %varargin{i} = rmfield(varargin{i}, 'labelcmb'); - else - % General case - sel = match_str(varargin{i}.label, cfg.refchannel); - siz = [size(varargin{i}.(cfg.parameter)) 1]; - if strcmp(cfg.directionality, 'inflow') || isempty(cfg.directionality) - %the interpretation of 'inflow' and 'outflow' depend on - %the definition in the bivariate representation of the data - %in FieldTrip the row index 'causes' the column index channel - %data.(cfg.parameter) = reshape(mean(data.(cfg.parameter)(:, sel, :), 2), [siz(1) 1 siz(3:end)]); - sel1 = 1:siz(1); - sel2 = sel; - meandir = 2; - elseif strcmp(cfg.directionality, 'outflow') - %data.(cfg.parameter) = reshape(mean(data.(cfg.parameter)(sel, :, :), 1), [siz(1) 1 siz(3:end)]); - sel1 = sel; - sel2 = 1:siz(1); - meandir = 1; - - elseif strcmp(cfg.directionality, 'ff-fd') - error('cfg.directionality = ''ff-fd'' is not supported anymore, you have to manually subtract the two before the call to ft_multiplotER'); - elseif strcmp(cfg.directionality, 'fd-ff') - error('cfg.directionality = ''fd-ff'' is not supported anymore, you have to manually subtract the two before the call to ft_multiplotER'); - end %if directionality - end %if ~isfull - end %for i -end %handle the bivariate data - -% Get physical min/max range of x +% Get physical min/max range of x, i.e. time or frequency if strcmp(cfg.xlim, 'maxmin') % Find maxmin throughout all varargins: xmin = []; xmax = []; - for i=1:length(varargin) - xmin = min([xmin varargin{i}.(xparam)]); - xmax = max([xmax varargin{i}.(xparam)]); + for i=1:Ndata + xmin = nanmin([xmin varargin{i}.(xparam)]); + xmax = nanmax([xmax varargin{i}.(xparam)]); end else xmin = cfg.xlim(1); xmax = cfg.xlim(2); end -% Get the index of the nearest bin -for i=1:Ndata - xidmin(i, 1) = nearest(varargin{i}.(xparam), xmin); - xidmax(i, 1) = nearest(varargin{i}.(xparam), xmax); -end - -if strcmp('freq',yparam) && strcmp('freq',dtype) - tmpcfg = keepfields(cfg, {'parameter'}); - tmpcfg.avgoverfreq = 'yes'; - tmpcfg.frequency = cfg.frequency; - [varargin{:}] = ft_selectdata(tmpcfg, varargin{:}); - % restore the provenance information - [cfg, varargin{:}] = rollback_provenance(cfg, varargin{:}); -elseif strcmp('time',yparam) && strcmp('freq',dtype) - tmpcfg = keepfields(cfg, {'parameter'}); - tmpcfg.avgovertime = 'yes'; - tmpcfg.latency = cfg.latency; - [varargin{:}] = ft_selectdata(tmpcfg, varargin{:}); - % restore the provenance information - [cfg, varargin{:}] = rollback_provenance(cfg, varargin{:}); -end - -% Get physical y-axis range (ylim / parameter): -if strcmp(cfg.ylim, 'maxmin') || strcmp(cfg.ylim, 'maxabs') - % Find maxmin throughout all varargins: +% Get the index of the nearest bin, this is the same in all datasets +xminindx = nearest(varargin{1}.(xparam), xmin); +xmaxindx = nearest(varargin{1}.(xparam), xmax); +xmin = varargin{1}.(xparam)(xminindx); +xmax = varargin{1}.(xparam)(xmaxindx); +selx = xminindx:xmaxindx; +xval = varargin{1}.(xparam)(selx); + +% Get physical y-axis range, i.e. of the parameter to be plotted +if ~isnumeric(cfg.ylim) + % Find maxmin throughout all varargins ymin = []; ymax = []; - for i=1:length(varargin) - % Select the channels in the data that match with the layout and that - % are selected for plotting: - dat = []; - dat = varargin{i}.(cfg.parameter); - seldat1 = match_str(varargin{i}.label, lay.label); % indexes labels corresponding in input and layout - seldat2 = match_str(varargin{i}.label, cfg.channel); % indexes labels corresponding in input and plot-selection - if isempty(seldat1) - error('labels in data and labels in layout do not match'); - end - data = dat(intersect(seldat1, seldat2), :); - ymin = min([ymin min(min(min(data)))]); - ymax = max([ymax max(max(max(data)))]); + for i=1:Ndata + % Select the channels in the data that match with the layout and that are selected for plotting + dat = varargin{i}.(cfg.parameter)(selchan,selx); + ymin = min([ymin min(min(min(dat)))]); + ymax = max([ymax max(max(max(dat)))]); end - if strcmp(cfg.ylim, 'maxabs') % handle maxabs, make y-axis center on 0 ymax = max([abs(ymax) abs(ymin)]); ymin = -ymax; @@ -591,153 +436,92 @@ elseif strcmp(cfg.ylim, 'minzero') ymax = 0; end - else ymin = cfg.ylim(1); ymax = cfg.ylim(2); end -% convert the layout to Ole's style of variable names -X = lay.pos(:, 1); -Y = lay.pos(:, 2); -width = lay.width; -height = lay.height; -Lbl = lay.label; - -% Create empty channel coordinates and labels arrays: -chanX(1:length(Lbl)) = NaN; -chanY(1:length(Lbl)) = NaN; -chanLabels = cell(1, length(Lbl)); - -hold on; -colorLabels = []; - -% Plot each data set: +% Gather the data from all input data structures +datamatrix = zeros(Ndata, length(selchan), length(selx)); for i=1:Ndata - % Make vector dat with one value for each channel - dat = varargin{i}.(cfg.parameter); - % get dimord dimensions - dims = textscan(varargin{i}.dimord, '%s', 'Delimiter', '_'); - dims = dims{1}; - ydim = find(strcmp(yparam, dims)); - xdim = find(strcmp(xparam, dims)); - zdim = setdiff(1:ndims(dat), [ydim xdim]); - % and permute - dat = permute(dat, [zdim(:)' ydim xdim]); - - xval = varargin{i}.(xparam); - - % Take subselection of channels, this only works - % in the non-interactive mode - if exist('selchannel', 'var') - sellab = match_str(varargin{i}.label, selchannel); - label = varargin{i}.label(sellab); - else - sellab = 1:numel(varargin{i}.label); - label = varargin{i}.label; - end - - if isfull - dat = dat(sel1, sel2, xidmin(i):xidmax(i)); - dat = nanmean(dat, meandir); - elseif haslabelcmb - dat = dat(sellab, xidmin(i):xidmax(i)); - else - dat = dat(sellab, xidmin(i):xidmax(i)); - end - xval = xval(xidmin(i):xidmax(i)); - - % Select the channels in the data that match with the layout: - [seldat, sellay] = match_str(label, cfg.layout.label); - if isempty(seldat) - error('labels in data and labels in layout do not match'); - end - - % gather the data of multiple input arguments - datamatrix{i} = dat(seldat, :); - - % Select x and y coordinates and labels of the channels in the data - layX = cfg.layout.pos(sellay, 1); - layY = cfg.layout.pos(sellay, 2); - layLabels = cfg.layout.label(sellay); + datamatrix(i,:,:) = varargin{i}.(cfg.parameter)(selchan, selx); +end - if ~isempty(cfg.maskparameter) - % one value for each channel, or one value for each channel-time point - maskmatrix = varargin{1}.(cfg.maskparameter)(seldat, :); - maskmatrix = maskmatrix(:, xidmin:xidmax); - else - % create an Nx0 matrix - maskmatrix = zeros(length(seldat), 0); - end +if ~isempty(cfg.maskparameter) + % one value for each channel-time point + maskmatrix = varargin{1}.(cfg.maskparameter)(selchan, selx); +else + % create an Nx0 matrix + maskmatrix = zeros(length(selchan), 0); +end - if Ndata > 1 - if ischar(GRAPHCOLOR); colorLabels = [colorLabels iname{i+1} '=' GRAPHCOLOR(i+1) '\n']; - elseif isnumeric(GRAPHCOLOR); colorLabels = [colorLabels iname{i+1} '=' num2str(GRAPHCOLOR(i+1, :)) '\n']; - end - end -end % for number of input data +chanX = cfg.layout.pos(sellay, 1); +chanY = cfg.layout.pos(sellay, 2); +chanWidth = cfg.layout.width(sellay); +chanHeight = cfg.layout.height(sellay); +chanLabel = cfg.layout.label(sellay); -for m=1:length(layLabels) - % Plot ER +%% Section 4: do the actual plotting - if ischar(GRAPHCOLOR); color = GRAPHCOLOR(2:end); - elseif isnumeric(GRAPHCOLOR); color = GRAPHCOLOR(2:end, :); - end +cla +hold on +% Plot the data +for m=1:length(selchan) mask = maskmatrix(m, :); - - for i=1:Ndata - yval(i, :) = datamatrix{i}(m, :); - end - + yval = squeeze(datamatrix(:,m,:)); + % Clip out of bounds y values: yval(yval > ymax) = ymax; yval(yval < ymin) = ymin; - - if strcmp(cfg.showlabels, 'yes') - label = layLabels(m); - else - % don't show labels - label = []; - end - - ft_plot_vector(xval, yval, 'width', width(m), 'height', height(m), 'hpos', layX(m), 'vpos', layY(m), 'hlim', [xmin xmax], 'vlim', [ymin ymax], 'color', color, 'style', cfg.linestyle{i}, 'linewidth', cfg.linewidth, 'axis', cfg.axes, 'highlight', mask, 'highlightstyle', cfg.maskstyle, 'label', label, 'box', cfg.box, 'fontsize', cfg.fontsize); - - if i==1, - % Keep ER plot coordinates (at centre of ER plot), and channel labels (will be stored in the figure's UserData struct): - chanX(m) = X(m) + 0.5 * width(m); - chanY(m) = Y(m) + 0.5 * height(m); - chanLabels{m} = Lbl{m}; - end + + ft_plot_vector(xval, yval, 'width', chanWidth(m), 'height', chanHeight(m), 'hpos', chanX(m), 'vpos', chanY(m), 'hlim', [xmin xmax], 'vlim', [ymin ymax], 'color', graphcolor, 'style', cfg.linestyle{i}, 'linewidth', cfg.linewidth, 'axis', cfg.axes, 'highlight', mask, 'highlightstyle', cfg.maskstyle); end % for number of channels +% plot the layout, labels and outline +ft_plot_lay(cfg.layout, 'box', istrue(cfg.box), 'label', istrue(cfg.showlabels), 'outline', istrue(cfg.showoutline), 'point', 'no', 'mask', 'no', 'fontsize', cfg.fontsize, 'labelyoffset', 1.4*median(cfg.layout.height/2), 'labelalignh', 'center', 'chanindx', find(~ismember(cfg.layout.label, {'COMNT', 'SCALE'})) ); -% Add the colors of the different datasets to the comment: -cfg.comment = [cfg.comment colorLabels]; - -% Write comment text: -l = cellstrmatch('COMNT', Lbl); -if ~isempty(l) - ft_plot_text(X(l), Y(l), sprintf(cfg.comment), 'Fontsize', cfg.fontsize, 'interpreter', 'none'); +% write comment +if istrue(cfg.showcomment) + % Add the colors of the different datasets to the comment + colorLabels = []; + if Ndata > 1 + for i=1:Ndata + if ischar(graphcolor) + colorLabels = [colorLabels '\n' dataname{i} '=' graphcolor(i) ]; + elseif isnumeric(graphcolor) + colorLabels = [colorLabels '\n' dataname{i} '=' num2str(graphcolor(i, :)) ]; + end + end + end + cfg.comment = [cfg.comment colorLabels]; + + k = find(strcmp('COMNT', cfg.layout.label)); + if ~isempty(k) + limittext = cfg.limittext; + if ~strcmp(limittext, 'default') + comment = limittext; + else + comment = cfg.comment; + comment = sprintf('%0s\nxlim=[%.3g %.3g]', comment, xmin, xmax); + comment = sprintf('%0s\nylim=[%.3g %.3g]', comment, ymin, ymax); + end + ft_plot_text(cfg.layout.pos(k, 1), cfg.layout.pos(k, 2), sprintf(comment), 'FontSize', cfg.fontsize, 'FontWeight', cfg.fontweight); + end end -% Plot scales: -l = cellstrmatch('SCALE', Lbl); -if ~isempty(l) - plotScales([xmin xmax], [ymin ymax], X(l), Y(l), width(1), height(1), cfg) +% Plot scales +if istrue(cfg.showscale) + l = find(strcmp(cfg.layout.label, 'SCALE')); + if ~isempty(l) + x = cfg.layout.pos(l,1); + y = cfg.layout.pos(l,2); + plotScales([xmin xmax], [ymin ymax], x, y, chanWidth(1), chanHeight(1), cfg) + end end % set the figure window title if isempty(get(gcf, 'Name')) - if nargin > 1 - dataname = {inputname(2)}; - for k = 2:Ndata - dataname{end+1} = inputname(k+1); - end - else % data provided through cfg.inputfile - dataname = cfg.inputfile; - end - if isempty(cfg.figurename) set(gcf, 'Name', sprintf('%d: %s: %s', double(gcf), mfilename, join_str(', ', dataname))); set(gcf, 'NumberTitle', 'off'); @@ -745,34 +529,17 @@ set(gcf, 'name', cfg.figurename); set(gcf, 'NumberTitle', 'off'); end -else - dataname = {}; -end - -% Make the figure interactive: -if strcmp(cfg.interactive, 'yes') - - % add the dataname and channel information to the figure - % this is used in the callbacks - info = guidata(gcf); - info.x = lay.pos(:, 1); - info.y = lay.pos(:, 2); - info.label = lay.label; - info.dataname = dataname; - guidata(gcf, info); - - set(gcf, 'WindowButtonUpFcn', {@ft_select_channel, 'multiple', true, 'callback', {@select_singleplotER, cfg, varargin{:}}, 'event', 'WindowButtonUpFcn'}); - set(gcf, 'WindowButtonDownFcn', {@ft_select_channel, 'multiple', true, 'callback', {@select_singleplotER, cfg, varargin{:}}, 'event', 'WindowButtonDownFcn'}); - set(gcf, 'WindowButtonMotionFcn', {@ft_select_channel, 'multiple', true, 'callback', {@select_singleplotER, cfg, varargin{:}}, 'event', 'WindowButtonMotionFcn'}); end axis tight axis off +hold off + +% Make the axis a little wider when boxes are shown if strcmp(cfg.box, 'yes') abc = axis; axis(abc + [-1 +1 -1 +1]*mean(abs(abc))/10) end -hold off % Set orientation for printing if specified if ~isempty(cfg.orient) @@ -784,11 +551,24 @@ set(gcf, 'renderer', cfg.renderer) end -% do the general cleanup and bookkeeping at the end of the function -ft_postamble debug -ft_postamble trackconfig -ft_postamble previous varargin -ft_postamble provenance +% Make the figure interactive +if strcmp(cfg.interactive, 'yes') + % add the cfg/data/channel information to the figure under identifier linked to this axis + ident = ['axh' num2str(round(sum(clock.*1e6)))]; % unique identifier for this axis + set(gca, 'tag', ident); + info = guidata(gcf); + info.(ident).x = cfg.layout.pos(:, 1); + info.(ident).y = cfg.layout.pos(:, 2); + info.(ident).label = cfg.layout.label; + info.(ident).dataname = dataname; + info.(ident).cfg = cfg; + info.(ident).varargin = varargin; + guidata(gcf, info); + + set(gcf, 'WindowButtonUpFcn', {@ft_select_channel, 'multiple', true, 'callback', {@select_singleplotER}, 'event', 'WindowButtonUpFcn'}); + set(gcf, 'WindowButtonDownFcn', {@ft_select_channel, 'multiple', true, 'callback', {@select_singleplotER}, 'event', 'WindowButtonDownFcn'}); + set(gcf, 'WindowButtonMotionFcn', {@ft_select_channel, 'multiple', true, 'callback', {@select_singleplotER}, 'event', 'WindowButtonMotionFcn'}); +end % add a menu to the figure, but only if the current figure does not have subplots % also, delete any possibly existing previous menu, this is safe because delete([]) does nothing @@ -799,6 +579,18 @@ uimenu(ftmenu, 'Label', 'About', 'Callback', @menu_about); end +% do the general cleanup and bookkeeping at the end of the function +ft_postamble debug +ft_postamble trackconfig +ft_postamble previous varargin +ft_postamble provenance + +if ~nargout + % don't return anything + clear cfg +end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % SUBFUNCTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -817,65 +609,29 @@ function plotScales(hlim, vlim, hpos, vpos, width, height, cfg) ft_plot_vector(hlim, [0 0], placement{:}, 'color', 'b'); end -ft_plot_text(hlim(1), vlim(1), [num2str(hlim(1), 3) ' '], placement{:}, 'rotation', 90, 'HorizontalAlignment', 'Right', 'VerticalAlignment', 'top', 'Fontsize', cfg.fontsize); -ft_plot_text(hlim(2), vlim(1), [num2str(hlim(2), 3) ' '], placement{:}, 'rotation', 90, 'HorizontalAlignment', 'Right', 'VerticalAlignment', 'top', 'Fontsize', cfg.fontsize); -ft_plot_text(hlim(1), vlim(1), [num2str(vlim(1), 3) ' '], placement{:}, 'HorizontalAlignment', 'Right', 'VerticalAlignment', 'bottom', 'Fontsize', cfg.fontsize); -ft_plot_text(hlim(1), vlim(2), [num2str(vlim(2), 3) ' '], placement{:}, 'HorizontalAlignment', 'Right', 'VerticalAlignment', 'bottom', 'Fontsize', cfg.fontsize); +ft_plot_text(hlim(1), vlim(1), [num2str(hlim(1), 3) ' '], placement{:}, 'rotation', 90, 'HorizontalAlignment', 'Right', 'VerticalAlignment', 'top', 'FontSize', cfg.fontsize); +ft_plot_text(hlim(2), vlim(1), [num2str(hlim(2), 3) ' '], placement{:}, 'rotation', 90, 'HorizontalAlignment', 'Right', 'VerticalAlignment', 'top', 'FontSize', cfg.fontsize); +ft_plot_text(hlim(1), vlim(1), [num2str(vlim(1), 3) ' '], placement{:}, 'HorizontalAlignment', 'Right', 'VerticalAlignment', 'bottom', 'FontSize', cfg.fontsize); +ft_plot_text(hlim(1), vlim(2), [num2str(vlim(2), 3) ' '], placement{:}, 'HorizontalAlignment', 'Right', 'VerticalAlignment', 'bottom', 'FontSize', cfg.fontsize); -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% SUBFUNCTION -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -function l = cellstrmatch(str, strlist) -l = []; -for k=1:length(strlist) - if strcmp(char(str), char(strlist(k))) - l = [l k]; - end -end - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% SUBFUNCTION which is called after selecting channels in case of cfg.refchannel='gui' -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -function select_multiplotER(label, cfg, varargin) -if ~isempty(label) - if isfield(cfg, 'inputfile') - % the reading has already been done and varargin contains the data - cfg = rmfield(cfg, 'inputfile'); - end - % put data name in here, this cannot be resolved by other means - info = guidata(gcf); - cfg.dataname = info.dataname; - if iscell(label) - label = label{1}; - end - cfg.refchannel = label; % FIXME this only works with label being a string - fprintf('selected cfg.refchannel = ''%s''\n', cfg.refchannel); - p = get(gcf, 'Position'); - f = figure; - set(f, 'Position', p); - ft_multiplotER(cfg, varargin{:}); -end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % SUBFUNCTION which is called after selecting channels in case of cfg.interactive='yes' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -function select_singleplotER(label, cfg, varargin) +function select_singleplotER(label, varargin) +% fetch cfg/data based on axis indentifier given as tag +ident = get(gca,'tag'); +info = guidata(gcf); +cfg = info.(ident).cfg; +datvarargin = info.(ident).varargin; if ~isempty(label) - if isfield(cfg, 'inputfile') - % the reading has already been done and varargin contains the data - cfg = rmfield(cfg, 'inputfile'); - end + cfg = removefields(cfg, 'inputfile'); % the reading has already been done and varargin contains the data + cfg.baseline = 'no'; % make sure the next function does not apply a baseline correction again cfg.channel = label; - % put data name in here, this cannot be resolved by other means - info = guidata(gcf); - cfg.dataname = info.dataname; - fprintf('selected cfg.channel = {'); - for i=1:(length(cfg.channel)-1) - fprintf('''%s'', ', cfg.channel{i}); - end - fprintf('''%s''}\n', cfg.channel{end}); - p = get(gcf, 'Position'); - f = figure; - set(f, 'Position', p); - ft_singleplotER(cfg, varargin{:}); + cfg.dataname = info.(ident).dataname; % put data name in here, this cannot be resolved by other means + cfg.trials = 'all'; % trial selection has already been taken care of + fprintf('selected cfg.channel = {%s}\n', join_str(', ', cfg.channel)); + % ensure that the new figure appears at the same position + f = figure('position', get(gcf, 'Position')); + ft_singleplotER(cfg, datvarargin{:}); end diff --git a/external/fieldtrip/ft_multiplotTFR.m b/external/fieldtrip/ft_multiplotTFR.m index 15b53c33..4b10723c 100644 --- a/external/fieldtrip/ft_multiplotTFR.m +++ b/external/fieldtrip/ft_multiplotTFR.m @@ -15,7 +15,7 @@ % cfg.parameter = field to be represented as color (default depends on data.dimord) % 'powspctrm' or 'cohspctrm' % cfg.maskparameter = field in the data to be used for opacity masking of data -% cfg.maskstyle = style used to masking, 'opacity', 'saturation' or 'outline' (default = 'opacity') +% cfg.maskstyle = style used to masking, 'opacity', 'saturation', 'outline' or 'colormix' (default = 'opacity') % use 'saturation' or 'outline' when saving to vector-format (like *.eps) to avoid all % sorts of image-problems (currently only possible with a white backgroud) % cfg.maskalpha = alpha value between 0 (transparant) and 1 (opaque) used for masking areas dictated by cfg.maskparameter (default = 1) @@ -35,11 +35,15 @@ % cfg.hotkeys = enables hotkeys (up/down arrows) for dynamic colorbar adjustment % cfg.colorbar = 'yes', 'no' (default = 'no') % cfg.colormap = any sized colormap, see COLORMAP -% cfg.comment = string of text (default = date + zlimits) -% Add 'comment' to graph (according to COMNT in the layout) % cfg.showlabels = 'yes', 'no' (default = 'no') % cfg.showoutline = 'yes', 'no' (default = 'no') +% cfg.showscale = 'yes', 'no' (default = 'yes') +% cfg.showcomment = 'yes', 'no' (default = 'yes') +% cfg.comment = string of text (default = date + limits) +% Add 'comment' to graph (according to COMNT in the layout) +% cfg.limittext = add user-defined text instead of cfg.comment, (default = cfg.comment) % cfg.fontsize = font size of comment and labels (if present) (default = 8) +% cfg.fontweight = font weight of comment and labels (if present) % cfg.interactive = Interactive plot 'yes' or 'no' (default = 'yes') % In a interactive plot you can select areas and produce a new % interactive plot when a selected area is clicked. Multiple areas @@ -102,6 +106,7 @@ % Copyright (C) 2003-2006, Ole Jensen % Copyright (C) 2007-2011, Roemer van der Meij & Jan-Mathijs Schoffelen +% Copyright (C) 2012-2017, F.C. Donders Centre % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -121,6 +126,17 @@ % % $Id$ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% DEVELOPERS NOTE: This code is organized in a similar fashion for multiplot/singleplot/topoplot +% and for ER/TFR and should remain consistent over those 6 functions. +% Section 1: general cfg handling that is independent from the data +% Section 2: data handling, this also includes converting bivariate (chan_chan and chancmb) into univariate data +% Section 3: select the data to be plotted and determine min/max range +% Section 4: do the actual plotting +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Section 1: general cfg handling that is independent from the data + % these are used by the ft_preamble/ft_postamble function and scripts ft_revision = '$Id$'; ft_nargin = nargin; @@ -143,30 +159,33 @@ data = ft_checkdata(data, 'datatype', 'freq'); % check if the input cfg is valid for this function -cfg = ft_checkconfig(cfg, 'unused', {'cohtargetchannel'}); -cfg = ft_checkconfig(cfg, 'renamed', {'matrixside', 'directionality'}); cfg = ft_checkconfig(cfg, 'renamed', {'cohrefchannel', 'refchannel'}); +cfg = ft_checkconfig(cfg, 'renamed', {'matrixside', 'directionality'}); cfg = ft_checkconfig(cfg, 'renamed', {'zparam', 'parameter'}); -cfg = ft_checkconfig(cfg, 'renamedval', {'zlim', 'absmax', 'maxabs'}); -cfg = ft_checkconfig(cfg, 'renamedval', {'directionality', 'feedforward', 'outflow'}); cfg = ft_checkconfig(cfg, 'renamedval', {'directionality', 'feedback', 'inflow'}); -cfg = ft_checkconfig(cfg, 'deprecated', {'xparam', 'yparam'}); +cfg = ft_checkconfig(cfg, 'renamedval', {'directionality', 'feedforward', 'outflow'}); +cfg = ft_checkconfig(cfg, 'renamedval', {'zlim', 'absmax', 'maxabs'}); +cfg = ft_checkconfig(cfg, 'unused', {'cohtargetchannel'}); +% cfg = ft_checkconfig(cfg, 'deprecated', {'xparam', 'yparam'}); % set the defaults +cfg.parameter = ft_getopt(cfg, 'parameter', 'powspctrm'); cfg.baseline = ft_getopt(cfg, 'baseline', 'no'); cfg.baselinetype = ft_getopt(cfg, 'baselinetype', 'absolute'); cfg.trials = ft_getopt(cfg, 'trials', 'all', 1); cfg.xlim = ft_getopt(cfg, 'xlim', 'maxmin'); cfg.ylim = ft_getopt(cfg, 'ylim', 'maxmin'); cfg.zlim = ft_getopt(cfg, 'zlim', 'maxmin'); -cfg.magscale = ft_getopt(cfg, 'magscale', 1); -cfg.gradscale = ft_getopt(cfg, 'gradscale', 1); cfg.colorbar = ft_getopt(cfg, 'colorbar', 'no'); cfg.comment = ft_getopt(cfg, 'comment', date); +cfg.limittext = ft_getopt(cfg, 'limittext', 'default'); cfg.showlabels = ft_getopt(cfg, 'showlabels', 'no'); cfg.showoutline = ft_getopt(cfg, 'showoutline', 'no'); +cfg.showscale = ft_getopt(cfg, 'showscale', 'yes'); +cfg.showcomment = ft_getopt(cfg, 'showcomment', 'yes'); cfg.channel = ft_getopt(cfg, 'channel', 'all'); cfg.fontsize = ft_getopt(cfg, 'fontsize', 8); +cfg.fontweight = ft_getopt(cfg, 'fontweight'); cfg.interactive = ft_getopt(cfg, 'interactive', 'yes'); cfg.hotkeys = ft_getopt(cfg, 'hotkeys', 'no'); cfg.renderer = ft_getopt(cfg, 'renderer'); % let MATLAB decide on default @@ -177,6 +196,7 @@ cfg.maskstyle = ft_getopt(cfg, 'maskstyle', 'opacity'); cfg.directionality = ft_getopt(cfg, 'directionality', ''); cfg.figurename = ft_getopt(cfg, 'figurename'); + if ~isfield(cfg, 'box') if ~isempty(cfg.maskparameter) cfg.box = 'yes'; @@ -184,359 +204,248 @@ cfg.box = 'no'; end end -if numel(findobj(gcf, 'type', 'axes', '-not', 'tag', 'ft-colorbar')) > 1 && strcmp(cfg.interactive, 'yes') - warning('using cfg.interactive = ''yes'' in subplots is not supported, setting cfg.interactive = ''no''') - cfg.interactive = 'no'; + +% set colormap +if isfield(cfg,'colormap') + if ~isnumeric(cfg.colormap) + cfg.colormap = colormap(cfg.colormap); + end + if size(cfg.colormap,2)~=3 + ft_error('colormap must be a n x 3 matrix'); + else + set(gcf,'colormap', cfg.colormap); + end +end + +% this is needed for the figure title and correct labeling of graphcolor later on +if nargin>1 + if isfield(cfg, 'dataname') + if iscell(cfg.dataname) + dataname = cfg.dataname{1}; % only one can be plotted + else + dataname = cfg.dataname; + end + else + if ~isempty(inputname(2)) + dataname = inputname(2); + else + dataname = ['data' num2str(1,'%02d')]; + end + end +else % data provided through cfg.inputfile + dataname = cfg.inputfile; end -dimord = data.dimord; + +%% Section 2: data handling, this also includes converting bivariate (chan_chan and chancmb) into univariate data + +hastime = isfield(data, 'time'); +hasfreq = isfield(data, 'freq'); + +assert((hastime && hasfreq), 'please use ft_multiplotER for time-only or frequency-only data'); + +xparam = ft_getopt(cfg, 'xparam', 'time'); +yparam = ft_getopt(cfg, 'yparam', 'freq'); + +% check whether rpt/subj is present and remove if necessary +dimord = getdimord(data, cfg.parameter); dimtok = tokenize(dimord, '_'); +hasrpt = any(ismember(dimtok, {'rpt' 'subj'})); -% Set x/y/parameter defaults -if ~any(ismember(dimtok, 'time')) - error('input data needs a time dimension'); +if ~hasrpt + assert(isequal(cfg.trials, 'all') || isequal(cfg.trials, 1), 'incorrect specification of cfg.trials for data without repetitions'); else - xparam = 'time'; - yparam = 'freq'; - cfg.parameter = ft_getopt(cfg, 'parameter', 'powspctrm'); + assert(~isempty(cfg.trials), 'empty specification of cfg.trials for data with repetitions'); end +% parse cfg.channel if isfield(cfg, 'channel') && isfield(data, 'label') cfg.channel = ft_channelselection(cfg.channel, data.label); elseif isfield(cfg, 'channel') && isfield(data, 'labelcmb') cfg.channel = ft_channelselection(cfg.channel, unique(data.labelcmb(:))); end -% perform channel selection but only allow this when cfg.interactive = 'no' -if isfield(data, 'label') && strcmp(cfg.interactive, 'no') - selchannel = ft_channelselection(cfg.channel, data.label); -elseif isfield(data, 'labelcmb') && strcmp(cfg.interactive, 'no') - selchannel = ft_channelselection(cfg.channel, unique(data.labelcmb(:))); -end - -% check whether rpt/subj is present and remove if necessary and whether -hasrpt = any(ismember(dimtok, {'rpt' 'subj'})); -if hasrpt, - % this also deals with fourier-spectra in the input - % or with multiple subjects in a frequency domain stat-structure - % on the fly computation of coherence spectrum is not supported - if isfield(data, 'crsspctrm'), - data = rmfield(data, 'crsspctrm'); - end +% Apply baseline correction: +if ~strcmp(cfg.baseline, 'no') % keep mask-parameter if it is set if ~isempty(cfg.maskparameter) tempmask = data.(cfg.maskparameter); end - tmpcfg = []; - tmpcfg.trials = cfg.trials; - tmpcfg.jackknife = 'no'; - if isfield(cfg, 'parameter') && ~strcmp(cfg.parameter, 'powspctrm') - % freqdesctiptives will only work on the powspctrm field - % hence a temporary copy of the data is needed - tempdata.dimord = data.dimord; - tempdata.freq = data.freq; - tempdata.label = data.label; - tempdata.powspctrm = data.(cfg.parameter); - if isfield(data, 'cfg') tempdata.cfg = data.cfg; end - tempdata = ft_freqdescriptives(tmpcfg, tempdata); - data.(cfg.parameter) = tempdata.powspctrm; - clear tempdata - else - data = ft_freqdescriptives(tmpcfg, data); - end + data = ft_freqbaseline(cfg, data); % put mask-parameter back if it is set if ~isempty(cfg.maskparameter) data.(cfg.maskparameter) = tempmask; end - dimord = data.dimord; - dimtok = tokenize(dimord, '_'); -end % if hasrpt +end -% Read or create the layout that will be used for plotting: -cla; -hold on -lay = ft_prepare_layout(cfg, data); -cfg.layout = lay; +% channels SHOULD be selected here, as no interactive action produces a new multiplot +tmpcfg = keepfields(cfg, {'channel', 'showcallinfo', 'trials'}); +if hasrpt + tmpcfg.avgoverrpt = 'yes'; +else + tmpcfg.avgoverrpt = 'no'; +end +tmpvar = data; +[data] = ft_selectdata(tmpcfg, data); +% restore the provenance information +[cfg, data] = rollback_provenance(cfg, data); +if isfield(tmpvar, cfg.maskparameter) && ~isfield(data, cfg.maskparameter) + % the mask parameter is not present after ft_selectdata, because it is + % not included in all input arguments. Make the same selection and copy + % it over + tmpvar = ft_selectdata(tmpcfg, tmpvar); + data.(cfg.maskparameter) = tmpvar.(cfg.maskparameter); +end -% Apply baseline correction: -if ~strcmp(cfg.baseline, 'no') - % keep mask-parameter if it is set - if ~isempty(cfg.maskparameter) - tempmask = data.(cfg.maskparameter); - end - data = ft_freqbaseline(cfg, data); - % put mask-parameter back if it is set - if ~isempty(cfg.maskparameter) - data.(cfg.maskparameter) = tempmask; +clear tmpvar tmpcfg dimord dimtok hastime hasfreq hasrpt + +% ensure that the preproc specific options are located in the cfg.preproc +% substructure, but also ensure that the field 'refchannel' remains at the +% highest level in the structure. This is a little hack by JM because the field +% refchannel can relate to connectivity or to an EEG reference. + +if isfield(cfg, 'refchannel'), refchannelincfg = cfg.refchannel; cfg = rmfield(cfg, 'refchannel'); end +cfg = ft_checkconfig(cfg, 'createsubcfg', {'preproc'}); +if exist('refchannelincfg', 'var'), cfg.refchannel = refchannelincfg; end + +if ~isempty(cfg.preproc) + % preprocess the data, i.e. apply filtering, baselinecorrection, etc. + fprintf('applying preprocessing options\n'); + if ~isfield(cfg.preproc, 'feedback') + cfg.preproc.feedback = cfg.interactive; end + data = ft_preprocessing(cfg.preproc, data); end % Handle the bivariate case +dimord = getdimord(data, cfg.parameter); +if startsWith(dimord, 'chan_chan_') || startsWith(dimord, 'chancmb_') + % convert the bivariate data to univariate and call this plotting function with univariate input + cfg.originalfunction = 'ft_multiplotTFR'; + cfg.trials = 'all'; % trial selection has been taken care off + bivariate_common(cfg, data); + return +end -% Check for bivariate metric with 'chan_chan' in the dimord -selchan = strmatch('chan', dimtok); -isfull = length(selchan)>1; +% Apply channel-type specific scaling +tmpcfg = keepfields(cfg, {'parameter', 'chanscale', 'ecgscale', 'eegscale', 'emgscale', 'eogscale', 'gradscale', 'magscale', 'megscale', 'mychan', 'mychanscale'}); +data = chanscale_common(tmpcfg, data); -% Check for bivariate metric with a labelcmb -haslabelcmb = isfield(data, 'labelcmb'); -if (isfull || haslabelcmb) && (isfield(data, cfg.parameter) && ~strcmp(cfg.parameter, 'powspctrm')) - % A reference channel is required: - if ~isfield(cfg, 'refchannel') - error('no reference channel is specified'); - end +%% Section 3: select the data to be plotted and determine min/max range - % check for refchannel being part of selection - if ~strcmp(cfg.refchannel, 'gui') - if haslabelcmb - cfg.refchannel = ft_channelselection(cfg.refchannel, unique(data.labelcmb(:))); - else - cfg.refchannel = ft_channelselection(cfg.refchannel, data.label); - end - if (isfull && ~any(ismember(data.label, cfg.refchannel))) || ... - (haslabelcmb && ~any(ismember(data.labelcmb(:), cfg.refchannel))) - error('cfg.refchannel is a not present in the (selected) channels)') - end - end +% Read or create the layout that will be used for plotting +tmpcfg = removefields(cfg, 'inputfile'); % ensure the inputfile field not to exist +cfg.layout = ft_prepare_layout(tmpcfg, data); - % Interactively select the reference channel - if strcmp(cfg.refchannel, 'gui') - % Open a single figure with the channel layout, the user can click on a reference channel - h = clf; - ft_plot_lay(lay, 'box', false); - title('Select the reference channel by dragging a selection window, more than 1 channel can be selected...'); - % add the channel information to the figure - info = guidata(gcf); - info.x = lay.pos(:, 1); - info.y = lay.pos(:, 2); - info.label = lay.label; - info.dataname = ''; - guidata(h, info); - %set(gcf, 'WindowButtonUpFcn', {@ft_select_channel, 'callback', {@select_topoplotER, cfg, data}}); - set(gcf, 'WindowButtonUpFcn', {@ft_select_channel, 'multiple', true, 'callback', {@select_multiplotTFR, cfg, data}, 'event', 'WindowButtonUpFcn'}); - set(gcf, 'WindowButtonDownFcn', {@ft_select_channel, 'multiple', true, 'callback', {@select_multiplotTFR, cfg, data}, 'event', 'WindowButtonDownFcn'}); - set(gcf, 'WindowButtonMotionFcn', {@ft_select_channel, 'multiple', true, 'callback', {@select_multiplotTFR, cfg, data}, 'event', 'WindowButtonMotionFcn'}); - return - end +% Take the subselection of channels that is contained in the layout, this is the same in all datasets +[selchan, sellay] = match_str(data.label, cfg.layout.label); - if ~isfull, - % Convert 2-dimensional channel matrix to a single dimension: - if isempty(cfg.directionality) - sel1 = find(strcmp(cfg.refchannel, data.labelcmb(:, 2))); - sel2 = find(strcmp(cfg.refchannel, data.labelcmb(:, 1))); - elseif strcmp(cfg.directionality, 'outflow') - sel1 = []; - sel2 = find(strcmp(cfg.refchannel, data.labelcmb(:, 1))); - elseif strcmp(cfg.directionality, 'inflow') - sel1 = find(strcmp(cfg.refchannel, data.labelcmb(:, 2))); - sel2 = []; - end - fprintf('selected %d channels for %s\n', length(sel1)+length(sel2), cfg.parameter); - if length(sel1)+length(sel2)==0 - error('there are no channels selected for plotting: you may need to look at the specification of cfg.directionality'); - end - data.(cfg.parameter) = data.(cfg.parameter)([sel1;sel2], :, :); - data.label = [data.labelcmb(sel1, 1);data.labelcmb(sel2, 2)]; - data.labelcmb = data.labelcmb([sel1;sel2], :); - %data = rmfield(data, 'labelcmb'); - else - % General case - sel = match_str(data.label, cfg.refchannel); - siz = [size(data.(cfg.parameter)) 1]; - if strcmp(cfg.directionality, 'inflow') || isempty(cfg.directionality) - %the interpretation of 'inflow' and 'outflow' depend on - %the definition in the bivariate representation of the data - %in FieldTrip the row index 'causes' the column index channel - %data.(cfg.parameter) = reshape(mean(data.(cfg.parameter)(:, sel, :), 2), [siz(1) 1 siz(3:end)]); - sel1 = 1:siz(1); - sel2 = sel; - meandir = 2; - elseif strcmp(cfg.directionality, 'outflow') - %data.(cfg.parameter) = reshape(mean(data.(cfg.parameter)(sel, :, :), 1), [siz(1) 1 siz(3:end)]); - sel1 = sel; - sel2 = 1:siz(1); - meandir = 1; - - elseif strcmp(cfg.directionality, 'ff-fd') - error('cfg.directionality = ''ff-fd'' is not supported anymore, you have to manually subtract the two before the call to ft_multiplotTFR'); - elseif strcmp(cfg.directionality, 'fd-ff') - error('cfg.directionality = ''fd-ff'' is not supported anymore, you have to manually subtract the two before the call to ft_multiplotTFR'); - end %if directionality - end %if ~isfull -end %handle the bivariate data - - -% Get physical x-axis range: +% Get physical min/max range of x, i.e. time if strcmp(cfg.xlim, 'maxmin') - xmin = min(data.(xparam)); - xmax = max(data.(xparam)); + xmin = nanmin(data.(xparam)); + xmax = nanmax(data.(xparam)); else xmin = cfg.xlim(1); xmax = cfg.xlim(2); end -% Replace value with the index of the nearest bin -if ~isempty(xparam) - xmin = nearest(data.(xparam), xmin); - xmax = nearest(data.(xparam), xmax); -end +% Get the index of the nearest bin, this is the same in all datasets +xminindx = nearest(data.(xparam), xmin); +xmaxindx = nearest(data.(xparam), xmax); +xmin = data.(xparam)(xminindx); +xmax = data.(xparam)(xmaxindx); +selx = xminindx:xmaxindx; +xval = data.(xparam)(selx); -% Get physical y-axis range: +% Get physical min/max range of y, i.e. frequency if strcmp(cfg.ylim, 'maxmin') - ymin = min(data.(yparam)); - ymax = max(data.(yparam)); + ymin = nanmin(data.(yparam)); + ymax = nanmax(data.(yparam)); else ymin = cfg.ylim(1); ymax = cfg.ylim(2); end -% Replace value with the index of the nearest bin -if ~isempty(yparam) - ymin = nearest(data.(yparam), ymin); - ymax = nearest(data.(yparam), ymax); -end +% Get the index of the nearest bin, this is the same in all datasets +yminindx = nearest(data.(yparam), ymin); +ymaxindx = nearest(data.(yparam), ymax); +ymin = data.(yparam)(yminindx); +ymax = data.(yparam)(ymaxindx); +sely = yminindx:ymaxindx; +yval = data.(yparam)(sely); % test if X and Y are linearly spaced (to within 10^-12): % FROM UIMAGE -x = data.(xparam)(xmin:xmax); -y = data.(yparam)(ymin:ymax); -dx = min(diff(x)); % smallest interval for X -dy = min(diff(y)); % smallest interval for Y -evenx = all(abs(diff(x)/dx-1)<1e-12); % true if X is linearly spaced -eveny = all(abs(diff(y)/dy-1)<1e-12); % true if Y is linearly spaced +dx = min(diff(xval)); % smallest interval for X +dy = min(diff(yval)); % smallest interval for Y +evenx = all(abs(diff(xval)/dx-1)<1e-12); % true if X is linearly spaced +eveny = all(abs(diff(yval)/dy-1)<1e-12); % true if Y is linearly spaced if ~evenx || ~eveny - warning('(one of the) axis is/are not evenly spaced, but plots are made as if axis are linear') + ft_warning('(one of the) axis is/are not evenly spaced, but plots are made as if axis are linear') end -% Take subselection of channels, this only works -% in the interactive mode -if exist('selchannel', 'var') - sellab = match_str(data.label, selchannel); - label = data.label(sellab); -else - sellab = 1:numel(data.label); - label = data.label; +% masking is only possible for evenly spaced axis +if strcmp(cfg.masknans, 'yes') && (~evenx || ~eveny) + ft_warning('(one of the) axis are not evenly spaced -> nans cannot be masked out -> cfg.masknans is set to ''no'';') + cfg.masknans = 'no'; end -dat = data.(cfg.parameter); -% get dimord dimensions -dims = textscan(data.dimord, '%s', 'Delimiter', '_'); -dims = dims{1}; -ydim = find(strcmp(yparam, dims)); -xdim = find(strcmp(xparam, dims)); -zdim = setdiff(1:ndims(dat), [ydim xdim]); -% and permute -dat = permute(dat, [zdim(:)' ydim xdim]); -if isfull - dat = dat(sel1, sel2, ymin:ymax, xmin:xmax); - dat = nanmean(dat, meandir); - siz = size(dat); - dat = reshape(dat, [max(siz(1:2)) siz(3) siz(4)]); - dat = dat(sellab, :, :); -% this makes no sense, so COMMENTED OUT AS OF FEBURARY 22 2012 -% elseif haslabelcmb -% dat = dat(sellab, ymin:ymax, xmin:xmax); -else - dat = dat(sellab, ymin:ymax, xmin:xmax); -end +% the usual data is chan_freq_time, but other dimords should also work +dimtok = tokenize(dimord, '_'); +datamatrix = data.(cfg.parameter); +[c, ia, ib] = intersect(dimtok, {'chan', yparam, xparam}); +datamatrix = permute(datamatrix, ia); +datamatrix = datamatrix(selchan, sely, selx); if ~isempty(cfg.maskparameter) - mask = data.(cfg.maskparameter); - mask = permute(mask, [zdim(:)' ydim xdim]); - if isfull && cfg.maskalpha == 1 - mask = mask(sel1, sel2, ymin:ymax, xmin:xmax); - mask = nanmean(nanmean(nanmean(mask, meandir), 4), 3); - elseif haslabelcmb && cfg.maskalpha == 1 - mask = mask(sellab, ymin:ymax, xmin:xmax); - %mask = nanmean(nanmean(mask, 3), 2); - elseif cfg.maskalpha == 1 - mask = mask(sellab, ymin:ymax, xmin:xmax); - %mask = nanmean(nanmean(mask, 3), 2); - elseif isfull && cfg.maskalpha ~= 1 - maskl = mask(sel1, sel2, ymin:ymax, xmin:xmax); %% check this for full representation - mask = zeros(size(maskl)); - mask(maskl) = 1; - mask(~maskl) = cfg.maskalpha; - elseif haslabelcmb && cfg.maskalpha ~= 1 - maskl = mask(sellab, ymin:ymax, xmin:xmax); - mask = zeros(size(maskl)); - mask(maskl) = 1; - mask(~maskl) = cfg.maskalpha; - elseif cfg.maskalpha ~= 1 - maskl = mask(sellab, ymin:ymax, xmin:xmax); - mask = zeros(size(maskl)); - mask(maskl) = 1; - mask(~maskl) = cfg.maskalpha; + % one value for each channel-freq-time point + maskmatrix = data.(cfg.maskparameter)(selchan, sely, selx); + if cfg.maskalpha ~= 1 + maskmatrix( maskmatrix) = 1; + maskmatrix(~maskmatrix) = cfg.maskalpha; end +else + % create an Nx0x0 matrix + maskmatrix = zeros(length(selchan), 0, 0); end -% Select the channels in the data that match with the layout: -[chanseldat, chansellay] = match_str(label, lay.label); -if isempty(chanseldat) - error('labels in data and labels in layout do not match'); -end - -% if magnetometer/gradiometer scaling is requested, get indices for -% channels -if (cfg.magscale ~= 1) - magInd = match_str(label, ft_channelselection('MEGMAG', label)); -end -if (cfg.gradscale ~= 1) - gradInd = match_str(label, ft_channelselection('MEGGRAD', label)); -end +chanX = cfg.layout.pos(sellay, 1); +chanY = cfg.layout.pos(sellay, 2); +chanWidth = cfg.layout.width(sellay); +chanHeight = cfg.layout.height(sellay); -datsel = dat(chanseldat, :, :); -if ~isempty(cfg.maskparameter) - maskdat = mask(chanseldat, :, :); -end +%% Section 4: do the actual plotting -% Select x and y coordinates and labels of the channels in the data -chanX = lay.pos(chansellay, 1); -chanY = lay.pos(chansellay, 2); -chanWidth = lay.width(chansellay); -chanHeight = lay.height(chansellay); +cla +hold on % Get physical z-axis range (color axis): if strcmp(cfg.zlim, 'maxmin') - zmin = min(datsel(:)); - zmax = max(datsel(:)); + zmin = nanmin(datamatrix(:)); + zmax = nanmax(datamatrix(:)); elseif strcmp(cfg.zlim, 'maxabs') - zmin = -max(abs(datsel(:))); - zmax = max(abs(datsel(:))); + zmin = -nanmax(abs(datamatrix(:))); + zmax = nanmax(abs(datamatrix(:))); elseif strcmp(cfg.zlim, 'zeromax') zmin = 0; - zmax = max(datsel(:)); + zmax = nanmax(datamatrix(:)); elseif strcmp(cfg.zlim, 'minzero') - zmin = min(datsel(:)); + zmin = nanmin(datamatrix(:)); zmax = 0; else zmin = cfg.zlim(1); zmax = cfg.zlim(2); end -% set colormap -if isfield(cfg, 'colormap') - if size(cfg.colormap, 2)~=3, error('multiplotTFR(): Colormap must be a n x 3 matrix'); end - set(gcf, 'colormap', cfg.colormap); -end - -% Plot channels: -for k=1:length(chanseldat) - % Get cdata: - cdata = shiftdim(datsel(k, :, :)); +% Plot channels +for k=1:length(selchan) + cdata = shiftdim(datamatrix(k, :, :)); if ~isempty(cfg.maskparameter) - mdata = shiftdim(maskdat(k, :, :)); + mdata = shiftdim(maskmatrix(k, :, :)); end - - % scale if needed - if (cfg.magscale ~= 1 && any(magInd == chanseldat(k))) - cdata = cdata .* cfg.magscale; - end - if (cfg.gradscale ~= 1 && any(gradInd == chanseldat(k))) - cdata = cdata .* cfg.gradscale; - end - + % Draw plot (and mask Nan's with maskfield if requested) if isequal(cfg.masknans, 'yes') && isempty(cfg.maskparameter) nans_mask = ~isnan(cdata); @@ -554,56 +463,65 @@ else ft_plot_matrix(cdata, 'clim', [zmin zmax], 'tag', 'cip', 'hpos', chanX(k), 'vpos', chanY(k), 'width', chanWidth(k), 'height', chanHeight(k)) end - + % Currently the handle isn't being used below, this is here for possible use in the future h = findobj('tag', 'cip'); -end % for chanseldat - -% write comment: -k = cellstrmatch('COMNT', lay.label); -if ~isempty(k) - comment = cfg.comment; - comment = sprintf('%0s\nxlim=[%.3g %.3g]', comment, data.(xparam)(xmin), data.(xparam)(xmax)); - comment = sprintf('%0s\nylim=[%.3g %.3g]', comment, data.(yparam)(ymin), data.(yparam)(ymax)); - comment = sprintf('%0s\nzlim=[%.3g %.3g]', comment, zmin, zmax); - ft_plot_text(lay.pos(k, 1), lay.pos(k, 2), sprintf(comment), 'Fontsize', cfg.fontsize); -end +end % plot channels -% plot scale: -k = cellstrmatch('SCALE', lay.label); -if ~isempty(k) - % Get average cdata across channels: - cdata = shiftdim(mean(datsel, 1)); +% plot the layout, labels and outline +ft_plot_lay(cfg.layout, 'box', istrue(cfg.box), 'label', istrue(cfg.showlabels), 'outline', istrue(cfg.showoutline), 'point', 'no', 'mask', 'no', 'fontsize', cfg.fontsize, 'labelyoffset', 1.4*median(cfg.layout.height/2), 'labelalignh', 'center', 'chanindx', find(~ismember(cfg.layout.label, {'COMNT', 'SCALE'})) ); - % Draw plot (and mask Nan's with maskfield if requested) - if isequal(cfg.masknans, 'yes') && isempty(cfg.maskparameter) - mask = ~isnan(cdata); - mask = double(mask); - ft_plot_matrix(cdata, 'clim', [zmin zmax], 'tag', 'cip', 'highlightstyle', cfg.maskstyle, 'highlight', mask, 'hpos', lay.pos(k, 1), 'vpos', lay.pos(k, 2), 'width', lay.width(k, 1), 'height', lay.height(k, 1)) - elseif isequal(cfg.masknans, 'yes') && ~isempty(cfg.maskparameter) - mask = ~isnan(cdata); - mask = mask .* mdata; - mask = double(mask); - ft_plot_matrix(cdata, 'clim', [zmin zmax], 'tag', 'cip', 'highlightstyle', cfg.maskstyle, 'highlight', mask, 'hpos', lay.pos(k, 1), 'vpos', lay.pos(k, 2), 'width', lay.width(k, 1), 'height', lay.height(k, 1)) - elseif isequal(cfg.masknans, 'no') && ~isempty(cfg.maskparameter) - mask = mdata; - mask = double(mask); - ft_plot_matrix(cdata, 'clim', [zmin zmax], 'tag', 'cip', 'highlightstyle', cfg.maskstyle, 'highlight', mask, 'hpos', lay.pos(k, 1), 'vpos', lay.pos(k, 2), 'width', lay.width(k, 1), 'height', lay.height(k, 1)) - else - ft_plot_matrix(cdata, 'clim', [zmin zmax], 'tag', 'cip', 'hpos', lay.pos(k, 1), 'vpos', lay.pos(k, 2), 'width', lay.width(k, 1), 'height', lay.height(k, 1)) - end - % Currently the handle isn't being used below, this is here for possible use in the future - h = findobj('tag', 'cip'); +% show colormap +if isfield(cfg, 'colormap') + if size(cfg.colormap, 2)~=3, ft_error('multiplotTFR(): Colormap must be a n x 3 matrix'); end + set(gcf, 'colormap', cfg.colormap); +end +% show comment +if istrue(cfg.showcomment) + k = find(strcmp('COMNT', cfg.layout.label)); + if ~isempty(k) + limittext = cfg.limittext; + if ~strcmp(limittext, 'default') + comment = limittext; + else + comment = cfg.comment; + comment = sprintf('%0s\nxlim=[%.3g %.3g]', comment, xmin, xmax); + comment = sprintf('%0s\nylim=[%.3g %.3g]', comment, ymin, ymax); + comment = sprintf('%0s\nzlim=[%.3g %.3g]', comment, zmin, zmax); + end + ft_plot_text(cfg.layout.pos(k, 1), cfg.layout.pos(k, 2), sprintf(comment), 'FontSize', cfg.fontsize, 'FontWeight', cfg.fontweight); + end end -% plot layout -boxflg = istrue(cfg.box); -labelflg = istrue(cfg.showlabels); -outlineflg = istrue(cfg.showoutline); -ft_plot_lay(lay, 'box', boxflg, 'label', labelflg, 'outline', outlineflg, 'point', 'no', 'mask', 'no'); +% show scale +if istrue(cfg.showscale) + k = cellstrmatch('SCALE', cfg.layout.label); + if ~isempty(k) + % Get average cdata across channels: + cdata = shiftdim(mean(datamatrix, 1)); + + % Draw plot (and mask Nan's with maskfield if requested) + if isequal(cfg.masknans, 'yes') && isempty(cfg.maskparameter) + mask = ~isnan(cdata); + mask = double(mask); + ft_plot_matrix(cdata, 'clim', [zmin zmax], 'tag', 'cip', 'highlightstyle', cfg.maskstyle, 'highlight', mask, 'hpos', cfg.layout.pos(k, 1), 'vpos', cfg.layout.pos(k, 2), 'width', cfg.layout.width(k), 'height', cfg.layout.height(k)) + elseif isequal(cfg.masknans, 'yes') && ~isempty(cfg.maskparameter) + mask = ~isnan(cdata); + mask = mask .* mdata; + mask = double(mask); + ft_plot_matrix(cdata, 'clim', [zmin zmax], 'tag', 'cip', 'highlightstyle', cfg.maskstyle, 'highlight', mask, 'hpos', cfg.layout.pos(k, 1), 'vpos', cfg.layout.pos(k, 2), 'width', cfg.layout.width(k), 'height', cfg.layout.height(k)) + elseif isequal(cfg.masknans, 'no') && ~isempty(cfg.maskparameter) + mask = mdata; + mask = double(mask); + ft_plot_matrix(cdata, 'clim', [zmin zmax], 'tag', 'cip', 'highlightstyle', cfg.maskstyle, 'highlight', mask, 'hpos', cfg.layout.pos(k, 1), 'vpos', cfg.layout.pos(k, 2), 'width', cfg.layout.width(k), 'height', cfg.layout.height(k)) + else + ft_plot_matrix(cdata, 'clim', [zmin zmax], 'tag', 'cip', 'hpos', cfg.layout.pos(k, 1), 'vpos', cfg.layout.pos(k, 2), 'width', cfg.layout.width(k), 'height', cfg.layout.height(k)) + end + end +end % show scale -% plot colorbar: +% show colorbar if isfield(cfg, 'colorbar') && (strcmp(cfg.colorbar, 'yes')) colorbar; end @@ -622,15 +540,6 @@ else funcname = mfilename; end - - if isfield(cfg, 'dataname') - dataname = cfg.dataname; - elseif nargin > 1 - dataname = inputname(2); - else % data provided through cfg.inputfile - dataname = cfg.inputfile; - end - if isempty(cfg.figurename) set(gcf, 'Name', sprintf('%d: %s: %s', double(gcf), funcname, dataname)); set(gcf, 'NumberTitle', 'off'); @@ -638,30 +547,18 @@ set(gcf, 'name', cfg.figurename); set(gcf, 'NumberTitle', 'off'); end -else - funcname = ''; - dataname = ''; -end - -% Make the figure interactive: -if strcmp(cfg.interactive, 'yes') - % add the channel information to the figure - info = guidata(gcf); - info.x = lay.pos(:, 1); - info.y = lay.pos(:, 2); - info.label = lay.label; - info.dataname = dataname; - guidata(gcf, info); - - set(gcf, 'WindowButtonUpFcn', {@ft_select_channel, 'multiple', true, 'callback', {@select_singleplotTFR, cfg, data}, 'event', 'WindowButtonUpFcn'}); - set(gcf, 'WindowButtonDownFcn', {@ft_select_channel, 'multiple', true, 'callback', {@select_singleplotTFR, cfg, data}, 'event', 'WindowButtonDownFcn'}); - set(gcf, 'WindowButtonMotionFcn', {@ft_select_channel, 'multiple', true, 'callback', {@select_singleplotTFR, cfg, data}, 'event', 'WindowButtonMotionFcn'}); end axis tight axis off hold off +% Make the axis a little wider when boxes are shown +if strcmp(cfg.box, 'yes') + abc = axis; + axis(abc + [-1 +1 -1 +1]*mean(abs(abc))/10) +end + % Set orientation for printing if specified if ~isempty(cfg.orient) orient(gcf, cfg.orient); @@ -672,18 +569,44 @@ set(gcf, 'renderer', cfg.renderer) end +% Make the figure interactive: +if strcmp(cfg.interactive, 'yes') + % add the cfg/data/channel information to the figure under identifier linked to this axis + ident = ['axh' num2str(round(sum(clock.*1e6)))]; % unique identifier for this axis + set(gca,'tag',ident); + info = guidata(gcf); + info.(ident).x = cfg.layout.pos(:, 1); + info.(ident).y = cfg.layout.pos(:, 2); + info.(ident).label = cfg.layout.label; + info.(ident).dataname = dataname; + info.(ident).cfg = cfg; + info.(ident).data = data; + guidata(gcf, info); + set(gcf, 'WindowButtonUpFcn', {@ft_select_channel, 'multiple', true, 'callback', {@select_singleplotTFR}, 'event', 'WindowButtonUpFcn'}); + set(gcf, 'WindowButtonDownFcn', {@ft_select_channel, 'multiple', true, 'callback', {@select_singleplotTFR}, 'event', 'WindowButtonDownFcn'}); + set(gcf, 'WindowButtonMotionFcn', {@ft_select_channel, 'multiple', true, 'callback', {@select_singleplotTFR}, 'event', 'WindowButtonMotionFcn'}); +end + +% add a menu to the figure, but only if the current figure does not have subplots +% also, delete any possibly existing previous menu, this is safe because delete([]) does nothing +delete(findobj(gcf, 'type', 'uimenu', 'label', 'FieldTrip')); +if numel(findobj(gcf, 'type', 'axes')) <= 1 + ftmenu = uimenu(gcf, 'Label', 'FieldTrip'); + uimenu(ftmenu, 'Label', 'Show pipeline', 'Callback', {@menu_pipeline, cfg}); + uimenu(ftmenu, 'Label', 'About', 'Callback', @menu_about); +end + % do the general cleanup and bookkeeping at the end of the function ft_postamble debug ft_postamble trackconfig ft_postamble previous data ft_postamble provenance -% add a menu to the figure -% also, delete any possibly existing previous menu, this is safe because delete([]) does nothing -delete(findobj(gcf, 'type', 'uimenu', 'label', 'FieldTrip')); -ftmenu = uimenu(gcf, 'Label', 'FieldTrip'); -uimenu(ftmenu, 'Label', 'Show pipeline', 'Callback', {@menu_pipeline, cfg}); -uimenu(ftmenu, 'Label', 'About', 'Callback', @menu_about); +if ~nargout + % don't return anything + clear cfg +end + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % SUBFUNCTION @@ -696,53 +619,25 @@ end end -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% SUBFUNCTION which is called by ft_select_channel in case cfg.refchannel='gui' -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -function select_multiplotTFR(label, cfg, varargin) -if isfield(cfg, 'inputfile') - % the reading has already been done and varargin contains the data - cfg = rmfield(cfg, 'inputfile'); -end - -% put data name in here, this cannot be resolved by other means -info = guidata(gcf); -cfg.dataname = info.dataname; - -cfg.refchannel = label; -fprintf('selected cfg.refchannel = ''%s''\n', join_str(', ', cfg.refchannel)); -p = get(gcf, 'Position'); -f = figure; -set(f, 'Position', p); -ft_multiplotTFR(cfg, varargin{:}); - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % SUBFUNCTION which is called after selecting channels in case of cfg.interactive='yes' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -function select_singleplotTFR(label, cfg, varargin) +function select_singleplotTFR(label, varargin) +% fetch cfg/data based on axis indentifier given as tag +ident = get(gca,'tag'); +info = guidata(gcf); +cfg = info.(ident).cfg; +data = info.(ident).data; if ~isempty(label) - if isfield(cfg, 'inputfile') - % the reading has already been done and varargin contains the data - cfg = rmfield(cfg, 'inputfile'); - end + cfg = removefields(cfg, 'inputfile'); % the reading has already been done and varargin contains the data + cfg.baseline = 'no'; % make sure the next function does not apply a baseline correction again cfg.channel = label; - - % make sure ft_singleplotTFR does not apply a baseline correction again - cfg.baseline = 'no'; - - % put data name in here, this cannot be resolved by other means - info = guidata(gcf); - cfg.dataname = info.dataname; - - fprintf('selected cfg.channel = {'); - for i=1:(length(cfg.channel)-1) - fprintf('''%s'', ', cfg.channel{i}); - end - fprintf('''%s''}\n', cfg.channel{end}); - p = get(gcf, 'Position'); - f = figure; - set(f, 'Position', p); - ft_singleplotTFR(cfg, varargin{:}); + cfg.dataname = info.(ident).dataname; % put data name in here, this cannot be resolved by other means + cfg.trials = 'all'; % trial selection has already been taken care of + fprintf('selected cfg.channel = {%s}\n', join_str(', ', cfg.channel)); + % ensure that the new figure appears at the same position + f = figure('Position', get(gcf, 'Position')); + ft_singleplotTFR(cfg, data); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -753,10 +648,10 @@ function key_sub(handle, eventdata, varargin) % symmetrically scale color bar down by 10 percent if strcmp(eventdata.Key, 'uparrow') caxis([min(caxis)-incr max(caxis)+incr]); -% symmetrically scale color bar up by 10 percent + % symmetrically scale color bar up by 10 percent elseif strcmp(eventdata.Key, 'downarrow') caxis([min(caxis)+incr max(caxis)-incr]); -% resort to minmax of data for colorbar + % resort to minmax of data for colorbar elseif strcmp(eventdata.Key, 'm') - caxis([varargin{1} varargin{2}]); + caxis([data varargin{2}]); end diff --git a/external/fieldtrip/ft_mvaranalysis.m b/external/fieldtrip/ft_mvaranalysis.m index 7982578e..4a351f8e 100644 --- a/external/fieldtrip/ft_mvaranalysis.m +++ b/external/fieldtrip/ft_mvaranalysis.m @@ -14,12 +14,12 @@ % covariance of the residuals in the field noisecov. % % The configuration should contain: -% cfg.toolbox = the name of the toolbox containing the function for the +% cfg.method = the name of the toolbox containing the function for the % actual computation of the ar-coefficients % this can be 'biosig' (default) or 'bsmart' -% you should have a copy of the specified toolbox in order +% you should have a copy of the specified toolbox in order % to use mvaranalysis (both can be downloaded directly). -% cfg.mvarmethod = scalar (only required when cfg.toolbox = 'biosig'). +% cfg.mvarmethod = scalar (only required when cfg.method = 'biosig'). % default is 2, relates to the algorithm used for the % computation of the AR-coefficients by mvar.m % cfg.order = scalar, order of the autoregressive model (default=10) @@ -100,6 +100,14 @@ ft_nargin = nargin; ft_nargout = nargout; +% this must be done prior to "ft_preamble init" which merges the cfg with the global ft_default +if isfield(cfg, 'toolbox') && any(strcmp(cfg.toolbox, {'bsmart', 'biosig'})) + ft_warning('please use cfg.method instead of cfg.toolbox'); + % cfg.toolbox is used in ft_default + cfg.method = cfg.toolbox; + cfg = rmfield(cfg, 'toolbox'); +end + % do the general setup of the function ft_defaults ft_preamble init @@ -121,7 +129,7 @@ cfg = ft_checkconfig(cfg, 'renamed', {'blcwindow', 'baselinewindow'}); % set default configuration options -cfg.toolbox = ft_getopt(cfg, 'toolbox', 'biosig'); +cfg.method = ft_getopt(cfg, 'method', 'biosig'); cfg.mvarmethod = ft_getopt(cfg, 'mvarmethod', 2); % only relevant for biosig cfg.order = ft_getopt(cfg, 'order', 10); cfg.channel = ft_getopt(cfg, 'channel', 'all'); @@ -151,7 +159,7 @@ end % check whether the requested toolbox is present and check the configuration -switch cfg.toolbox +switch cfg.method case 'biosig' % check the configuration cfg = ft_checkconfig(cfg, 'required', 'mvarmethod'); @@ -161,7 +169,7 @@ ft_hastoolbox('bsmart', 1); nnans = 0; otherwise - error('toolbox %s is not yet supported', cfg.toolbox); + ft_error('toolbox %s is not yet supported', cfg.method); end if isempty(cfg.toi) && isempty(cfg.t_ftimwin) @@ -169,23 +177,23 @@ % check whether this is allowed nsmp = cellfun('size', data.trial, 2); - if all(nsmp==nsmp(1)); + if all(nsmp==nsmp(1)) oktoolbox = {'bsmart' 'biosig'}; else oktoolbox = 'biosig'; % bsmart does not work with variable trials end - if ~ismember(cfg.toolbox, oktoolbox), - error('fitting the mvar-model is not possible with the ''%s'' toolbox',cfg.toolbox); + if ~ismember(cfg.method, oktoolbox) + error('fitting the mvar-model is not possible with the ''%s'' toolbox',cfg.method); end latency = [-inf inf]; elseif ~isempty(cfg.toi) && ~isempty(cfg.t_ftimwin) % do sliding window approach for k = 1:numel(cfg.toi) - latency(k,:) = cfg.toi + cfg.t_ftimwin.*[-0.5 0.5]; + latency(k,:) = cfg.toi + cfg.t_ftimwin.*[-0.5 0.5-1./data.fsample]; end else - error('cfg should contain both cfg.toi and cfg.t_ftimwin'); + ft_error('cfg should contain both cfg.toi and cfg.t_ftimwin'); end @@ -196,8 +204,8 @@ dobvar = isfield(cfg, 'channelcmb'); dounivariate = istrue(cfg. univariate); -if ~keeptap, error('not keeping tapers is not possible yet'); end -if dojack && keeprpt, error('you cannot simultaneously keep trials and do jackknifing'); end +if ~keeptap, ft_error('not keeping tapers is not possible yet'); end +if dojack && keeprpt, ft_error('you cannot simultaneously keep trials and do jackknifing'); end tfwin = round(data.fsample.*cfg.t_ftimwin); ntrl = length(data.trial); @@ -263,7 +271,7 @@ %data = ft_redefinetrial(tmpcfg, data); %---demean -if strcmp(cfg.demean, 'yes'), +if strcmp(cfg.demean, 'yes') tmpcfg = []; tmpcfg.demean = 'yes'; tmpcfg.baselinewindow = latency([1 end]); @@ -279,7 +287,7 @@ end %---zscore -if dozscore, +if dozscore zwindow = latency([1 end]); sumval = 0; sumsqr = 0; @@ -288,7 +296,7 @@ for k = 1:ntrl begsmp = nearest(data.time{k}, zwindow(1)); endsmp = nearest(data.time{k}, zwindow(2)); - if endsmp>=begsmp, + if endsmp>=begsmp sumval = sumval + sum(data.trial{k}(:, begsmp:endsmp), 2); sumsqr = sumsqr + sum(data.trial{k}(:, begsmp:endsmp).^2, 2); numsmp = numsmp + endsmp - begsmp + 1; @@ -321,10 +329,10 @@ %---allocate memory if dobvar && (keeprpt || dojack) % not yet implemented - error('doing bivariate model fits in combination with multiple replicates is not yet possible'); + ft_error('doing bivariate model fits in combination with multiple replicates is not yet possible'); elseif dobvar - coeffs = zeros(1, size(cmbindx,1), 2*nchan, cfg.order, ntoi, ntap); - noisecov = zeros(1, size(cmbindx,1), 2*nchan, ntoi, ntap); + coeffs = zeros(1, 2*nchan, size(cmbindx,1), cfg.order, ntoi, ntap); + noisecov = zeros(1, 2*nchan, size(cmbindx,1), ntoi, ntap); elseif dounivariate && (keeprpt || dojack) error('doing univariate model fits in combination with multiple replicates is not yet possible'); elseif dounivariate @@ -352,10 +360,10 @@ end tmpnsmp = cellfun('size', tmpdata.trial, 2); - if ntoi>1 && strcmp(cfg.toolbox, 'bsmart') + if ntoi>1 && strcmp(cfg.method, 'bsmart') % ensure all segments to be of equal length if ~all(tmpnsmp==tmpnsmp(1)) - error('the epochs are of unequal length, possibly due to numerical time axis issues, or due to partial artifacts, use cfg.toolbox=''biosig'''); + error('the epochs are of unequal length, possibly due to numerical time axis issues, or due to partial artifacts, use cfg.method=''biosig'''); end ix = find(tmpnsmp==mode(tmpnsmp), 1, 'first'); cfg.toi(j) = mean(tmpdata.time{ix}([1 end]))+0.5./data.fsample; %FIXME think about this @@ -388,7 +396,7 @@ dat = catnan(tmpdata.trial, cmbindx(k,:), rpt{rlop}, tap(m,:), nnans, dobvar); %---estimate autoregressive model - switch cfg.toolbox + switch cfg.method case 'biosig' [ar, rc, pe] = mvar(dat', cfg.order, cfg.mvarmethod); @@ -400,13 +408,13 @@ %FIXME check which is which: X(t) = A1*X(t-1) + ... + An*X(t-n) + E %the other is then X(t) + A1*X(t-1) + ... + An*X(t-n) = E end - coeffs(rlop,k,:,:,j,m) = reshape(ar, [nchan*2 cfg.order]); + coeffs(rlop,:,k,:,j,m) = reshape(ar, [nchan*2 cfg.order]); %---rescale noisecov if necessary if dozscore, % FIX ME for bvar - noisecov(rlop,k,:,:,j,m) = diag(datstd)*tmpnoisecov*diag(datstd); + noisecov(rlop,:,k,:,j,m) = diag(datstd)*tmpnoisecov*diag(datstd); else - noisecov(rlop,k,:,j,m) = reshape(tmpnoisecov,[1 4]); + noisecov(rlop,:,k,j,m) = reshape(tmpnoisecov,[1 4]); end dof(rlop,:,j) = numel(rpt{rlop}); end @@ -417,12 +425,12 @@ dat = catnan(tmpdata.trial, chanindx, rpt{rlop}, tap(m,:), nnans, dobvar); %---estimate autoregressive model - if dounivariate, + if dounivariate %---loop across the channels for p = 1:size(dat,1) - switch cfg.toolbox + switch cfg.method case 'biosig' [ar, rc, pe] = mvar(dat(p,:)', cfg.order, cfg.mvarmethod); @@ -437,7 +445,7 @@ coeffs(rlop,p,:,j,m) = reshape(ar, [1 cfg.order]); %---rescale noisecov if necessary - if dozscore, + if dozscore noisecov(rlop,p,j,m) = diag(datstd)*tmpnoisecov*diag(datstd); else noisecov(rlop,p,j,m) = tmpnoisecov; @@ -446,7 +454,7 @@ end else - switch cfg.toolbox + switch cfg.method case 'biosig' [ar, rc, pe] = mvar(dat', cfg.order, cfg.mvarmethod); @@ -461,7 +469,7 @@ coeffs(rlop,:,:,:,j,m) = reshape(ar, [nchan nchan cfg.order]); %---rescale noisecov if necessary - if dozscore, + if dozscore noisecov(rlop,:,:,j,m) = diag(datstd)*tmpnoisecov*diag(datstd); else noisecov(rlop,:,:,j,m) = tmpnoisecov; @@ -480,9 +488,9 @@ %---create output-structure mvardata = []; -if ~dobvar && ~dounivariate && dojack, +if ~dobvar && ~dounivariate && dojack mvardata.dimord = 'rptjck_chan_chan_lag'; -elseif ~dobvar && ~dounivariate && keeprpt, +elseif ~dobvar && ~dounivariate && keeprpt mvardata.dimord = 'rpt_chan_chan_lag'; elseif ~dobvar && ~dounivariate mvardata.dimord = 'chan_chan_lag'; @@ -545,7 +553,7 @@ P = mvardata.coeffs(:,:,m); end - if strcmp(cfg.output, 'residual'), + if strcmp(cfg.output, 'residual') P = -P; end @@ -584,7 +592,7 @@ %---fill the matrix for k = 1:nrpt - if k==1, + if k==1 begsmp = sumsmp(k) + 1; endsmp = sumsmp(k+1) ; else diff --git a/external/fieldtrip/ft_neighbourplot.m b/external/fieldtrip/ft_neighbourplot.m index e4ad0745..2a868d41 100644 --- a/external/fieldtrip/ft_neighbourplot.m +++ b/external/fieldtrip/ft_neighbourplot.m @@ -10,11 +10,12 @@ % ft_neighbourplot(cfg, data) % % where the configuration can contain -% cfg.verbose = 'yes' or 'no', if 'yes' then the plot callback will include text output +% cfg.verbose = string, 'yes' or 'no', whether the function will print feedback text in the command window % cfg.neighbours = neighbourhood structure, see FT_PREPARE_NEIGHBOURS (optional) -% cfg.enableedit = 'yes' or 'no' (default). allows the user to -% flexibly add or remove edges between vertices -% or one of the following options +% cfg.visible = string, 'on' or 'off', whether figure will be visible (default = 'on') +% cfg.enableedit = string, 'yes' or 'no', allows the user to flexibly add or remove edges between vertices (default = 'no') +% +% and either one of the following options % cfg.layout = filename of the layout, see FT_PREPARE_LAYOUT % cfg.elec = structure with electrode definition % cfg.grad = structure with gradiometer definition @@ -76,7 +77,9 @@ data = ft_checkdata(data); end +% set the defaults cfg.enableedit = ft_getopt(cfg, 'enableedit', 'no'); +cfg.visible = ft_getopt(cfg, 'visible', 'on'); if isfield(cfg, 'neighbours') cfg.neighbours = cfg.neighbours; @@ -121,7 +124,7 @@ % use 3-dimensional data for plotting proj = sens.chanpos; end -hf = figure; +hf = figure('visible', cfg.visible); axis equal axis vis3d axis off @@ -181,7 +184,7 @@ 'UserData', i, ... 'ButtonDownFcn', @showLabelInTitle); else - error('Channel coordinates are too high dimensional'); + ft_error('Channel coordinates are too high dimensional'); end end hold off; @@ -194,7 +197,7 @@ userdata.hs = hs; userdata.hl = hl; userdata.quit = false; -hf = getparent(hf); +hf = getparent(hf); set(hf, 'UserData', userdata); if istrue(cfg.enableedit) @@ -205,7 +208,7 @@ end cfg = userdata.cfg; - hf = getparent(hf); + hf = getparent(hf); delete(hf); end % in any case remove SCALE and COMNT @@ -344,7 +347,7 @@ function showLabelInTitle(gcbo, EventData, handles) 'UserData', lastSensId, ... 'ButtonDownFcn', @showLabelInTitle); else - error('Channel coordinates are too high dimensional'); + ft_error('Channel coordinates are too high dimensional'); end if cfg.verbose diff --git a/external/fieldtrip/ft_networkanalysis.m b/external/fieldtrip/ft_networkanalysis.m index 59493304..b6f0ff33 100644 --- a/external/fieldtrip/ft_networkanalysis.m +++ b/external/fieldtrip/ft_networkanalysis.m @@ -89,8 +89,16 @@ ft_hastoolbox('BCT', 1); % check the data for the correct dimord and for the presence of the requested parameter -if ~strcmp(data.dimord(1:7), 'pos_pos') && ~strcmp(data.dimord(1:9), 'chan_chan'), - error('the dimord of the input data should start with ''chan_chan'' or ''pos_pos'''); +if isfield(data, [cfg.parameter,'dimord']) + dimord = data.([cfg.parameter,'dimord']); +elseif isfield(data, 'dimord') + dimord = data.dimord; +else + ft_error('input data needs a ''dimord'' field'); +end + +if ~strcmp(dimord(1:7), 'pos_pos') && ~strcmp(dimord(1:9), 'chan_chan') + ft_error('the dimord of the input data should start with ''chan_chan'' or ''pos_pos'''); end % conversion to double is needed because some BCT functions want to do matrix @@ -99,7 +107,7 @@ % some metrics explicitly require a certain parameter if strcmp(cfg.method, 'charpath') && ~strcmp(cfg.parameter, 'distance') - error('characteristic path length can only be computed on distance matrices'); + ft_error('characteristic path length can only be computed on distance matrices'); end % check for binary or not @@ -108,7 +116,7 @@ for m = 1:size(input,4) tmp = input(:,:,k,m); isbinary = all(ismember(tmp(:), [0 1])); - if ~isbinary, + if ~isbinary break; end end @@ -138,7 +146,7 @@ for m = 1:size(input,4) tmp = input(:,:,k,m); isdirected = ~all(all(tmp==tmp.')); - if ~isdirected, + if ~isdirected break; end end @@ -158,10 +166,10 @@ outsiz = [size(input) 1]; outsiz(1:2) = []; output = zeros(outsiz); - if strcmp(data.dimord(1:3), 'pos') - dimord = data.dimord(9:end); - elseif strcmp(data.dimord(1:4), 'chan') - dimord = data.dimord(11:end); + if strcmp(dimord(1:3), 'pos') + dimord = dimord(9:end); + elseif strcmp(dimord(1:4), 'chan') + dimord = dimord(11:end); end needlabel = false; case {'betweenness' 'clustering_coef' 'degrees'} @@ -169,16 +177,16 @@ outsiz = [size(input) 1]; outsiz(1) = []; output = zeros(outsiz); - if strcmp(data.dimord(1:3), 'pos') - dimord = data.dimord(5:end); - elseif strcmp(data.dimord(1:4), 'chan') - dimord = data.dimord(6:end); + if strcmp(dimord(1:3), 'pos') + dimord = dimord(5:end); + elseif strcmp(dimord(1:4), 'chan') + dimord = dimord(6:end); end case {'distance' 'edge_betweenness'} % 1 value per node pair outsiz = [size(input) 1]; output = zeros(outsiz); - dimord = data.dimord; + dimord = dimord; end binarywarning = 'weights are not taken into account and graph is converted to binary values by thresholding'; @@ -203,7 +211,7 @@ output(:,k,m) = betweenness_wei(input(:,:,k,m)); end case 'breadthdist' - error('not yet implemented'); + ft_error('not yet implemented'); case 'charpath' % this needs the distance matrix as input, this is dealt with % above @@ -248,11 +256,11 @@ output(:,:,k,m) = edge_betweenness_wei(input(:,:,k,m)); end case 'efficiency' - error('not yet implemented'); + ft_error('not yet implemented'); case 'modularity' - error('not yet implemented'); + ft_error('not yet implemented'); case 'participation_coef' - error('not yet implemented'); + ft_error('not yet implemented'); case 'transitivity' if isbinary && isdirected output(k,m) = transitivity_bd(input(:,:,k,m)); @@ -264,7 +272,7 @@ output(k,m) = transitivity_wu(input(:,:,k,m)); end otherwise - error('unsupported connectivity metric %s requested'); + ft_error('unsupported connectivity metric %s requested'); end end % for m @@ -275,15 +283,9 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%% stat = []; +stat = keepfields(data, {'label', 'freq', 'time', 'grad', 'elec', 'opto', 'dof', 'pos', 'tri', 'inside', 'brainordinate'}); stat.(cfg.method) = output; stat.dimord = dimord; -if isfield(data, 'label') && needlabel, stat.label = data.label; end -if isfield(data, 'freq'), stat.freq = data.freq; end -if isfield(data, 'time'), stat.time = data.time; end -if isfield(data, 'grad'), stat.grad = data.grad; end -if isfield(data, 'elec'), stat.elec = data.elec; end -if exist('dof', 'var'), stat.dof = dof; end -% FIXME this needs to be implemented still % do the general cleanup and bookkeeping at the end of the function ft_postamble debug diff --git a/external/fieldtrip/ft_prepare_bemmodel.m b/external/fieldtrip/ft_prepare_bemmodel.m deleted file mode 100644 index 1ffdb2f2..00000000 --- a/external/fieldtrip/ft_prepare_bemmodel.m +++ /dev/null @@ -1,303 +0,0 @@ -function [headmodel, cfg] = ft_prepare_bemmodel(cfg, mri) - -% FT_PREPARE_BEMMODEL is deprecated, please use FT_PREPARE_HEADMODEL and -% FT_PREPARE_MESH -% -% See also FT_PREPARE_HEADMODEL - -% Copyright (C) 2005-2009, Robert Oostenveld -% -% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org -% for the documentation and details. -% -% FieldTrip is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. -% -% FieldTrip is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with FieldTrip. If not, see . -% -% $Id$ - -warning('FT_PREPARE_BEMMODEL is deprecated, please use FT_PREPARE_HEADMODEL with cfg.method = ''dipoli/openmeeg/bemcp'' instead.') - -% these are used by the ft_preamble/ft_postamble function and scripts -ft_revision = '$Id$'; -ft_nargin = nargin; -ft_nargout = nargout; - -% do the general setup of the function -ft_defaults -ft_preamble init -ft_preamble debug -ft_preamble provenance mri -ft_preamble trackconfig - -% the ft_abort variable is set to true or false in ft_preamble_init -if ft_abort - return -end - -cfg = ft_checkconfig(cfg, 'renamed', {'hdmfile', 'headmodel'}); -cfg = ft_checkconfig(cfg, 'renamed', {'vol', 'headmodel'}); - -% set the defaults -if ~isfield(cfg, 'tissue'), cfg.tissue = [8 12 14]; end -if ~isfield(cfg, 'numvertices'), cfg.numvertices = [1 2 3] * 500; end -if ~isfield(cfg, 'isolatedsource'), cfg.isolatedsource = []; end -if ~isfield(cfg, 'method'), cfg.method = 'dipoli'; end % dipoli, openmeeg, bemcp - -% start with an empty volume conductor -try - hdm = ft_fetch_vol(cfg); - headmodel.bnd = hdm.bnd; - if isfield(hdm, 'cond') - % also copy the conductivities - headmodel.cond = hdm.cond; - end -catch - headmodel = []; - geom = fixpos(mri); - % copy the boundaries from the geometry into the volume conduction model - headmodel.bnd = geom.bnd; -end - -% determine the number of compartments -Ncompartment = numel(headmodel.bnd); - -% assign the conductivity -if ~isfield(headmodel,'cond') - if ~isfield(cfg, 'conductivity') - if isfield(mri, 'cond') - headmodel.cond = mri.cond; - elseif isfield(mri, 'c') - headmodel.cond = mri.c; - else - fprintf('warning: using default values for the conductivity') - headmodel.cond = [1 1/80 1] * 0.33; - end - else - if ~isempty(cfg.conductivity) - headmodel.cond = cfg.conductivity; - elseif isempty(cfg.conductivity) && Ncompartment==3 - fprintf('warning: using default values for the conductivity') - headmodel.cond = [1 1/80 1] * 0.33; - else - fprintf('warning: using 1 for all conductivities') - headmodel.cond = ones(1,Ncompartment); - end - end -end - -if ~isfield(headmodel, 'bnd') - % construct the geometry of the BEM boundaries - if nargin==1 - headmodel.bnd = ft_prepare_mesh(cfg); - else - headmodel.bnd = ft_prepare_mesh(cfg, mri); - end -end - -headmodel.source = find_innermost_boundary(headmodel.bnd); -headmodel.skin_surface = find_outermost_boundary(headmodel.bnd); -fprintf('determining source compartment (%d)\n', headmodel.source); -fprintf('determining skin compartment (%d)\n', headmodel.skin_surface); - -if ~isempty(cfg.isolatedsource) - isolatedsource = istrue(cfg.isolatedsource); -else - isolatedsource = false; -end - -if isempty(cfg.isolatedsource) && Ncompartment>1 && strcmp(cfg.method, 'dipoli') - % the isolated source compartment is by default the most inner one - isolatedsource = true; -elseif isempty(cfg.isolatedsource) && Ncompartment==1 - % the isolated source interface should be contained within at least one other interface - isolatedsource = false; -elseif ~islogical(isolatedsource) - error('cfg.isolatedsource should be true or false'); -end - -if cfg.isolatedsource - fprintf('using compartment %d for the isolated source approach\n', headmodel.source); -else - fprintf('not using the isolated source approach\n'); -end - -if strcmp(cfg.method, 'dipoli') - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - % this uses an implementation that was contributed by Thom Oostendorp - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - ft_hastoolbox('dipoli', 1); - - % use the dipoli wrapper function - headmodel = dipoli(headmodel, isolatedsource); - headmodel.type = 'dipoli'; - -elseif strcmp(cfg.method, 'bemcp') - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - % this uses an implementation that was contributed by Christophe Philips - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - ft_hastoolbox('bemcp', 1); - - % do some sanity checks - if length(headmodel.bnd)~=3 - error('this only works for three surfaces'); - end - - numboundaries = length(headmodel.bnd); - % determine the nesting of the compartments - nesting = zeros(numboundaries); - for i=1:numboundaries - for j=1:numboundaries - if i~=j - % determine for a single vertex on each surface if it is inside or outside the other surfaces - curpos = headmodel.bnd(i).pos(1,:); % any point on the boundary is ok - curpnt = headmodel.bnd(j).pos; - curtri = headmodel.bnd(j).tri; - nesting(i,j) = bounding_mesh(curpos, curpnt, curtri); - end - end - end - - if sum(nesting(:))~=(numboundaries*(numboundaries-1)/2) - error('the compartment nesting cannot be determined'); - end - - % for a three compartment model, the nesting matrix should look like - % 0 1 1 the first is nested inside the 2nd and 3rd, i.e. the inner skull - % 0 0 1 the second is nested inside the 3rd, i.e. the outer skull - % 0 0 0 the third is the most outside, i.e. the skin - [dum, order] = sort(-sum(nesting,2)); - - fprintf('reordering the boundaries to: '); - fprintf('%d ', order); - fprintf('\n'); - - % update the order of the compartments - headmodel.bnd = headmodel.bnd(order); - headmodel.cond = headmodel.cond(order); - headmodel.skin_surface = numboundaries; - headmodel.source = 1; - - % Build Triangle 4th point - headmodel = triangle4pt(headmodel); - - % 2. BEM model estimation, only for the scalp surface - - defl =[ 0 0 1/size(headmodel.bnd(headmodel.skin_surface).pos,1)]; - % ensure deflation for skin surface, i.e. average reference over skin - - % NOTE: - % Calculation proceeds by estimating each submatrix C_ij and combine them. - % There are 2 options: - % - calculating the matrices once, as it takes some time, keep them in - % memory and use them the 2-3 times they're needed. - % - calculating the matrices every time they're needed, i.e. 2-3 times - % The former option is faster but requires more memory space as up to *8* - % square matrices of size C_ij have to be kept in memory at once. - % The latter option requires less memory, but would take much more time to - % estimate. - % This faster but memory hungry solution is implemented here. - - % Deal first with surface 1 and 2 (inner and outer skull - %-------------------------------- - - % NOTE: - % C11st/C22st/C33st are simply the matrix C11/C22/C33 minus the identity - % matrix, i.e. C11st = C11-eye(N) - - weight = (headmodel.cond(1)-headmodel.cond(2))/((headmodel.cond(1)+headmodel.cond(2))*2*pi); - C11st = bem_Cii_lin(headmodel.bnd(1).tri,headmodel.bnd(1).pos, weight,defl(1),headmodel.bnd(1).pnt4); - weight = (headmodel.cond(1)-headmodel.cond(2))/((headmodel.cond(2)+headmodel.cond(3))*2*pi); - C21 = bem_Cij_lin(headmodel.bnd(2).pos,headmodel.bnd(1).pos,headmodel.bnd(1).tri, weight,defl(1)); - tmp1 = C21/C11st; - - weight = (headmodel.cond(2)-headmodel.cond(3))/((headmodel.cond(1)+headmodel.cond(2))*2*pi); - C12 = bem_Cij_lin(headmodel.bnd(1).pos,headmodel.bnd(2).pos,headmodel.bnd(2).tri, weight,defl(2)); - weight = (headmodel.cond(2)-headmodel.cond(3))/((headmodel.cond(2)+headmodel.cond(3))*2*pi); - C22st = bem_Cii_lin(headmodel.bnd(2).tri,headmodel.bnd(2).pos, weight,defl(2),headmodel.bnd(2).pnt4); - tmp2 = C12/C22st; - - % Try to spare some memory: - tmp10 = - tmp2 * C21 + C11st; - clear C21 C11st - tmp11 = - tmp1 * C12 + C22st; - clear C12 C22st - - % Combine with the effect of surface 3 (scalp) on the first 2 - %------------------------------------------------------------ - weight = (headmodel.cond(1)-headmodel.cond(2))/(headmodel.cond(3)*2*pi); - C31 = bem_Cij_lin(headmodel.bnd(3).pos,headmodel.bnd(1).pos,headmodel.bnd(1).tri, weight,defl(1)); - % tmp4 = C31/(- tmp2 * C21 + C11st ); - % clear C31 C21 C11st - tmp4 = C31/tmp10; - clear C31 tmp10 - - weight = (headmodel.cond(2)-headmodel.cond(3))/(headmodel.cond(3)*2*pi); - C32 = bem_Cij_lin(headmodel.bnd(3).pos,headmodel.bnd(2).pos,headmodel.bnd(2).tri, weight,defl(2)); - % tmp3 = C32/(- tmp1 * C12 + C22st ); - % clear C12 C22st C32 - tmp3 = C32/tmp11; - clear C32 tmp11 - - tmp5 = tmp3*tmp1-tmp4; - tmp6 = tmp4*tmp2-tmp3; - clear tmp1 tmp2 tmp3 tmp4 - - % Finally include effect of surface 3 on the others - %-------------------------------------------------- - % As the gama1 intermediate matrix is built as the sum of 3 matrices, I can - % spare some memory by building them one at a time, and summing directly - weight = headmodel.cond(3)/((headmodel.cond(1)+headmodel.cond(2))*2*pi); - Ci3 = bem_Cij_lin(headmodel.bnd(1).pos,headmodel.bnd(3).pos,headmodel.bnd(3).tri, weight,defl(3)); - gama1 = - tmp5*Ci3; % gama1 = - tmp5*C13; - - weight = headmodel.cond(3)/((headmodel.cond(2)+headmodel.cond(3))*2*pi); - Ci3 = bem_Cij_lin(headmodel.bnd(2).pos,headmodel.bnd(3).pos,headmodel.bnd(3).tri, weight,defl(3)); - gama1 = gama1 - tmp6*Ci3; % gama1 = - tmp5*C13 - tmp6*C23; - - weight = 1/(2*pi); - Ci3 = bem_Cii_lin(headmodel.bnd(3).tri,headmodel.bnd(3).pos, weight,defl(3),headmodel.bnd(3).pnt4); - gama1 = gama1 - Ci3; % gama1 = - tmp5*C13 - tmp6*C23 - C33st; - clear Ci3 - - % Build system matrix - %-------------------- - i_gama1 = inv(gama1); - headmodel.mat = [i_gama1*tmp5 i_gama1*tmp6 i_gama1]; - headmodel.type = 'bemcp'; - -elseif strcmp(cfg.method, 'openmeeg') - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - % this uses an implementation that was contributed by INRIA Odyssee Team - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - ft_hastoolbox('openmeeg', 1); - - if size(headmodel.bnd(1).pos,1)>10000 - error('OpenMEEG does not manage meshes with more than 10000 vertices (use reducepatch)') - else - % use the openmeeg wrapper function - headmodel = openmeeg(headmodel,cfg.isolatedsource); - headmodel.type = 'openmeeg'; - end - -else - error('unsupported method'); -end % which method - -% ensure that the geometrical units are specified -headmodel = ft_convert_units(headmodel); - -% do the general cleanup and bookkeeping at the end of the function -ft_postamble debug -ft_postamble trackconfig -ft_postamble provenance headmodel -ft_postamble history headmodel diff --git a/external/fieldtrip/ft_prepare_concentricspheres.m b/external/fieldtrip/ft_prepare_concentricspheres.m deleted file mode 100644 index dcdb7cba..00000000 --- a/external/fieldtrip/ft_prepare_concentricspheres.m +++ /dev/null @@ -1,152 +0,0 @@ -function [headmodel, cfg] = ft_prepare_concentricspheres(cfg) - -% FT_PREPARE_CONCENTRICSPHERES is deprecated, please use FT_PREPARE_HEADMODEL and -% FT_PREPARE_MESH -% -% See also FT_PREPARE_HEADMODEL - -% Copyright (C) 2009, Vladimir Litvak & Robert Oostenveld -% -% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org -% for the documentation and details. -% -% FieldTrip is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. -% -% FieldTrip is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with FieldTrip. If not, see . -% -% $Id$ - -warning('FT_PREPARE_CONCENTRICSPHERES is deprecated, please use FT_PREPARE_HEADMODEL with cfg.method = ''concentricspheres'' instead.') - -% these are used by the ft_preamble/ft_postamble function and scripts -ft_revision = '$Id$'; -ft_nargin = nargin; -ft_nargout = nargout; - -% do the general setup of the function -ft_defaults -ft_preamble init -ft_preamble debug -ft_preamble provenance -ft_preamble trackconfig - -% the ft_abort variable is set to true or false in ft_preamble_init -if ft_abort - return -end - -% check if the input cfg is valid for this function -cfg = ft_checkconfig(cfg, 'forbidden', 'nonlinear'); - -% set the defaults -if ~isfield(cfg, 'fitind'), cfg.fitind = 'all'; end -if ~isfield(cfg, 'feedback'), cfg.feedback = 'yes'; end -if ~isfield(cfg, 'conductivity'), cfg.conductivity = []; end % this should be specified by the user -if ~isfield(cfg, 'numvertices'), cfg.numvertices = 'same'; end - -if isfield(cfg, 'headshape') && isa(cfg.headshape, 'config') - % convert the nested config-object back into a normal structure - cfg.headshape = struct(cfg.headshape); -end - -% get the surface describing the head shape -headshape = prepare_mesh_headshape(cfg); - -if isempty(cfg.conductivity) - if numel(headshape)==1 - warning('using default conductivity values'); - cfg.conductivity = 1; - elseif numel(headshape)==3 - warning('using default conductivity values'); - cfg.conductivity = [1 1/80 1]*0.33; - else - % for a 2 or 4 sphere model the order of the compartments is potentially ambiguous, hence no default should be supplied - error('a conductivity value should be specified for each compartment'); - end -end - -if strcmp(cfg.fitind, 'all') - fitind = 1:numel(headshape); -else - fitind = cfg.fitind; -end - -% concatenate the vertices of all surfaces -pos = []; -for i = fitind - pos = [pos ; headshape(i).pos]; -end -% remove double vertices -pos = unique(pos, 'rows'); - -Npos = size(pos, 1); - -% set up an empty figure -if strcmp(cfg.feedback, 'yes') - clf - hold on - axis equal - axis vis3d - axis off - drawnow - colors = {'b', 'y', 'm', 'r'}; - [sphere_pos, sphere_tri] = icosahedron162; -end - -% fit a single sphere to all headshape points -[single_o, single_r] = fitsphere(pos); -fprintf('initial sphere: number of surface points = %d\n', Npos); -fprintf('initial sphere: center = [%.1f %.1f %.1f]\n', single_o(1), single_o(2), single_o(3)); -fprintf('initial sphere: radius = %.1f\n', single_r); - -% fit the radius of each concentric sphere to the corresponding surface points -headmodel = []; -headmodel.o = single_o; -for i = 1:numel(headshape) - dist = sqrt(sum(((headshape(end-i+1).pos - repmat(single_o, size(headshape(end-i+1).pos,1), 1)).^2), 2)); - headmodel.r(i) = mean(dist); - - if strcmp(cfg.feedback, 'yes') - if ~isfield(headshape(end-i+1), 'tri') - headshape(end-i+1).tri = []; - end - - % plot the original surface - bndtmp = []; - bndtmp.pos = headshape(end-i+1).pos; - bndtmp.tri = headshape(end-i+1).tri; - ft_plot_mesh(bndtmp,'facecolor','none') - - % plot the sphere surface - bndtmp = []; - bndtmp.pos = sphere_pos*headmodel.r(i) + repmat(single_o, size(sphere_pos, 1), 1); - bndtmp.tri = sphere_tri; - ft_plot_mesh(bndtmp,'edgecolor',colors{mod(i, numel(colors)) + 1},'facecolor','none'); - end -end - -if numel(cfg.conductivity)==numel(headshape) - headmodel.cond = cfg.conductivity; -else - error('incorrect specification of cfg.conductivity'); -end - -headmodel.type = 'concentricspheres'; - -% ensure that the geometrical units are specified -headmodel = ft_convert_units(headmodel); - -% do the general cleanup and bookkeeping at the end of the function -ft_postamble debug -ft_postamble trackconfig -ft_postamble provenance headmodel -ft_postamble history headmodel diff --git a/external/fieldtrip/ft_prepare_headmodel.m b/external/fieldtrip/ft_prepare_headmodel.m index a26f196d..bf822868 100644 --- a/external/fieldtrip/ft_prepare_headmodel.m +++ b/external/fieldtrip/ft_prepare_headmodel.m @@ -233,42 +233,38 @@ % the construction of the volume conductor model is performed below switch cfg.method - + case 'interpolate' % the "data" here represents the output of FT_PREPARE_LEADFIELD, i.e. a regular dipole % grid with pre-computed leadfields sens = ft_fetch_sens(cfg, data); headmodel = ft_headmodel_interpolate(cfg.outputfile, sens, data, 'smooth', cfg.smooth); - + case 'besa' % the cfg.headmodel? points to the filename of the FEM solution that was computed % in BESA, cfg.elecfile should point to the corresponding electrode specification sens = ft_fetch_sens(cfg, data); headmodel = ft_headmodel_interpolate(cfg.outputfile, sens, cfg.headmodel, 'smooth', cfg.smooth); - + case 'asa' if ~ft_filetype(cfg.headmodel, 'asa_vol') - error('You must supply a valid cfg.headmodel for use with ASA headmodel') + ft_error('You must supply a valid cfg.headmodel for use with ASA headmodel') end headmodel = ft_headmodel_asa(cfg.headmodel); - + case {'bemcp' 'dipoli' 'openmeeg'} % the low-level functions all need a mesh - if input_mesh - if ~isfield(data, 'tri') - error('Please give a mesh with closed triangulation'); - else - geometry = data; - end - elseif input_seg + if isfield(data, 'pos') && isfield(data, 'tri') + geometry = data; + elseif isfield(data, 'transform') && isfield(data, 'dim') tmpcfg = []; tmpcfg.numvertices = cfg.numvertices; tmpcfg.tissue = cfg.tissue; geometry = ft_prepare_mesh(tmpcfg, data); else - error('Either a segmentated MRI or data with closed triangulated mesh is required as data input for the bemcp, dipoli or openmeeg method'); + ft_error('Either a segmentated MRI or data with closed triangulated mesh is required as data input for the bemcp, dipoli or openmeeg method'); end - + if strcmp(cfg.method, 'bemcp') headmodel = ft_headmodel_bemcp(geometry, 'conductivity', cfg.conductivity); if any(isnan(headmodel.mat(:))) @@ -277,7 +273,7 @@ geometry(1).pos = geometry(1).pos + randn(size(geometry(1).pos))*ft_scalingfactor('um', geometry(1).unit); geometry(2).pos = geometry(2).pos + randn(size(geometry(2).pos))*ft_scalingfactor('um', geometry(2).unit); geometry(3).pos = geometry(3).pos + randn(size(geometry(3).pos))*ft_scalingfactor('um', geometry(3).unit); - warning('NaN detected, trying once more with slightly different vertex positions'); + ft_warning('NaN detected, trying once more with slightly different vertex positions'); headmodel = ft_headmodel_bemcp(geometry, 'conductivity', cfg.conductivity); end elseif strcmp(cfg.method, 'dipoli') @@ -285,7 +281,7 @@ else headmodel = ft_headmodel_openmeeg(geometry, 'conductivity', cfg.conductivity, 'isolatedsource', cfg.isolatedsource); end - + case 'concentricspheres' % the low-level functions needs surface points, triangles are not needed if input_mesh || input_pos @@ -305,30 +301,30 @@ elseif ~isempty(cfg.headshape) && ischar(cfg.headshape) geometry = ft_read_headshape(cfg.headshape); else - error('You must give a mesh, segmented MRI, sensor data type, or cfg.headshape'); + ft_error('You must give a mesh, segmented MRI, sensor data type, or cfg.headshape'); end - + headmodel = ft_headmodel_concentricspheres(geometry, 'conductivity', cfg.conductivity, 'fitind', cfg.fitind); - + case 'halfspace' if input_mesh || input_pos geometry = data; else - error('a surface mesh is required as input for the halfspace method'); + ft_error('a surface mesh is required as input for the halfspace method'); end if isempty(cfg.point) - error('cfg.point is required for halfspace method'); + ft_error('cfg.point is required for halfspace method'); end - + headmodel = ft_headmodel_halfspace(geometry, cfg.point, 'conductivity', cfg.conductivity, 'sourcemodel', cfg.submethod); - + case 'infinite' % this takes no input arguments headmodel = ft_headmodel_infinite(); - + case {'localspheres' 'singlesphere' 'singleshell'} cfg.grad = ft_getopt(cfg, 'grad'); % used for localspheres - + % these three methods all require a set of surface points if input_mesh || input_pos geometry = data; @@ -355,7 +351,7 @@ end end if isempty(geometry) - error('please specificy cfg.tissue and pass an appropriate segmented MRI as input data') + ft_error('please specificy cfg.tissue and pass an appropriate segmented MRI as input data') end end elseif input_elec @@ -370,9 +366,9 @@ elseif ~isempty(cfg.headmodel) % the CTF *.hdm file will be read further down else - error('this requires a mesh, set of surface points or a segmented mri'); + ft_error('this requires a mesh, set of surface points or a segmented mri'); end - + switch cfg.method case 'singlesphere' if ~isempty(cfg.headmodel) @@ -385,7 +381,7 @@ headmodel.o = [tmp.orig.MEG_Sphere.ORIGIN_X tmp.orig.MEG_Sphere.ORIGIN_Y tmp.orig.MEG_Sphere.ORIGIN_Z]; headmodel.unit = 'cm'; catch - error('the volume conduction model in "%s" is invalid', cfg.headmodel); + ft_error('the volume conduction model in "%s" is invalid', cfg.headmodel); end else % construct the volume conduction model @@ -402,13 +398,13 @@ headmodel.o = tmp.o; headmodel.unit = 'cm'; catch - error('the volume conduction model in "%s" is invalid', cfg.headmodel); + ft_error('the volume conduction model in "%s" is invalid', cfg.headmodel); end else % construct the volume conduction model cfg.grad = ft_getopt(cfg, 'grad'); if isempty(cfg.grad) - error('for cfg.method = %s, you need to supply a cfg.grad structure', cfg.method); + ft_error('for cfg.method = %s, you need to supply a cfg.grad structure', cfg.method); end headmodel = ft_headmodel_localspheres(geometry, cfg.grad, 'feedback', cfg.feedback, 'radius', cfg.radius, 'maxradius', cfg.maxradius, 'baseline', cfg.baseline, 'singlesphere', cfg.singlesphere); end % headmodel @@ -420,31 +416,31 @@ end headmodel = ft_headmodel_singleshell(geometry); end - + case {'simbio'} if input_elec || isfield(data, 'pos') || input_mesh geometry = data; % more serious checks of validity of the mesh occur inside ft_headmodel_simbio else - error('You must provide a mesh with tetrahedral or hexahedral elements, where each element has a scalar or tensor conductivity'); + ft_error('You must provide a mesh with tetrahedral or hexahedral elements, where each element has a scalar or tensor conductivity'); end headmodel = ft_headmodel_simbio(geometry, 'conductivity', cfg.conductivity); - + case {'fns'} if input_seg data = ft_datatype_segmentation(data, 'segmentationstyle', 'indexed'); else - error('segmented MRI must be given as data input') + ft_error('segmented MRI must be given as data input') end sens = ft_fetch_sens(cfg, data); headmodel = ft_headmodel_fns(data.seg, 'tissue', cfg.tissue, 'tissueval', cfg.tissueval, 'tissuecond', cfg.conductivity, 'sens', sens, 'transform', cfg.transform); - + otherwise - error('unsupported method "%s"', cfg.method); + ft_error('unsupported method "%s"', cfg.method); end % switch method % ensure that the geometrical units are specified -if ~ft_voltype(headmodel, 'infinite'), - headmodel = ft_convert_units(headmodel); +if ~ft_voltype(headmodel, 'infinite') + headmodel = ft_determine_units(headmodel); end % do the general cleanup and bookkeeping at the end of the function diff --git a/external/fieldtrip/ft_prepare_layout.m b/external/fieldtrip/ft_prepare_layout.m index 849e3f13..6b9c1ddb 100644 --- a/external/fieldtrip/ft_prepare_layout.m +++ b/external/fieldtrip/ft_prepare_layout.m @@ -1,60 +1,82 @@ function [layout, cfg] = ft_prepare_layout(cfg, data) -% FT_PREPARE_LAYOUT loads or creates a 2-D layout of the channel locations. -% This layout is required for plotting the topographical distribution of -% the potential or field distribution, or for plotting timecourses in a -% topographical arrangement. +% FT_PREPARE_LAYOUT loads or creates a 2-D layout of the channel locations. This +% layout is required for plotting the topographical distribution of the potential or +% field distribution, or for plotting timecourses in a topographical arrangement. % % Use as % layout = ft_prepare_layout(cfg, data) % -% There are several ways in which a 2-D layout can be made: it can be read -% directly from a *.mat file containing a variable 'lay', it can be created -% based on 3-D electrode or gradiometer positions in the configuration or -% in the data, or it can be created based on the specification of an -% electrode or gradiometer file. Layouts can also come from an ASCII *.lay -% file, but this type of layout is no longer recommended. +% There are several ways in which a 2-D layout can be made: 1) it can be read +% directly from a layout file, 2) it can be created on basis of an image or photo, 3) +% it can be created based on 3-D sensor positions in the configuration, in the data, +% or in an electrode or gradiometer file. +% +% Layout files are MATLAB files with a single variable representing the layout (see +% below). The layout file can also be an ASCII *.lay file, but this type of layout is +% no longer recommended, since the outline of the head and the mask within which the +% interpolation is done is less refined for an ASCII layout. A large number of +% template layout files is provided in the fieldtrip/template/layout directory. See +% also http://fieldtriptoolbox.org/template/layout % % You can specify any one of the following configuration options -% cfg.layout filename containg the layout (.mat or .lay file) -% can also be a layout structure, which is simply -% returned as-is (see below for details) -% cfg.rotate number, rotation around the z-axis in degrees (default = [], which means automatic) -% cfg.projection string, 2D projection method can be 'stereographic', 'orthographic', -% 'polar', 'gnomic' or 'inverse' (default = 'polar') -% cfg.elec structure with electrode definition, or -% cfg.elecfile filename containing electrode definition -% cfg.grad structure with gradiometer definition, or -% cfg.gradfile filename containing gradiometer definition -% cfg.opto structure with optode structure definition, or -% cfg.optofile filename containing optode structure definition -% cfg.output filename (ending in .mat or .lay) to which the layout -% will be written (default = []) -% cfg.montage 'no' or a montage structure (default = 'no') -% cfg.image filename, use an image to construct a layout (e.g. useful for ECoG grids) -% cfg.bw if an image is used and bw = 1 transforms the image in -% black and white (default = 0, do not transform) -% cfg.overlap string, how to deal with overlapping channels when -% layout is constructed from a sensor configuration -% structure (can be 'shift' (shift the positions in 2D -% space to remove the overlap (default)), 'keep' (don't -% shift, retain the overlap), 'no' (throw error when -% overlap is present)) -% cfg.skipscale 'yes' or 'no', whether the scale should be included in the layout or not (default = 'no') -% cfg.skipcomnt 'yes' or 'no', whether the comment should be included in the layout or not (default = 'no') +% cfg.layout = filename containg the input layout (*.mat or *.lay file), this can also be a layout +% structure, which is simply returned as-is (see below for details) +% cfg.output = filename (ending in .mat or .lay) to which the layout will be written (default = []) +% cfg.elec = structure with electrode definition, or +% cfg.elecfile = filename containing electrode definition +% cfg.grad = structure with gradiometer definition, or +% cfg.gradfile = filename containing gradiometer definition +% cfg.opto = structure with optode structure definition, or +% cfg.optofile = filename containing optode structure definition +% cfg.rotate = number, rotation around the z-axis in degrees (default = [], which means automatic) +% cfg.projection = string, 2D projection method can be 'stereographic', 'orthographic', 'polar' or 'gnomic' (default = 'polar') +% When 'orthographic', cfg.viewpoint can be used to indicate to specificy projection (keep empty for legacy projection) +% cfg.viewpoint = string indicating the view point that is used for orthographic projection of 3-D sensor +% positions to the 2-D plane. The possible viewpoints are +% 'left' - left sagittal view, L=anterior, R=posterior, top=top, bottom=bottom +% 'right' - right sagittal view, L=posterior, R=anterior, top=top, bottom=bottom +% 'inferior' - inferior axial view, L=R, R=L, top=anterior, bottom=posterior +% 'superior' - superior axial view, L=L, R=R, top=anterior, bottom=posterior +% 'anterior' - anterior coronal view, L=R, R=L, top=top, bottom=bottom +% 'posterior' - posterior coronal view, L=L, R=R, top=top, bottom=bottom +% 'auto' - automatic guess of the most optimal of the above +% tip: use cfg.viewpoint = 'auto' per iEEG electrode grid/strip/depth for more accurate results +% tip: to obtain an overview of all iEEG electrodes, choose superior/inferior, use cfg.headshape/mri, and plot using FT_LAYOUTPLOT with cfg.box/mask = 'no' +% cfg.outline = string, how to create the outline, can be 'circle', 'convex', 'headshape', 'mri' or 'no' (default is automatic) +% cfg.mask = string, how to create the mask, can be 'circle', 'convex', 'headshape', 'mri' or 'no' (default is automatic) +% cfg.headshape = surface mesh (e.g. pial, head, etc) to be used for generating an outline, see FT_READ_HEADSHAPE for details +% cfg.mri = segmented anatomical MRI to be used for generating an outline, see FT_READ_MRI and FT_VOLUMESEGMENT for details +% cfg.montage = 'no' or a montage structure (default = 'no') +% cfg.image = filename, use an image to construct a layout (e.g. useful for ECoG grids) +% cfg.bw = 'yes' or 'no', if an image is used and this option is true, the image is transformed in black and white (default = 'no', i.e. do not transform) +% cfg.overlap = string, how to deal with overlapping channels when the layout is constructed from a sensor configuration structure. This can be +% 'shift' - shift the positions in 2D space to remove the overlap (default) +% 'keep' - do not shift, retain the overlap +% 'no' - throw an error when overlap is present +% cfg.channel = 'all', or Nx1 cell-array with selection of channels, see FT_CHANNELSELECTION for details +% cfg.boxchannel = 'all', or Nx1 cell-array with selection of channels, see FT_CHANNELSELECTION for details +% specificies channels to use for determining channel box size (default = 'all', recommended for MEG/EEG, a selection is recommended for iEEG) +% cfg.skipscale = 'yes' or 'no', whether the scale should be included in the layout or not (default = 'no') +% cfg.skipcomnt = 'yes' or 'no', whether the comment should be included in the layout or not (default = 'no') +% +% If you use cfg.headshape or cfg.mri to create a headshape outline, the input +% geometry should be expressed in the same units and coordinate system as the input +% sensors. % -% Alternatively the layout can be constructed from either -% data.elec structure with electrode positions -% data.grad structure with gradiometer definition -% data.opto structure with optode structure definition +% Alternatively the layout can be constructed from either one of these in the input data structure: +% data.elec = structure with electrode positions +% data.grad = structure with gradiometer definition +% data.opto = structure with optode structure definition % -% Alternatively you can specify the following layouts which will be -% generated for all channels present in the data. Note that these layouts -% are suitable for multiplotting, but not for topoplotting. -% cfg.layout = 'ordered' will give you a NxN ordered layout -% cfg.layout = 'vertical' will give you a Nx1 ordered layout -% cfg.layout = 'butterfly' will give you a layout with all channels on top of each other -% cfg.layout = 'circular' will distribute the channels on a circle +% Alternatively you can specify the following systematic layouts which will be +% generated for all channels present in the data. Note that these layouts are only +% suitable for multiplotting, not for topoplotting. +% cfg.layout = 'ordered' will give you a NxN ordered layout +% cfg.layout = 'vertical' will give you a Nx1 ordered layout +% cfg.layout = 'horizontal' will give you a 1xN ordered layout +% cfg.layout = 'butterfly' will give you a layout with all channels on top of each other +% cfg.layout = 'circular' will distribute the channels on a circle % % The output layout structure will contain the following fields % layout.label = Nx1 cell-array with channel labels @@ -62,8 +84,7 @@ % layout.width = Nx1 vector with the width of each box for multiplotting % layout.height = Nx1 matrix with the height of each box for multiplotting % layout.mask = optional cell-array with line segments that determine the area for topographic interpolation -% layout.outline = optional cell-array with line segments that represent -% the head, nose, ears, sulci or other anatomical features +% layout.outline = optional cell-array with line segments that represent the head, nose, ears, sulci or other anatomical features % % See also FT_TOPOPLOTER, FT_TOPOPLOTTFR, FT_MULTIPLOTER, FT_MULTIPLOTTFR, FT_PLOT_LAY @@ -107,46 +128,109 @@ end % the data can be passed as input argument or can be read from disk -hasdata = exist('data', 'var'); +hasdata = exist('data', 'var') && ~isempty(data); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % basic check/initialization of input arguments %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% if ~hasdata data = struct([]); +else + data = ft_checkdata(data); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % set default configuration options %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -cfg.rotate = ft_getopt(cfg, 'rotate', []); % [] => rotation is determined based on the type of sensors -cfg.style = ft_getopt(cfg, 'style', '2d'); -cfg.projection = ft_getopt(cfg, 'projection', 'polar'); -cfg.layout = ft_getopt(cfg, 'layout', []); -cfg.grad = ft_getopt(cfg, 'grad', []); -cfg.elec = ft_getopt(cfg, 'elec', []); -cfg.opto = ft_getopt(cfg, 'opto', []); -cfg.gradfile = ft_getopt(cfg, 'gradfile', []); -cfg.elecfile = ft_getopt(cfg, 'elecfile', []); -cfg.optofile = ft_getopt(cfg, 'optofile', []); -cfg.output = ft_getopt(cfg, 'output', []); -cfg.feedback = ft_getopt(cfg, 'feedback', 'no'); -cfg.montage = ft_getopt(cfg, 'montage', 'no'); -cfg.image = ft_getopt(cfg, 'image', []); -cfg.mesh = ft_getopt(cfg, 'mesh', []); % experimental, should only work with meshes defined in 2D -cfg.bw = ft_getopt(cfg, 'bw', 0); -cfg.channel = ft_getopt(cfg, 'channel', 'all'); -cfg.skipscale = ft_getopt(cfg, 'skipscale', 'no'); -cfg.skipcomnt = ft_getopt(cfg, 'skipcomnt', 'no'); -cfg.overlap = ft_getopt(cfg, 'overlap', 'shift'); +cfg.rotate = ft_getopt(cfg, 'rotate', []); % [] => rotation is determined based on the type of sensors +cfg.style = ft_getopt(cfg, 'style', '2d'); +cfg.projection = ft_getopt(cfg, 'projection', 'polar'); +cfg.layout = ft_getopt(cfg, 'layout', []); +cfg.grad = ft_getopt(cfg, 'grad', []); +cfg.elec = ft_getopt(cfg, 'elec', []); +cfg.opto = ft_getopt(cfg, 'opto', []); +cfg.gradfile = ft_getopt(cfg, 'gradfile', []); +cfg.elecfile = ft_getopt(cfg, 'elecfile', []); +cfg.optofile = ft_getopt(cfg, 'optofile', []); +cfg.output = ft_getopt(cfg, 'output', []); +cfg.feedback = ft_getopt(cfg, 'feedback', 'no'); +cfg.montage = ft_getopt(cfg, 'montage', 'no'); +cfg.image = ft_getopt(cfg, 'image', []); +cfg.mesh = ft_getopt(cfg, 'mesh', []); % experimental, should only work with meshes defined in 2D +cfg.bw = ft_getopt(cfg, 'bw', 'no'); +cfg.channel = ft_getopt(cfg, 'channel', 'all'); +cfg.skipscale = ft_getopt(cfg, 'skipscale', []); % see below +cfg.skipcomnt = ft_getopt(cfg, 'skipcomnt', []); % see below +cfg.boxchannel = ft_getopt(cfg, 'boxchannel', 'all'); +cfg.overlap = ft_getopt(cfg, 'overlap', 'shift'); +cfg.viewpoint = ft_getopt(cfg, 'viewpoint', []); +cfg.headshape = ft_getopt(cfg, 'headshape', []); % separate form cfg.mesh +cfg.mri = ft_getopt(cfg, 'mri', []); +cfg.outline = ft_getopt(cfg, 'outline', []); % default is handled below +cfg.mask = ft_getopt(cfg, 'mask', []); % default is handled below + +if isempty(cfg.skipscale) && ischar(cfg.layout) && any(strcmp(cfg.layout, {'ordered', 'vertical', 'horizontal', 'butterfly', 'circular', '1column', '2column', '3column', '4column', '5column', '6column', '7column', '8column', '9column', '1row', '2row', '3row', '4row', '5row', '6row', '7row', '8row', '9row'})) + cfg.skipscale = 'yes'; +else + cfg.skipscale = 'no'; +end + +if isempty(cfg.skipcomnt) && ischar(cfg.layout) && any(strcmp(cfg.layout, {'ordered', 'vertical', 'horizontal', 'butterfly', 'circular', '1column', '2column', '3column', '4column', '5column', '6column', '7column', '8column', '9column', '1row', '2row', '3row', '4row', '5row', '6row', '7row', '8row', '9row'})) + cfg.skipcomnt = 'yes'; +else + cfg.skipcomnt = 'no'; +end + +if isempty(cfg.outline) + if ~isempty(cfg.headshape) + cfg.outline = 'headshape'; + elseif ~isempty(cfg.mri) + cfg.outline = 'mri'; + elseif ~strcmp(cfg.projection, 'orthographic') + cfg.outline = 'circle'; + else + cfg.outline = 'no'; + end +end + +if isempty(cfg.mask) + if ~isempty(cfg.headshape) + cfg.mask = 'headshape'; + elseif ~isempty(cfg.mri) + cfg.mask = 'mri'; + elseif ~strcmp(cfg.projection, 'orthographic') + cfg.mask = 'circle'; + else + cfg.mask = 'convex'; + end +end + +% headshape/mri are mutually exclusive +if ~isempty(cfg.headshape) && ~isempty(cfg.mri) + ft_error('cfg.headshape and cfg.mri are mutually exclusive, please use only one of the two') +end +% cfg.viewpoint can only be used together with cfg.projection = 'orthographic' +if ~isempty(cfg.viewpoint) && ~isequal(cfg.projection, 'orthographic') + ft_error('cfg.viewpoint can only used in the case of orthographic projection') +end +if ~isempty(cfg.viewpoint) && ~isempty(cfg.rotate) + ft_error('cfg.viewpoint and cfg.rotate are mutually exclusive, please use only one of the two') +end + +% update the selection of channels according to the data +if hasdata && isfield(data, 'label') + cfg.channel = ft_channelselection(cfg.channel, data.label); +elseif hasdata && isfield(data, 'labelcmb') + cfg.channel = ft_channelselection(cfg.channel, unique(data.labelcmb(:))); +end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % try to generate the layout structure %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -skipscale = strcmp(cfg.skipscale, 'yes'); % in general a scale is desired -skipcomnt = strcmp(cfg.skipcomnt, 'yes'); % in general a comment desired +skipscale = istrue(cfg.skipscale); % in general a scale is desired +skipcomnt = istrue(cfg.skipcomnt); % in general a comment desired if isa(cfg.layout, 'config') % convert the nested config-object back into a normal structure @@ -154,7 +238,7 @@ end % ensure that there is a label field in the data, which is needed for -% ordered/vertical/butterfly modes +% ordered/vertical//horizontal/butterfly modes if hasdata && ~isfield(data, 'label') && isfield(data, 'labelcmb') data.label = unique(data.labelcmb(:)); end @@ -164,7 +248,7 @@ % a layout structure) if isstruct(cfg.layout) && isfield(cfg.layout, 'pos') && isfield(cfg.layout, 'label') && isfield(cfg.layout, 'width') && isfield(cfg.layout, 'height') layout = cfg.layout; - + elseif isstruct(cfg.layout) && isfield(cfg.layout, 'pos') && isfield(cfg.layout, 'label') && (~isfield(cfg.layout, 'width') || ~isfield(cfg.layout, 'height')) layout = cfg.layout; % add width and height for multiplotting @@ -176,10 +260,10 @@ mindist = min(d(:)); layout.width = ones(nchans,1) * mindist * 0.8; layout.height = ones(nchans,1) * mindist * 0.6; - + elseif isequal(cfg.layout, 'circular') rho = ft_getopt(cfg, 'rho', []); - + if hasdata && ~isempty(data) % look at the data to determine the overlapping channels cfg.channel = ft_channelselection(cfg.channel, data.label); @@ -191,30 +275,28 @@ nchan = length(cfg.channel); layout.label = cfg.channel; end - + if isempty(rho) % do an equally spaced layout, starting at 12 o'clock, going clockwise rho = linspace(0,1,nchan+1); rho = 2.*pi.*rho(1:end-1); else if numel(rho) ~= nchan - error('the number of elements in the polar angle vector should be equal to the number of channels'); + ft_error('the number of elements in the polar angle vector should be equal to the number of channels'); end - + % convert to radians rho = 2.*pi.*rho./360; end x = sin(rho); y = cos(rho); - + layout.pos = [x(:) y(:)]; layout.width = ones(nchan,1) * 0.01; layout.height = ones(nchan,1) * 0.01; layout.mask = {}; layout.outline = {}; - skipscale = true; % a scale is not desired - skipcomnt = true; % a comment is initially not desired, or at least requires more thought - + elseif isequal(cfg.layout, 'butterfly') if hasdata && ~isempty(data) % look at the data to determine the overlapping channels @@ -232,13 +314,10 @@ layout.height = ones(nchan,1) * 1.0; layout.mask = {}; layout.outline = {}; - skipscale = true; % a scale is not desired - skipcomnt = true; % a comment is initially not desired, or at least requires more thought - -elseif isequal(cfg.layout, 'vertical') + +elseif isequal(cfg.layout, 'vertical') || isequal(cfg.layout,'horizontal') if hasdata && ~isempty(data) % look at the data to determine the overlapping channels - data = ft_checkdata(data); originalorder = cfg.channel; cfg.channel = ft_channelselection(cfg.channel, data.label); if iscell(originalorder) && length(originalorder)==length(cfg.channel) @@ -256,11 +335,20 @@ layout.label = cfg.channel; end for i=1:(nchan+2) - x = 0.5; - y = 1-i/(nchan+1+2); - layout.pos (i,:) = [x y]; - layout.width (i,1) = 0.9; - layout.height(i,1) = 0.9 * 1/(nchan+1+2); + switch cfg.layout + case 'vertical' + x = 0.5; + y = 1-i/(nchan+1+2); + layout.pos (i,:) = [x y]; + layout.width (i,1) = 0.9; + layout.height(i,1) = 0.9 * 1/(nchan+1+2); + case 'horizontal' + x = i/(nchan+1+2); + y = 0.5; + layout.pos (i,:) = [x y]; + layout.width (i,1) = 0.9 * 1/(nchan+1+2); + layout.height(i,1) = 0.9; + end if i==(nchan+1) layout.label{i} = 'SCALE'; elseif i==(nchan+2) @@ -269,13 +357,12 @@ end layout.mask = {}; layout.outline = {}; - + elseif any(strcmp(cfg.layout, {'1column', '2column', '3column', '4column', '5column', '6column', '7column', '8column', '9column'})) % it can be 2column, 3column, etcetera % note that this code (in combination with the code further down) fails for 1column if hasdata && ~isempty(data) % look at the data to determine the overlapping channels - data = ft_checkdata(data); originalorder = cfg.channel; cfg.channel = ft_channelselection(cfg.channel, data.label); if iscell(originalorder) && length(originalorder)==length(cfg.channel) @@ -292,10 +379,10 @@ nchan = length(cfg.channel); layout.label = cfg.channel; end - + ncol = find(strcmp(cfg.layout, {'1column', '2column', '3column', '4column', '5column', '6column', '7column', '8column', '9column'})); nrow = ceil(nchan/ncol); - + k = 0; for i=1:ncol for j=1:nrow @@ -310,20 +397,60 @@ layout.height(k,1) = 0.9 * 1/(nrow+1); end end - + layout.mask = {}; layout.outline = {}; - skipscale = true; % a scale is not desired - skipcomnt = true; % a comment is initially not desired, or at least requires more thought - -elseif isequal(cfg.layout, 'ordered') + +elseif any(strcmp(cfg.layout, {'1row', '2row', '3row', '4row', '5row', '6row', '7row', '8row', '9row'})) + % it can be 2row, 3row, etcetera + % note that this code (in combination with the code further down) fails for 1row if hasdata && ~isempty(data) % look at the data to determine the overlapping channels - data = ft_checkdata(data); + originalorder = cfg.channel; cfg.channel = ft_channelselection(cfg.channel, data.label); - chanindx = match_str(data.label, cfg.channel); - nchan = length(data.label(chanindx)); - layout.label = data.label(chanindx); + if iscell(originalorder) && length(originalorder)==length(cfg.channel) + % try to keep the order identical to that specified in the configuration + [sel1, sel2] = match_str(originalorder, cfg.channel); + % re-order them according to the cfg specified by the user + cfg.channel = cfg.channel(sel2); + end + assert(iscell(cfg.channel), 'cfg.channel should be a valid set of channels'); + nchan = length(cfg.channel); + layout.label = cfg.channel; + else + assert(iscell(cfg.channel), 'cfg.channel should be a valid set of channels'); + nchan = length(cfg.channel); + layout.label = cfg.channel; + end + + nrow = find(strcmp(cfg.layout, {'1row', '2row', '3row', '4row', '5row', '6row', '7row', '8row', '9row'})); + ncol = ceil(nchan/nrow); + + k = 0; + for i=1:nrow + for j=1:ncol + k = k+1; + if k>nchan + continue + end + x = j/(ncol+1); + y = 1/(nrow*2) - i/nrow; + layout.pos (k,:) = [x y]; + layout.width (k,1) = 0.85/ncol; + layout.height(k,1) = 0.9 * 1/(nrow+1); + end + end + + layout.mask = {}; + layout.outline = {}; + +elseif isequal(cfg.layout, 'ordered') + if hasdata + % look at the data to determine the overlapping channels + cfg.channel = ft_channelselection(cfg.channel, data.label); + chanindx = match_str(data.label, cfg.channel); + nchan = length(data.label(chanindx)); + layout.label = data.label(chanindx); else assert(iscell(cfg.channel), 'cfg.channel should be a valid set of channels'); nchan = length(cfg.channel); @@ -344,27 +471,32 @@ end end end - + layout.label{end+1} = 'SCALE'; layout.width(end+1) = 0.8 * 1/ncol; layout.height(end+1) = 0.8 * 1/nrow; x = (ncol-2)/ncol; y = 0/nrow; layout.pos(end+1,:) = [x y]; - + layout.label{end+1} = 'COMNT'; layout.width(end+1) = 0.8 * 1/ncol; layout.height(end+1) = 0.8 * 1/nrow; x = (ncol-1)/ncol; y = 0/nrow; layout.pos(end+1,:) = [x y]; + + layout.mask = {}; + layout.outline = {}; + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % try to generate layout from other configuration options + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% elseif ischar(cfg.layout) - + % layout file name specified if isempty(strfind(cfg.layout, '.')) - + cfg.layout = [cfg.layout '.mat']; if exist(cfg.layout, 'file') fprintf('layout file without .mat (or .lay) extension specified, appending .mat\n'); @@ -375,12 +507,12 @@ layout = ft_prepare_layout(cfg); return; end - + elseif ft_filetype(cfg.layout, 'matlab') - + fprintf('reading layout from file %s\n', cfg.layout); if ~exist(cfg.layout, 'file') - error('the specified layout file %s was not found', cfg.layout); + ft_error('the specified layout file %s was not found', cfg.layout); end tmp = load(cfg.layout, 'lay*'); if isfield(tmp, 'layout') @@ -388,106 +520,103 @@ elseif isfield(tmp, 'lay') layout = tmp.lay; else - error('mat file does not contain a layout'); + ft_error('mat file does not contain a layout'); end - + elseif ft_filetype(cfg.layout, 'layout') - + if exist(cfg.layout, 'file') fprintf('reading layout from file %s\n', cfg.layout); layout = readlay(cfg.layout); else - ft_warning(sprintf('layout file %s was not found on your path, attempting to use a similarly named .mat file instead',cfg.layout)); - cfg.layout = [cfg.layout(1:end-3) 'mat']; + [p, f, x] = fileparts(cfg.layout); + ft_warning('the file "%s" was not found on your path, attempting "%s" instead', cfg.layout, fullfile(p, [f '.mat'])); + cfg.layout = fullfile(p, [f '.mat']); layout = ft_prepare_layout(cfg); return; end - + elseif ~ft_filetype(cfg.layout, 'layout') % assume that cfg.layout is an electrode file - fprintf('creating layout from electrode file %s\n', cfg.layout); - layout = sens2lay(ft_read_sens(cfg.layout), cfg.rotate, cfg.projection, cfg.style, cfg.overlap); + fprintf('creating layout from sensor description file %s\n', cfg.layout); + sens = ft_read_sens(cfg.layout); + layout = sens2lay(sens, cfg.rotate, cfg.projection, cfg.style, cfg.overlap, cfg.viewpoint, cfg.boxchannel); end - -elseif ischar(cfg.elecfile) - fprintf('creating layout from electrode file %s\n', cfg.elecfile); - layout = sens2lay(ft_read_sens(cfg.elecfile), cfg.rotate, cfg.projection, cfg.style, cfg.overlap); - -elseif ~isempty(cfg.elec) && isstruct(cfg.elec) - fprintf('creating layout from cfg.elec\n'); - layout = sens2lay(cfg.elec, cfg.rotate, cfg.projection, cfg.style, cfg.overlap); - -elseif isfield(data, 'elec') && isstruct(data.elec) - fprintf('creating layout from data.elec\n'); - data = ft_checkdata(data); - layout = sens2lay(data.elec, cfg.rotate, cfg.projection, cfg.style, cfg.overlap); - + elseif ischar(cfg.gradfile) fprintf('creating layout from gradiometer file %s\n', cfg.gradfile); - layout = sens2lay(ft_read_sens(cfg.gradfile), cfg.rotate, cfg.projection, cfg.style, cfg.overlap); - + sens = ft_read_sens(cfg.gradfile, 'senstype', 'meg'); + layout = sens2lay(sens, cfg.rotate, cfg.projection, cfg.style, cfg.overlap, cfg.viewpoint, cfg.boxchannel); + elseif ~isempty(cfg.grad) && isstruct(cfg.grad) fprintf('creating layout from cfg.grad\n'); - layout = sens2lay(cfg.grad, cfg.rotate, cfg.projection, cfg.style, cfg.overlap); - + sens = ft_datatype_sens(cfg.grad); + layout = sens2lay(sens, cfg.rotate, cfg.projection, cfg.style, cfg.overlap, cfg.viewpoint, cfg.boxchannel); + elseif isfield(data, 'grad') && isstruct(data.grad) fprintf('creating layout from data.grad\n'); - data = ft_checkdata(data); - layout = sens2lay(data.grad, cfg.rotate, cfg.projection, cfg.style, cfg.overlap); + sens = ft_datatype_sens(data.grad); + layout = sens2lay(sens, cfg.rotate, cfg.projection, cfg.style, cfg.overlap, cfg.viewpoint, cfg.boxchannel); + +elseif ischar(cfg.elecfile) + fprintf('creating layout from electrode file %s\n', cfg.elecfile); + sens = ft_read_sens(cfg.elecfile, 'senstype', 'eeg'); + layout = sens2lay(sens, cfg.rotate, cfg.projection, cfg.style, cfg.overlap, cfg.viewpoint, cfg.boxchannel); + +elseif ~isempty(cfg.elec) && isstruct(cfg.elec) + fprintf('creating layout from cfg.elec\n'); + sens = ft_datatype_sens(cfg.elec); + layout = sens2lay(sens, cfg.rotate, cfg.projection, cfg.style, cfg.overlap, cfg.viewpoint, cfg.boxchannel); + +elseif isfield(data, 'elec') && isstruct(data.elec) + fprintf('creating layout from data.elec\n'); + sens = ft_datatype_sens(data.elec); + layout = sens2lay(sens, cfg.rotate, cfg.projection, cfg.style, cfg.overlap, cfg.viewpoint, cfg.boxchannel); elseif ischar(cfg.optofile) fprintf('creating layout from optode file %s\n', cfg.optofile); - opto = ft_read_sens(cfg.optofile); + sens = ft_read_sens(cfg.optofile, 'senstype', 'nirs'); if (hasdata) - layout = opto2lay(opto, data.label); + layout = opto2lay(sens, data.label); else - layout = opto2lay(opto, opto.label); + layout = opto2lay(sens, sens.label); end - elseif ~isempty(cfg.opto) && isstruct(cfg.opto) fprintf('creating layout from cfg.opto\n'); - opto = cfg.opto; + sens = cfg.opto; if (hasdata) - layout = opto2lay(opto, data.label); + layout = opto2lay(sens, data.label); else - layout = opto2lay(opto, opto.label); - end; - + layout = opto2lay(sens, sens.label); + end elseif isfield(data, 'opto') && isstruct(data.opto) fprintf('creating layout from data.opto\n'); - opto = data.opto; + sens = data.opto; if (hasdata) - layout = opto2lay(opto, data.label); + layout = opto2lay(sens, data.label); else - layout = opto2lay(opto, opto.label); - end; - + layout = opto2lay(sens, sens.label); + end + elseif (~isempty(cfg.image) || ~isempty(cfg.mesh)) && isempty(cfg.layout) % deal with image file if ~isempty(cfg.image) - + fprintf('reading background image from %s\n', cfg.image); - [p,f,e] = fileparts(cfg.image); + [p, f, e] = fileparts(cfg.image); switch e case '.mat' - tmp = load(cfg.image); - fnames = fieldnames(tmp); - if numel(fnames)~=1 - error('there is not just a single variable in %s', cfg.image); - else - img = tmp.(fname{1}); - end + img = loadvar(cfg.image); otherwise img = imread(cfg.image); end img = flipdim(img, 1); % in combination with "axis xy" - + figure - bw = cfg.bw; - - if bw + + if istrue(cfg.bw) % convert to greyscale image img = mean(img, 3); imagesc(img); @@ -496,20 +625,20 @@ % plot as RGB image image(img); end - + elseif ~isempty(cfg.mesh) if isfield(cfg.mesh, 'sulc') - ft_plot_mesh(cfg.mesh, 'edgecolor','none','vertexcolor',cfg.mesh.sulc);colormap gray; + ft_plot_mesh(cfg.mesh, 'edgecolor', 'none', 'vertexcolor', cfg.mesh.sulc); colormap gray; else - ft_plot_mesh(cfg.mesh, 'edgecolor','none'); + ft_plot_mesh(cfg.mesh, 'edgecolor', 'none'); end end hold on axis equal axis off axis xy - - + + % get the electrode positions pos = zeros(0,2); electrodehelp = [ ... @@ -529,14 +658,14 @@ % this happens if the figure is closed return; end - + switch k case 1 pos = cat(1, pos, [x y]); % add it to the figure plot(x, y, 'b.'); plot(x, y, 'yo'); - + case 8 if size(pos,1)>0 % remove the last point @@ -546,7 +675,7 @@ if ~isempty(cfg.image) h = image(img); else - h = ft_plot_mesh(cfg.mesh,'edgecolor','none','vertexcolor',cfg.mesh.sulc); + h = ft_plot_mesh(cfg.mesh, 'edgecolor', 'none', 'vertexcolor', cfg.mesh.sulc); end hold on axis equal @@ -554,16 +683,16 @@ plot(pos(:,1), pos(:,2), 'b.'); plot(pos(:,1), pos(:,2), 'yo'); end - + case 'q' again = 0; - + otherwise - warning('invalid button (%d)', k); + ft_warning('invalid button (%d)', k); end end - - % get the mask outline + + % get the interpolation mask polygon = {}; thispolygon = 1; polygon{thispolygon} = zeros(0,2); @@ -575,21 +704,21 @@ 'press "c" on the keyboard to close this polygon and start with another\n' ... 'press "q" on the keyboard to continue\n' ... ]; - again = 1; + again = true; while again fprintf(maskhelp); fprintf('\n'); for i=1:length(polygon) fprintf('polygon %d has %d points\n', i, size(polygon{i},1)); end - + try [x, y, k] = ginput(1); catch % this happens if the figure is closed return; end - + switch k case 1 polygon{thispolygon} = cat(1, polygon{thispolygon}, [x y]); @@ -599,7 +728,7 @@ y = polygon{i}([end-1 end],2); end plot(x, y, 'g.-'); - + case 8 % backspace if size(polygon{thispolygon},1)>0 % remove the last point @@ -609,7 +738,7 @@ if ~isempty(cfg.image) h = image(img); else - h = ft_plot_mesh(cfg.mesh,'edgecolor','none','vertexcolor',cfg.mesh.sulc); + h = ft_plot_mesh(cfg.mesh, 'edgecolor', 'none', 'vertexcolor', cfg.mesh.sulc); end hold on axis equal @@ -628,7 +757,7 @@ plot(x, y, 'g.-'); end end - + case 'c' if size(polygon{thispolygon},1)>0 % close the polygon @@ -641,7 +770,7 @@ thispolygon = thispolygon + 1; polygon{thispolygon} = zeros(0,2); end - + case 'q' if size(polygon{thispolygon},1)>0 % close the polygon @@ -652,20 +781,19 @@ plot(x, y, 'g.-'); end again = 0; - + otherwise - warning('invalid button (%d)', k); + ft_warning('invalid button (%d)', k); end - end + end % while again % remember this set of polygons as the mask mask = polygon; - - - % get the outline, e.g. head shape and sulci + + % get the outline, e.g. head shape, nose, ears, sulci, etc. polygon = {}; thispolygon = 1; polygon{thispolygon} = zeros(0,2); - maskhelp = [ ... + outlinehelp = [ ... '-----------------------------------------------------------------------------------\n' ... 'specify polygons for adding outlines (e.g. head shape and sulci) to the layout\n' ... 'press the right mouse button to add another point to the current polygon\n' ... @@ -674,21 +802,21 @@ 'press "n" on the keyboard to start with another without closing the current polygon\n' ... 'press "q" on the keyboard to continue\n' ... ]; - again = 1; + again = true; while again - fprintf(maskhelp); + fprintf(outlinehelp); fprintf('\n'); for i=1:length(polygon) fprintf('polygon %d has %d points\n', i, size(polygon{i},1)); end - + try [x, y, k] = ginput(1); catch % this happens if the figure is closed return; end - + switch k case 1 polygon{thispolygon} = cat(1, polygon{thispolygon}, [x y]); @@ -698,7 +826,7 @@ y = polygon{i}([end-1 end],2); end plot(x, y, 'm.-'); - + case 8 % backspace if size(polygon{thispolygon},1)>0 % remove the last point @@ -708,7 +836,7 @@ if ~isempty(cfg.image) h = image(img); else - h = ft_plot_mesh(cfg.mesh,'edgecolor','none','vertexcolor',cfg.mesh.sulc); + h = ft_plot_mesh(cfg.mesh, 'edgecolor', 'none', 'vertexcolor', cfg.mesh.sulc); end hold on axis equal @@ -727,7 +855,7 @@ plot(x, y, 'm.-'); end end - + case 'c' if size(polygon{thispolygon},1)>0 x = polygon{thispolygon}(1,1); @@ -741,31 +869,31 @@ thispolygon = thispolygon + 1; polygon{thispolygon} = zeros(0,2); end - + case 'n' if size(polygon{thispolygon},1)>0 % switch to the next polygon thispolygon = thispolygon + 1; polygon{thispolygon} = zeros(0,2); end - + case 'q' again = 0; - + otherwise - warning('invalid button (%d)', k); + ft_warning('invalid button (%d)', k); end - end + end % while again % remember this set of polygons as the outline outline = polygon; - - % convert electrode positions into a layout structure + + % convert the sensor positions into a layout structure layout.pos = pos; nchans = size(pos,1); for i=1:nchans - layout.label{i,1} = sprintf('chan%03d', i); + layout.label{i,1} = num2str(i); end - % add width and height for multiplotting + % compute the width and height for multiplotting d = dist(pos'); for i=1:nchans d(i,i) = inf; % exclude the diagonal @@ -773,31 +901,41 @@ mindist = min(d(:)); layout.width = ones(nchans,1) * mindist * 0.8; layout.height = ones(nchans,1) * mindist * 0.6; - % add mask and outline polygons + % add the polygons that describe the mask and outline layout.mask = mask; layout.outline = outline; - + + finalhelp = [ ... + '-----------------------------------------------------------------------------------\n' ... + 'you should update the channel labels, and check the width and height in the output layout\n' ... + ]; + fprintf(finalhelp); + fprintf('\n'); + else - error('no layout detected, please specify cfg.layout') + ft_error('no layout detected, please specify cfg.layout') end -% FIXME there is a conflict between the use of cfg.style here and in topoplot -if ~strcmp(cfg.style, '3d') - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - % check whether outline and mask are available - % if not, add default "circle with triangle" to resemble the head - % in case of "circle with triangle", the electrode positions should also be - % scaled - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - if ~isfield(layout, 'outline') || ~isfield(layout, 'mask') - rmax = 0.5; - l = 0:2*pi/100:2*pi; - HeadX = cos(l).*rmax; - HeadY = sin(l).*rmax; - NoseX = [0.18*rmax 0 -0.18*rmax]; - NoseY = [rmax-.004 rmax*1.15 rmax-.004]; - EarX = [.497 .510 .518 .5299 .5419 .54 .547 .532 .510 .489]; - EarY = [.0555 .0775 .0783 .0746 .0555 -.0055 -.0932 -.1313 -.1384 -.1199]; +% make the subset as specified in cfg.channel +cfg.channel = ft_channelselection(cfg.channel, setdiff(layout.label, {'COMNT', 'SCALE'})); % COMNT and SCALE are not really channels +chansel = match_str(layout.label, cat(1, cfg.channel(:), 'COMNT', 'SCALE')); % include COMNT and SCALE, keep all channels in the order of the layout +% return the layout for the subset of channels +layout.pos = layout.pos(chansel,:); +layout.label = layout.label(chansel); +if strcmpi(cfg.style, '2d') + % width and height only apply to the 2D layout + layout.width = layout.width(chansel); + layout.height = layout.height(chansel); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% check whether the outline and mask are available, create them if needed +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +if (~isfield(layout, 'outline') || ~isfield(layout, 'mask')) && ~strcmpi(cfg.style, '3d') + % the reason to check for style=3d rather than 2d is that cfg.style is also an option in ft_topoplotER and ft_topoplotTFR + % the style option of that function easily "leaks" into here, causing the default 2d not to be selected at the top + + if strcmp(cfg.outline, 'circle') || strcmp(cfg.mask, 'circle') % Scale the electrode positions to fit within a unit circle, i.e. electrode radius = 0.45 ind_scale = strmatch('SCALE', layout.label); ind_comnt = strmatch('COMNT', layout.label); @@ -806,41 +944,65 @@ y = layout.pos(sel,2); xrange = range(x); yrange = range(y); + if xrange==0 + xrange = 1; + end + if yrange==0 + yrange = 1; + end % First scale the width and height of the box for multiplotting layout.width = layout.width./xrange; layout.height = layout.height./yrange; % Then shift and scale the electrode positions layout.pos(:,1) = 0.9*((layout.pos(:,1)-min(x))/xrange-0.5); layout.pos(:,2) = 0.9*((layout.pos(:,2)-min(y))/yrange-0.5); - % Define the outline of the head, ears and nose - layout.outline{1} = [HeadX(:) HeadY(:)]; - layout.outline{2} = [NoseX(:) NoseY(:)]; - layout.outline{3} = [ EarX(:) EarY(:)]; - layout.outline{4} = [-EarX(:) EarY(:)]; - % Define the anatomical mask based on a circular head - layout.mask{1} = [HeadX(:) HeadY(:)]; end -end + + if ~isfield(layout, 'outline') + switch cfg.outline + case 'circle' + layout.outline = outline_circle(); + case 'convex' + layout.outline = outline_convex(layout); + case {'headshape', 'mri'} + % the configuration should contain the headshape or mri + % the (segmented) mri will be converted into a headshape on the fly + hsoutline = outline_headshape(cfg, sens); % used for mask if possible + layout.outline = hsoutline; + otherwise + layout.outline = {}; + end + end + + if ~isfield(layout, 'mask') + switch cfg.mask + case 'circle' + layout.mask = outline_circle(); + layout.mask = layout.mask(1); % the first is the circle, the others are nose and ears + case 'convex' + layout.mask = outline_convex(layout); + case {'headshape', 'mri'} + % the configuration should contain the headshape or mri + % the (segmented) mri will be converted into a headshape on the fly + if isequal(cfg.mask,cfg.outline) && exist('hsoutline','var') + layout.mask = hsoutline; + else + layout.mask = outline_headshape(cfg, sens); + end + otherwise + layout.mask = {}; + end + end + +end % create outline if style=2d -% make the subset as specified in cfg.channel -cfg.channel = ft_channelselection(cfg.channel, setdiff(layout.label, {'COMNT', 'SCALE'})); % COMNT and SCALE are not really channels -chansel = match_str(layout.label, cat(1, cfg.channel(:), 'COMNT', 'SCALE')); % include COMNT and SCALE, keep all channels in the order of the layout -% return the layout for the subset of channels -layout.pos = layout.pos(chansel,:); -layout.label = layout.label(chansel); -if ~strcmp(cfg.style, '3d') - % these don't exist for the 3D layout - layout.width = layout.width(chansel); - layout.height = layout.height(chansel); -end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% apply the montage, i.e. combine bipolar channels into a new representation +% apply the montage, e.g. convert from monopolar to bipolar channels %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% if ~strcmp(cfg.montage, 'no') - Norg = length(cfg.montage.labelorg); + Nold = length(cfg.montage.labelold); Nnew = length(cfg.montage.labelnew); - for i=1:Nnew cfg.montage.tra(i,:) = abs(cfg.montage.tra(i,:)); cfg.montage.tra(i,:) = cfg.montage.tra(i,:) ./ sum(cfg.montage.tra(i,:)); @@ -863,58 +1025,65 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % add axes positions for comments and scale information if required %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -if ~any(strcmp('COMNT', layout.label)) && strcmpi(cfg.style, '2d') && ~skipcomnt +if ~any(strcmp('COMNT', layout.label)) && ~strcmpi(cfg.style, '3d') && ~skipcomnt % add a placeholder for the comment in the upper left corner layout.label{end+1} = 'COMNT'; layout.width(end+1) = mean(layout.width); layout.height(end+1) = mean(layout.height); - if ~isempty(layout.pos) - XY = layout.pos; - else - XY = cat(1, layout.outline{:}, layout.mask{:}); + XY = layout.pos; + if isfield(layout, 'outline') + XY = cat(1, XY, layout.outline{:}); + end + if isfield(layout, 'mask') + XY = cat(1, XY, layout.mask{:}); end layout.pos(end+1,:) = [min(XY(:,1)) min(XY(:,2))]; elseif any(strcmp('COMNT', layout.label)) && skipcomnt % remove the scale entry sel = find(strcmp('COMNT', layout.label)); - layout.label(sel) = []; - layout.pos(sel,:) = []; - layout.width(sel) = []; + layout.label(sel) = []; + layout.pos(sel,:) = []; + layout.width(sel) = []; layout.height(sel) = []; end -if ~any(strcmp('SCALE', layout.label)) && strcmpi(cfg.style, '2d') && ~skipscale +if ~any(strcmp('SCALE', layout.label)) && ~strcmpi(cfg.style, '3d') && ~skipscale % add a placeholder for the scale in the upper right corner layout.label{end+1} = 'SCALE'; layout.width(end+1) = mean(layout.width); layout.height(end+1) = mean(layout.height); - if ~isempty(layout.pos) - XY = layout.pos; - else - XY = cat(1, layout.outline{:}, layout.mask{:}); + XY = layout.pos; + if isfield(layout, 'outline') + XY = cat(1, XY, layout.outline{:}); + end + if isfield(layout, 'mask') + XY = cat(1, XY, layout.mask{:}); end layout.pos(end+1,:) = [max(XY(:,1)) min(XY(:,2))]; elseif any(strcmp('SCALE', layout.label)) && skipscale % remove the scale entry sel = find(strcmp('SCALE', layout.label)); - layout.label(sel) = []; - layout.pos(sel,:) = []; - layout.width(sel) = []; + layout.label(sel) = []; + layout.pos(sel,:) = []; + layout.width(sel) = []; layout.height(sel) = []; end -% ensure proper format of some of label (see bug 1909 -roevdmei) +% these should be represented in a column vector (see bug 1909 -roevdmei) layout.label = layout.label(:); +% the width and height are not present in a 3D layout as used in SPM +if isfield(layout, 'width'), layout.width = layout.width(:); end +if isfield(layout, 'height'), layout.height = layout.height(:); end % to plot the layout for debugging, you can use this code snippet -if strcmp(cfg.feedback, 'yes') && strcmpi(cfg.style, '2d') +if strcmp(cfg.feedback, 'yes') && ~strcmpi(cfg.style, '3d') tmpcfg = []; tmpcfg.layout = layout; - ft_layoutplot(tmpcfg); + ft_layoutplot(tmpcfg); % FIXME this should use ft_plot_lay end % to write the layout to a .mat or text file, you can use this code snippet -if ~isempty(cfg.output) && strcmpi(cfg.style, '2d') +if ~isempty(cfg.output) && ~strcmpi(cfg.style, '3d') fprintf('writing layout to ''%s''\n', cfg.output); if strcmpi(cfg.output((end-3):end), '.mat') save(cfg.output,'layout'); @@ -929,10 +1098,9 @@ elseif ~isempty(cfg.output) && strcmpi(cfg.style, '3d') % the layout file format does not support 3D positions, furthermore for % a 3D layout the width and height are currently set to NaN - error('writing a 3D layout to an output file is not supported'); + ft_error('writing a 3D layout to an output file is not supported'); end - % do the general cleanup and bookkeeping at the end of the function ft_postamble provenance ft_postamble previous data @@ -944,7 +1112,7 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function layout = readlay(filename) if ~exist(filename, 'file') - error(sprintf('could not open layout file: %s', filename)); + ft_error('could not open layout file "%s"', filename); end fid=fopen(filename); lay_string=fread(fid,inf,'char=>char')'; @@ -960,11 +1128,11 @@ single_newline='\n'; pat=[integer, space, ... - float, space, ... - float, space, ... - float, space, ... - float, space, ... - channel_label, single_newline]; + float, space, ... + float, space, ... + float, space, ... + float, space, ... + channel_label, single_newline]; matches=regexp(sprintf('%s\n',lay_string),pat,'tokens'); @@ -988,112 +1156,153 @@ layout.label = label; return % function readlay + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % SUBFUNCTION % convert 3D electrode positions into 2D layout %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -function layout = sens2lay(sens, rz, method, style, overlap) - -% ensure that the sens structure is according to the latest conventions, -% i.e. deal with backward compatibility -sens = ft_datatype_sens(sens); +function layout = sens2lay(sens, rotatez, projmethod, style, overlap, viewpoint, boxchannel) % remove the balancing from the sensor definition, e.g. 3rd order gradients, PCA-cleaned data or ICA projections % this not only removed the linear projections, but also ensures that the channel labels are correctly named -if isfield(sens, 'chanposorg') - chanposorg = sens.chanposorg; + +if isfield(sens, 'chanposold') + chanposold = sens.chanposold; else - chanposorg = []; + chanposold = []; end if isfield(sens, 'balance') && ~strcmp(sens.balance.current, 'none') - sens = undobalancing(sens); - if size(chanposorg, 1) == numel(sens.label) - sens.chanpos = chanposorg; - end -% In case not all the locations have NaNs it might still be useful to plot them -% But perhaps it'd be better to have any(any + sens = undobalancing(sens); + if size(chanposold, 1) == numel(sens.label) + sens.chanpos = chanposold; + end + % In case not all the locations have NaNs it might still be useful to plot them + % But perhaps it'd be better to have any(any elseif any(all(isnan(sens.chanpos))) - [sel1, sel2] = match_str(sens.label, sens.labelorg); - sens.chanpos = chanposorg(sel2, :); - sens.label = sens.labelorg(sel2); + [sel1, sel2] = match_str(sens.label, sens.labelold); + sens.chanpos = chanposold(sel2, :); + sens.label = sens.labelold(sel2); end fprintf('creating layout for %s system\n', ft_senstype(sens)); -% apply rotation -if isempty(rz) - switch ft_senstype(sens) - case {'ctf151', 'ctf275', 'bti148', 'bti248', 'ctf151_planar', 'ctf275_planar', 'bti148_planar', 'bti248_planar', 'yokogawa160', 'yokogawa160_planar', 'yokogawa64', 'yokogawa64_planar', 'yokogawa440', 'yokogawa440_planar', 'magnetometer', 'meg'} - rz = 90; - case {'neuromag122', 'neuromag306'} - rz = 0; - case 'electrode' - rz = 90; - otherwise - rz = 0; +% apply rotation, but only if viewpoint is not used specifically +if isempty(viewpoint) + if isempty(rotatez) + switch ft_senstype(sens) + case {'ctf151', 'ctf275', 'bti148', 'bti248', 'ctf151_planar', 'ctf275_planar', 'bti148_planar', 'bti248_planar', 'yokogawa160', 'yokogawa160_planar', 'yokogawa64', 'yokogawa64_planar', 'yokogawa440', 'yokogawa440_planar', 'magnetometer', 'meg'} + rotatez = 90; + case {'neuromag122', 'neuromag306'} + rotatez = 0; + case 'electrode' + rotatez = 90; + otherwise + rotatez = 0; + end end + sens.chanpos = ft_warp_apply(rotate([0 0 rotatez]), sens.chanpos, 'homogenous'); end -sens.chanpos = ft_warp_apply(rotate([0 0 rz]), sens.chanpos, 'homogenous'); % determine the 3D channel positions -pnt = sens.chanpos; +pos = sens.chanpos; label = sens.label; if strcmpi(style, '3d') - layout.pos = pnt; + layout.pos = pos; layout.label = label; + else - prj = elproj(pnt, method); - + if isempty(viewpoint) + % projection other than viewpoint-specific orthographic projection is requested, use elproj + prj = elproj(pos, projmethod); + + else + % apply viewpoint-specific orthographic projection + + % determine auto view if requested + if strcmp(viewpoint, 'auto') + % simple automatic determination of the 'ideal' viewpoint + % first, depth or not: if Xvar (l/r axis) is bigger than both Yvar (post/ant axis) and Zvar (top/bottom axis), it's a depth + % if yes, superior (screw inferior) is more appriorate if Yvar > Zvar, otherwise posterior (screw anterior) + % if no, it's left/right, sign of mean(X) indicates which side the grid is on (note, for interhemispheric grids, both left/right (doenst) work) + posvar = var(pos); + if (posvar(1)>posvar(2)) && (posvar(1)>posvar(3)) % if they're roughly equal, it's likely a diagonal depth, and any view would (not) work + if posvar(2)>posvar(3) + viewpoint = 'superior'; + else + viewpoint = 'posterior'; + end + else + if sign(mean(pos(:,1))) == -1 + viewpoint = 'left'; + else + viewpoint = 'right'; + end + end + end + + % 3D to 2D + prj = getorthoviewpos(pos, sens.coordsys, viewpoint); + end + % this copy will be used to determine the minimum distance between channels % we need a copy because prj retains the original positions, and % prjForDist might need to be changed if the user wants to keep % overlapping channels - prjForDist = prj; - - % check whether many channels occupy identical positions, if so shift - % them around if requested - if size(unique(prj,'rows'),1) / size(prj,1) < 0.8 + % also subselect channels for computing width/height if requested by boxchannel + boxchannel = ft_channelselection(boxchannel, label); + boxchansel = match_str(label, boxchannel); + prjForDist = prj(boxchansel,:); + + % check whether many channels occupy identical positions, if so shift them around if requested + if size(unique(prjForDist,'rows'),1) / size(prjForDist,1) < 0.8 if strcmp(overlap, 'shift') - ft_warning('the specified sensor configuration has many overlapping channels, creating a layout by shifting them around (use a template layout for better control over the positioning)'); + ft_warning('the specified sensor configuration has many overlapping channels, creating a layout by shifting them around - use a template layout for better control over the positioning'); prj = shiftxy(prj', 0.2)'; - prjForDist = prj; + prjForDist = prj(boxchansel,:); elseif strcmp(overlap, 'no') - error('the specified sensor configuration has many overlapping channels, you specified not to allow that'); + ft_error('the specified sensor configuration has many overlapping channels, you specified not to allow that'); elseif strcmp(overlap, 'keep') - prjForDist = unique(prj, 'rows'); + prjForDist = unique(prj(boxchansel,:), 'rows'); else - error('unknown value for cfg.overlap = ''%s''', overlap); + ft_error('unknown value for cfg.overlap = ''%s''', overlap); end end - + d = dist(prjForDist'); d(logical(eye(size(d)))) = inf; - + % This is a fix for .sfp files, containing positions of 'fiducial % electrodes'. Their presence determines the minimum distance between % projected electrode positions, leading to very small boxes. % This problem has been detected and reported by Matt Mollison. % FIXME: consider changing the box-size being determined by mindist % by a mean distance or so; this leads to overlapping boxes, but that - % also exists for some .lay files - if any(strmatch('Fid', label)) - tmpsel = strmatch('Fid', label); + % also exists for some .lay files. + if any(strmatch('Fid', label(boxchansel))) + tmpsel = strmatch('Fid', label(boxchansel)); d(tmpsel, :) = inf; d(:, tmpsel) = inf; end - + if any(isfinite(d(:))) - % take mindist as the median of the first quartile of closest channel pairs with non-zero distance - mindist = min(d); % get closest neighbour for all channels - mindist = sort(mindist(mindist>1e-6),'ascend'); - mindist = mindist(1:round(numel(label)/4)); + % take mindist as the median of the first quartile of closest channel pairs with non-zero distance + mindist = min(d); % get closest neighbour for all channels + mindist = sort(mindist(mindist>1e-6),'ascend'); + mindist = mindist(1:round(numel(label(boxchansel))/4)); + mindist = median(mindist); + %%% /workaround - make a safe guess to detect iEEG until a better solution is found + if any(strcmp(ft_senstype(sens),{'eeg','unknown'})) && ~isempty(viewpoint) && (numel(boxchannel) ~= numel(label)) + mindist = min(d); + mindist = mindist(mindist>1e-6); % allows for substantially more overlap than the above mindist = median(mindist); + end + %%% \workaround - make a safe guess to detect iEEG until a better solution is found else - mindist = eps; % not sure this is a good value but it's just to prevent crashes when - % the EEG sensor definition is meaningless + mindist = eps; % not sure this is a good value but it's just to prevent crashes when + % the EEG sensor definition is meaningless end - + X = prj(:,1); Y = prj(:,2); Width = ones(size(X)) * mindist * 0.8; @@ -1101,6 +1310,7 @@ layout.pos = [X Y]; layout.width = Width; layout.height = Height; + layout.pos = prj; layout.label = label; end @@ -1119,7 +1329,7 @@ [rxnames, rem] = strtok(label, {'-', ' '}); [txnames, rem] = strtok(rem, {'-', ' '}); -for i=1:numel(label) +for i=1:numel(label) % create average positions rxid = ismember(opto.fiberlabel, rxnames(i)); txid = ismember(opto.fiberlabel, txnames(i)); @@ -1129,6 +1339,7 @@ layout.height(end+1) = 1; end + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % SUBFUNCTION % shift 2D positions around so that the minimum distance between any pair @@ -1136,8 +1347,7 @@ % % Credit for this code goes to Laurence Hunt at UCL. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -function xy = shiftxy(xy,mindist) +function xy = shiftxy(xy, mindist) x = xy(1,:); y = xy(2,:); @@ -1149,11 +1359,11 @@ xdiff = repmat(x,length(x),1) - repmat(x',1,length(x)); ydiff = repmat(y,length(y),1) - repmat(y',1,length(y)); xydist= sqrt(xdiff.^2 + ydiff.^2); %euclidean distance between all sensor pairs - + [i,j] = find(xydistj - - for m = 1:length(i); + + for m = 1:length(i) if (xydist(i(m),j(m)) == 0) diffvec = [mindist./sqrt(2) mindist./sqrt(2)]; else @@ -1169,3 +1379,248 @@ end xy = [x; y]; + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION to obtain XY pos from XYZ pos as orthographic projections depending on +% the viewpoint and coordsys. See also ELPROJ and COORDSYS2LABEL +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function pos = getorthoviewpos(pos, coordsys, viewpoint) +% see also + +if size(pos,2)~=3 + ft_error('XYZ coordinates are required to obtain the orthographic projections based on a viewpoint') +end + +% create view(az,el) transformation matrix +switch coordsys + case {'ras' 'itab' 'neuromag' 'acpc' 'spm' 'mni' 'tal'} + switch viewpoint + case 'left' + transmat = viewmtx(-90, 0); + case 'right' + transmat = viewmtx(90, 0); + case 'superior' + transmat = viewmtx(0, 90); + case 'inferior' + transmat = viewmtx(180, -90); + case 'posterior' + transmat = viewmtx(0, 0); + case 'anterior' + transmat = viewmtx(180, 0); + otherwise + ft_error('orthographic projection using viewpoint "%s" is not supported', viewpoint) + end % switch viewpoint + case {'als' 'ctf' '4d' 'bti'} + switch viewpoint + case 'left' + transmat = viewmtx(180, 0); + case 'right' + transmat = viewmtx(0, 0); + case 'superior' + transmat = viewmtx(-90, 90); + case 'inferior' + transmat = viewmtx(90, -90); + case 'posterior' + transmat = viewmtx(-90, 0); + case 'anterior' + transmat = viewmtx(90, 0); + otherwise + ft_error('orthographic projection using viewpoint "%s" is not supported', viewpoint) + end % switch viewpoint + otherwise + ft_error('orthographic projection using coordinate system "%s" is not supported', coordsys) +end % switch coordsys + + +% extract xy +pos = ft_warp_apply(transmat, pos, 'homogenous'); +pos = pos(:,[1 2]); + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION generate an outline from the boundary/convex hull of pos+width/height +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function outline = outline_circle() +% create the default "circle with triangle" to resemble the head +% note that the electrode positions should be scaled accordingly +rmax = 0.5; +l = 0:2*pi/100:2*pi; +HeadX = cos(l).*rmax; +HeadY = sin(l).*rmax; +NoseX = [0.18*rmax 0 -0.18*rmax]; +NoseY = [rmax-.004 rmax*1.15 rmax-.004]; +EarX = [.497 .510 .518 .5299 .5419 .54 .547 .532 .510 .489]; +EarY = [.0555 .0775 .0783 .0746 .0555 -.0055 -.0932 -.1313 -.1384 -.1199]; +% Define the outline of the head, ears and nose +outline{1} = [HeadX(:) HeadY(:)]; +outline{2} = [NoseX(:) NoseY(:)]; +outline{3} = [ EarX(:) EarY(:)]; +outline{4} = [-EarX(:) EarY(:)]; + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION generate an outline from the boundary/convex hull of pos+width/height +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function outline = outline_convex(layout) + +% get index of all relevant channels +ind1 = strcmp(layout.label,'COMNT'); +ind2 = strcmp(layout.label,'SCALE'); +ind = ~(ind1 | ind2); +% get position of all channel 'boxes' and draw boundary around it, or, in older matlabs, a convex hull +x = layout.pos(ind,1); +y = layout.pos(ind,2); +w = layout.width(ind); +h = layout.height(ind); +boxpos = [ + x - (w/2) y - (h/2); % lb + x - (w/2) y + (h/2); % lt + x + (w/2) y - (h/2); % rb + x + (w/2) y + (h/2); % rt + ]; +if ft_platform_supports('boundary') + k = boundary(boxpos,.2); + outline{1} = boxpos(k,:); +else + outline{1} = boxpos(convhull(boxpos(:,1),boxpos(:,2)),:); +end + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION generate an outline from the headshape or anatomical mri +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function outline = outline_headshape(cfg, sens) + +if ~isempty(cfg.headshape) + if ischar(cfg.headshape) && exist(cfg.headshape, 'file') + fprintf('reading headshape from file %s\n', cfg.headshape); + outlbase = ft_read_headshape(cfg.headshape); + elseif isstruct(cfg.headshape) + outlbase = cfg.headshape; + else + ft_error('incorrect specification of cfg.headshape') + end +elseif ~isempty(cfg.mri) + if ischar(cfg.mri) && exist(cfg.mri, 'file') + fprintf('reading MRI from file %s\n', cfg.mri); + outlbase = ft_read_mri(cfg.mri); + elseif ft_datatype(cfg.mri, 'volume') + outlbase = cfg.mri; + else + ft_error('incorrect specification of cfg.mri') + end + % create mesh from anatomical field, this will be used as headshape below + cfgpm = []; + cfgpm.method = 'projectmesh'; + cfgpm.tissue = 'brain'; + cfgpm.numvertices = 1e5; + outlbase = ft_prepare_mesh(cfgpm, outlbase); +end + +% check that we have the right data in outlbase +assert(isfield(outlbase, 'pos'), 'the headshape does not contain any vertices') + +% check coordinate system of outlbase +assert(isfield(outlbase, 'coordsys'), 'no coordsys field found in headshape/mri, use ft_determine_coordsys') +assert(isfield(sens, 'coordsys'), 'no coordsys field found in sensor structure, use ft_determine_coordsys') +assert(isequal(outlbase.coordsys, sens.coordsys), 'the coordinate system of headshape/mri does not match that of sensors') + +% match head geometry units with that of the sensors +outlbase = ft_convert_units(outlbase, sens.unit); + +% there can be multiple meshes, e.g. left and right hemispheres +outline = cell(size(outlbase)); +for i=1:numel(outlbase) + % generate outline based on matlab version + if ft_platform_supports('boundary') + + % extract points indicating brain + braincoords = outlbase(i).pos; + % apply projection and extract XY + if isequal(cfg.projection,'orthographic') && ~isempty(cfg.viewpoint) + braincoords = getorthoviewpos(braincoords, outlbase(i).coordsys, cfg.viewpoint); + else + % project identically as in sens2lay using cfg.rotate and elproj (this should be kept identical to sens2lay) + if isempty(cfg.rotate) + switch ft_senstype(sens) + case {'ctf151', 'ctf275', 'bti148', 'bti248', 'ctf151_planar', 'ctf275_planar', 'bti148_planar', 'bti248_planar', 'yokogawa160', 'yokogawa160_planar', 'yokogawa64', 'yokogawa64_planar', 'yokogawa440', 'yokogawa440_planar', 'magnetometer', 'meg'} + rotatez = 90; + case {'neuromag122', 'neuromag306'} + rotatez = 0; + case 'electrode' + rotatez = 90; + otherwise + rotatez = 0; + end + end + braincoords = ft_warp_apply(rotate([0 0 rotatez]), braincoords, 'homogenous'); + braincoords = elproj(braincoords, cfg.projection); + end + + % get outline + k = boundary(braincoords,.8); + outline{i} = braincoords(k,:); + + else % matlab version fallback + + % plot mesh in rotated view, rotate, screencap, and trace frame to generate outline + if isequal(cfg.projection,'orthographic') && ~isempty(cfg.viewpoint) + outlbase(i).pos = getorthoviewpos(outlbase(i).pos, outlbase(i).coordsys, cfg.viewpoint); + else + % project identically as in sens2lay using cfg.rotate and elproj (this should be kept identical to sens2lay) + if isempty(cfg.rotate) + switch ft_senstype(sens) + case {'ctf151', 'ctf275', 'bti148', 'bti248', 'ctf151_planar', 'ctf275_planar', 'bti148_planar', 'bti248_planar', 'yokogawa160', 'yokogawa160_planar', 'yokogawa64', 'yokogawa64_planar', 'yokogawa440', 'yokogawa440_planar', 'magnetometer', 'meg'} + rotatez = 90; + case {'neuromag122', 'neuromag306'} + rotatez = 0; + case 'electrode' + rotatez = 90; + otherwise + rotatez = 0; + end + end + outlbase(i).pos = ft_warp_apply(rotate([0 0 rotatez]), outlbase(i).pos, 'homogenous'); + outlbase(i).pos = elproj(outlbase(i).pos, cfg.projection); + end + h = figure('visible', 'off'); + ft_plot_mesh(outlbase(i), 'facecolor', [0 0 0], 'EdgeColor', 'none'); + view([0 90]) + axis tight + xlim = get(gca, 'xlim'); + ylim = get(gca, 'ylim'); + set(gca,'OuterPosition', [0.2 0.2 .6 .6]) % circumvent weird matlab bug, wth? + % extract frame for tracing + drawnow % need to flush buffer, otherwise frame will not get extracted properly + frame = getframe(h); + close(h) + imtotrace = double(~logical(sum(frame.cdata,3))); % needs to be binary to trace + % image is not in regular xy space, flip, and transpose + imtotrace = flipud(imtotrace).'; + + % trace image generated above + [row, col] = find(imtotrace, 1, 'first'); % set an arbitrary starting point + trace = bwtraceboundary(imtotrace, [row, col], 'N'); + + % convert to sens coordinates + x = trace(:,1); + y = trace(:,2); + x = x - min(x); + x = x ./ max(x); + x = x .* (xlim(2)-xlim(1)); + x = x - abs(xlim(1)); + y = y - min(y); + y = y ./ max(y); + y = y .* (ylim(2)-ylim(1)); + y = y - abs(ylim(1)); + + outline{i} = [x y]; + end + + % subsample the outline + if size(outline{i},1)>5e3 % 5e3 points should be more than enough to get an outine with acceptable detail + outline{i} = outline{i}(1:floor(size(outline,1)/5e3):end,:); + end + +end % for numel(outlbase) diff --git a/external/fieldtrip/ft_prepare_leadfield.m b/external/fieldtrip/ft_prepare_leadfield.m index 87a94f4b..1ca4487f 100644 --- a/external/fieldtrip/ft_prepare_leadfield.m +++ b/external/fieldtrip/ft_prepare_leadfield.m @@ -137,7 +137,7 @@ cfg = ft_checkconfig(cfg, 'index2logical', 'yes'); if strcmp(cfg.sel50p, 'yes') && strcmp(cfg.lbex, 'yes') - error('subspace projection with either lbex or sel50p is mutually exclusive'); + ft_error('subspace projection with either lbex or sel50p is mutually exclusive'); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -153,7 +153,7 @@ end % construct the dipole grid according to the configuration -tmpcfg = keepfields(cfg, {'grid', 'mri', 'headshape', 'symmetry', 'smooth', 'threshold', 'spheremesh', 'inwardshift'}); +tmpcfg = keepfields(cfg, {'grid', 'mri', 'headshape', 'symmetry', 'smooth', 'threshold', 'spheremesh', 'inwardshift', 'showcallinfo'}); tmpcfg.headmodel = headmodel; tmpcfg.grad = sens; % either electrodes or gradiometers grid = ft_prepare_sourcemodel(tmpcfg); @@ -162,10 +162,10 @@ % this check can be removed if the underlying bug is resolved. See % http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2387 if ~isfield(headmodel, 'unit') || ~isfield(grid, 'unit') || ~isfield(sens, 'unit') - warning('cannot determine the units of all geometric objects required for leadfield computation (headmodel, sourcemodel, sensor configuration). THIS CAN LEAD TO WRONG RESULTS! (refer to http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2387)'); + ft_warning('cannot determine the units of all geometric objects required for leadfield computation (headmodel, sourcemodel, sensor configuration). THIS CAN LEAD TO WRONG RESULTS! (refer to http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2387)'); else if ~strcmp(headmodel.unit, grid.unit) || ~strcmp(grid.unit, sens.unit) - error('geometric objects (headmodel, sourcemodel, sensor configuration) are not expressed in the same units (this used to be allowed, and will be again in the future, but for now there is a bug which prevents a correct leadfield from being computed; see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2387)'); + ft_error('geometric objects (headmodel, sourcemodel, sensor configuration) are not expressed in the same units (this used to be allowed, and will be again in the future, but for now there is a bug which prevents a correct leadfield from being computed; see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2387)'); end end diff --git a/external/fieldtrip/ft_prepare_localspheres.m b/external/fieldtrip/ft_prepare_localspheres.m deleted file mode 100644 index 61591289..00000000 --- a/external/fieldtrip/ft_prepare_localspheres.m +++ /dev/null @@ -1,195 +0,0 @@ -function [headmodel, cfg] = ft_prepare_localspheres(cfg, mri) - -% FT_PREPARE_LOCALSPHERES is deprecated, please use FT_PREPARE_HEADMODEL and -% FT_PREPARE_MESH -% -% See also FT_PREPARE_HEADMODEL - -% Copyright (C) 2005-2006, Jan-Mathijs Schoffelen & Robert Oostenveld -% -% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org -% for the documentation and details. -% -% FieldTrip is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. -% -% FieldTrip is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with FieldTrip. If not, see . -% -% $Id$ - -warning('FT_PREPARE_LOCALSPHERES is deprecated, please use FT_PREPARE_HEADMODEL with cfg.method = ''localspheres'' instead.') - -% these are used by the ft_preamble/ft_postamble function and scripts -ft_revision = '$Id$'; -ft_nargin = nargin; -ft_nargout = nargout; - -% do the general setup of the function -ft_defaults -ft_preamble init -ft_preamble debug -ft_preamble loadvar mri -ft_preamble provenance mri -ft_preamble trackconfig - -% the ft_abort variable is set to true or false in ft_preamble_init -if ft_abort - return -end - -% check if the input cfg is valid for this function -cfg = ft_checkconfig(cfg, 'renamed', {'spheremesh', 'numvertices'}); - -% set the defaults -if ~isfield(cfg, 'radius'), cfg.radius = 8.5; end -if ~isfield(cfg, 'maxradius'), cfg.maxradius = 20; end -if ~isfield(cfg, 'baseline'), cfg.baseline = 5; end -if ~isfield(cfg, 'feedback'), cfg.feedback = 'yes'; end -if ~isfield(cfg, 'smooth'); cfg.smooth = 5; end % in voxels -if ~isfield(cfg, 'threshold'), cfg.threshold = 0.5; end % relative -if ~isfield(cfg, 'numvertices'), cfg.numvertices = []; end -if ~isfield(cfg, 'singlesphere'), cfg.singlesphere = 'no'; end -if ~isfield(cfg, 'headshape'), cfg.headshape = []; end - -hasmri = exist('mri', 'var'); % note that nargin will not work in case of cfg.inputfile -if hasmri - headshape = ft_prepare_mesh(cfg, mri); -elseif isfield(cfg,'headshape') && nargin == 1 - if ischar(cfg.headshape) - headshape = ft_read_headshape(cfg.headshape); - else - headshape = cfg.headshape; - end -else - error('no head shape available') -end - -% read the gradiometer definition from file or copy it from the configuration -if isfield(cfg, 'gradfile') - grad = ft_read_sens(cfg.gradfile); -else - grad = cfg.grad; -end - -Nshape = size(headshape.pos, 1); -Nchan = size(grad.tra, 1); - -% set up an empty figure -if strcmp(cfg.feedback, 'yes') - clf - hold on - axis equal - axis vis3d - axis off - drawnow -end - -% plot all channels and headshape points -if strcmp(cfg.feedback, 'yes') - cla - ft_plot_sens(grad); - ft_plot_mesh(headshape, 'vertexcolor', 'g', 'facecolor', 'none', 'edgecolor', 'none'); - drawnow -end - -% fit a single sphere to all headshape points -[single_o, single_r] = fitsphere(headshape.pos); -fprintf('single sphere, %5d surface points, center = [%4.1f %4.1f %4.1f], radius = %4.1f\n', Nshape, single_o(1), single_o(2), single_o(3), single_r); - -headmodel = []; - -if strcmp(cfg.singlesphere, 'yes') - % only return a single sphere - headmodel.r = single_r; - headmodel.o = single_o; - return; -end - -% start with an empty structure that will hold the results -headmodel.r = zeros(Nchan,1); % radius of every sphere -headmodel.o = zeros(Nchan,3); % origin of every sphere -headmodel.label = cell(Nchan,1); % corresponding gradiometer channel label for every sphere - -for chan=1:Nchan - coilsel = find(grad.tra(chan,:)~=0); - allpos = grad.coilpos(coilsel, :); % position of all coils belonging to this channel - allori = grad.coilori(coilsel, :); % orientation of all coils belonging to this channel - - if strcmp(cfg.feedback, 'yes') - cla - plot3(grad.coilpos(:,1), grad.coilpos(:,2), grad.coilpos(:,3), 'b.'); % all coils - plot3(allpos(:,1), allpos(:,2), allpos(:,3), 'r*'); % this channel in red - end - - % determine the average position and orientation of this channel - thispos = mean(allpos,1); - [u, s, v] = svd(allori); - thisori = v(:,1)'; - if dot(thispos,thisori)<0 - % the orientation should be outwards pointing - thisori = -thisori; - end - - % compute the distance from every coil along this channels orientation - dist = zeros(size(coilsel)); - for i=1:length(coilsel) - dist(i) = dot((allpos(i,:)-thispos), thisori); - end - - [m, i] = min(dist); - % check whether the minimum difference is larger than a typical distance - if abs(m)>(cfg.baseline/4) - % replace the position of this channel by the coil that is the closest to the head (axial gradiometer) - % except when the center of the channel is approximately just as good (planar gradiometer) - thispos = allpos(i,:); - end - - % find the headshape points that are close to this channel - dist = sqrt(sum((headshape.pos-repmat(thispos,Nshape,1)).^2, 2)); - shapesel = find(dist10 - [o, r] = fitsphere(headshape.pos(shapesel,:)); - fprintf('channel = %s, %5d surface points, center = [%4.1f %4.1f %4.1f], radius = %4.1f\n', grad.label{chan}, length(shapesel), o(1), o(2), o(3), r); - else - fprintf('channel = %s, not enough surface points, using all points\n', grad.label{chan}); - o = single_o; - r = single_r; - end - - if r > cfg.maxradius - fprintf('channel = %s, not enough surface points, using all points\n', grad.label{chan}); - o = single_o; - r = single_r; - end - - % add this sphere to the volume conductor - headmodel.o(chan,:) = o; - headmodel.r(chan) = r; - headmodel.label{chan} = grad.label{chan}; -end % for all channels - -headmodel.type = 'localspheres'; - -% ensure that the geometrical units are specified -headmodel = ft_convert_units(headmodel); - -% do the general cleanup and bookkeeping at the end of the function -ft_postamble debug -ft_postamble trackconfig -ft_postamble previous mri -ft_postamble provenance headmodel -ft_postamble history headmodel diff --git a/external/fieldtrip/ft_prepare_mesh.m b/external/fieldtrip/ft_prepare_mesh.m index ff83fe43..d1260eb6 100644 --- a/external/fieldtrip/ft_prepare_mesh.m +++ b/external/fieldtrip/ft_prepare_mesh.m @@ -20,14 +20,14 @@ % cfg.tissue = cell-array with tissue types or numeric vector with integer values % cfg.numvertices = numeric vector, should have same number of elements as cfg.tissue % cfg.downsample = integer number (default = 1, i.e. no downsampling), see FT_VOLUMEDOWNSAMPLE -% cfg.headshape = (optional) a filename containing headshape, a Nx3 matrix with surface -% points, or a structure with a single or multiple boundaries +% cfg.spmversion = string, 'spm2', 'spm8', 'spm12' (default = 'spm8') % -% Method 'cortexhull' has its own specific configuration options: -% cfg.headshape = a filename containing the pial surface computed by -% freesurfer recon-all ('/path/to/surf/lh.pial') -% cfg. +% For method 'headshape you should specify +% cfg.headshape = a filename containing headshape, a Nx3 matrix with surface +% points, or a structure with a single or multiple boundaries % +% For method 'cortexhull' you should specify +% cfg.headshape = sting, filename containing the pial surface computed by freesurfer recon-all % % To facilitate data-handling and distributed computing you can use % cfg.inputfile = ... @@ -52,6 +52,7 @@ % cfg = []; % cfg.method = 'cortexhull'; % cfg.headshape = '/path/to/surf/lh.pial'; +% cfg.fshome = '/path/to/freesurfer dir'; % cortex_hull = ft_prepare_mesh(cfg); % % See also FT_VOLUMESEGMENT, FT_PREPARE_HEADMODEL, FT_PLOT_MESH @@ -114,36 +115,23 @@ % get the options cfg.downsample = ft_getopt(cfg, 'downsample', 1); % default is no downsampling cfg.numvertices = ft_getopt(cfg, 'numvertices'); % no default - -% This was changed on 3 December 2013, this backward compatibility can be removed in 6 months from now. -if isfield(cfg, 'interactive') - if strcmp(cfg.interactive, 'yes') - warning('please specify cfg.method=''interactive'' instead of cfg.interactive=''yes'''); - cfg.method = 'interactive'; - end - cfg = rmfield(cfg, 'interactive'); -end - -% This was changed on 3 December 2013, it makes sense to keep it like this on the -% long term (previously there was no explicit use of cfg.method, now there is). -% Translate the input options in the appropriate cfg.method. -if ~isfield(cfg, 'method') - if isfield(cfg, 'headshape') && ~isempty(cfg.headshape) - warning('please specify cfg.method=''headshape'''); - cfg.method = 'headshape'; - elseif hasdata && ~strcmp(ft_voltype(mri), 'unknown') - % the input is a spherical volume conduction model - cfg.method = ft_voltype(mri); - elseif hasdata - warning('please specify cfg.method=''projectmesh'', ''iso2mesh'' or ''isosurface'''); - warning('using ''projectmesh'' as default'); - cfg.method = 'projectmesh'; - end +cfg.smooth = ft_getopt(cfg, 'smooth'); % no default +cfg.spmversion = ft_getopt(cfg, 'spmversion', 'spm8'); + +% Translate the input options in the appropriate default for cfg.method +if isfield(cfg, 'headshape') && ~isempty(cfg.headshape) + cfg.method = ft_getopt(cfg, 'method', 'headshape'); +elseif hasdata && ~strcmp(ft_voltype(mri), 'unknown') + cfg.method = ft_getopt(cfg, 'method', ft_voltype(mri)); +elseif hasdata + cfg.method = ft_getopt(cfg, 'method', 'projectmesh'); +else + cfg.method = ft_getopt(cfg, 'method', []); end if hasdata && cfg.downsample~=1 % optionally downsample the anatomical volume and/or tissue segmentations - tmpcfg = keepfields(cfg, {'downsample'}); + tmpcfg = keepfields(cfg, {'downsample', 'showcallinfo'}); mri = ft_volumedownsample(tmpcfg, mri); % restore the provenance information [cfg, mri] = rollback_provenance(cfg, mri); @@ -154,32 +142,32 @@ % this makes sense with a non-segmented MRI as input % call the corresponding helper function bnd = prepare_mesh_manual(cfg, mri); - + case {'projectmesh', 'iso2mesh', 'isosurface'} % this makes sense with a segmented MRI as input % call the corresponding helper function bnd = prepare_mesh_segmentation(cfg, mri); - + case 'headshape' % call the corresponding helper function bnd = prepare_mesh_headshape(cfg); - + case 'hexahedral' % the MRI is assumed to contain a segmentation % call the corresponding helper function bnd = prepare_mesh_hexahedral(cfg, mri); - + case 'tetrahedral' % the MRI is assumed to contain a segmentation % call the corresponding helper function bnd = prepare_mesh_tetrahedral(cfg, mri); - + case {'singlesphere' 'concentricspheres' 'localspheres'} % FIXME for localspheres it should be replaced by an outline of the head, see private/headsurface fprintf('triangulating the sphere in the volume conductor\n'); [pos, tri] = makesphere(cfg.numvertices); bnd = []; - mri = ft_convert_units(mri); % ensure that it has units + mri = ft_determine_units(mri); % ensure that it has units headmodel = ft_datatype_headmodel(mri); % rename it and ensure that it is consistent and up-to-date for i=1:length(headmodel.r) bnd(i).pos(:,1) = pos(:,1)*headmodel.r(i) + headmodel.o(1); @@ -187,12 +175,12 @@ bnd(i).pos(:,3) = pos(:,3)*headmodel.r(i) + headmodel.o(3); bnd(i).tri = tri; end - + case 'cortexhull' - bnd = prepare_cortexhull(cfg); - + bnd = prepare_mesh_cortexhull(cfg); + otherwise - error('unsupported cfg.method') + ft_error('unsupported cfg.method') end % copy the geometrical units from the input to the output @@ -201,7 +189,21 @@ bnd(i).unit = mri.unit; end elseif ~isfield(bnd, 'unit') - bnd = ft_convert_units(bnd); + bnd = ft_determine_units(bnd); +end + +% copy the coordinate system from the input to the output +if ~isfield(bnd, 'coordsys') && hasdata && isfield(mri, 'coordsys') + for i=1:numel(bnd) + bnd(i).coordsys = mri.coordsys; + end +end + +% smooth the mesh +if ~isempty(cfg.smooth) + cfg.headshape = bnd; + cfg.numvertices = []; + bnd = prepare_mesh_headshape(cfg); end % do the general cleanup and bookkeeping at the end of the function diff --git a/external/fieldtrip/ft_prepare_montage.m b/external/fieldtrip/ft_prepare_montage.m new file mode 100644 index 00000000..4a6e18f7 --- /dev/null +++ b/external/fieldtrip/ft_prepare_montage.m @@ -0,0 +1,111 @@ +function [montage, cfg] = ft_prepare_montage(cfg, data) + +% FT_PREPARE_MONTAGE creates a referencing scheme based on the input configuration +% options and the channels in the data structure. The resulting montage can be +% given as input to ft_apply_montage, or as cfg.montage to ft_preprocessing. +% +% Use as +% montage = ft_prepare_montage(cfg, data) +% +% The configuration can contain the following fields: +% cfg.implicitref = 'label' or empty, add the implicit EEG reference as zeros (default = []) +% cfg.refchannel = cell-array with new EEG reference channel(s), this can be 'all' for a common average reference +% +% See also FT_PREPROCESSING + +% Copyright (C) 2017, Robert Oostenveld +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +% these are used by the ft_preamble/ft_postamble function and scripts +ft_revision = '$Id$'; +ft_nargin = nargin; +ft_nargout = nargout; + +% do the general setup of the function +ft_defaults +ft_preamble init +ft_preamble loadvar data +ft_preamble provenance data + +% the ft_abort variable is set to true or false in ft_preamble_init +if ft_abort + return +end + +% the data can be passed as input argument or can be read from disk +hasdata = exist('data', 'var') && ~isempty(data); + +% basic check/initialization of input arguments +if ~hasdata + data = struct([]); +else + data = ft_checkdata(data); +end + +% do a sanity check for incompatible options which are used in ft_preprocessing +cfg = ft_checkconfig(cfg, 'forbidden', {'refmethod', 'montage'}); + +% set default configuration options +cfg.reref = ft_getopt(cfg, 'reref', 'yes'); +cfg.channel = ft_getopt(cfg, 'channel', 'all'); +cfg.implicitref = ft_getopt(cfg, 'implicitref'); +cfg.refchannel = ft_getopt(cfg, 'refchannel'); + +assert(istrue(cfg.reref), 'cannot create a montage without cfg.reref=''yes'''); + +% here the actual work starts +if hasdata + cfg.channel = ft_channelselection(cfg.channel, data.label); + cfg.refchannel = ft_channelselection(cfg.refchannel, cat(1, data.label(:), cfg.implicitref)); +else + if ischar(cfg.channel) + cfg.channel = {cfg.channel}; + end + if ischar(cfg.refchannel) + cfg.refchannel = {cfg.refchannel}; + end +end + +% the first montage serves to add the implicit reference channel +montage1 = []; +montage1.labelold = cfg.channel(:); +montage1.labelnew = cfg.channel(:); +if ~isempty(cfg.implicitref) + montage1.labelnew{end+1} = cfg.implicitref; +end +% the last row for the implicitref will be all zero +montage1.tra = eye(numel(montage1.labelnew), numel(montage1.labelold)); + +% the second montage serves to subtract the selected reference channels +montage2 = []; +montage2.labelold = montage1.labelnew; +montage2.labelnew = montage1.labelnew; +montage2.tra = eye(numel(montage2.labelnew)); +refsel = match_str(montage2.labelold, cfg.refchannel); +% subtract the mean of the reference channels +montage2.tra(:,refsel) = montage2.tra(:,refsel) - 1/numel(refsel); + +% apply montage2 to montage1, the result is the combination of both +montage = ft_apply_montage(montage1, montage2); + +% do the general cleanup and bookkeeping at the end of the function +ft_postamble provenance +ft_postamble previous data +ft_postamble history montage diff --git a/external/fieldtrip/ft_prepare_neighbours.m b/external/fieldtrip/ft_prepare_neighbours.m index 31c7d329..856a7979 100644 --- a/external/fieldtrip/ft_prepare_neighbours.m +++ b/external/fieldtrip/ft_prepare_neighbours.m @@ -96,6 +96,16 @@ if hasdata % check if the input data is valid for this function data = ft_checkdata(data); + % set the default for senstype depending on the data + if isfield(data, 'grad') + cfg.senstype = ft_getopt(cfg, 'senstype', 'meg'); + elseif isfield(data, 'elec') + cfg.senstype = ft_getopt(cfg, 'senstype', 'eeg'); + elseif isfield(data, 'opto') + cfg.senstype = ft_getopt(cfg, 'senstype', 'opto'); + else + cfg.senstype = ft_getopt(cfg, 'senstype', []); + end end if strcmp(cfg.method, 'template') @@ -124,7 +134,7 @@ % check whether a layout can be used if ~isfield(cfg, 'layout') % error if that fails as well - error('You need to define a template or layout or give data as an input argument when ft_prepare_neighbours is called with cfg.method=''template'''); + ft_error('You need to define a template or layout or give data as an input argument when ft_prepare_neighbours is called with cfg.method=''template'''); end fprintf('Using the 2-D layout filename to determine the template filename\n'); cfg.template = [strtok(cfg.layout, '.') '_neighb.mat']; @@ -142,10 +152,11 @@ end % check for existence if ~exist(cfg.template, 'file') - error('Template file could not be found - please check spelling or see http://www.fieldtriptoolbox.org/faq/how_can_i_define_my_own_neighbourhood_template (please consider sharing it with others via the FT mailing list)'); + ft_error('Template file could not be found - please check spelling or see http://www.fieldtriptoolbox.org/faq/how_can_i_define_my_own_neighbourhood_template (please consider sharing it with others via the FT mailing list)'); end load(cfg.template); fprintf('Successfully loaded neighbour structure from %s\n', cfg.template); + else % get the the grad or elec if not present in the data if hasdata @@ -155,7 +166,7 @@ end if strcmp(ft_senstype(sens), 'neuromag306') - warning('Neuromag306 system detected - be aware of different sensor types, see http://www.fieldtriptoolbox.org/faq/why_are_there_multiple_neighbour_templates_for_the_neuromag306_system'); + ft_warning('Neuromag306 system detected - be aware of different sensor types, see http://www.fieldtriptoolbox.org/faq/why_are_there_multiple_neighbour_templates_for_the_neuromag306_system'); end chanpos = sens.chanpos; label = sens.label; @@ -179,18 +190,7 @@ % use a smart default for the distance if ~isfield(cfg, 'neighbourdist') sens = ft_checkdata(sens, 'hasunit', 'yes'); - if isfield(sens, 'unit') && strcmp(sens.unit, 'm') - cfg.neighbourdist = 0.04; - elseif isfield(sens, 'unit') && strcmp(sens.unit, 'dm') - cfg.neighbourdist = 0.4; - elseif isfield(sens, 'unit') && strcmp(sens.unit, 'cm') - cfg.neighbourdist = 4; - elseif isfield(sens, 'unit') && strcmp(sens.unit, 'mm') - cfg.neighbourdist = 40; - else - % don't provide a default in case the dimensions of the sensor array are unknown - error('Sensor distance is measured in an unknown unit type'); - end + cfg.neighbourdist = 40 * ft_scalingfactor('mm', sens.unit); fprintf('using a distance threshold of %g\n', cfg.neighbourdist); end @@ -210,13 +210,13 @@ tri = [tri; tri_x; tri_y]; neighbours = compneighbstructfromtri(chanpos, label, tri); otherwise - error('Method ''%s'' not known', cfg.method); + ft_error('Method ''%s'' not known', cfg.method); end end % removed as from Nov 09 2011 - hope there are no problems with this % if iscell(neighbours) -% warning('Neighbourstructure is in old format - converting to structure array'); +% ft_warning('Neighbourstructure is in old format - converting to structure array'); % neighbours = fixneighbours(neighbours); % end @@ -243,7 +243,7 @@ k = 0; for i=1:length(neighbours) if isempty(neighbours(i).neighblabel) - warning('FIELDTRIP:NoNeighboursFound', 'no neighbours found for %s\n', neighbours(i).label); + ft_warning('FIELDTRIP:NoNeighboursFound', 'no neighbours found for %s\n', neighbours(i).label); % JMH: I removed this in Feb 2013 - this is handled above now % note however that in case of using a template, this function behaves % differently now (neighbourschans can still be channels not in @@ -255,7 +255,7 @@ end if k==0 - error('No neighbours were found!'); + ft_error('No neighbours were found!'); end fprintf('there are on average %.1f neighbours per channel\n', k/length(neighbours)); diff --git a/external/fieldtrip/ft_prepare_singleshell.m b/external/fieldtrip/ft_prepare_singleshell.m deleted file mode 100644 index 9b79a982..00000000 --- a/external/fieldtrip/ft_prepare_singleshell.m +++ /dev/null @@ -1,79 +0,0 @@ -function [headmodel, cfg] = ft_prepare_singleshell(cfg, mri) - -% FT_PREPARE_SINGLESHELL is deprecated, please use FT_PREPARE_HEADMODEL and -% FT_PREPARE_MESH -% -% See also FT_PREPARE_HEADMODEL - -% TODO the spheremesh option should be renamed consistently with other mesh generation cfgs -% TODO shape should contain pnt as subfield and not be equal to pnt (for consistency with other use of shape) - -% Copyright (C) 2006-2012, Robert Oostenveld -% -% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org -% for the documentation and details. -% -% FieldTrip is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. -% -% FieldTrip is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with FieldTrip. If not, see . -% -% $Id$ - -warning('FT_PREPARE_SINGLESHELL is deprecated, please use FT_PREPARE_HEADMODEL with cfg.method = ''singleshell'' instead.') - -% these are used by the ft_preamble/ft_postamble function and scripts -ft_revision = '$Id$'; -ft_nargin = nargin; -ft_nargout = nargout; - -% do the general setup of the function -ft_defaults -ft_preamble init -ft_preamble debug -ft_preamble loadvar mri -ft_preamble provenance mri -ft_preamble trackconfig - -% the ft_abort variable is set to true or false in ft_preamble_init -if ft_abort - return -end - -% check if the input cfg is valid for this function -cfg = ft_checkconfig(cfg, 'renamed', {'spheremesh', 'numvertices'}); -cfg = ft_checkconfig(cfg, 'deprecated', 'mriunits'); - -% set the defaults -if ~isfield(cfg, 'smooth'); cfg.smooth = 5; end % in voxels -if ~isfield(cfg, 'threshold'), cfg.threshold = 0.5; end % relative -if ~isfield(cfg, 'numvertices'), cfg.numvertices = []; end % approximate number of vertices in sphere - -% the data is specified as input variable or input file -hasmri = exist('mri', 'var'); - -if hasmri - headmodel.bnd = ft_prepare_mesh(cfg, mri); -else - headmodel.bnd = ft_prepare_mesh(cfg); -end - -headmodel.type = 'singleshell'; - -% ensure that the geometrical units are specified -headmodel = ft_convert_units(headmodel); - -% do the general cleanup and bookkeeping at the end of the function -ft_postamble debug -ft_postamble trackconfig -ft_postamble previous mri -ft_postamble provenance headmodel -ft_postamble history headmodel diff --git a/external/fieldtrip/ft_prepare_sourcemodel.m b/external/fieldtrip/ft_prepare_sourcemodel.m index d5d3750d..675a0046 100644 --- a/external/fieldtrip/ft_prepare_sourcemodel.m +++ b/external/fieldtrip/ft_prepare_sourcemodel.m @@ -1,6 +1,6 @@ function [grid, cfg] = ft_prepare_sourcemodel(cfg, headmodel, sens) -% FT_PREPARE_SOURCEMODEL constructs a source model, for example a 3-D grid or a +% FT_PREPARE_SOURCEMODEL constructs a source model, for example a 3D grid or a % cortical sheet. The source model that can be used for source reconstruction, % beamformer scanning, linear estimation and MEG interpolation. % @@ -22,7 +22,7 @@ % The approach that will be used depends on the configuration options that % you specify. % -% Configuration options for generating a regular 3-D grid +% Configuration options for generating a regular 3D grid % cfg.grid.xgrid = vector (e.g. -20:1:20) or 'auto' (default = 'auto') % cfg.grid.ygrid = vector (e.g. -20:1:20) or 'auto' (default = 'auto') % cfg.grid.zgrid = vector (e.g. 0:1:20) or 'auto' (default = 'auto') @@ -31,7 +31,7 @@ % Configuration options for a predefined grid % cfg.grid.pos = N*3 matrix with position of each source % cfg.grid.inside = N*1 vector with boolean value whether grid point is inside brain (optional) -% cfg.grid.dim = [Nx Ny Nz] vector with dimensions in case of 3-D grid (optional) +% cfg.grid.dim = [Nx Ny Nz] vector with dimensions in case of 3D grid (optional) % % The following fields are not used in this function, but will be copied along to the output % cfg.grid.leadfield @@ -81,6 +81,7 @@ % cfg.symmetry = 'x', 'y' or 'z' symmetry for two dipoles, can be empty (default = []) % cfg.headshape = a filename for the headshape, a structure containing a single surface, % or a Nx3 matrix with headshape surface points (default = []) +% cfg.spmversion = string, 'spm2', 'spm8', 'spm12' (default = 'spm8') % % See also FT_PREPARE_LEADFIELD, FT_PREPARE_HEADMODEL, FT_SOURCEANALYSIS, % FT_DIPOLEFITTING, FT_MEGREALIGN @@ -137,8 +138,8 @@ cfg.spherify = ft_getopt(cfg, 'spherify', 'no'); cfg.headshape = ft_getopt(cfg, 'headshape', []); cfg.symmetry = ft_getopt(cfg, 'symmetry', []); -cfg.grid = ft_getopt(cfg, 'grid', []); cfg.spmversion = ft_getopt(cfg, 'spmversion', 'spm8'); +cfg.grid = ft_getopt(cfg, 'grid', []); cfg.grid.unit = ft_getopt(cfg.grid, 'unit', 'auto'); % this code expects the inside to be represented as a logical array @@ -163,13 +164,13 @@ end if isfield(cfg.grid, 'resolution') && isfield(cfg.grid, 'xgrid') && ~ischar(cfg.grid.xgrid) - error('You cannot specify cfg.grid.resolution and an explicit cfg.grid.xgrid simultaneously'); + ft_error('You cannot specify cfg.grid.resolution and an explicit cfg.grid.xgrid simultaneously'); end if isfield(cfg.grid, 'resolution') && isfield(cfg.grid, 'ygrid') && ~ischar(cfg.grid.ygrid) - error('You cannot specify cfg.grid.resolution and an explicit cfg.grid.ygrid simultaneously'); + ft_error('You cannot specify cfg.grid.resolution and an explicit cfg.grid.ygrid simultaneously'); end if isfield(cfg.grid, 'resolution') && isfield(cfg.grid, 'zgrid') && ~ischar(cfg.grid.zgrid) - error('You cannot specify cfg.grid.resolution and an explicit cfg.grid.zgrid simultaneously'); + ft_error('You cannot specify cfg.grid.resolution and an explicit cfg.grid.zgrid simultaneously'); end % the source model can be constructed in a number of ways @@ -253,18 +254,12 @@ % these are mutually exclusive if sum([basedonresolution basedongrid basedonpos basedonshape basedonmri basedonvol basedoncortex basedonmni])~=1 - error('incorrect cfg specification for constructing a dipole grid'); + ft_error('incorrect cfg specification for constructing a dipole grid'); end if (isfield(cfg, 'smooth') && ~strcmp(cfg.smooth, 'no')) || basedonmni - % check that SPM is on the path, try to add the preferred version - if strcmpi(cfg.spmversion, 'spm2'), - ft_hastoolbox('SPM2', 1); - elseif strcmpi(cfg.spmversion, 'spm8'), - ft_hastoolbox('SPM8', 1); - elseif strcmpi(cfg.spmversion, 'spm12'), - ft_hastoolbox('SPM12', 1); - end + % check that the preferred SPM version is on the path + ft_hastoolbox(cfg.spmversion, 1); end % start with an empty grid @@ -287,8 +282,8 @@ if strcmp(cfg.grid.unit, 'auto') if isfield(cfg.grid, 'pos') && size(cfg.grid.pos,1)>10 % estimate the units based on the existing source positions - cfg.grid = rmfield(cfg.grid, 'unit'); % remove 'auto' and have ft_convert_units determine it properly - cfg.grid = ft_convert_units(cfg.grid); + cfg.grid = rmfield(cfg.grid, 'unit'); % remove 'auto' and have ft_determine_units determine it properly + cfg.grid = ft_determine_units(cfg.grid); elseif ~isempty(sens) % copy the units from the sensor array cfg.grid.unit = sens.unit; @@ -296,7 +291,7 @@ % copy the units from the volume conduction model cfg.grid.unit = headmodel.unit; else - warning('assuming "cm" as default source units'); + ft_warning('assuming "cm" as default source units'); cfg.grid.unit = 'cm'; end end @@ -316,32 +311,43 @@ % construct a regular 3D grid that spans a box encompassing all electrode % or gradiometer coils, this will typically also cover the complete brain %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - if ~isempty(sens) + if ~isempty(sens) && isfield(headmodel, 'chanpos') + % determine the bounding box of the sensor array minpos = min(sens.chanpos,[],1); maxpos = max(sens.chanpos,[],1); elseif ~isempty(headmodel) - minpos = [inf inf inf]; - maxpos = [-inf -inf -inf]; - for k = 1:numel(headmodel.bnd) - tmpbnd = headmodel.bnd(k); - if ~isfield(tmpbnd, 'pnt') && isfield(tmpbnd, 'pos') - pos = tmpbnd.pos; - elseif isfield(tmpbnd, 'pnt') && ~isfield(tmpbnd, 'pos') - pos = tmpbnd.pnt; - end - minpos = min(minpos, min(pos,[],1)); - maxpos = max(maxpos, max(pos,[],1)); + % determine the bounding box of the volume conduction model + if isfield(headmodel, 'bnd') && isfield(headmodel.bnd, 'pos') + pos = cat(1, headmodel.bnd(:).pos); + elseif isfield(headmodel, 'bnd') && isfield(headmodel.bnd, 'pnt') + pos = cat(1, headmodel.bnd(:).pnt); + elseif isfield(headmodel, 'pos') + pos = headmodel.pos; + elseif ft_voltype(headmodel, 'localspheres') + pos = headsurface(headmodel, sens); + elseif ft_voltype(headmodel, 'singlesphere') + pos = [ + headmodel.o - headmodel.r + headmodel.o + headmodel.r + ]; + elseif ft_voltype(headmodel, 'concentricspheres') + pos = [ + headmodel.o - max(headmodel.r) + headmodel.o + max(headmodel.r) + ]; end - - % add a few % on either side + minpos = min(pos,[],1); + maxpos = max(pos,[],1); + % add a few percent on either side minpos(minpos<0) = minpos(minpos<0).*1.08; maxpos(maxpos>0) = maxpos(maxpos>0).*1.08; minpos(minpos>0) = minpos(minpos>0).*0.92; maxpos(maxpos<0) = maxpos(maxpos<0).*0.92; else - error('creating a 3D-grid sourcemodel this way requires either sensor position information or a headmodel to estimate the extent of the brain'); + ft_error('creating a 3D grid based on resolution requires either sensor positions or a headmodel to estimate the extent'); end - fprintf('creating dipole grid with %g %s resolution\n', cfg.grid.resolution, cfg.grid.unit); + + fprintf('creating 3D grid with %g %s resolution\n', cfg.grid.resolution, cfg.grid.unit); % round the bounding box limits to the nearest cm switch cfg.grid.unit @@ -369,6 +375,7 @@ [X, Y, Z] = ndgrid(grid.xgrid, grid.ygrid, grid.zgrid); grid.pos = [X(:) Y(:) Z(:)]; grid.unit = cfg.grid.unit; + fprintf('initial 3D grid dimensions are [%d %d %d]\n', grid.dim(1), grid.dim(2), grid.dim(3)); end if basedongrid @@ -407,7 +414,7 @@ % ensure the mri to have units if ~isfield(mri, 'unit') - mri = ft_convert_units(mri); + mri = ft_determine_units(mri); end if ~isfield(cfg.grid, 'resolution') @@ -466,7 +473,7 @@ end dat = double(dat); else - error('cannot determine the format of the segmentation in cfg.mri'); + ft_error('cannot determine the format of the segmentation in cfg.mri'); end @@ -549,7 +556,7 @@ % read the headshape from file headshape = ft_read_headshape(cfg.headshape); else - error('cfg.headshape is not specified correctly') + ft_error('cfg.headshape is not specified correctly') end % ensure that the headshape is in the same units as the source headshape = ft_convert_units(headshape, cfg.grid.unit); @@ -578,7 +585,7 @@ if basedonmni if ~isfield(cfg.grid, 'template') && ~isfield(cfg.grid, 'resolution') - error('you either need to specify the filename of a template grid in cfg.grid.template, or a resolution in cfg.grid.resolution'); + ft_error('you either need to specify the filename of a template grid in cfg.grid.template, or a resolution in cfg.grid.resolution'); elseif isfield(cfg.grid, 'template') % let the template filename prevail fname = cfg.grid.template; @@ -598,7 +605,7 @@ % get the mri if ischar(cfg.mri) if ~exist(fname, 'file') - error('the MNI template grid based on the specified resolution does not exist'); + ft_error('the MNI template grid based on the specified resolution does not exist'); end mri = ft_read_mri(cfg.mri); else @@ -657,7 +664,7 @@ if strcmp(cfg.spherify, 'yes') if ~ft_voltype(headmodel, 'singlesphere') && ~ft_voltype(headmodel, 'concentricspheres') - error('this only works for spherical volume conduction models'); + ft_error('this only works for spherical volume conduction models'); end % deform the cortex so that it fits in a unit sphere pos = mesh_spherify(grid.pos, [], 'shift', 'range'); @@ -726,7 +733,7 @@ if ~isempty(cfg.symmetry) if size(grid.pos,2)>3 % sanity check, see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=3119 - warning('the construction of a symmetric dipole model requires to start with a Nx3 description of the dipole positions, discarding subsequent columns'); + ft_warning('the construction of a symmetric dipole model requires to start with a Nx3 description of the dipole positions, discarding subsequent columns'); grid.pos = grid.pos(:,1:3); end if strcmp(cfg.symmetry, 'x') @@ -742,7 +749,7 @@ expand = [1 2 3 1 2 3]; % repeat them as [x1 y1 z1 x1 y1 z1] mirror = [1 1 1 1 1 -1]; % multiply each of them with 1 or -1, resulting in [x1 y1 z1 x1 y1 else - error('unrecognized symmetry constraint'); + ft_error('unrecognized symmetry constraint'); end fprintf('each source describes two dipoles with symmetry along %s axis\n', cfg.symmetry); % expand the number of parameters from one (3) to two dipoles (6) @@ -771,7 +778,7 @@ inside = mask(sub2ind(dim, pos(:,1), pos(:,2), pos(:,3))); else % only loop over the points that can be dealt with - inside = zeros(size(pos,1), 1); + inside = false(size(pos,1), 1); for i=setdiff(1:size(pos,1), sel(:)') inside(i) = mask(pos(i,1), pos(i,2), pos(i,3)); end diff --git a/external/fieldtrip/ft_preprocessing.m b/external/fieldtrip/ft_preprocessing.m index 1605c471..50fee354 100644 --- a/external/fieldtrip/ft_preprocessing.m +++ b/external/fieldtrip/ft_preprocessing.m @@ -31,10 +31,9 @@ % cfg.datafile = string with the filename % cfg.headerfile = string with the filename % -% If you are calling FT_PREPROCESSING with also the second input argument -% "data", then that should contain data that was already read from file in -% a previous call to FT_PREPROCESSING. In that case only the configuration -% options below apply. +% If you are calling FT_PREPROCESSING with the second input argument "data", then +% that should contain data that was already read from file in a previous call to +% FT_PREPROCESSING. In that case only the configuration options below apply. % % The channels that will be read and/or preprocessed are specified with % cfg.channel = Nx1 cell-array with selection of channels (default = 'all'), @@ -49,7 +48,7 @@ % cfg.medianfilter = 'no' or 'yes' jump preserving median filter (default = 'no') % cfg.lpfreq = lowpass frequency in Hz % cfg.hpfreq = highpass frequency in Hz -% cfg.bpfreq = bandpass frequency range, specified as [low high] in Hz +% cfg.bpfreq = bandpass frequency range, specified as [lowFreq highFreq] in Hz % cfg.bsfreq = bandstop frequency range, specified as [low high] in Hz % cfg.dftfreq = line noise frequencies in Hz for DFT filter (default = [50 100 150]) % cfg.lpfiltord = lowpass filter order (default set in low-level function) @@ -80,6 +79,9 @@ % cfg.hpfiltdev = highpass max passband deviation (firws with 'kaiser' window, default 0.001 set in low-level function) % cfg.bpfiltdev = bandpass max passband deviation (firws with 'kaiser' window, default 0.001 set in low-level function) % cfg.bsfiltdev = bandstop max passband deviation (firws with 'kaiser' window, default 0.001 set in low-level function) +% cfg.dftreplace = 'zero' or 'neighbour', method used to reduce line noise, 'zero' implies DFT filter, 'neighbour' implies spectrum interpolation (default = 'zero') +% cfg.dftbandwidth = bandwidth of line noise frequencies, applies to spectrum interpolation, in Hz (default = [1 2 3]) +% cfg.dftneighbourwidth = bandwidth of frequencies neighbouring line noise frequencies, applies to spectrum interpolation, in Hz (default = [2 2 2]) % cfg.plotfiltresp = 'no' or 'yes', plot filter responses (firws, default = 'no') % cfg.usefftfilt = 'no' or 'yes', use fftfilt instead of filter (firws, default = 'no') % cfg.medianfiltord = length of median filter (default = 9) @@ -198,34 +200,37 @@ cfg = ft_checkconfig(cfg, 'renamed', {'output', 'export'}); % set the defaults -cfg.method = ft_getopt(cfg, 'method', 'trial'); -cfg.channel = ft_getopt(cfg, 'channel', 'all'); -cfg.removemcg = ft_getopt(cfg, 'removemcg', 'no'); -cfg.removeeog = ft_getopt(cfg, 'removeeog', 'no'); -cfg.precision = ft_getopt(cfg, 'precision', 'double'); -cfg.padding = ft_getopt(cfg, 'padding', 0); % padding is only done when filtering -cfg.paddir = ft_getopt(cfg, 'paddir', 'both'); -cfg.headerformat = ft_getopt(cfg, 'headerformat'); % is passed to low-level function, empty implies autodetection -cfg.dataformat = ft_getopt(cfg, 'dataformat'); % is passed to low-level function, empty implies autodetection -cfg.coordsys = ft_getopt(cfg, 'coordsys', 'head'); % is passed to low-level function -cfg.coilaccuracy = ft_getopt(cfg, 'coilaccuracy'); % is passed to low-level function +cfg.method = ft_getopt(cfg, 'method', 'trial'); +cfg.channel = ft_getopt(cfg, 'channel', 'all'); +cfg.removemcg = ft_getopt(cfg, 'removemcg', 'no'); +cfg.removeeog = ft_getopt(cfg, 'removeeog', 'no'); +cfg.precision = ft_getopt(cfg, 'precision', 'double'); +cfg.padding = ft_getopt(cfg, 'padding', 0); % padding is only done when filtering +cfg.paddir = ft_getopt(cfg, 'paddir', 'both'); +cfg.headerformat = ft_getopt(cfg, 'headerformat'); % is passed to low-level function, empty implies autodetection +cfg.dataformat = ft_getopt(cfg, 'dataformat'); % is passed to low-level function, empty implies autodetection +cfg.coordsys = ft_getopt(cfg, 'coordsys', 'head'); % is passed to low-level function +cfg.coilaccuracy = ft_getopt(cfg, 'coilaccuracy'); % is passed to low-level function +cfg.checkmaxfilter = ft_getopt(cfg, 'checkmaxfilter'); % this allows to read non-maxfiltered neuromag data recorded with internal active shielding +cfg.montage = ft_getopt(cfg, 'montage', 'no'); +cfg.updatesens = ft_getopt(cfg, 'updatesens', 'no'); % in case a montage or rereferencing is specified % these options relate to the actual preprocessing, it is neccessary to specify here because of padding -cfg.dftfilter = ft_getopt(cfg, 'dftfilter', 'no'); -cfg.lpfilter = ft_getopt(cfg, 'lpfilter', 'no'); -cfg.hpfilter = ft_getopt(cfg, 'hpfilter', 'no'); -cfg.bpfilter = ft_getopt(cfg, 'bpfilter', 'no'); -cfg.bsfilter = ft_getopt(cfg, 'bsfilter', 'no'); -cfg.medianfilter = ft_getopt(cfg, 'medianfilter', 'no'); -cfg.padtype = ft_getopt(cfg, 'padtype', 'data'); +cfg.dftfilter = ft_getopt(cfg, 'dftfilter', 'no'); +cfg.lpfilter = ft_getopt(cfg, 'lpfilter', 'no'); +cfg.hpfilter = ft_getopt(cfg, 'hpfilter', 'no'); +cfg.bpfilter = ft_getopt(cfg, 'bpfilter', 'no'); +cfg.bsfilter = ft_getopt(cfg, 'bsfilter', 'no'); +cfg.medianfilter = ft_getopt(cfg, 'medianfilter', 'no'); +cfg.padtype = ft_getopt(cfg, 'padtype', 'data'); % these options relate to the actual preprocessing, it is neccessary to specify here because of channel selection -cfg.reref = ft_getopt(cfg, 'reref', 'no'); -cfg.refchannel = ft_getopt(cfg, 'refchannel', {}); -cfg.refmethod = ft_getopt(cfg, 'refmethod', 'avg'); -cfg.implicitref = ft_getopt(cfg, 'implicitref'); +cfg.reref = ft_getopt(cfg, 'reref', 'no'); +cfg.refchannel = ft_getopt(cfg, 'refchannel', {}); +cfg.refmethod = ft_getopt(cfg, 'refmethod', 'avg'); +cfg.implicitref = ft_getopt(cfg, 'implicitref'); -if ~isfield(cfg, 'feedback'), +if ~isfield(cfg, 'feedback') if strcmp(cfg.method, 'channel') cfg.feedback = 'none'; else @@ -234,28 +239,28 @@ end % support for the following options was removed on 20 August 2004 in Revision 1.46 -if isfield(cfg, 'emgchannel'), error('EMG specific preprocessing is not supported any more'); end -if isfield(cfg, 'emghpfreq'), error('EMG specific preprocessing is not supported any more'); end -if isfield(cfg, 'emgrectify'), error('EMG specific preprocessing is not supported any more'); end -if isfield(cfg, 'emghilbert'), error('EMG specific preprocessing is not supported any more'); end -if isfield(cfg, 'eegchannel'), error('EEG specific preprocessing is not supported any more'); end -if isfield(cfg, 'resamplefs'), error('resampling is not supported any more, see RESAMPLEDATA'); end +if isfield(cfg, 'emgchannel'), ft_error('EMG specific preprocessing is not supported any more'); end +if isfield(cfg, 'emghpfreq'), ft_error('EMG specific preprocessing is not supported any more'); end +if isfield(cfg, 'emgrectify'), ft_error('EMG specific preprocessing is not supported any more'); end +if isfield(cfg, 'emghilbert'), ft_error('EMG specific preprocessing is not supported any more'); end +if isfield(cfg, 'eegchannel'), ft_error('EEG specific preprocessing is not supported any more'); end +if isfield(cfg, 'resamplefs'), ft_error('resampling is not supported any more, see RESAMPLEDATA'); end if isfield(cfg, 'lnfilter') && strcmp(cfg.lnfilter, 'yes') - error('line noise filtering using the option cfg.lnfilter is not supported any more, use cfg.bsfilter instead') + ft_error('line noise filtering using the option cfg.lnfilter is not supported any more, use cfg.bsfilter instead') end % this relates to a previous fix to handle 32 bit neuroscan data -if isfield(cfg, 'nsdf'), +if isfield(cfg, 'nsdf') % FIXME this should be handled by ft_checkconfig, but ft_checkconfig does not allow yet for % specific errors in the case of forbidden fields - error('The use of cfg.nsdf is deprecated. FieldTrip tries to determine the bit resolution automatically. You can overrule this by specifying cfg.dataformat and cfg.headerformat. See: http://www.fieldtriptoolbox.org/faq/i_have_problems_reading_in_neuroscan_.cnt_files._how_can_i_fix_this'); + ft_error('The use of cfg.nsdf is deprecated. FieldTrip tries to determine the bit resolution automatically. You can overrule this by specifying cfg.dataformat and cfg.headerformat. See: http://www.fieldtriptoolbox.org/faq/i_have_problems_reading_in_neuroscan_.cnt_files._how_can_i_fix_this'); end if isfield(cfg, 'export') && ~isempty(cfg.export) % export the data to an output file if ~strcmp(cfg.method, 'trial') - error('exporting to an output file is only possible when processing all channels at once') + ft_error('exporting to an output file is only possible when processing all channels at once') end end @@ -302,10 +307,10 @@ % some options don't make sense on component data if isfield(data, 'comp') if ~isempty(cfg.montage) - error('the application of a montage on component data is not supported'); + ft_error('the application of a montage on component data is not supported'); end if strcmp(cfg.reref, 'yes') - error('rereferencing component data is not supported'); + ft_error('rereferencing component data is not supported'); end end @@ -313,7 +318,7 @@ cfg.trials = ft_getopt(cfg, 'trials', 'all', 1); % select trials of interest - tmpcfg = keepfields(cfg, {'channel', 'trials'}); + tmpcfg = keepfields(cfg, {'channel', 'trials', 'showcallinfo'}); data = ft_selectdata(tmpcfg, data); % restore the provenance information [cfg, data] = rollback_provenance(cfg, data); @@ -335,6 +340,9 @@ % the trial is already longer than the total length requested begpadding = 0; endpadding = 0; + if padding > 0 + ft_warning('no padding applied because the padding duration is shorter than the trial'); + end else switch cfg.paddir case 'both' @@ -348,7 +356,7 @@ begpadding = 0; endpadding = padding-nsamples; otherwise - error('unsupported requested direction of padding'); + ft_error('unsupported requested direction of padding'); end end @@ -359,16 +367,6 @@ end % for all trials - if isfield(dataout, 'grad') && isfield(cfg, 'montage') && ~strcmp(cfg.montage, 'no') && isstruct(cfg.montage) - % apply the montage also to the MEG-sensor description - if isfield(cfg.montage, 'type'), - bname = cfg.montage.type; - else - bname = 'preproc'; - end - dataout.grad = ft_apply_montage(dataout.grad, cfg.montage, 'feedback', 'none', 'keepunused', 'yes', 'balancename', bname); - end - % convert back to input type if necessary switch convert case 'timelock' @@ -384,7 +382,7 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% if isfield(cfg, 'trialdef') && ~isfield(cfg, 'trl') - error('you must call FT_DEFINETRIAL prior to FT_PREPROCESSING'); + ft_error('you must call FT_DEFINETRIAL prior to FT_PREPROCESSING'); end % check if the input cfg is valid for this function @@ -394,7 +392,7 @@ cfg = ft_checkconfig(cfg, 'renamedval', {'continuous', 'continuous', 'yes'}); % read the header - hdr = ft_read_header(cfg.headerfile, 'headerformat', cfg.headerformat, 'coordsys', cfg.coordsys, 'coilaccuracy', cfg.coilaccuracy); + hdr = ft_read_header(cfg.headerfile, 'headerformat', cfg.headerformat, 'coordsys', cfg.coordsys, 'coilaccuracy', cfg.coilaccuracy, 'checkmaxfilter', istrue(cfg.checkmaxfilter)); % this option relates to reading over trial boundaries in a pseudo-continuous dataset if ~isfield(cfg, 'continuous') @@ -435,12 +433,13 @@ % do a sanity check for the re-referencing if strcmp(cfg.reref, 'no') && ~isempty(cfg.refchannel) - warning('no re-referencing is performed'); + ft_warning('no re-referencing is performed'); cfg.refchannel = {}; end % translate the channel groups (like 'all' and 'MEG') into real labels - cfg.channel = ft_channelselection(cfg.channel, hdr.label); + cfg.channel = ft_channelselection(cfg.channel, hdr); + assert(~isempty(cfg.channel), 'the selection of channels is empty'); if ~isempty(cfg.implicitref) % add the label of the implicit reference channel to these cell-arrays @@ -474,12 +473,12 @@ any(strmatch('rejectmuscle', fieldnames(cfg))) || ... any(strmatch('rejectjump', fieldnames(cfg))) % this is only for backward compatibility - error('you should call FT_REJECTARTIFACT prior to FT_PREPROCESSING, please update your scripts'); + ft_error('you should call FT_REJECTARTIFACT prior to FT_PREPROCESSING, please update your scripts'); end ntrl = size(cfg.trl,1); if ntrl<1 - error('no trials were selected for preprocessing, see FT_DEFINETRIAL for help'); + ft_error('no trials were selected for preprocessing, see FT_DEFINETRIAL for help'); end % compute the template for MCG and the QRS latency indices, and add it to the configuration @@ -488,7 +487,7 @@ mcgchannel = ft_channelselection(cfg.artfctdef.mcg.channel, hdr.label); mcgindx = match_str(cfg.channel, mcgchannel); for i=1:length(mcgchannel) - fprintf('removing mcg on channel %s\n', mcgchannel{i}); + ft_info('removing mcg on channel %s\n', mcgchannel{i}); end end @@ -506,7 +505,7 @@ rawloop = {rawindx}; else - error('unsupported option for cfg.method'); + ft_error('unsupported option for cfg.method'); end for j=1:length(chnloop) @@ -515,7 +514,7 @@ chnindx = chnloop{j}; rawindx = rawloop{j}; - fprintf('processing channel { %s}\n', sprintf('''%s'' ', hdr.label{rawindx})); + ft_info('processing channel { %s}\n', sprintf('''%s'' ', hdr.label{rawindx})); % initialize cell arrays cutdat = cell(1, ntrl); @@ -534,6 +533,9 @@ offset = cfg.trl(i,3); begpadding = 0; endpadding = 0; + if padding > 0 + ft_warning('no padding applied because the padding duration is shorter than the trial'); + end else switch cfg.paddir case 'both' @@ -547,7 +549,7 @@ begpadding = 0; endpadding = padding-nsamples; otherwise - error('unsupported requested direction of padding'); + ft_error('unsupported requested direction of padding'); end if strcmp(cfg.padtype, 'data'); @@ -559,12 +561,12 @@ endsample = cfg.trl(i,2); end if begsample<1 - warning('cannot apply enough padding at begin of file'); + ft_warning('cannot apply enough padding at begin of file'); begpadding = begpadding - (1 - begsample); begsample = 1; end if endsample>(hdr.nSamples*hdr.nTrials) - warning('cannot apply enough padding at end of file'); + ft_warning('cannot apply enough padding at end of file'); endpadding = endpadding - (endsample - hdr.nSamples*hdr.nTrials); endsample = hdr.nSamples*hdr.nTrials; end @@ -629,19 +631,53 @@ dataout.trialinfo = cfg.trl(:,4:end); end if isfield(hdr, 'grad') - dataout.grad = hdr.grad; % gradiometer system in head coordinates + dataout.grad = hdr.grad; % MEG gradiometer information in header (f.e. headerformat = 'ctf_ds') end if isfield(hdr, 'elec') - dataout.elec = hdr.elec; % EEG information in header (f.e. headerformat = 'neuromag_fif') + dataout.elec = hdr.elec; % EEG electrode information in header (f.e. headerformat = 'neuromag_fif') end if isfield(hdr, 'opto') - dataout.opto = hdr.opto; % NIRS information in header (f.e. headerformat = 'artinis') + dataout.opto = hdr.opto; % NIRS optode information in header (f.e. headerformat = 'artinis') end end % for all channel groups end % if hasdata +if strcmp(cfg.updatesens, 'yes') + % updating the sensor descriptions can be done on basis of the montage or the rereference settings + if ~isempty(cfg.montage) && ~isequal(cfg.montage, 'no') + montage = cfg.montage; + elseif strcmp(cfg.reref, 'yes') + tmpcfg = keepfields(cfg, {'reref', 'implicitref', 'refchannel', 'channel'}); + montage = ft_prepare_montage(tmpcfg, data); + else + % do not update anything + montage = []; + end + + if ~isempty(montage) + % apply the linear projection also to the sensor description + if issubfield(montage, 'type') + bname = montage.type; + else + bname = 'preproc'; + end + if isfield(dataout, 'grad') + ft_info('applying the montage to the grad structure\n'); + dataout.grad = ft_apply_montage(dataout.grad, montage, 'feedback', 'none', 'keepunused', 'no', 'balancename', bname); + end + if isfield(dataout, 'elec') + ft_info('applying the montage to the grad structure\n'); + dataout.elec = ft_apply_montage(dataout.elec, montage, 'feedback', 'none', 'keepunused', 'no', 'balancename', bname); + end + if isfield(dataout, 'opto') + ft_info('applying the montage to the opto structure\n'); + dataout.opto = ft_apply_montage(dataout.opto, montage, 'feedback', 'none', 'keepunused', 'no', 'balancename', bname); + end + end +end % if updatesens + % do the general cleanup and bookkeeping at the end of the function ft_postamble debug ft_postamble trackconfig diff --git a/external/fieldtrip/ft_qualitycheck.m b/external/fieldtrip/ft_qualitycheck.m index 56c2019d..b702cf8e 100644 --- a/external/fieldtrip/ft_qualitycheck.m +++ b/external/fieldtrip/ft_qualitycheck.m @@ -195,7 +195,7 @@ summary.avg = NaN(length(summary.label), ntrials); % updated in loop % try add gradiometer info - if isfield(info.hdr, 'grad'), + if isfield(info.hdr, 'grad') timelock.grad = info.hdr.grad; freq.grad = info.hdr.grad; summary.grad = info.hdr.grad; @@ -295,11 +295,10 @@ fprintf('visualizing %s of %s \n', num2str(p), num2str(nplots)); toi = [p*cfg.plotunit-(cfg.plotunit-5) p*cfg.plotunit-5]; % select 1-hour chunks - tmpcfg.toi = toi; - temp_timelock = ft_selectdata(tmpcfg, timelock); - temp_timelock.cfg = cfg; % be sure to add the cfg here - temp_freq = ft_selectdata(tmpcfg, freq); - temp_summary = ft_selectdata(tmpcfg, summary); + tmpcfg.latency = toi; + temp_timelock = ft_selectdata(tmpcfg, timelock); + temp_freq = ft_selectdata(tmpcfg, freq); + temp_summary = ft_selectdata(tmpcfg, summary); if exist('headpos','var') temp_headpos = ft_selectdata(tmpcfg, headpos); draw_figure(info, temp_timelock, temp_freq, temp_summary, temp_headpos, toi); diff --git a/external/fieldtrip/ft_recodeevent.m b/external/fieldtrip/ft_recodeevent.m index c3b2546c..4a025cca 100644 --- a/external/fieldtrip/ft_recodeevent.m +++ b/external/fieldtrip/ft_recodeevent.m @@ -111,12 +111,12 @@ trl = []; end if isempty(event) - error('could not locate event structure in the data'); + ft_error('could not locate event structure in the data'); elseif isempty(trl) - error('could not locate trial definition in the data'); + ft_error('could not locate trial definition in the data'); end elseif nargin~=3 - error('incorrect number of input arguments'); + ft_error('incorrect number of input arguments'); end Ntrl = size(trl,1); @@ -149,7 +149,7 @@ Nevent = length(event); if Nevent<1 - error('there are no events to analyze'); + ft_error('there are no events to analyze'); end % make a list with the sample, offset and duration of each event @@ -189,7 +189,7 @@ elseif strcmp(cfg.nearestto, 'trialend') trlsample = trlend; % the sample at which the trial ends else - error('incorrect specification of cfg.nearestto') + ft_error('incorrect specification of cfg.nearestto') end % compute a "distance" measure for each event towards this trial @@ -215,13 +215,13 @@ distance = abs(sample - trlsample); distance(find((sample>=trlbeg) & (sample<=trlend))) = inf; otherwise - error('incorrect specification of cfg.searchrange'); + ft_error('incorrect specification of cfg.searchrange'); end % determine the event that has the shortest distance towards this trial [mindist, minindx] = min(distance); if length(find(distance==mindist))>1 - error('multiple events are at the same distance from the trial'); + ft_error('multiple events are at the same distance from the trial'); end if isinf(mindist) @@ -247,7 +247,7 @@ case 'samplefromend' ev(i) = event(minindx).sample - trlend; otherwise - error('incorrect specification of cfg.output'); + ft_error('incorrect specification of cfg.output'); end end diff --git a/external/fieldtrip/ft_redefinetrial.m b/external/fieldtrip/ft_redefinetrial.m index e3d5daa2..b3f7a48f 100644 --- a/external/fieldtrip/ft_redefinetrial.m +++ b/external/fieldtrip/ft_redefinetrial.m @@ -10,7 +10,7 @@ % where the input data should correspond to the output of FT_PREPROCESSING and % the configuration should be specified as explained below. Note that some % options are mutually exclusive, and require two calls to this function to -% avoid confucion about the order in which they are applied. +% avoid confusion about the order in which they are applied. % % For selecting a subset of trials you can specify % cfg.trials = 'all' or a selection given as a 1xN vector (default = 'all') @@ -122,7 +122,7 @@ if fb, fprintf('selecting %d trials\n', length(cfg.trials)); end % select trials of interest - tmpcfg = keepfields(cfg, 'trials'); + tmpcfg = keepfields(cfg, {'trials', 'showcallinfo'}); data = ft_selectdata(tmpcfg, data); % restore the provenance information [cfg, data] = rollback_provenance(cfg, data); @@ -142,10 +142,10 @@ % check the input arguments, only one method for processing is allowed numoptions = ~isempty(cfg.toilim) + ~isempty(cfg.offset) + (~isempty(cfg.begsample) || ~isempty(cfg.endsample)) + ~isempty(cfg.trl) + ~isempty(cfg.length); if numoptions>1 - error('you should specify only one of the options for redefining the data segments'); + ft_error('you should specify only one of the options for redefining the data segments'); end if numoptions==0 && isempty(cfg.minlength) && strcmp(cfg.trials, 'all') - error('you should specify at least one configuration option'); + ft_error('you should specify at least one configuration option'); end % start processing @@ -170,7 +170,7 @@ end % also correct the sample information - if isfield(data, 'sampleinfo'), + if isfield(data, 'sampleinfo') data.sampleinfo(:, 1) = data.sampleinfo(:, 1) + begsample - 1; data.sampleinfo(:, 2) = data.sampleinfo(:, 1) + endsample - begsample; end @@ -238,6 +238,10 @@ data.trial = cell(1,size(trl,1)); data.time = cell(1,size(trl,1)); data = copyfields(dataold, data, {'fsample' 'label' 'topo' 'topolabel' 'unmixing' 'mixing' 'grad' 'elec' 'opto'}); % account for all potential fields to be copied over + + if isfield(dataold,'trialinfo') + ft_warning('Original data has trialinfo, using user specified trialinfo instead'); + end for iTrl=1:length(trl(:,1)) begsample = trl(iTrl,1); @@ -251,19 +255,18 @@ % ensure correct handling of trialinfo. % original trial iTrlorig = find(begsample <= dataold.sampleinfo(:,2) & endsample >= dataold.sampleinfo(:,1)); % Determines which old trials are present in new trials - + if size(cfg.trl,2)>3 %In case user specified a trialinfo data.trialinfo(iTrl,:) = cfg.trl(iTrl,4:end); - if isfield(dataold,'trialinfo') - ft_warning('Original data has trialinfo, using user specified trialinfo instead'); - end; elseif isfield(dataold,'trialinfo') % If old data has trialinfo - if isequal(dataold.trialinfo(iTrlorig,:),1) || numel(iTrlorig)==1 % Checks whether trials that are combined have same trialinfo + if (numel(iTrlorig) == 1 ... % only 1 old trial to copy trialinfo from, or + || size(unique(dataold.trialinfo(iTrlorig,:),'rows'),1)) ... % all old trialinfo rows are identical + && ~any(diff(dataold.sampleinfo(:,1))<=0) % and the trials are consecutive segments data.trialinfo(iTrl,:) = dataold.trialinfo(iTrlorig(1),:); else - error('Old trialinfo cannot be combined into new trialinfo, please specify trialinfo in cfg.trl(:,4)'); - end; - end; + ft_error('Old trialinfo cannot be combined into new trialinfo, please specify trialinfo in cfg.trl(:,4)'); + end + end end %for iTrl % adjust the sampleinfo in the output @@ -295,9 +298,11 @@ end end - tmpcfg = []; + tmpcfg = keepfields(cfg, {'showcallinfo'}); tmpcfg.trl = newtrl; data = ft_redefinetrial(tmpcfg, data); + % restore the provenance information + [cfg, data] = rollback_provenance(cfg, data); end % processing the realignment or data selection diff --git a/external/fieldtrip/ft_regressconfound.m b/external/fieldtrip/ft_regressconfound.m index 5535d609..2e5718e3 100644 --- a/external/fieldtrip/ft_regressconfound.m +++ b/external/fieldtrip/ft_regressconfound.m @@ -22,17 +22,15 @@ % are to be rejected (default = 'all') % cfg.normalize = string, 'yes' or 'no', normalization to % make the confounds orthogonal (default = 'yes') -% cfg.statistics = string, 'yes' or 'no', whether to add the statistics -% on the regression weights to the output (default = 'no') -% cfg.model = string, 'yes' or 'no', whether to add the model to -% the output (default = 'no') -% cfg.ftest = string array, {N X Nconfounds}, to F-test whether -% the full model explains more variance than reduced models -% (e.g. {'1 2'; '3 4'; '5'} where iteratively the added value of -% regressors 1 and 2, and then 3 and 4, etc., are tested) +% cfg.output = 'residual' (default), 'beta', or 'model'. +% If 'residual' is specified, the output is a data +% structure containing the residuals after regressing +% out the in cfg.reject listed confounds. If 'beta' or 'model' +% is specified, the output is a data structure containing +% the regression weights or the model, respectively. % % This method is described by Stolk et al., Online and offline tools for head -% movement compensation in MEG. NeuroImage, 2012. +% movement compensation in MEG (Neuroimage, 2013) % % To facilitate data-handling and distributed computing you can use % cfg.inputfile = ... @@ -44,7 +42,16 @@ % % See also FT_REJECTCOMPONENT, FT_REJECTARTIFACT -% Copyright (C) 2011, Arjen Stolk, Robert Oostenveld, Lennart Verhagen +% Undocumented local options: +% cfg.ftest = string array, {N X Nconfounds}, to F-test whether +% the full model explains more variance than reduced models +% (e.g. {'1 2'; '3 4'; '5'} where iteratively the added value of +% regressors 1 and 2, and then 3 and 4, etc., are tested) +% cfg.statistics = string, 'yes' or 'no', whether to add the statistics +% on the regression weights to the output (default = 'no', +% applies only when cfg.output = 'beta') + +% Copyright (C) 2011-2017, Arjen Stolk, Robert Oostenveld, Lennart Verhagen % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -85,21 +92,25 @@ % check if the input data is valid for this function datain = ft_checkdata(datain, 'datatype', {'timelock', 'freq', 'source'}, 'feedback', 'yes'); +if isfield(cfg, 'beta') || isfield(cfg, 'model') + ft_error('The options cfg.beta and cfg.model have been removed as of Aug 2017, please use cfg.output instead'); +end + % ensure that the required options are present -cfg = ft_checkconfig(cfg, 'required', {'confound'}, 'renamed', {'Ftest','ftest'}); +cfg = ft_checkconfig(cfg, 'required', {'confound'}, 'renamed', {'Ftest','ftest'}, 'forbidden', {'beta','model'}); % specify the defaults cfg.confound = ft_getopt(cfg, 'confound'); cfg.reject = ft_getopt(cfg, 'reject', 'all'); cfg.normalize = ft_getopt(cfg, 'normalize', 'yes'); -cfg.model = ft_getopt(cfg, 'model', 'no'); +cfg.output = ft_getopt(cfg, 'output', 'residual'); cfg.statistics = ft_getopt(cfg, 'statistics', 'no'); cfg.ftest = ft_getopt(cfg, 'ftest'); cfg.parameter = ft_getopt(cfg, 'parameter'); % the default is handled further down regr = cfg.confound; if any(isnan(regr(:))) - error('the confounds may not contain NaNs'); + ft_error('the confounds may not contain NaNs'); end nconf = size(regr,2); conflist = 1:nconf; @@ -147,7 +158,6 @@ nrpt = dimsiz(rptdim); - dat = datain.(cfg.parameter); if strcmp(dimtok{1}, '{pos}') indx = find(datain.inside); @@ -163,79 +173,6 @@ dat = reshape(dat, nrpt, []); -% determine datatype -isfreq = false; % ft_datatype(datain, 'freq'); -istimelock = false; % ft_datatype(datain, 'timelock'); -issource = false; % ft_datatype(datain, 'source'); - - -% input handling -if istimelock - switch datain.dimord - case {'rpt_chan_time', 'subj_chan_time'} - - % descriptives - nrpt = size(datain.trial, 1); - nchan = size(datain.trial, 2); - ntime = size(datain.trial, 3); - - if nrpt~=size(regr,1) - error('the size of your confound matrix does not match with the number of trials/subjects'); - end - - % get the data on which the contribution of the confounds has to be estimated - dat = reshape(datain.trial, [nrpt, nchan*ntime]); - - otherwise - error('unsupported timelock dimord "%s"', datain.dimord); - end % switch - -elseif isfreq - switch datain.dimord - case {'rpt_chan_freq_time', 'subj_chan_freq_time', 'rpttap_chan_freq_time', 'rpt_chan_freq', 'subj_chan_freq', 'rpttap_chan_freq'} - - % descriptives - nrpt = size(datain.powspctrm, 1); - nchan = size(datain.powspctrm, 2); - nfreq = size(datain.powspctrm, 3); - ntime = size(datain.powspctrm, 4); % this will be a singleton dimension in case there is no time - - if nrpt~=size(regr,1) - error('the size of your confound matrix does not match with the number of trials/subjects'); - end - - % get the data on which the contribution of the confounds has to be estimated - dat = reshape(datain.powspctrm, [nrpt, nchan*nfreq*ntime]); - - otherwise - error('unsupported freq dimord "%s"', datain.dimord); - end % switch - -elseif issource - - % ensure that the source structure contains inside/outside specification - datain = ft_checkdata(datain, 'datatype', 'source', 'hasinside', 'yes'); - - % descriptives - nrpt = size(datain.trial, 2); - nvox = size(datain.pos, 1); - ninside = size(datain.inside, 2); - - if nrpt~=size(regr,1) - error('the size of your confound matrix does not match with the number of trials/subjects'); - end - - % get the data on which the contribution of the confounds has to be estimated - dat = zeros(nrpt, ninside); - for i = 1:nrpt - dat(i,:) = datain.trial(1,i).pow(datain.inside); % reshape to [nrpt, nvox] - end - - % else - % error('the input data should be either timelock, freq, or source with trials') - -end - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % GLM MODEL % Y = X * B + err, where Y is data, X is the model, and B are beta's @@ -251,12 +188,9 @@ % estimate and remove the confounds fprintf('estimating the regression weights and removing the confounds \n'); -if isempty(find(isnan(dat))) % if there are no NaNs, process all at once - - beta = regr\dat; % B = X\Y - -else % otherwise process per colum set as defined by the nan distribution - +if isempty(find(isnan(dat))) % if there are no NaNs, process all at once + beta = regr\dat; % B = X\Y +else % otherwise process per colum set as defined by the nan distribution [u,i,j] = unique(~isnan(dat)','rows','first'); % find unique rows uniquecolumns = u'; % unique column types Nuniques = numel(i); % number of unique types @@ -269,38 +203,18 @@ end end beta = reshape(nansum(beta_temp,1),[nconf size(dat,2)]); % sum the betas - clear beta_temp; - + clear beta_temp end model = regr(:, cfg.reject) * beta(cfg.reject, :); % model = confounds * weights = X * X\Y Yc = dat - model; % Yclean = Y - X * X\Y -% beta statistics -if strcmp(cfg.statistics, 'yes') - - fprintf('performing statistics on the regression weights \n'); - dfe = nrpt - nconf; % degrees of freedom - err = dat - regr * beta; % err = Y - X * B - mse = sum((err).^2)/dfe; % mean squared error - covar = diag(regr'*regr)'; % regressor covariance - bvar = repmat(mse',1,size(covar,2))./repmat(covar,size(mse,2),1); % beta variance - tval = (beta'./sqrt(bvar))'; % betas -> t-values - prob = (1-tcdf(tval,dfe))*2; % p-values - clear err dfe mse bvar; - % FIXME: drop in replace tcdf from the statfun/private dir - -end - % reduced models analyses -if ~isempty(cfg.ftest) - +if ~isempty(cfg.ftest) dfe = nrpt - nconf; % degrees of freedom err = dat - regr * beta; % err = Y - X * B tmse = sum((err).^2)/dfe; % mean squared error - - for iter = 1:numel(cfg.ftest) - + for iter = 1:numel(cfg.ftest) % regressors to test if they explain additional variance r = str2num(cfg.ftest{iter}); fprintf('F-testing explained additional variance of regressors %s \n', num2str(r)); @@ -316,7 +230,7 @@ rerr = dat-rX*rb; % residual error rmse = sum(rerr'.^2,2)./rdfe; % mean squared error % F-test - F(iter,:) = ((rmse'-tmse)./(nconf-rnr)) ./ (tmse./(dfe-2)); + F(iter,:) = ((rmse'-tmse)./(nconf-rnr)) ./ (tmse./(dfe-2)); % Rik Henson defined F-test % F = ( ( rerr'*rerr - err'*err ) / ( nconf-rnr ) ) / ( err'*err/ ( nrpt-nconf ) ); % convert F-value to p-value @@ -326,185 +240,57 @@ p(iter,idx_pos) = (1-fcdf(F(iter,idx_pos),rnr,rdfe)); p(iter,idx_neg) = fcdf(-F(iter,idx_neg),rnr,rdfe); clear rerr rmse - % FIXME: drop in replace tcdf from the statfun/private dir - + % FIXME: drop in replace tcdf from the statfun/private dir end - - clear dfe err tmse; + clear dfe err tmse end -% prepare the output, start with only the administrative fields +% organize the output dataout = keepfields(datain, {'label', 'time', 'freq', 'pos', 'dim', 'transform', 'inside', 'outside', 'trialinfo', 'sampleinfo', 'dimord'}); - -if strcmp(cfg.model, 'yes') - fprintf('outputting the model which contains the confounds x weights \n'); - dataout.model = keepfields(datain, {'label', 'time', 'freq', 'pos', 'dim', 'transform', 'inside', 'outside', 'trialinfo', 'sampleinfo', 'dimord'}); - dataout.model.(cfg.parameter) = reshape(model, [nrpt, dimsiz(datdim)]); - clear model; -end - -% beta statistics -if strcmp(cfg.statistics, 'yes') - dataout.stat = reshape(tval, [nconf dimsiz(datdim)]); - dataout.prob = reshape(prob, [nconf dimsiz(datdim)]); - clear tval prob; +switch cfg.output + case 'residual' + dataout.(cfg.parameter) = reshape(Yc, [nrpt dimsiz(datdim)]); % either powspctrm, trial, or pow + clear Yc + case 'beta' + dataout.beta = reshape(beta, [nconf, dimsiz(datdim)]); + if strcmp(cfg.statistics, 'yes') % beta statistics + fprintf('performing statistics on the regression weights \n'); + dfe = nrpt - nconf; % degrees of freedom + err = dat - regr * beta; % err = Y - X * B + mse = sum((err).^2)/dfe; % mean squared error + covar = diag(regr'*regr)'; % regressor covariance + bvar = repmat(mse',1,size(covar,2))./repmat(covar,size(mse,2),1); % beta variance + tval = (beta'./sqrt(bvar))'; % betas -> t-values + prob = (1-tcdf(tval,dfe))*2; % p-values + clear err dfe mse bvar + % FIXME: drop in replace tcdf from the statfun/private dir + dataout.stat = reshape(tval, [nconf dimsiz(datdim)]); + dataout.prob = reshape(prob, [nconf dimsiz(datdim)]); + clear tval prob + end + case 'model' + dataout.model = keepfields(datain, {'label', 'time', 'freq', 'pos', 'dim', 'transform', 'inside', 'outside', 'trialinfo', 'sampleinfo', 'dimord'}); + dataout.model.(cfg.parameter) = reshape(model, [nrpt, dimsiz(datdim)]); + otherwise + error('output ''%s'' is not supported', cfg.output); end % reduced models analyses if ~isempty(cfg.ftest) dataout.fvar = reshape(F, [numel(cfg.ftest) dimsiz(datdim)]); dataout.pvar = reshape(p, [numel(cfg.ftest) dimsiz(datdim)]); - clear F p; -end - -dataout.(cfg.parameter) = reshape(Yc, [nrpt dimsiz(datdim)]); -clear Yc; - -if istimelock && strcmp(cfg.parameter, 'trial') - - if isfield(datain, 'avg') - % recompute the average - fprintf('updataing average and variance\n'); - tempcfg = []; - tempcfg.keeptrials = 'yes'; - dataout = ft_timelockanalysis(tempcfg, dataout); % reaveraging - - if strcmp(cfg.model, 'yes') - % also average the model - tempcfg = []; - tempcfg.keeptrials = 'yes'; - dataout.model = ft_timelockanalysis(tempcfg, dataout.model); % reaveraging - end - end -end - - -if istimelock - - % put the clean data back into place - dataout.trial = reshape(Yc, [nrpt, nchan, ntime]); clear Yc; - dataout.dimord = 'rpt_chan_time'; - - if isfield(datain, 'avg') % recompute the average - fprintf('updataing average and variance\n'); - tempcfg = []; - tempcfg.keeptrials = 'yes'; - dataout = ft_timelockanalysis(tempcfg, dataout); % reaveraging - end - - % make a nested timelock structure that contains the model - if strcmp(cfg.model, 'yes') - fprintf('outputting the model which contains the confounds x weights \n'); - dataout.model.trial = reshape(model, [nrpt, nchan, ntime]); clear model; - dataout.model.dimord = dataout.dimord; - dataout.model.time = dataout.time; - dataout.model.label = dataout.label; - - if isfield(datain, 'avg') - % also average the model - tempcfg = []; - tempcfg.keeptrials = 'yes'; - dataout.model = ft_timelockanalysis(tempcfg, dataout.model); % reaveraging - end - end - - % beta statistics - if strcmp(cfg.statistics, 'yes') - dataout.stat = reshape(tval, [nconf, nchan, ntime]); - dataout.prob = reshape(prob, [nconf, nchan, ntime]); - clear tval prob; - end - - % reduced models analyses - if ~isempty(cfg.ftest) - dataout.fvar = reshape(F, [numel(cfg.ftest), nchan, ntime]); - dataout.pvar = reshape(p, [numel(cfg.ftest), nchan, ntime]); - clear F p; - end - - % add the beta weights to the output - dataout.beta = reshape(beta, [nconf, nchan, ntime]); - clear beta dat; - -elseif isfreq - - % put the clean data back into place - dataout.powspctrm = reshape(Yc, [nrpt, nchan, nfreq, ntime]); clear Yc; - dataout.dimord = 'rpt_chan_freq_time'; - - % make a nested freq structure that contains the model - if strcmp(cfg.model, 'yes') - fprintf('outputting the model which contains the confounds x weights \n'); - dataout.model.trial = reshape(model, [nrpt, nchan, nfreq, ntime]); clear model; - dataout.model.dimord = dataout.dimord; - dataout.model.label = dataout.label; - if isfield(dataout, 'time') - dataout.model.time = dataout.time; - end - end - - % beta statistics - if isfield(cfg, 'statistics') && strcmp(cfg.statistics, 'yes') - dataout.stat = reshape(tval, [nconf, nchan, nfreq, ntime]); - dataout.prob = reshape(prob, [nconf, nchan, nfreq, ntime]); - clear tval prob; - end - - % reduced models analyses - if isfield(cfg, 'ftest') && ~isempty(cfg.ftest) - dataout.fvar = reshape(F, [numel(cfg.ftest), nchan, nfreq, ntime]); - dataout.pvar = reshape(p, [numel(cfg.ftest), nchan, nfreq, ntime]); - clear F p; - end - - % add the beta weights to the output - dataout.beta = reshape(beta, [nconf, nchan, nfreq, ntime]); - clear beta dat; - -elseif issource - - % put the clean data back into place - for i = 1:nrpt - dataout.trial(1,i).pow = zeros(nvox,1); - dataout.trial(1,i).pow(dataout.inside) = Yc(i,:); - end - clear Yc; - - % make a nested source structure that contains the model - if strcmp(cfg.model, 'yes') - fprintf('outputting the model which contains the confounds x weights \n'); - for i = 1:nrpt - dataout.model.trial(1,i).pow = zeros(nvox,1); - dataout.model.trial(1,i).pow(dataout.inside) = model(i,:); - end - clear model; - end - - % beta statistics - if isfield(cfg, 'statistics') && strcmp(cfg.statistics, 'yes') - dataout.stat = zeros(nconf, nvox); - dataout.stat(:,dataout.inside) = tval; - dataout.prob = zeros(nconf, nvox); - dataout.prob(:,dataout.inside) = prob; - clear tval prob; - end - - % add the beta weights to the output - dataout.beta = zeros(nconf, nvox); - dataout.beta(:,dataout.inside) = beta; - clear beta dat; - + clear F p end % discard the gradiometer information because the weightings have been changed if isfield(dataout, 'grad') - warning('discarding gradiometer information because the weightings have been changed'); + ft_warning('discarding gradiometer information because the weightings have been changed'); dataout = rmfield(dataout, 'grad'); end % discard the electrode information because the weightings have been changed if isfield(dataout, 'elec') - warning('discarding electrode information because the weightings have been changed'); + ft_warning('discarding electrode information because the weightings have been changed'); dataout = rmfield(dataout, 'elec'); end diff --git a/external/fieldtrip/ft_rejectartifact.m b/external/fieldtrip/ft_rejectartifact.m index e5f118f1..95cc3133 100644 --- a/external/fieldtrip/ft_rejectartifact.m +++ b/external/fieldtrip/ft_rejectartifact.m @@ -105,9 +105,6 @@ return end -% the data can be passed as input arguments or can be read from disk -hasdata = exist('data', 'var'); - % ft_checkdata is done further down % check if the input cfg is valid for this function @@ -123,14 +120,14 @@ % convert from old-style to new-style configuration if isfield(cfg,'reject') - warning('converting from old-style artifact configuration to new-style'); + ft_warning('converting from old-style artifact configuration to new-style'); cfg.artfctdef.reject = cfg.reject; cfg = rmfield(cfg, 'reject'); end % convert from old-style to new-style configuration if isfield(cfg.artfctdef,'common') - warning('converting from old-style artifact configuration to new-style'); + ft_warning('converting from old-style artifact configuration to new-style'); if isfield(cfg.artfctdef.common,'minaccepttim') cfg.artfctdef.minaccepttim = cfg.artfctdef.common.minaccepttim; cfg.artfctdef = rmfield(cfg.artfctdef, 'common'); @@ -200,20 +197,25 @@ if hasdata % check if the input data is valid for this function data = ft_checkdata(data, 'hassampleinfo', 'yes'); - + if isfield(data, 'sampleinfo') trl = zeros(numel(data.trial), 3); trl(:,[1 2]) = data.sampleinfo; - + % recreate offset vector (artifact functions depend on this) % TODO: the artifact rejection stuff should be rewritten to avoid % needing this workaround for ntrl = 1:numel(data.trial) trl(ntrl,3) = time2offset(data.time{ntrl}, data.fsample); end - + if isfield(data, 'trialinfo') - trl(:, 3+(1:size(data.trialinfo,2))) = data.trialinfo; + if istable(data.trialinfo) + % convert table into normal array, keep the column labels + VariableNames = data.trialinfo.Properties.VariableNames; + data.trialinfo = table2array(data.trialinfo); + end + trl = [trl data.trialinfo]; end else trl = []; @@ -225,18 +227,18 @@ % ensure the crittoilim input argument is valid if ~isempty(cfg.artfctdef.crittoilim) - + if (size(cfg.artfctdef.crittoilim,2) ~= 2 ... - || (size(cfg.artfctdef.crittoilim,1) ~= size(trl,1) ... - && size(cfg.artfctdef.crittoilim,1) ~= 1)) - error('if specified, cfg.artfctdef.crittoilim should be a 1x2 or Nx2 vector'); + || (size(cfg.artfctdef.crittoilim,1) ~= size(trl,1) ... + && size(cfg.artfctdef.crittoilim,1) ~= 1)) + ft_error('if specified, cfg.artfctdef.crittoilim should be a 1x2 or Nx2 vector'); end - + % if specified as 1x2 vector, expand into Nx2 if (size(cfg.artfctdef.crittoilim,1) == 1) cfg.artfctdef.crittoilim = repmat(cfg.artfctdef.crittoilim,size(trl,1),1); end - + checkCritToi = 1; % flag for convenience else checkCritToi = 0; @@ -244,7 +246,7 @@ % ensure that there are trials that can be scanned for artifacts and/or rejected if isempty(trl) - error('no trials were selected, cannot perform artifact detection/rejection'); + ft_error('no trials were selected, cannot perform artifact detection/rejection'); end % prevent double occurences of artifact types, ensure that the order remains the same @@ -255,8 +257,8 @@ % If bad parts are to be filled with nans, make sure data is available if strcmp(cfg.artfctdef.reject, 'nan') && ~hasdata - error('If bad parts are to be filled with nans, input data has to be specified'); -end; + ft_error('If bad parts are to be filled with nans, input data has to be specified'); +end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % call the appropriate function for each of the artifact types @@ -275,7 +277,7 @@ % collect the artifacts that have been detected from cfg.artfctdef.xxx.artifact dum = fieldnames(cfg.artfctdef); -sel = []; +sel = false(size(dum)); artifact = {}; for i=1:length(dum) sel(i) = issubfield(cfg.artfctdef, dum{i}) && issubfield(cfg.artfctdef, [dum{i} '.artifact']); @@ -289,13 +291,13 @@ end end % update the configuration to reflect the artifacts types that were scanned -cfg.artfctdef.type = dum(find(sel)); +cfg.artfctdef.type = dum(sel); % combine all trials into a single boolean vector -trialall = convert_event(trl, 'boolvec'); +trialall = convert_event(trl(:,1:2), 'boolvec'); % combine all artifacts into a single vector -rejectall = zeros(1,max(trl(:,2))); +rejectall = zeros(1, max(trl(:,2))); for i=1:length(cfg.artfctdef.type) dum = artifact{i}; for j=1:size(dum,1) @@ -333,7 +335,7 @@ for i=1:size(trl,1) time{i} = offset2time(trl(i,3), hdr.Fs, trl(i,2)-trl(i,1)+1); end - + figure title('linear display of the continuous data') xlabel('sample number'); @@ -355,7 +357,7 @@ smpend = dum(end) + hdr.Fs; axis([smpbeg smpend 0 1]); legend({'defined trials', cfg.artfctdef.type{:}}); - + figure title('individual trials after alignment') xlabel('time (s)'); @@ -389,7 +391,7 @@ if isfield(cfg.artfctdef, 'writerej') && ~isempty(cfg.artfctdef.writerej) fid = fopen(cfg.artfctdef.writerej, 'w'); if fid<0 - error('could not open rejection file for writing'); + ft_error('could not open rejection file for writing'); else % determine the begin and end of each rejected period (in samples) rejectonset = find(diff([0 rejectall])== 1); @@ -409,34 +411,42 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% if strcmp(cfg.artfctdef.reject, 'partial') || strcmp(cfg.artfctdef.reject, 'complete') || strcmp(cfg.artfctdef.reject, 'nan') trialok = []; - + count_complete_reject = 0; count_partial_reject = 0; - count_nan = 0; - count_outsidecrit = 0; - - trlRemovedInd = []; - trlPartiallyRemovedInd = []; - + count_nan = 0; + count_outsidecrit = 0; + + trlCompletelyRemovedInd = []; + trlPartiallyRemovedInd = []; + for trial=1:size(trl,1) % cut out the part of the rejection-axis corresponding with this trial rejecttrial = rejectall(trl(trial,1):trl(trial,2)); + if all(not(rejecttrial)) % the whole trial is good trialok = [trialok; trl(trial,:)]; + + elseif all(rejecttrial) && strcmp(cfg.artfctdef.reject, 'nan') + % the whole trial is bad, but it is requested to be replaced with nans + data.trial{trial}(:,rejecttrial) = nan; + count_nan = count_nan + 1; + trialok = [trialok; trl(trial,:)]; % Mark the trial as good as nothing will be removed + elseif all(rejecttrial) % the whole trial is bad count_complete_reject = count_complete_reject + 1; - trlRemovedInd = [trlRemovedInd trial]; + trlCompletelyRemovedInd = [trlCompletelyRemovedInd trial]; + elseif any(rejecttrial) && strcmp(cfg.artfctdef.reject, 'complete') - % some part of the trial is bad, check if within crittoilim? if (checkCritToi) critInd = (data.time{trial} >= cfg.artfctdef.crittoilim(trial,1) ... & data.time{trial} <= cfg.artfctdef.crittoilim(trial,2)); if (any(critInd & rejecttrial)) count_complete_reject = count_complete_reject + 1; - trlRemovedInd = [trlRemovedInd trial]; + trlCompletelyRemovedInd = [trlCompletelyRemovedInd trial]; continue; else trialok = [trialok; trl(trial,:)]; @@ -444,10 +454,10 @@ end else % no crittoilim checking required count_complete_reject = count_complete_reject + 1; - trlRemovedInd = [trlRemovedInd trial]; + trlCompletelyRemovedInd = [trlCompletelyRemovedInd trial]; continue; end - + elseif any(rejecttrial) && strcmp(cfg.artfctdef.reject, 'partial') % some part of the trial is bad, reject only the bad part trialnew = []; @@ -462,19 +472,19 @@ trialnew(:,i) = trl(trial,i); end minacceptnumsmp = round(cfg.artfctdef.minaccepttim .* hdr.Fs); - trialnew(find(trialnew(:,2)-trialnew(:,1)ncomps - error('you cannot remove components that are not present in the data'); + ft_error('you cannot remove components that are not present in the data'); end if hasdata && strcmp(cfg.demean, 'yes') @@ -127,7 +127,7 @@ % set the rejected component amplitudes to zero fprintf('removing %d components\n', length(reject)); -if ~hasdata, +if ~hasdata fprintf('keeping %d components\n', ncomps-length(reject)); else fprintf('keeping %d components\n', nchans-length(reject)); @@ -138,105 +138,104 @@ [seldat, selcomp] = match_str(label, comp.topolabel); if hasdata && length(seldat)~=length(label) - warning('the subspace projection is not guaranteed to be correct for non-orthogonal components'); + ft_warning('the subspace projection is not guaranteed to be correct for non-orthogonal components'); end if hasdata mixing = comp.topo(selcomp,:); unmixing = comp.unmixing(:,selcomp); - + % I am not sure about this, but it gives comparable results to the ~hasdata case % when comp contains non-orthogonal (=ica) topographies, and contains a complete decomposition - + montage = []; montage.tra = eye(length(selcomp)) - mixing(:, reject)*unmixing(reject, :); % we are going from data to components, and back again - montage.labelorg = comp.topolabel(selcomp); + montage.labelold = comp.topolabel(selcomp); montage.labelnew = comp.topolabel(selcomp); - + keepunused = 'yes'; % keep the original data which are not present in the mixing provided - + bname = 'reject'; + else mixing = comp.topo(selcomp, :); mixing(:, reject) = 0; - + montage = []; montage.tra = mixing; % we are going from components to data - montage.labelorg = comp.label; + montage.labelold = comp.label; montage.labelnew = comp.topolabel(selcomp); - + keepunused = 'no'; % don't need to keep the original rejected components + bname = 'invcomp'; - % create data structure - data = []; - data.trial = comp.trial; - data.time = comp.time; - data.label = comp.label; - data.fsample = comp.fsample; - if isfield(comp, 'grad'), data.grad = comp.grad; end - if isfield(comp, 'elec'), data.elec = comp.elec; end - if isfield(comp, 'trialinfo'), data.trialinfo = comp.trialinfo; end - if isfield(comp, 'sampleinfo'), data.sampleinfo = comp.sampleinfo; end + % create the initial data structure, remove all component details + data = keepfields(comp, {'trial', 'time', 'label', 'fsample', 'grad', 'elec', 'opto', 'trialinfo', 'sampleinfo'}); end % if hasdata -% apply the montage to the data and to the sensor description +% apply the linear projection to the data data = ft_apply_montage(data, montage, 'keepunused', keepunused, 'feedback', cfg.feedback); -% apply the montage also to the elec/grad, if present if isfield(data, 'grad') sensfield = 'grad'; - if strcmp(cfg.updatesens, 'yes') - fprintf('applying the backprojection matrix to the gradiometer description\n'); - else - fprintf('not applying the backprojection matrix to the gradiometer description\n'); - end -elseif isfield(data, 'elec') && isfield(data.elec, 'tra') +elseif isfield(data, 'elec') sensfield = 'elec'; - if strcmp(cfg.updatesens, 'yes') - fprintf('applying the backprojection matrix to the electrode description\n'); - else - fprintf('not applying the backprojection matrix to the electrode description\n'); - end +elseif isfield(data, 'opto') + sensfield = 'opto'; else - fprintf('not applying the backprojection matrix to the sensor description\n'); sensfield = []; end -if ~isempty(sensfield) && strcmp(cfg.updatesens, 'yes') - % keepunused = 'yes' is required to get back e.g. reference or otherwise - % unused sensors in the sensor description. the unused components need to - % be removed in a second step - sens = ft_apply_montage(data.(sensfield), montage, 'keepunused', 'yes', 'balancename', 'invcomp', 'feedback', cfg.feedback); - - % there could have been sequential subspace projections, so the - % invcomp-field may have been renamed into invcompX. If this it the case, - % take the one with the highest suffix - invcompfield = 'invcomp'; - if ~isfield(sens.balance, 'invcomp') - for k = 10:-1:1 - if isfield(sens.balance, ['invcomp',num2str(k)]) - invcompfield = [invcompfield,num2str(k)]; - break; +% apply the linear projection also to the sensor description +if ~isempty(sensfield) + if strcmp(cfg.updatesens, 'yes') + fprintf('also applying the backprojection matrix to the %s structure\n', sensfield); + + % the balance field is needed to keep the sequence of linear projections + if ~isfield(data.(sensfield), 'balance') + data.(sensfield).balance.current = 'none'; + end + + % keepunused = 'yes' is required to get back e.g. reference or otherwise + % unused sensors in the sensor description. the unused components need to + % be removed in a second step + sens = ft_apply_montage(data.(sensfield), montage, 'keepunused', 'yes', 'balancename', bname, 'feedback', cfg.feedback); + + % remove the unused channels from the grad/elec/opto + [junk, remove] = match_str(comp.label, sens.label); + sens.tra(remove,:) = []; + sens.label(remove) = []; + sens.chanpos(remove,:) = []; + if isfield(sens, 'chanori') + sens.chanori(remove,:) = []; + end + + % there could have been sequential subspace projections, so the + % invcomp-field may have been renamed into invcompX. If this it the case, + % take the one with the highest suffix + invcompfield = bname; + if ~isfield(sens.balance, invcompfield) + for k = 10:-1:1 + if isfield(sens.balance, [bname num2str(k)]) + invcompfield = [invcompfield num2str(k)]; + break; + end end end + + % remove the unused components from the balancing + [junk, remove] = match_str(comp.label, sens.balance.(invcompfield).labelnew); + sens.balance.(invcompfield).tra(remove, :) = []; + sens.balance.(invcompfield).labelnew(remove) = []; + data.(sensfield) = sens; + + else + fprintf('not applying the backprojection matrix to the %s structure\n', sensfield); + % simply copy it over + comp.(sensfield) = data.(sensfield); end - - % remove the unused channels from the grad/elec - [junk, remove] = match_str(comp.label, sens.label); - sens.tra(remove,:) = []; - sens.label(remove) = []; - sens.chanpos(remove,:) = []; - if isfield(sens, 'chanori') - sens.chanori(remove,:) = []; - end - - % remove the unused components from the balancing and from the tra - [junk, remove] = match_str(comp.label, sens.balance.(invcompfield).labelnew); - sens.balance.(invcompfield).tra(remove, :) = []; - sens.balance.(invcompfield).labelnew(remove) = []; - data.(sensfield) = sens; -end +end % if sensfield if istlck % convert the raw structure back into a timelock structure diff --git a/external/fieldtrip/ft_rejectvisual.m b/external/fieldtrip/ft_rejectvisual.m index 74261ae2..d314894a 100644 --- a/external/fieldtrip/ft_rejectvisual.m +++ b/external/fieldtrip/ft_rejectvisual.m @@ -284,7 +284,7 @@ [chansel, trlsel, cfg] = rejectvisual_summary(cfg, tmpdata); otherwise - error('unsupported method %s', cfg.method); + ft_error('unsupported method %s', cfg.method); end % switch method fprintf('%d trials marked as GOOD, %d trials marked as BAD\n', sum(trlsel), sum(~trlsel)); @@ -348,7 +348,7 @@ cfg = copyfields(orgcfg, cfg, {'trials'}); otherwise - error('invalid specification of cfg.keepchannel') + ft_error('invalid specification of cfg.keepchannel') end % case end % if ~all(chansel) @@ -381,7 +381,7 @@ end otherwise - error('invalid specification of cfg.keeptrial') + ft_error('invalid specification of cfg.keeptrial') end % case end % if ~all(trlsel) diff --git a/external/fieldtrip/ft_removetemplateartifact.m b/external/fieldtrip/ft_removetemplateartifact.m index b6eb4a34..fbcfdfd8 100644 --- a/external/fieldtrip/ft_removetemplateartifact.m +++ b/external/fieldtrip/ft_removetemplateartifact.m @@ -1,7 +1,7 @@ function data = ft_removetemplateartifact(cfg, data, template) % FT_REMOVETEMPLATEARTIFACT removes an artifact from preprocessed data by template -% subtraction. The template can for example be formed by averaging an ECG triggered +% subtraction. The template can for example be formed by averaging an ECG-triggered % MEG timecourse. % % Use as @@ -84,10 +84,12 @@ cfg.channel = ft_channelselection(cfg.channel, data.label); cfg.channel = ft_channelselection(cfg.channel, template.label); -tmpcfg = []; -tmpcfg.channel = cfg.channel; +tmpcfg = keepfields(cfg, {'channel'}); data = ft_selectdata(tmpcfg, data); template = ft_selectdata(tmpcfg, template); +% restore the provenance information +[cfg, data] = rollback_provenance(cfg, data); +[cfg, template] = rollback_provenance(cfg, template); ntrial = length(data.trial); nchan = length(cfg.channel); diff --git a/external/fieldtrip/ft_removetmsartifact.m b/external/fieldtrip/ft_removetmsartifact.m deleted file mode 100644 index 469650ec..00000000 --- a/external/fieldtrip/ft_removetmsartifact.m +++ /dev/null @@ -1,282 +0,0 @@ -function data = ft_removetmsartifact(cfg, data) - -% FT_REMOVETMSARTIFACT removes TMS artifacts from EEG data -% -% %% -% NOTE: Please be aware that this function is deprecated. Please follow the -% TMS-EEG tutorial instead at http://www.fieldtriptoolbox.org/tutorial/tms-eeg -% %% -% -% Use as -% data = ft_removetmsartifact(cfg, data) -% where the input data is a raw data, for example obtained from FT_PREPROCESSING, and -% cfg is a configuratioun structure that should contain -% cfg.method = string, can be 'twopassfilter', 'interpolatepulse' -% cfg.pulseonset = value or vector, time in seconds of the TMS pulse in seconds -% -% The following options pertain to the 'replace' method -% cfg.pulsewidth = value, pulse pulsewidth to be removed in seconds -% cfg.offset = value, offset with respect to pulse onset to start -% replacing, in seconds. -% -% The following options pertain to the 'twopassfilter' method -% cfg.lpfreq = number in Hz -% cfg.lpfiltord = lowpass filter order -% cfg.lpfilttype = digital filter type, 'but' or 'fir' or 'firls' (default = 'but') -% cfg.pulsewidth = value, pulse pulsewidth to be removed in seconds. If -% set to 0, entire trial will be filtered. -% cfg.offset = value, offset with respect to pulse onset to start -% filtering, in seconds. -% -% See also FT_REJECTARTIFACT, FT_REJECTCOMPONENT - -% Copyrights (C) 2012, Robert Oostenveld -% -% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org -% for the documentation and details. -% -% FieldTrip is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. -% -% FieldTrip is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with FieldTrip. If not, see . -% -% $Id$ - -% DEPRECATED by jimher on 19 September 2013 -% see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=1791 for more details -warning('FT_REMOVETMSARTIFACT is deprecated, please follow TMS-EEG tutorial instead (http://www.fieldtriptoolbox.org/tutorial/tms-eeg).') - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% the initial part deals with parsing the input options and data -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -% these are used by the ft_preamble/ft_postamble function and scripts -ft_revision = '$Id$'; -ft_nargin = nargin; -ft_nargout = nargout; - -% do the general setup of the function -ft_defaults -ft_preamble init -ft_preamble debug -ft_preamble loadvar datain -ft_preamble provenance datain -ft_preamble trackconfig - -% the ft_abort variable is set to true or false in ft_preamble_init -if ft_abort - return -end - -% check if the input data is valid for this function -data = ft_checkdata(data, 'datatype', {'raw'}, 'feedback', 'yes'); - -% ensure that the required options are present -cfg = ft_checkconfig(cfg, 'required', {'method'}); - -% get the options -cfg.method = ft_getopt(cfg, 'method'); % there is no default -cfg.pulseonset = ft_getopt(cfg, 'pulseonset'); -cfg.pulsewidth = ft_getopt(cfg, 'pulsewidth'); -cfg.lpfiltord = ft_getopt(cfg, 'lpfiltord', 2); -cfg.lpfilttype = ft_getopt(cfg, 'lpfilttype', 'but'); -cfg.lpfreq = ft_getopt(cfg, 'lpfreq', 30); -cfg.offset = ft_getopt(cfg, 'offset', 0); -cfg.fillmethod = ft_getopt(cfg, 'fillmethod'); - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% the actual computation is done in the middle part -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -numtrl = length(data.trial); -temp_pulse = []; - -if ~isfield(data, 'fsample') - fsample = 1/mean(diff(data.time{1})); -else - fsample = data.fsample; -end - -if isnumeric(cfg.pulsewidth) && numel(cfg.pulsewidth)==1; temp_pulse = cfg.pulsewidth; end; - -% copy for all trials -if isnumeric(cfg.pulseonset) && numel(cfg.pulseonset)==1; cfg.pulseonset = repmat(cfg.pulseonset, numtrl, 1); end -if isnumeric(cfg.pulsewidth) && numel(cfg.pulsewidth)==1; cfg.pulsewidth = repmat(cfg.pulsewidth, numtrl, 1); end - -% check wether fields are cell where necessary -if ~iscell(cfg.pulseonset); cfg.pulseonset = num2cell(cfg.pulseonset); end; -if ~iscell(cfg.pulsewidth); cfg.pulsewidth = num2cell(cfg.pulsewidth); end; - -if isempty(cfg.pulseonset) || isempty(cfg.pulsewidth) - for i=1:numtrl - [onset, width] = pulsedetect(data.trial{i}); - % these should be expressed in seconds - cfg.pulseonset{i} = data.time{i}(onset); - - if ~isempty(temp_pulse) - cfg.pulsewidth{i} = repmat(temp_pulse, 1, length(onset)); - else - cfg.pulsewidth{i} = width; - end; - - fprintf('detected %d pulses in trial %d\n', length(onset), i); - end -end % estimate pulse onset and width - -switch cfg.method - - case 'twopassfilter' - for i=1:numtrl - for j=1:length(cfg.pulseonset{i}) - %tmssample = nearest(data.time{i}, cfg.pulseonset{i}(j)); - pulseonset = cfg.pulseonset{i}(j); - pulsewidth = cfg.pulsewidth{i}(j); - offset = cfg.offset; - - % express it in samples, - pulseonset = nearest(data.time{i}, pulseonset); - pulsewidth = round(pulsewidth*fsample); - offset = round(offset*fsample); - - % get the part of the data that is left and right of the TMS pulse artifact - dat1 = data.trial{i}(:,1:pulseonset); - dat2 = data.trial{i}(:,(pulseonset+1:end)); - - % filter the two pieces, prevent filter artifacts - [filt1] = ft_preproc_lowpassfilter(dat1,fsample,cfg.lpfreq,cfg.lpfiltord,cfg.lpfilttype,'onepass'); - [filt2] = ft_preproc_lowpassfilter(dat2,fsample,cfg.lpfreq,cfg.lpfiltord,cfg.lpfilttype,'onepass-reverse'); - - % stitch the left and right parts of the data back together - %data.trial{i} = [filt1 filt2]; - fill = [filt1 filt2]; - - % determine a short window around the tms pulse - begsample = pulseonset + offset; - endsample = pulseonset + pulsewidth + offset - 1; - - % replace data in the pulse window with a filtered version - if pulsewidth == 0 - data.trial{i} = fill; - else - data.trial{i}(:,begsample:endsample) = fill(:,begsample:endsample); - end; - end % for pulses - end % for trials - - case 'interpolatepulse' - for i=1:numtrl - for j=1:length(cfg.pulseonset{i}) - - pulseonset = cfg.pulseonset{i}(j); - pulsewidth = cfg.pulsewidth{i}(j); - offset = cfg.offset; - - % express it in samples, - pulseonset = nearest(data.time{i}, pulseonset); - pulsewidth = round(pulsewidth*fsample); - offset = round(offset*fsample); - - begsample = pulseonset + offset; - endsample = pulseonset + pulsewidth + offset - 1; - - % determine a short window before the TMS pulse - begsample1 = begsample - pulsewidth; - endsample1 = begsample - 1; - - % determine a short window after the TMS pulse - begsample2 = endsample + 1; - endsample2 = endsample + pulsewidth; - - dat1 = data.trial{i}(:,begsample1:endsample1); - dat2 = data.trial{i}(:,begsample2:endsample2); - %fill = dat1(:,randperm(size(dat1,2))); % randomly shuffle the data points - %fill = mean(dat1,2) + cumsum(std(dat1,[],2).*randn(size(dat1,1),size(dat1,2))); -% fill = linspace(mean(dat1,2),mean(dat2,2),endsample1-begsample1+1); -% fill = fill + cumsum(std(dat1,[],2).*randn(size(dat1,1),size(dat1,2))); - -% fill = cumsum(std(dat1,[],2).*randn(size(dat1,1),size(dat1,2))); - - - switch cfg.fillmethod - case 'fft' - fft_dat1 = fft(dat1); - fft_dat2 = fft(dat2); - fill = real(ifft(mean([fft_dat1; fft_dat2]))); - % fill = std(dat1,[],2).*randn(size(dat1,1),size(dat1,2)); - % fill = fill .* repmat(hann(size(fill,2))',size(fill,1),1); - % %fill = fill - linspace(fill(:,1),fill(:,end),endsample1-begsample1+1); - % % fill = fill + linspace(mean(dat1,2),mean(dat2,2),endsample1-begsample1+1); - % fill = fill + linspace(dat1(:,end),dat2(:,1),endsample1-begsample1+1); - case 'zeros' - fill = zeros(size(dat1,1),size(dat1,2)); - case 'randperm' - fill = dat1(:,randperm(size(dat1,2))); % randomly shuffle the data points - case 'brown' - fill = linspace(mean(dat1,2),mean(dat2,2),endsample1-begsample1+1); - fill = fill + cumsum(std(dat1,[],2).*randn(size(dat1,1),size(dat1,2))); - case 'linear' - fill = interp1([1:size(dat1,2) 2*size(dat1,2)+1:3*size(dat1,2)], [dat1 dat2]', size(dat1,2)+1:2*size(dat1,2),'linear')'; - case 'linear+noise' - fill = interp1([1:size(dat1,2) 2*size(dat1,2)+1:3*size(dat1,2)], [dat1 dat2]', size(dat1,2)+1:2*size(dat1,2),'linear')'; - fill = fill(2:end-1) + std(dat1,[],2).*randn(size(dat1,1),size(dat1,2)); - case 'spline' - fill = interp1([1:size(dat1,2) 2*size(dat1,2)+1:3*size(dat1,2)], [dat1 dat2]', size(dat1,2)+1:2*size(dat1,2),'spline')'; - case 'cubic' - fill = interp1([1:size(dat1,2) 2*size(dat1,2)+1:3*size(dat1,2)], [dat1 dat2]', size(dat1,2)+1:2*size(dat1,2),'cubic')'; - case 'cubic+noise' - fill = interp1([1:size(dat1,2) 2*size(dat1,2)+1:3*size(dat1,2)], [dat1 dat2]', size(dat1,2)+1:2*length(dat1),'cubic')'; - fill = fill + std(dat1,[],2).*randn(size(dat1,1),size(dat1,2)); - end; - - % FIXME an alternative would be to replace it with an interpolated version of the signal just around it - % FIXME an alternative would be to replace it with nan - % FIXME an alternative would be to replace it with random noise - - % replace the data in the pulse window with a random shuffled version of the data just around it - data.trial{i}(:,begsample:endsample) = fill; - - end % for pulses - end % for trials - - otherwise - error('unsupported method'); -end - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% deal with the output -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -ft_postamble debug -ft_postamble trackconfig -ft_postamble previous data -ft_postamble provenance data -ft_postamble history data -ft_postamble savevar data - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% SUBFUNCTION that detects the onset and pulsewidth of one or multiple TMS pulses -% that are present as artifact in a segment of multi-channel EEG data -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -function [onset, pulsewidth] = pulsedetect(dat) -[nchan, ntime] = size(dat); -for i=1:nchan - dat(i,:) = dat(i,:) - median(dat(i,:)); -end -dat = sum(abs(dat),1); -threshold = 0.5 * max(dat); -dat = dat>threshold; -dat = [0 diff(dat) 0]; -onset = find(dat== 1); -offset = find(dat==-1) - 1; -pulsewidth = offset - onset; -% make the pulse a bit wider -offset = offset - 2*pulsewidth; -pulsewidth = pulsewidth*5; diff --git a/external/fieldtrip/ft_resampledata.m b/external/fieldtrip/ft_resampledata.m index a266b719..3b2eb8e5 100644 --- a/external/fieldtrip/ft_resampledata.m +++ b/external/fieldtrip/ft_resampledata.m @@ -9,7 +9,8 @@ % the FT_PREPROCESSING function. The configuration should contain % cfg.resamplefs = frequency at which the data will be resampled (default = 256 Hz) % cfg.detrend = 'no' or 'yes', detrend the data prior to resampling (no default specified, see below) -% cfg.demean = 'no' or 'yes', baseline correct the data prior to resampling (default = 'no') +% cfg.demean = 'no' or 'yes', whether to apply baseline correction (default = 'no') +% cfg.baselinewindow = [begin end] in seconds, the default is the complete trial (default = 'all') % cfg.feedback = 'no', 'text', 'textbar', 'gui' (default = 'text') % cfg.trials = 'all' or a selection given as a 1xN vector (default = 'all') % cfg.sampleindex = 'no' or 'yes', add a channel with the original sample indices (default = 'no') @@ -94,17 +95,17 @@ cfg = ft_checkconfig(cfg, 'renamed', {'blc', 'demean'}); % set the defaults -cfg.resamplefs = ft_getopt(cfg, 'resamplefs', []); -cfg.time = ft_getopt(cfg, 'time', {}); -cfg.detrend = ft_getopt(cfg, 'detrend', 'no'); -cfg.demean = ft_getopt(cfg, 'demean', 'no'); -cfg.feedback = ft_getopt(cfg, 'feedback', 'text'); -cfg.trials = ft_getopt(cfg, 'trials', 'all', 1); -cfg.method = ft_getopt(cfg, 'method', 'pchip'); -cfg.sampleindex = ft_getopt(cfg, 'sampleindex', 'no'); - -% give the user control over whether to use resample (applies anti-aliasing -% filter) or downsample (does not apply filter) +cfg.resamplefs = ft_getopt(cfg, 'resamplefs', []); +cfg.time = ft_getopt(cfg, 'time', {}); +cfg.detrend = ft_getopt(cfg, 'detrend', 'no'); +cfg.demean = ft_getopt(cfg, 'demean', 'no'); +cfg.baselinewindow = ft_getopt(cfg, 'baselinewindow', 'all'); +cfg.feedback = ft_getopt(cfg, 'feedback', 'text'); +cfg.trials = ft_getopt(cfg, 'trials', 'all', 1); +cfg.method = ft_getopt(cfg, 'method', 'pchip'); +cfg.sampleindex = ft_getopt(cfg, 'sampleindex', 'no'); + +% give the user control over whether to use resample (applies anti-aliasing filter) or downsample (does not apply filter) cfg.resamplemethod = ft_getopt(cfg, 'resamplemethod', 'resample'); % store original datatype @@ -113,13 +114,13 @@ % check if the input data is valid for this function, this will convert it to raw if needed data = ft_checkdata(data, 'datatype', {'raw+comp', 'raw'}, 'feedback', 'yes'); -%set default resampling frequency -if isempty(cfg.resamplefs) && isempty(cfg.time), +% set default resampling frequency +if isempty(cfg.resamplefs) && isempty(cfg.time) cfg.resamplefs = 256; end % select trials of interest -tmpcfg = keepfields(cfg, 'trials'); +tmpcfg = keepfields(cfg, {'trials', 'showcallinfo'}); data = ft_selectdata(tmpcfg, data); % restore the provenance information [cfg, data] = rollback_provenance(cfg, data); @@ -131,11 +132,11 @@ data.trial{i}(end+1,:) = data.sampleinfo(i,1):data.sampleinfo(i,2); end elseif strcmp(cfg.sampleindex, 'yes') - warning('no sampleinfo present, cannot add sampleindex as channel'); + ft_warning('no sampleinfo present, cannot add sampleindex as channel'); end % sampleinfo, if present, becomes invalid because of the resampling -if isfield(data, 'sampleinfo'), +if isfield(data, 'sampleinfo') data = rmfield(data, 'sampleinfo'); end @@ -143,18 +144,17 @@ usetime = ~isempty(cfg.time); if usefsample && usetime - error('you should either specify cfg.resamplefs or cfg.time') + ft_error('you should either specify cfg.resamplefs or cfg.time') end % whether to use downsample() or resample() -usedownsample = 0; if strcmp(cfg.resamplemethod, 'resample') usedownsample = 0; elseif strcmp(cfg.resamplemethod, 'downsample') - warning('using cfg.resamplemethod = ''downsample'', only use this if you have applied an anti-aliasing filter prior to downsampling!'); + ft_warning('using cfg.resamplemethod = ''downsample'', only use this if you have applied an anti-aliasing filter prior to downsampling!'); usedownsample = 1; else - error('unknown resamplemethod ''%s''', cfg.resamplemethod); + ft_error('unknown resamplemethod ''%s''', cfg.resamplemethod); end % remember the original sampling frequency in the configuration @@ -184,7 +184,7 @@ nchan = numel(data.label); if any(padsmp~=0) - warning('not all of the trials have the same original time axis: to avoid rounding issues in the resampled time axes, data will be zero-padded to the left prior to resampling'); + ft_warning('not all of the trials have the same original time axis: to avoid rounding issues in the resampled time axes, data will be zero-padded to the left prior to resampling'); end for itr = 1:ntr @@ -193,9 +193,19 @@ data.trial{itr} = ft_preproc_detrend(data.trial{itr}); end + % Compute mean based on a window (cfg.baselinewindow) or the whole + % trial. This does not support nan values anymore. Fix in + % ft_preproc_plyremoval. + % previously --> bsl = nanmean(data.trial{itr},2); + if ~strcmp(cfg.baselinewindow, 'all') + begsample = ceil(data.fsample*cfg.baselinewindow(1))+find(data.time{itr}==0); + endsample = floor(data.fsample*cfg.baselinewindow(2))-1+find(data.time{itr}==0); + [~,bsl] = ft_preproc_baselinecorrect(data.trial{itr}, begsample, endsample); + else + [~,bsl] = ft_preproc_baselinecorrect(data.trial{itr}); + end % always remove the mean to avoid edge effects when there's a strong - % offset, the cfg.demean option is dealt with below - bsl = nanmean(data.trial{itr},2); + % offset, the cfg.demean option is dealt with below data.trial{itr} = data.trial{itr} - bsl(:,ones(1,size(data.trial{itr},2))); % pad the data with zeros to the left @@ -205,7 +215,7 @@ % perform the resampling if usedownsample if mod(fsorig, fsres) ~= 0 - error('when using cfg.resamplemethod = ''downsample'', new sampling rate needs to be a proper divisor of original sampling rate'); + ft_error('when using cfg.resamplemethod = ''downsample'', new sampling rate needs to be a proper divisor of original sampling rate'); end if isa(data.trial{itr}, 'single') @@ -258,13 +268,25 @@ data.trial{itr} = ft_preproc_detrend(data.trial{itr}); end + + + % Compute mean based on a window (cfg.baselinewindow) or the whole + % trial. This does not support nan values anymore. Fix in + % ft_preproc_plyremoval. + % previously --> bsl = nanmean(data.trial{itr},2); + if ~strcmp(cfg.baselinewindow, 'all') + begsample = ceil(data.fsample*cfg.baselinewindow(1))+find(data.time{itr}==0); + endsample = floor(data.fsample*cfg.baselinewindow(2))-1+find(data.time{itr}==0); + [dum,bsl] = ft_preproc_baselinecorrect(data.trial{itr}, begsample, endsample); + else + [dum,bsl] = ft_preproc_baselinecorrect(data.trial{itr}); + end % always remove the mean to avoid edge effects when there's a strong - % offset, the cfg.demean option is dealt with below - bsl = nanmean(data.trial{itr},2); + % offset, the cfg.demean option is dealt with below data.trial{itr} = data.trial{itr} - bsl(:,ones(1,size(data.trial{itr},2))); % perform the resampling - if length(data.time{itr})>1, + if length(data.time{itr})>1 data.trial{itr} = interp1(data.time{itr}', data.trial{itr}', cfg.time{itr}', cfg.method)'; else data.trial{itr} = repmat(data.trial{itr}, [1 length(cfg.time{itr}')]); @@ -287,7 +309,7 @@ end % if usefsample or usetime -fprintf('original sampling rate = %d Hz\nnew sampling rate = %d Hz\n', cfg.origfs, data.fsample); +ft_info('original sampling rate = %d Hz\nnew sampling rate = %d Hz\n', cfg.origfs, data.fsample); % convert back to input type if necessary switch convert diff --git a/external/fieldtrip/ft_scalpcurrentdensity.m b/external/fieldtrip/ft_scalpcurrentdensity.m index 97004947..bbf5a029 100644 --- a/external/fieldtrip/ft_scalpcurrentdensity.m +++ b/external/fieldtrip/ft_scalpcurrentdensity.m @@ -16,13 +16,14 @@ % and can be used in combination with most other FieldTrip functions % such as FT_FREQNALYSIS or FT_TOPOPLOTER. % -% The configuration can contain +% The configuration should contain % cfg.method = 'finite' for finite-difference method or % 'spline' for spherical spline method % 'hjorth' for Hjorth approximation method % cfg.elecfile = string, file containing the electrode definition % cfg.elec = structure with electrode definition % cfg.trials = 'all' or a selection given as a 1xN vector (default = 'all') +% cfg.feedback = string, 'no', 'text', 'textbar', 'gui' (default = 'text') % % The finite method require the following % cfg.conductivity = conductivity of the skin (default = 0.33 S/m) @@ -32,10 +33,10 @@ % cfg.lambda = regularization parameter (default = 1e-05) % cfg.order = order of the splines (default = 4) % cfg.degree = degree of legendre polynomials (default for -% <=32 electrodes = 9, -% <=64 electrodes = 14, +% <=32 electrodes = 9, +% <=64 electrodes = 14, % <=128 electrodes = 20, -% else = 32 +% else = 32 % % The hjorth method requires the following % cfg.neighbours = neighbourhood structure, see FT_PREPARE_NEIGHBOURS @@ -118,6 +119,7 @@ cfg.method = ft_getopt(cfg, 'method', 'spline'); cfg.conductivity = ft_getopt(cfg, 'conductivity', 0.33); % in S/m cfg.trials = ft_getopt(cfg, 'trials', 'all', 1); +cfg.feedback = ft_getopt(cfg, 'feedback', 'text'); switch cfg.method case 'hjorth' @@ -138,7 +140,7 @@ else cfg.degree = 32; end - end; + end otherwise cfg = ft_checkconfig(cfg); % perform a simple consistency check end @@ -150,7 +152,7 @@ data = ft_checkdata(data, 'datatype', 'raw', 'feedback', 'yes', 'iseeg','yes','ismeg',[]); % select trials of interest -tmpcfg = keepfields(cfg, 'trials'); +tmpcfg = keepfields(cfg, {'trials', 'showcallinfo'}); data = ft_selectdata(tmpcfg, data); % restore the provenance information [cfg, data] = rollback_provenance(cfg, data); @@ -183,8 +185,7 @@ % compute SCD for each trial if strcmp(cfg.method, 'spline') - ft_progress('init', 'text'); - + ft_progress('init', cfg.feedback, 'computing SCD for trial...') for trlop=1:Ntrials % do not compute interpolation, but only one value at [0 0 1] % this also gives L1, the laplacian of the original data in which we @@ -203,7 +204,7 @@ tri = delaunay(prj(:,1), prj(:,2)); % the new electrode montage only needs to be computed once for all trials montage.tra = lapcal(elec.chanpos, tri); - montage.labelorg = data.label; + montage.labelold = data.label; montage.labelnew = data.label; % apply the montage to the data, also update the electrode definition scd = ft_apply_montage(data, montage); @@ -212,35 +213,35 @@ elseif strcmp(cfg.method, 'hjorth') % convert the neighbourhood structure into a montage labelnew = {}; - labelorg = {}; + labelold = {}; for i=1:length(cfg.neighbours) - labelnew = cat(2, labelnew, cfg.neighbours(i).label); - labelorg = cat(2, labelorg, cfg.neighbours(i).neighblabel(:)'); + labelnew = cat(2, labelnew, cfg.neighbours(i).label); + labelold = cat(2, labelold, cfg.neighbours(i).neighblabel(:)'); end - labelorg = cat(2, labelnew, labelorg); - labelorg = unique(labelorg); - tra = zeros(length(labelnew), length(labelorg)); + labelold = cat(2, labelnew, labelold); + labelold = unique(labelold); + tra = zeros(length(labelnew), length(labelold)); for i=1:length(cfg.neighbours) - thischan = match_str(labelorg, cfg.neighbours(i).label); - thisneighb = match_str(labelorg, cfg.neighbours(i).neighblabel); + thischan = match_str(labelold, cfg.neighbours(i).label); + thisneighb = match_str(labelold, cfg.neighbours(i).neighblabel); tra(i, thischan) = 1; tra(i, thisneighb) = -1/length(thisneighb); end % combine it in a montage montage.tra = tra; - montage.labelorg = labelorg; + montage.labelold = labelold; montage.labelnew = labelnew; % apply the montage to the data, also update the electrode definition scd = ft_apply_montage(data, montage); elec = ft_apply_montage(elec, montage); else - error('unknown method for SCD computation'); + ft_error('unknown method for SCD computation'); end if strcmp(cfg.method, 'spline') || strcmp(cfg.method, 'finite') % correct the units - warning('trying to correct the units, assuming uV and mm'); + ft_warning('trying to correct the units, assuming uV and mm'); for trlop=1:Ntrials % The surface laplacian is proportional to potential divided by squared distance which means that, if % - input potential is in uV, which is 10^6 too large diff --git a/external/fieldtrip/ft_sensorrealign.m b/external/fieldtrip/ft_sensorrealign.m deleted file mode 100644 index bb18d747..00000000 --- a/external/fieldtrip/ft_sensorrealign.m +++ /dev/null @@ -1,761 +0,0 @@ -function [elec_realigned] = ft_sensorrealign(cfg, elec_original) - -% FT_SENSORREALIGN rotates and translates electrode and gradiometer -% sensor positions to template electrode positions or towards the head -% surface. It can either perform a rigid body transformation, in which only -% the coordinate system is changed, or it can apply additional deformations -% to the input sensors. Different methods for aligning the input electrodes -% to the subjects head are implemented, which are described in detail -% below. -% -% FIDUCIAL - You can apply a rigid body realignment based on three fiducial -% locations. After realigning, the fiducials in the input electrode set -% (typically nose, left and right ear) are along the same axes as the -% fiducials in the template electrode set. -% -% TEMPLATE - You can apply a spatial transformation/deformation that -% automatically minimizes the distance between the electrodes or -% gradiometers and a template or sensor array. The warping methods use a -% non-linear search to minimize the distance between the input sensor -% positions and the corresponding template sensors. -% -% INTERACTIVE - You can display the skin surface together with the -% electrode or gradiometer positions, and manually (using the graphical -% user interface) adjust the rotation, translation and scaling parameters, -% so that the electrodes correspond with the skin. -% -% MANUAL - You can display the skin surface and manually determine the -% electrode positions by clicking on the skin surface. -% -% HEADSHAPE - You can apply a spatial transformation/deformation that -% automatically minimizes the distance between the electrodes and the head -% surface. The warping methods use a non-linear search to minimize the -% distance between the input sensor positions and the projection of the -% electrodes on the head surface. -% -% Use as -% [sensor] = ft_sensorrealign(cfg) or -% [sensor] = ft_sensorrealign(cfg, sensor) -% where you specify the electrodes or gradiometers in the configuration -% structure (see below) or as the second input argument. -% -% The configuration can contain the following options -% cfg.method = string representing the method for aligning or placing the electrodes -% 'fiducial' realign using three fiducials (e.g. NAS, LPA and RPA) -% 'template' realign the sensors to match a template set -% 'interactive' realign manually using a graphical user interface -% 'manual' manual positioning of the electrodes by clicking in a graphical user interface -% 'headshape' realign the sensors to fit the head surface -% cfg.warp = string describing the spatial transformation for the template method -% 'rigidbody' apply a rigid-body warp (default) -% 'globalrescale' apply a rigid-body warp with global rescaling -% 'traditional' apply a rigid-body warp with individual axes rescaling -% 'nonlin1' apply a 1st order non-linear warp -% 'nonlin2' apply a 2nd order non-linear warp -% 'nonlin3' apply a 3rd order non-linear warp -% 'nonlin4' apply a 4th order non-linear warp -% 'nonlin5' apply a 5th order non-linear warp -% cfg.channel = Nx1 cell-array with selection of channels (default = 'all'), -% see FT_CHANNELSELECTION for details -% cfg.fiducial = cell-array with the name of three fiducials used for -% realigning (default = {'nasion', 'lpa', 'rpa'}) -% cfg.casesensitive = 'yes' or 'no', determines whether string comparisons -% between electrode labels are case sensitive (default = 'yes') -% cfg.feedback = 'yes' or 'no' (default = 'no') -% -% The EEG or MEG sensor positions can be present in the second input argument or can be specified as -% cfg.elec = structure with electrode positions, see FT_DATATYPE_SENS -% cfg.grad = structure with gradiometer definition, see FT_DATATYPE_SENS -% cfg.elecfile = name of file containing the electrode positions, see FT_READ_SENS -% cfg.gradfile = name of file containing the gradiometer definition, see FT_READ_SENS -% -% To realign the sensors using the fiducials, the target has to contain the -% three template fiducials, e.g. -% cfg.target.pos(1,:) = [110 0 0] % location of the nose -% cfg.target.pos(2,:) = [0 90 0] % location of the left ear -% cfg.target.pos(3,:) = [0 -90 0] % location of the right ear -% cfg.target.label = {'NAS', 'LPA', 'RPA'} -% -% To align the sensors to a single template set or to multiple electrode -% sets (which will be averaged), you should specify the target as -% cfg.target = single electrode or gradiometer set that serves as standard -% or -% cfg.target(1..N) = list of electrode or gradiometer sets that are averaged into the standard -% The target electrode or gradiometer sets can be specified either as -% structures (i.e. when they are already read in memory) or as file names. -% -% To align existing electrodes to the head surface, or to manually position -% new electrodes using the head surface, you should specify -% cfg.headshape = a filename containing headshape, a structure containing a -% single triangulated boundary, or a Nx3 matrix with surface -% points -% -% See also FT_READ_SENS, FT_VOLUMEREALIGN, FT_INTERACTIVEREALIGN - -% Copyright (C) 2005-2011, Robert Oostenveld -% -% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org -% for the documentation and details. -% -% FieldTrip is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. -% -% FieldTrip is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with FieldTrip. If not, see . -% -% $Id$ - -% DEPRECATED by roboos on 11 November 2015 -% see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=1830 -% support for this functionality can be removed mid 2016 -warning('FT_SENSORREALIGN is deprecated, please use FT_ELECTRODEREALIGN instead.') - -% these are used by the ft_preamble/ft_postamble function and scripts -ft_revision = '$Id$'; -ft_nargin = nargin; -ft_nargout = nargout; - -% do the general setup of the function -ft_defaults -ft_preamble init -ft_preamble debug -ft_preamble provenance elec_original -ft_preamble trackconfig - -% the ft_abort variable is set to true or false in ft_preamble_init -if ft_abort - return -end - -% the interactive method uses a global variable to get the data from the figure when it is closed -global norm - -% set the defaults -if ~isfield(cfg, 'channel'), cfg.channel = 'all'; end -if ~isfield(cfg, 'coordsys'), cfg.coordsys = []; end -if ~isfield(cfg, 'feedback'), cfg.feedback = 'no'; end -if ~isfield(cfg, 'casesensitive'), cfg.casesensitive = 'yes'; end -if ~isfield(cfg, 'warp'), cfg.warp = 'rigidbody'; end -if ~isfield(cfg, 'label'), cfg.label = 'off'; end - -cfg = ft_checkconfig(cfg, 'renamed', {'template', 'target'}); -cfg = ft_checkconfig(cfg, 'renamedval', {'method', 'realignfiducials', 'fiducial'}); -cfg = ft_checkconfig(cfg, 'renamedval', {'method', 'realignfiducial', 'fiducial'}); -cfg = ft_checkconfig(cfg, 'renamedval', {'warp', 'homogenous', 'rigidbody'}); -cfg = ft_checkconfig(cfg, 'forbidden', 'outline'); - -if isfield(cfg, 'headshape') && isa(cfg.headshape, 'config') - % convert the nested config-object back into a normal structure - cfg.headshape = struct(cfg.headshape); -end - -if ~isempty(cfg.coordsys) - switch lower(cfg.coordsys) - case 'ctf' - cfg.target = []; - cfg.target.pos(1,:) = [100 0 0]; - cfg.target.pos(2,:) = [0 80 0]; - cfg.target.pos(3,:) = [0 -80 0]; - cfg.target.label{1} = 'NAS'; - cfg.target.label{2} = 'LPA'; - cfg.target.label{3} = 'RPA'; - otherwise - error('the %s coordinate system is not automatically supported, please specify the details in cfg.target') - end -end - -% ensure that the right cfg options have been set corresponding to the method -switch cfg.method - case 'template' % realign the sensors to match a template set - cfg = ft_checkconfig(cfg, 'required', 'target', 'forbidden', 'headshape'); - case 'headshape' % realign the sensors to fit the head surface - cfg = ft_checkconfig(cfg, 'required', 'headshape', 'forbidden', 'target'); - case 'fiducial' % realign using the NAS, LPA and RPA fiducials - cfg = ft_checkconfig(cfg, 'required', 'target', 'forbidden', 'headshape'); - case 'interactive' % realign manually using a graphical user interface - cfg = ft_checkconfig(cfg, 'required', 'headshape'); - case 'manual' % manual positioning of the electrodes by clicking in a graphical user interface - cfg = ft_checkconfig(cfg, 'required', 'headshape', 'forbidden', 'target'); -end % switch cfg.method - -% the data can be passed as input arguments or can be read from disk -hasdata = exist('data', 'var'); - -% get the electrode definition that should be warped -if ~hasdata - try % try to get the description from the cfg - elec_original = ft_fetch_sens(cfg); - catch - % the "catch me" syntax is broken on MATLAB74, this fixes it - me = lasterror; - % start with an empty set of electrodes, this is useful for manual positioning - elec_original = []; - elec_original.pos = zeros(0,3); - elec_original.label = cell(0,1); - elec_original.unit = 'mm'; - warning(me.message, me.identifier); - end -else - % the input electrodes were specified as second input argument - % or read from cfg.inputfile -end - -% ensure that the units are specified -elec_original = ft_convert_units(elec_original); -elec_original = ft_datatype_sens(elec_original); % ensure up-to-date sensor description (Oct 2011) - -% remember the original electrode locations and labels and do all the work -% with a temporary copy, this involves channel selection and changing to -% lower case -elec = elec_original; - -if strcmp(cfg.method, 'fiducial') && isfield(elec, 'fid') - % instead of working with all sensors, only work with the fiducials - % this is useful for gradiometer structures - fprintf('using the fiducials instead of the sensor positions\n'); - elec.fid.unit = elec.unit; - elec = elec.fid; -end - -usetemplate = isfield(cfg, 'target') && ~isempty(cfg.target); -useheadshape = isfield(cfg, 'headshape') && ~isempty(cfg.headshape); - -if usetemplate - % get the template electrode definitions - if ~iscell(cfg.target) - cfg.target = {cfg.target}; - end - Ntemplate = length(cfg.target); - for i=1:Ntemplate - if isstruct(cfg.target{i}) - template(i) = cfg.target{i}; - else - template(i) = ft_read_sens(cfg.target{i}); - end - end - - clear tmp - for i=1:Ntemplate - tmp(i) = ft_datatype_sens(template(i)); % ensure up-to-date sensor description - tmp(i) = ft_convert_units(template(i), elec.unit); % ensure that the units are consistent with the electrodes - end - template = tmp; -end - -if useheadshape - % get the surface describing the head shape - if isstruct(cfg.headshape) - % use the headshape surface specified in the configuration - headshape = fixpos(cfg.headshape); - elseif isnumeric(cfg.headshape) && size(cfg.headshape,2)==3 - % use the headshape points specified in the configuration - headshape.pos = cfg.headshape; - elseif ischar(cfg.headshape) - % read the headshape from file - headshape = ft_read_headshape(cfg.headshape); - else - error('cfg.headshape is not specified correctly') - end - if ~isfield(headshape, 'tri') - % generate a closed triangulation from the surface points - headshape.pos = unique(headshape.pos, 'rows'); - headshape.tri = projecttri(headshape.pos); - end - headshape = ft_convert_units(headshape, elec.unit); % ensure that the units are consistent with the electrodes -end - -% convert all labels to lower case for string comparisons -% this has to be done AFTER keeping the original labels and positions -if strcmp(cfg.casesensitive, 'no') - for i=1:length(elec.label) - elec.label{i} = lower(elec.label{i}); - end - for j=1:length(template) - for i=1:length(template(j).label) - template(j).label{i} = lower(template(j).label{i}); - end - end -end - -if strcmp(cfg.feedback, 'yes') - % create an empty figure, continued below... - figure - axis equal - axis vis3d - hold on - xlabel('x') - ylabel('y') - zlabel('z') -end - -% start with an empty structure, this will be returned at the end -norm = []; - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -if strcmp(cfg.method, 'template') - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - % determine electrode selection and overlapping subset for warping - cfg.channel = ft_channelselection(cfg.channel, elec.label); - for i=1:Ntemplate - cfg.channel = ft_channelselection(cfg.channel, template(i).label); - end - - % make consistent subselection of electrodes - [cfgsel, datsel] = match_str(cfg.channel, elec.label); - elec.label = elec.label(datsel); - elec.chanpos = elec.chanpos(datsel,:); - for i=1:Ntemplate - [cfgsel, datsel] = match_str(cfg.channel, template(i).label); - template(i).label = template(i).label(datsel); - template(i).pos = template(i).pos(datsel,:); - end - - % compute the average of the template electrode positions - average = ft_average_sens(template); - - fprintf('warping electrodes to average template... '); % the newline comes later - [norm.chanpos, norm.m] = ft_warp_optim(elec.chanpos, average.chanpos, cfg.warp); - norm.label = elec.label; - - dpre = mean(sqrt(sum((average.chanpos - elec.chanpos).^2, 2))); - dpost = mean(sqrt(sum((average.chanpos - norm.chanpos).^2, 2))); - fprintf('mean distance prior to warping %f, after warping %f\n', dpre, dpost); - - if strcmp(cfg.feedback, 'yes') - % plot all electrodes before warping - ft_plot_sens(elec, 'r*'); - - % plot all electrodes after warping - ft_plot_sens(norm, 'm.', 'label', 'label'); - - % plot the template electrode locations - ft_plot_sens(average, 'b.'); - - % plot lines connecting the input and the realigned electrode locations with the template locations - my_line3(elec.chanpos, average.chanpos, 'color', 'r'); - my_line3(norm.chanpos, average.chanpos, 'color', 'm'); - end - - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -elseif strcmp(cfg.method, 'headshape') - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - % determine electrode selection and overlapping subset for warping - cfg.channel = ft_channelselection(cfg.channel, elec.label); - - % make subselection of electrodes - [cfgsel, datsel] = match_str(cfg.channel, elec.label); - elec.label = elec.label(datsel); - elec.chanpos = elec.chanpos(datsel,:); - - fprintf('warping electrodes to skin surface... '); % the newline comes later - [norm.chanpos, norm.m] = ft_warp_optim(elec.chanpos, headshape, cfg.warp); - norm.label = elec.label; - - dpre = ft_warp_error([], elec.chanpos, headshape, cfg.warp); - dpost = ft_warp_error(norm.m, elec.chanpos, headshape, cfg.warp); - fprintf('mean distance prior to warping %f, after warping %f\n', dpre, dpost); - - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -elseif strcmp(cfg.method, 'fiducial') - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - % the fiducials have to be present in the electrodes and in the template set - label = intersect(lower(elec.label), lower(template.label)); - - if ~isfield(cfg, 'fiducial') || isempty(cfg.fiducial) - % try to determine the names of the fiducials automatically - option1 = {'nasion' 'left' 'right'}; - option2 = {'nasion' 'lpa' 'rpa'}; - option3 = {'nz' 'left' 'right'}; - option4 = {'nz' 'lpa' 'rpa'}; - option5 = {'nas' 'left' 'right'}; - option6 = {'nas' 'lpa' 'rpa'}; - if length(match_str(label, option1))==3 - cfg.fiducial = option1; - elseif length(match_str(label, option2))==3 - cfg.fiducial = option2; - elseif length(match_str(label, option3))==3 - cfg.fiducial = option3; - elseif length(match_str(label, option4))==3 - cfg.fiducial = option4; - elseif length(match_str(label, option5))==3 - cfg.fiducial = option5; - elseif length(match_str(label, option6))==3 - cfg.fiducial = option6; - else - error('could not determine consistent fiducials in the input and the target, please specify cfg.fiducial or cfg.coordsys') - end - end - fprintf('matching fiducials {''%s'', ''%s'', ''%s''}\n', cfg.fiducial{1}, cfg.fiducial{2}, cfg.fiducial{3}); - - % determine electrode selection - cfg.channel = ft_channelselection(cfg.channel, elec.label); - [cfgsel, datsel] = match_str(cfg.channel, elec.label); - elec.label = elec.label(datsel); - elec.chanpos = elec.chanpos(datsel,:); - - if length(cfg.fiducial)~=3 - error('you must specify three fiducials'); - end - - % do case-insensitive search for fiducial locations - nas_indx = match_str(lower(elec.label), lower(cfg.fiducial{1})); - lpa_indx = match_str(lower(elec.label), lower(cfg.fiducial{2})); - rpa_indx = match_str(lower(elec.label), lower(cfg.fiducial{3})); - if length(nas_indx)~=1 || length(lpa_indx)~=1 || length(rpa_indx)~=1 - error('not all fiducials were found in the electrode set'); - end - elec_nas = elec.chanpos(nas_indx,:); - elec_lpa = elec.chanpos(lpa_indx,:); - elec_rpa = elec.chanpos(rpa_indx,:); - - % FIXME change the flow in the remainder - % if one or more template electrode sets are specified, then align to the average of those - % if no template is specified, then align so that the fiducials are along the axis - - % find the matching fiducials in the template and average them - templ_nas = nan(Ntemplate,3); - templ_lpa = nan(Ntemplate,3); - templ_rpa = nan(Ntemplate,3); - for i=1:Ntemplate - nas_indx = match_str(lower(template(i).label), lower(cfg.fiducial{1})); - lpa_indx = match_str(lower(template(i).label), lower(cfg.fiducial{2})); - rpa_indx = match_str(lower(template(i).label), lower(cfg.fiducial{3})); - if length(nas_indx)~=1 || length(lpa_indx)~=1 || length(rpa_indx)~=1 - error(sprintf('not all fiducials were found in template %d', i)); - end - templ_nas(i,:) = template(i).pos(nas_indx,:); - templ_lpa(i,:) = template(i).pos(lpa_indx,:); - templ_rpa(i,:) = template(i).pos(rpa_indx,:); - end - templ_nas = mean(templ_nas,1); - templ_lpa = mean(templ_lpa,1); - templ_rpa = mean(templ_rpa,1); - - % realign both to a common coordinate system - elec2common = ft_headcoordinates(elec_nas, elec_lpa, elec_rpa); - templ2common = ft_headcoordinates(templ_nas, templ_lpa, templ_rpa); - - % compute the combined transform and realign the electrodes to the template - norm = []; - norm.m = elec2common * inv(templ2common); - norm.chanpos = ft_warp_apply(norm.m, elec.chanpos, 'homogeneous'); - norm.label = elec.label; - - nas_indx = match_str(lower(elec.label), lower(cfg.fiducial{1})); - lpa_indx = match_str(lower(elec.label), lower(cfg.fiducial{2})); - rpa_indx = match_str(lower(elec.label), lower(cfg.fiducial{3})); - dpre = mean(sqrt(sum((elec.chanpos([nas_indx lpa_indx rpa_indx],:) - [templ_nas; templ_lpa; templ_rpa]).^2, 2))); - nas_indx = match_str(lower(norm.label), lower(cfg.fiducial{1})); - lpa_indx = match_str(lower(norm.label), lower(cfg.fiducial{2})); - rpa_indx = match_str(lower(norm.label), lower(cfg.fiducial{3})); - dpost = mean(sqrt(sum((norm.chanpos([nas_indx lpa_indx rpa_indx],:) - [templ_nas; templ_lpa; templ_rpa]).^2, 2))); - fprintf('mean distance between fiducials prior to realignment %f, after realignment %f\n', dpre, dpost); - - if strcmp(cfg.feedback, 'yes') - % plot the first three electrodes before transformation - my_plot3(elec.chanpos(1,:), 'r*'); - my_plot3(elec.chanpos(2,:), 'r*'); - my_plot3(elec.chanpos(3,:), 'r*'); - my_text3(elec.chanpos(1,:), elec.label{1}, 'color', 'r'); - my_text3(elec.chanpos(2,:), elec.label{2}, 'color', 'r'); - my_text3(elec.chanpos(3,:), elec.label{3}, 'color', 'r'); - - % plot the template fiducials - my_plot3(templ_nas, 'b*'); - my_plot3(templ_lpa, 'b*'); - my_plot3(templ_rpa, 'b*'); - my_text3(templ_nas, ' nas', 'color', 'b'); - my_text3(templ_lpa, ' lpa', 'color', 'b'); - my_text3(templ_rpa, ' rpa', 'color', 'b'); - - % plot all electrodes after transformation - my_plot3(norm.chanpos, 'm.'); - my_plot3(norm.chanpos(1,:), 'm*'); - my_plot3(norm.chanpos(2,:), 'm*'); - my_plot3(norm.chanpos(3,:), 'm*'); - my_text3(norm.chanpos(1,:), norm.label{1}, 'color', 'm'); - my_text3(norm.chanpos(2,:), norm.label{2}, 'color', 'm'); - my_text3(norm.chanpos(3,:), norm.label{3}, 'color', 'm'); - end - - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -elseif strcmp(cfg.method, 'interactive') - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - % give the user instructions - disp('Use the mouse to rotate the head and the electrodes around, and click "redisplay"'); - disp('Close the figure when you are done'); - % open a figure - fig = figure; - % add the data to the figure - set(fig, 'CloseRequestFcn', @cb_close); - setappdata(fig, 'elec', elec); - setappdata(fig, 'transform', eye(4)); - if useheadshape - setappdata(fig, 'headshape', headshape); - end - if usetemplate - % FIXME interactive realigning to template electrodes is not yet supported - % this requires a consistent handling of channel selection etc. - setappdata(fig, 'template', template); - end - % add the GUI elements - cb_creategui(gca); - cb_redraw(gca); - rotate3d on - waitfor(fig); - % get the data from the figure that was left behind as global variable - tmp = norm; - clear global norm - norm = tmp; - clear tmp - - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -elseif strcmp(cfg.method, 'manual') - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - % give the user instructions - disp('Use the mouse to click on the desired electrode positions'); - disp('Afterwards you manually have to assign the electrode names to "elec.label"'); - disp('Close the figure or press "q" when you are done'); - % open a figure - figure; - % plot the faces of the 2D or 3D triangulation - skin = [255 213 119]/255; - ft_plot_mesh(headshape,'facecolor', skin,'EdgeColor','none','facealpha',0.7); - lighting gouraud - material shiny - camlight - % rotate3d on - xyz = ft_select_point3d(headshape, 'multiple', true); - norm.chanpos = xyz; - for i=1:size(norm.chanpos,1) - norm.label{i,1} = sprintf('%d', i); - end - -else - error('unknown method'); -end - -% apply the spatial transformation to all electrodes, and replace the -% electrode labels by their case-sensitive original values -switch cfg.method - case {'template', 'headshape'} - try - % convert the vector with fitted parameters into a 4x4 homogenous transformation - % apply the transformation to the original complete set of sensors - elec_realigned = ft_transform_sens(feval(cfg.warp, norm.m), elec_original); - catch - % the previous section will fail for nonlinear transformations - elec_realigned.label = elec_original.label; - elec_realigned.chanpos = ft_warp_apply(norm.m, elec_original.chanpos, cfg.warp); - end - % remember the transformation - elec_realigned.(cfg.warp) = norm.m; - case {'fiducial', 'interactive'} - % the transformation is a 4x4 homogenous matrix - homogenous = norm.m; - % apply the transformation to the original complete set of sensors - elec_realigned = ft_transform_sens(homogenous, elec_original); - % remember the transformation - elec_realigned.homogenous = norm.m; - case 'manual' - % the positions are already assigned in correspondence with the mesh - elec_realigned = norm; - otherwise - error('unknown method'); -end - -% do the general cleanup and bookkeeping at the end of the function -ft_postamble debug -ft_postamble trackconfig -ft_postamble previous elec_original -ft_postamble provenance elec_realigned -ft_postamble history elec_realigned - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% some simple SUBFUNCTIONs that facilitate 3D plotting -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -function h = my_plot3(xyz, varargin) -h = plot3(xyz(:,1), xyz(:,2), xyz(:,3), varargin{:}); -function h = my_text3(xyz, varargin) -h = text(xyz(:,1), xyz(:,2), xyz(:,3), varargin{:}); -function my_line3(xyzB, xyzE, varargin) -for i=1:size(xyzB,1) - line([xyzB(i,1) xyzE(i,1)], [xyzB(i,2) xyzE(i,2)], [xyzB(i,3) xyzE(i,3)], varargin{:}) -end - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -function cb_creategui(hObject, eventdata, handles) -% % define the position of each GUI element -fig = get(hObject, 'parent'); -% constants -CONTROL_WIDTH = 0.05; -CONTROL_HEIGHT = 0.06; -CONTROL_HOFFSET = 0.7; -CONTROL_VOFFSET = 0.5; -% rotateui -uicontrol('tag', 'rotateui', 'parent', fig, 'units', 'normalized', 'style', 'text', 'string', 'rotate', 'callback', []) -uicontrol('tag', 'rx', 'parent', fig, 'units', 'normalized', 'style', 'edit', 'string', '0', 'callback', @cb_redraw) -uicontrol('tag', 'ry', 'parent', fig, 'units', 'normalized', 'style', 'edit', 'string', '0', 'callback', @cb_redraw) -uicontrol('tag', 'rz', 'parent', fig, 'units', 'normalized', 'style', 'edit', 'string', '0', 'callback', @cb_redraw) -ft_uilayout(fig, 'tag', 'rotateui', 'BackgroundColor', [0.8 0.8 0.8], 'width', 2*CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'hpos', CONTROL_HOFFSET, 'vpos', CONTROL_VOFFSET); -ft_uilayout(fig, 'tag', 'rx', 'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'hpos', CONTROL_HOFFSET+3*CONTROL_WIDTH, 'vpos', CONTROL_VOFFSET); -ft_uilayout(fig, 'tag', 'ry', 'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'hpos', CONTROL_HOFFSET+4*CONTROL_WIDTH, 'vpos', CONTROL_VOFFSET); -ft_uilayout(fig, 'tag', 'rz', 'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'hpos', CONTROL_HOFFSET+5*CONTROL_WIDTH, 'vpos', CONTROL_VOFFSET); - -% scaleui -uicontrol('tag', 'scaleui', 'parent', fig, 'units', 'normalized', 'style', 'text', 'string', 'scale', 'callback', []) -uicontrol('tag', 'sx', 'parent', fig, 'units', 'normalized', 'style', 'edit', 'string', '1', 'callback', @cb_redraw) -uicontrol('tag', 'sy', 'parent', fig, 'units', 'normalized', 'style', 'edit', 'string', '1', 'callback', @cb_redraw) -uicontrol('tag', 'sz', 'parent', fig, 'units', 'normalized', 'style', 'edit', 'string', '1', 'callback', @cb_redraw) -ft_uilayout(fig, 'tag', 'scaleui', 'BackgroundColor', [0.8 0.8 0.8], 'width', 2*CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'hpos', CONTROL_HOFFSET, 'vpos', CONTROL_VOFFSET-CONTROL_HEIGHT); -ft_uilayout(fig, 'tag', 'sx', 'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'hpos', CONTROL_HOFFSET+3*CONTROL_WIDTH, 'vpos', CONTROL_VOFFSET-CONTROL_HEIGHT); -ft_uilayout(fig, 'tag', 'sy', 'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'hpos', CONTROL_HOFFSET+4*CONTROL_WIDTH, 'vpos', CONTROL_VOFFSET-CONTROL_HEIGHT); -ft_uilayout(fig, 'tag', 'sz', 'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'hpos', CONTROL_HOFFSET+5*CONTROL_WIDTH, 'vpos', CONTROL_VOFFSET-CONTROL_HEIGHT); - -% translateui -uicontrol('tag', 'translateui', 'parent', fig, 'units', 'normalized', 'style', 'text', 'string', 'translate', 'callback', []) -uicontrol('tag', 'tx', 'parent', fig, 'units', 'normalized', 'style', 'edit', 'string', '0', 'callback', @cb_redraw) -uicontrol('tag', 'ty', 'parent', fig, 'units', 'normalized', 'style', 'edit', 'string', '0', 'callback', @cb_redraw) -uicontrol('tag', 'tz', 'parent', fig, 'units', 'normalized', 'style', 'edit', 'string', '0', 'callback', @cb_redraw) -ft_uilayout(fig, 'tag', 'translateui', 'BackgroundColor', [0.8 0.8 0.8], 'width', 2*CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'hpos', CONTROL_HOFFSET, 'vpos', CONTROL_VOFFSET-2*CONTROL_HEIGHT); -ft_uilayout(fig, 'tag', 'tx', 'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'hpos', CONTROL_HOFFSET+3*CONTROL_WIDTH, 'vpos', CONTROL_VOFFSET-2*CONTROL_HEIGHT); -ft_uilayout(fig, 'tag', 'ty', 'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'hpos', CONTROL_HOFFSET+4*CONTROL_WIDTH, 'vpos', CONTROL_VOFFSET-2*CONTROL_HEIGHT); -ft_uilayout(fig, 'tag', 'tz', 'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'hpos', CONTROL_HOFFSET+5*CONTROL_WIDTH, 'vpos', CONTROL_VOFFSET-2*CONTROL_HEIGHT); - -% control buttons -uicontrol('tag', 'redisplaybtn', 'parent', fig, 'units', 'normalized', 'style', 'pushbutton', 'string', 'redisplay', 'value', [], 'callback', @cb_redraw); -uicontrol('tag', 'applybtn', 'parent', fig, 'units', 'normalized', 'style', 'pushbutton', 'string', 'apply', 'value', [], 'callback', @cb_apply); -uicontrol('tag', 'toggle labels', 'parent', fig, 'units', 'normalized', 'style', 'pushbutton', 'string', 'toggle label', 'value', 0, 'callback', @cb_redraw); -uicontrol('tag', 'toggle axes', 'parent', fig, 'units', 'normalized', 'style', 'pushbutton', 'string', 'toggle axes', 'value', 0, 'callback', @cb_redraw); -ft_uilayout(fig, 'tag', 'redisplaybtn', 'BackgroundColor', [0.8 0.8 0.8], 'width', 6*CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'vpos', CONTROL_VOFFSET-3*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET); -ft_uilayout(fig, 'tag', 'applybtn', 'BackgroundColor', [0.8 0.8 0.8], 'width', 6*CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'vpos', CONTROL_VOFFSET-4*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET); -ft_uilayout(fig, 'tag', 'toggle labels', 'BackgroundColor', [0.8 0.8 0.8], 'width', 6*CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'vpos', CONTROL_VOFFSET-5*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET); -ft_uilayout(fig, 'tag', 'toggle axes', 'BackgroundColor', [0.8 0.8 0.8], 'width', 6*CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'vpos', CONTROL_VOFFSET-6*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET); - -% alpha ui (somehow not implemented, facealpha is fixed at 0.7 -uicontrol('tag', 'alphaui', 'parent', fig, 'units', 'normalized', 'style', 'text', 'string', 'alpha', 'value', [], 'callback', []); -uicontrol('tag', 'alpha', 'parent', fig, 'units', 'normalized', 'style', 'edit', 'string', '0.7', 'value', [], 'callback', @cb_redraw); -ft_uilayout(fig, 'tag', 'alphaui', 'BackgroundColor', [0.8 0.8 0.8], 'width', 3*CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'vpos', CONTROL_VOFFSET-7*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET); -ft_uilayout(fig, 'tag', 'alpha', 'BackgroundColor', [0.8 0.8 0.8], 'width', 3*CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'vpos', CONTROL_VOFFSET-7*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET+3*CONTROL_WIDTH); - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -function cb_redraw(hObject, eventdata, handles) -fig = get(hObject, 'parent'); -headshape = getappdata(fig, 'headshape'); -elec = getappdata(fig, 'elec'); -template = getappdata(fig, 'template'); -% get the transformation details -rx = str2num(get(findobj(fig, 'tag', 'rx'), 'string')); -ry = str2num(get(findobj(fig, 'tag', 'ry'), 'string')); -rz = str2num(get(findobj(fig, 'tag', 'rz'), 'string')); -tx = str2num(get(findobj(fig, 'tag', 'tx'), 'string')); -ty = str2num(get(findobj(fig, 'tag', 'ty'), 'string')); -tz = str2num(get(findobj(fig, 'tag', 'tz'), 'string')); -sx = str2num(get(findobj(fig, 'tag', 'sx'), 'string')); -sy = str2num(get(findobj(fig, 'tag', 'sy'), 'string')); -sz = str2num(get(findobj(fig, 'tag', 'sz'), 'string')); -R = rotate ([rx ry rz]); -T = translate([tx ty tz]); -S = scale ([sx sy sz]); -H = S * T * R; -elec = ft_transform_sens(H, elec); -axis vis3d; cla -xlabel('x') -ylabel('y') -zlabel('z') - -if ~isempty(template) - disp('Plotting the template electrodes in blue'); - if size(template.chanpos, 2)==2 - hs = plot(template.chanpos(:,1), template.chanpos(:,2), 'b.', 'MarkerSize', 20); - else - hs = plot3(template.chanpos(:,1), template.chanpos(:,2), template.chanpos(:,3), 'b.', 'MarkerSize', 20); - end -end - -if ~isempty(headshape) - % plot the faces of the 2D or 3D triangulation - skin = [255 213 119]/255; - ft_plot_mesh(headshape,'facecolor', skin,'EdgeColor','none','facealpha',0.7); - lighting gouraud - material shiny - camlight -end - -if isfield(elec, 'fid') && ~isempty(elec.fid.pos) - disp('Plotting the fiducials in red'); - ft_plot_sens(elec.fid,'style', 'r*'); -end - -if get(findobj(fig, 'tag', 'toggle axes'), 'value') - axis on - grid on -else - axis off - grid on -end - -hold on -if get(findobj(fig, 'tag', 'toggle labels'), 'value') - ft_plot_sens(elec,'label', 'on'); -else - ft_plot_sens(elec,'label', 'off'); -end - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -function cb_apply(hObject, eventdata, handles) -fig = get(hObject, 'parent'); -elec = getappdata(fig, 'elec'); -transform = getappdata(fig, 'transform'); -% get the transformation details -rx = str2num(get(findobj(fig, 'tag', 'rx'), 'string')); -ry = str2num(get(findobj(fig, 'tag', 'ry'), 'string')); -rz = str2num(get(findobj(fig, 'tag', 'rz'), 'string')); -tx = str2num(get(findobj(fig, 'tag', 'tx'), 'string')); -ty = str2num(get(findobj(fig, 'tag', 'ty'), 'string')); -tz = str2num(get(findobj(fig, 'tag', 'tz'), 'string')); -sx = str2num(get(findobj(fig, 'tag', 'sx'), 'string')); -sy = str2num(get(findobj(fig, 'tag', 'sy'), 'string')); -sz = str2num(get(findobj(fig, 'tag', 'sz'), 'string')); -R = rotate ([rx ry rz]); -T = translate([tx ty tz]); -S = scale ([sx sy sz]); -H = S * T * R; -elec = ft_transform_headshape(H, elec); -transform = H * transform; -set(findobj(fig, 'tag', 'rx'), 'string', 0); -set(findobj(fig, 'tag', 'ry'), 'string', 0); -set(findobj(fig, 'tag', 'rz'), 'string', 0); -set(findobj(fig, 'tag', 'tx'), 'string', 0); -set(findobj(fig, 'tag', 'ty'), 'string', 0); -set(findobj(fig, 'tag', 'tz'), 'string', 0); -set(findobj(fig, 'tag', 'sx'), 'string', 1); -set(findobj(fig, 'tag', 'sy'), 'string', 1); -set(findobj(fig, 'tag', 'sz'), 'string', 1); -setappdata(fig, 'elec', elec); -setappdata(fig, 'transform', transform); -cb_redraw(hObject); - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -function cb_close(hObject, eventdata, handles) -% make the current transformation permanent and subsequently allow deleting the figure -cb_apply(gca); -% get the updated electrode from the figure -fig = hObject; -% hmmm, this is ugly -global norm -norm = getappdata(fig, 'elec'); -norm.m = getappdata(fig, 'transform'); -set(fig, 'CloseRequestFcn', @delete); -delete(fig); diff --git a/external/fieldtrip/ft_singleplotER.m b/external/fieldtrip/ft_singleplotER.m index f1132047..3e82e958 100644 --- a/external/fieldtrip/ft_singleplotER.m +++ b/external/fieldtrip/ft_singleplotER.m @@ -22,19 +22,20 @@ % cfg.maskstyle = style used for masking of data, 'box', 'thickness' or 'saturation' (default = 'box') % cfg.xlim = 'maxmin' or [xmin xmax] (default = 'maxmin') % cfg.ylim = 'maxmin', 'maxabs', 'zeromax', 'minzero', or [ymin ymax] (default = 'maxmin') -% cfg.channel = nx1 cell-array with selection of channels (default = 'all'), +% cfg.channel = nx1 cell-array with selection of channels (default = 'all') % see ft_channelselection for details +% cfg.title = string, title of plot % cfg.refchannel = name of reference channel for visualising connectivity, can be 'gui' -% cfg.baseline = 'yes','no' or [time1 time2] (default = 'no'), see ft_timelockbaseline +% cfg.baseline = 'yes', 'no' or [time1 time2] (default = 'no'), see ft_timelockbaseline % cfg.baselinetype = 'absolute' or 'relative' (default = 'absolute') % cfg.trials = 'all' or a selection given as a 1xn vector (default = 'all') % cfg.fontsize = font size of title (default = 8) -% cfg.hotkeys = enables hotkeys (up/down/left/right arrows) for dynamic x/y axis translation (Ctrl+) and zoom adjustment +% cfg.hotkeys = enables hotkeys (leftarrow/rightarrow/uparrow/downarrow/m) for dynamic zoom and translation (ctrl+) of the axes % cfg.interactive = interactive plot 'yes' or 'no' (default = 'yes') % in a interactive plot you can select areas and produce a new % interactive plot when a selected area is clicked. multiple areas % can be selected by holding down the shift key. -% cfg.renderer = 'painters', 'zbuffer',' opengl' or 'none' (default = []) +% cfg.renderer = 'painters', 'zbuffer', ' opengl' or 'none' (default = []) % cfg.linestyle = linestyle/marker type, see options of the PLOT function (default = '-') % can be a single style for all datasets, or a cell-array containing one style for each dataset % cfg.linewidth = linewidth in points (default = 0.5) @@ -75,9 +76,9 @@ % Undocumented local options: % cfg.zlim/xparam (set to a specific frequency range or time range [zmax zmin] for an average % over the frequency/time bins for TFR data. Use in conjunction with e.g. xparam = 'time', and cfg.parameter = 'powspctrm'). -% cfg.preproc % Copyright (C) 2003-2006, Ole Jensen +% Copyright (C) 2006-2017, F.C. Donders Centre % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -97,6 +98,17 @@ % % $Id$ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% DEVELOPERS NOTE: This code is organized in a similar fashion for multiplot/singleplot/topoplot +% and for ER/TFR and should remain consistent over those 6 functions. +% Section 1: general cfg handling that is independent from the data +% Section 2: data handling, this also includes converting bivariate (chan_chan and chancmb) into univariate data +% Section 3: select the data to be plotted and determine min/max range +% Section 4: do the actual plotting +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Section 1: general cfg handling that is independent from the data + % these are used by the ft_preamble/ft_postamble function and scripts ft_revision = '$Id$'; ft_nargin = nargin; @@ -115,6 +127,12 @@ return end +Ndata = numel(varargin); +for i=1:Ndata + % check if the input data is valid for this function + varargin{i} = ft_checkdata(varargin{i}, 'datatype', {'timelock', 'freq'}); +end + % check if the input cfg is valid for this function cfg = ft_checkconfig(cfg, 'unused', {'cohtargetchannel'}); cfg = ft_checkconfig(cfg, 'renamedval', {'zlim', 'absmax', 'maxabs'}); @@ -128,297 +146,229 @@ cfg = ft_checkconfig(cfg, 'deprecated', {'xparam'}); % set the defaults -cfg.baseline = ft_getopt(cfg, 'baseline', 'no'); -cfg.trials = ft_getopt(cfg, 'trials', 'all', 1); -cfg.xlim = ft_getopt(cfg, 'xlim', 'maxmin'); -cfg.ylim = ft_getopt(cfg, 'ylim', 'maxmin'); -cfg.zlim = ft_getopt(cfg, 'zlim', 'maxmin'); -cfg.comment = ft_getopt(cfg, 'comment', strcat([date '\n'])); -cfg.axes = ft_getopt(cfg,' axes', 'yes'); -cfg.fontsize = ft_getopt(cfg, 'fontsize', 8); -cfg.graphcolor = ft_getopt(cfg, 'graphcolor', 'brgkywrgbkywrgbkywrgbkyw'); -cfg.hotkeys = ft_getopt(cfg, 'hotkeys', 'no'); -cfg.interactive = ft_getopt(cfg, 'interactive', 'yes'); -cfg.renderer = ft_getopt(cfg, 'renderer', []); -cfg.maskparameter = ft_getopt(cfg, 'maskparameter',[]); -cfg.linestyle = ft_getopt(cfg, 'linestyle', '-'); -cfg.linewidth = ft_getopt(cfg, 'linewidth', 0.5); -cfg.maskstyle = ft_getopt(cfg, 'maskstyle', 'box'); -cfg.channel = ft_getopt(cfg, 'channel', 'all'); -cfg.directionality = ft_getopt(cfg, 'directionality', []); -cfg.figurename = ft_getopt(cfg, 'figurename', []); -cfg.preproc = ft_getopt(cfg, 'preproc', []); -cfg.frequency = ft_getopt(cfg, 'frequency', 'all'); % needed for frequency selection with TFR data -cfg.latency = ft_getopt(cfg, 'latency', 'all'); % needed for latency selection with TFR data, FIXME, probably not used - - -Ndata = numel(varargin); +cfg.baseline = ft_getopt(cfg, 'baseline', 'no'); +cfg.trials = ft_getopt(cfg, 'trials', 'all', 1); +cfg.xlim = ft_getopt(cfg, 'xlim', 'maxmin'); +cfg.ylim = ft_getopt(cfg, 'ylim', 'maxmin'); +cfg.zlim = ft_getopt(cfg, 'zlim', 'maxmin'); +cfg.comment = ft_getopt(cfg, 'comment', strcat([date '\n'])); +cfg.axes = ft_getopt(cfg, ' axes', 'yes'); +cfg.fontsize = ft_getopt(cfg, 'fontsize', 8); +cfg.graphcolor = ft_getopt(cfg, 'graphcolor', 'brgkywrgbkywrgbkywrgbkyw'); +cfg.hotkeys = ft_getopt(cfg, 'hotkeys', 'yes'); +cfg.interactive = ft_getopt(cfg, 'interactive', 'yes'); +cfg.renderer = ft_getopt(cfg, 'renderer', []); +cfg.maskparameter = ft_getopt(cfg, 'maskparameter', []); +cfg.linestyle = ft_getopt(cfg, 'linestyle', '-'); +cfg.linewidth = ft_getopt(cfg, 'linewidth', 0.5); +cfg.maskstyle = ft_getopt(cfg, 'maskstyle', 'box'); +cfg.channel = ft_getopt(cfg, 'channel', 'all'); +cfg.title = ft_getopt(cfg, 'title', []); +cfg.directionality = ft_getopt(cfg, 'directionality', []); +cfg.figurename = ft_getopt(cfg, 'figurename', []); +cfg.preproc = ft_getopt(cfg, 'preproc', []); +cfg.frequency = ft_getopt(cfg, 'frequency', 'all'); % needed for frequency selection with TFR data +cfg.latency = ft_getopt(cfg, 'latency', 'all'); % needed for latency selection with TFR data, FIXME, probably not used -% interactive plotting is not allowed with more than 1 input -% if Ndata >1 && strcmp(cfg.interactive, 'yes') -% error('interactive plotting is not supported with more than 1 input data set'); -% end - -% FIXME rename directionality and cohrefchannel in more meaningful options if ischar(cfg.graphcolor) - graphcolor = ['k' cfg.graphcolor]; + graphcolor = cfg.graphcolor(1:Ndata); elseif isnumeric(cfg.graphcolor) - graphcolor = [0 0 0; cfg.graphcolor]; + graphcolor = cfg.graphcolor(1:Ndata,:); end -% check for linestyle being a cell-array, check it's length, and lengthen it if does not have enough styles in it +% check for linestyle being a cell-array if ischar(cfg.linestyle) cfg.linestyle = {cfg.linestyle}; end -if Ndata > 1 - if (length(cfg.linestyle) < Ndata ) && (length(cfg.linestyle) > 1) - error('either specify cfg.linestyle as a cell-array with one cell for each dataset, or only specify one linestyle') - elseif (length(cfg.linestyle) < Ndata ) && (length(cfg.linestyle) == 1) - tmpstyle = cfg.linestyle{1}; - cfg.linestyle = cell(Ndata , 1); - for idataset = 1:Ndata - cfg.linestyle{idataset} = tmpstyle; - end +% check linestyle length, and lengthen it if does not have enough styles in it +if (length(cfg.linestyle) < Ndata ) && (length(cfg.linestyle) > 1) + ft_error('either specify cfg.linestyle as a cell-array with one cell for each dataset, or only specify one linestyle') +elseif (length(cfg.linestyle) < Ndata ) && (length(cfg.linestyle) == 1) + tmpstyle = cfg.linestyle{1}; + cfg.linestyle = cell(Ndata , 1); + for idataset = 1:Ndata + cfg.linestyle{idataset} = tmpstyle; end end -% ensure that the input is correct, also backward compatibility with old data structures: -dtype = cell(Ndata, 1); -for i=1:Ndata - % check if the input data is valid for this function - varargin{i} = ft_checkdata(varargin{i}, 'datatype', {'timelock', 'freq'}); - dtype{i} = ft_datatype(varargin{i}); - - % this is needed for correct treatment of graphcolor later on - if nargin>1, - if ~isempty(inputname(i+1)) - iname{i+1} = inputname(i+1); - else - iname{i+1} = ['input',num2str(i,'%02d')]; - end +% this is needed for the figure title and correct labeling of graphcolor later on +if nargin>1 + if isfield(cfg, 'dataname') + dataname = cfg.dataname; else - iname{i+1} = cfg.inputfile{i}; - end -end - -if Ndata >1, - if ~all(strcmp(dtype{1}, dtype)) - error('input data are of different type; this is not supported'); + dataname = cell(1,Ndata); + for i=1:Ndata + if ~isempty(inputname(i+1)) + dataname{i} = inputname(i+1); + else + dataname{i} = ['data' num2str(i,'%02d')]; + end + end end +else % data provided through cfg.inputfile + dataname = cfg.inputfile; end -dtype = dtype{1}; -dimord = varargin{1}.dimord; -dimtok = tokenize(dimord, '_'); -% ensure that the preproc specific options are located in the cfg.preproc -% substructure, but also ensure that the field 'refchannel' is present at the -% highest level in the structure. This is a little hack by JM because the field -% refchannel can also refer to the plotting of a connectivity metric. Also, -% the freq2raw conversion does not work at all in the call to ft_preprocessing. -% Therefore, for now, the preprocessing will not be done when there is freq -% data in the input. A more generic solution should be considered. +%% Section 2: data handling, this also includes converting bivariate (chan_chan and chancmb) into univariate data -if isfield(cfg, 'refchannel'), refchannelincfg = cfg.refchannel; end -if ~any(strcmp({'freq','freqmvar'},dtype)), - cfg = ft_checkconfig(cfg, 'createsubcfg', {'preproc'}); +for i=1:Ndata + dtype{i} = ft_datatype(varargin{i}); + hastime(i) = isfield(varargin{i}, 'time'); + hasfreq(i) = isfield(varargin{i}, 'freq'); end -if exist('refchannelincfg', 'var'), cfg.refchannel = refchannelincfg; end -if ~isempty(cfg.preproc) - % preprocess the data, i.e. apply filtering, baselinecorrection, etc. - fprintf('applying preprocessing options\n'); - if ~isfield(cfg.preproc, 'feedback') - cfg.preproc.feedback = cfg.interactive; - end - for i=1:Ndata - varargin{i} = ft_preprocessing(cfg.preproc, varargin{i}); - end +% check if the input has consistent datatypes +if ~all(strcmp(dtype, dtype{1})) || ~all(hastime==hastime(1)) || ~all(hasfreq==hasfreq(1)) + ft_error('different datatypes are not allowed as input'); +else + dtype = dtype{1}; + hastime = hastime(1); + hasfreq = hasfreq(1); end -% set x/y/parameter defaults according to datatype and dimord +% Set x/y/parameter according to datatype and dimord switch dtype case 'timelock' xparam = 'time'; - yparam = ''; - cfg.parameter = ft_getopt(cfg, 'parameter', 'avg'); + if isfield(varargin{1}, 'trial') + cfg.parameter = ft_getopt(cfg, 'parameter', 'trial'); + elseif isfield(varargin{1}, 'individual') + cfg.parameter = ft_getopt(cfg, 'parameter', 'individual'); + elseif isfield(varargin{1}, 'avg') + cfg.parameter = ft_getopt(cfg, 'parameter', 'avg'); + end case 'freq' - if sum(ismember(dimtok, 'time')) - xparam = 'time'; - yparam = 'freq'; - cfg.parameter = ft_getopt(cfg, 'parameter', 'powspctrm'); - elseif sum(ismember(dimtok, 'time')) - xparam = 'freq'; - yparam = 'time'; - cfg.parameter = ft_getopt(cfg, 'parameter', 'powspctrm'); + if hastime && hasfreq + xparam = 'time'; % average over selected frequencies else xparam = 'freq'; - yparam = ''; - cfg.parameter = ft_getopt(cfg, 'parameter', 'powspctrm'); end + cfg.parameter = ft_getopt(cfg, 'parameter', 'powspctrm'); case 'comp' % not supported otherwise % not supported end -% user specified own fields, but no yparam (which is not asked in help) -if exist('xparam', 'var') && isfield(cfg, 'parameter') && ~exist('yparam', 'var') - yparam = ''; +% check whether rpt/subj is present and remove if necessary +dimord = getdimord(varargin{1}, cfg.parameter); +dimtok = tokenize(dimord, '_'); +hasrpt = any(ismember(dimtok, {'rpt' 'subj'})); + +if ~hasrpt + assert(isequal(cfg.trials, 'all') || isequal(cfg.trials, 1), 'incorrect specification of cfg.trials for data without repetitions'); +else + assert(~isempty(cfg.trials), 'empty specification of cfg.trials for data with repetitions'); end +% parse cfg.channel if isfield(cfg, 'channel') && isfield(varargin{1}, 'label') cfg.channel = ft_channelselection(cfg.channel, varargin{1}.label); elseif isfield(cfg, 'channel') && isfield(varargin{1}, 'labelcmb') cfg.channel = ft_channelselection(cfg.channel, unique(varargin{1}.labelcmb(:))); end -% check whether rpt/subj is present and remove if necessary and whether -hasrpt = sum(ismember(dimtok, {'rpt' 'subj'})); -if strcmp(dtype, 'timelock') && hasrpt, - tmpcfg = []; - tmpcfg.trials = cfg.trials; - for i=1:Ndata - varargin{i} = ft_timelockanalysis(tmpcfg, varargin{i}); - end - if ~strcmp(cfg.parameter, 'avg') - % rename avg back into the parameter - varargin{i}.(cfg.parameter) = varargin{i}.avg; - varargin{i} = rmfield(varargin{i}, 'avg'); - end - dimord = varargin{1}.dimord; - dimtok = tokenize(dimord, '_'); -elseif strcmp(dtype, 'freq') && hasrpt, - % this also deals with fourier-spectra in the input - % or with multiple subjects in a frequency domain stat-structure - % on the fly computation of coherence spectrum is not supported - for i=1:Ndata - if isfield(varargin{i}, 'crsspctrm'), - varargin{i} = rmfield(varargin{i}, 'crsspctrm'); - end - end - - tmpcfg = []; - tmpcfg.trials = cfg.trials; - tmpcfg.jackknife = 'no'; - for i=1:Ndata - if isfield(cfg, 'parameter') && ~strcmp(cfg.parameter,'powspctrm') - % freqdesctiptives will only work on the powspctrm field - % hence a temporary copy of the data is needed - tempdata.dimord = varargin{i}.dimord; - tempdata.freq = varargin{i}.freq; - tempdata.label = varargin{i}.label; - tempdata.powspctrm = varargin{i}.(cfg.parameter); - if isfield(varargin{i}, 'cfg') tempdata.cfg = varargin{i}.cfg; end - tempdata = ft_freqdescriptives(tmpcfg, tempdata); - varargin{i}.(cfg.parameter) = tempdata.powspctrm; - clear tempdata - else - varargin{i} = ft_freqdescriptives(tmpcfg, varargin{i}); - end - end - dimord = varargin{1}.dimord; - dimtok = tokenize(dimord, '_'); -end - % apply baseline correction if ~strcmp(cfg.baseline, 'no') for i=1:Ndata + % keep mask-parameter if it is set + if ~isempty(cfg.maskparameter) + tempmask = varargin{i}.(cfg.maskparameter); + end if strcmp(dtype, 'timelock') && strcmp(xparam, 'time') varargin{i} = ft_timelockbaseline(cfg, varargin{i}); elseif strcmp(dtype, 'freq') && strcmp(xparam, 'time') varargin{i} = ft_freqbaseline(cfg, varargin{i}); elseif strcmp(dtype, 'freq') && strcmp(xparam, 'freq') - error('baseline correction is not supported for spectra without a time dimension'); + ft_error('baseline correction is not supported for spectra without a time dimension'); else - warning('baseline correction not applied, please set xparam'); + ft_warning('baseline correction not applied, please set xparam'); + end + % put mask-parameter back if it is set + if ~isempty(cfg.maskparameter) + varargin{i}.(cfg.maskparameter) = tempmask; end end end -% handle the bivariate case -% check for bivariate metric with 'chan_chan' in the dimord -selchan = strmatch('chan', dimtok); -isfull = length(selchan)>1; +% channels should NOT be selected and averaged here, since a topoplot might follow in interactive mode +tmpcfg = keepfields(cfg, {'showcallinfo', 'trials'}); +if hasrpt + tmpcfg.avgoverrpt = 'yes'; +else + tmpcfg.avgoverrpt = 'no'; +end +if hastime && hasfreq + tmpcfg.avgoverfreq = 'yes'; % average over selected frequencies + tmpcfg.frequency = cfg.frequency; % not to be confused with cfg.xlim or cfg.ylim + tmpcfg.keepfreqdim = 'no'; +else + tmpcfg.avgoverfreq = 'no'; +end +tmpvar = varargin{1}; +[varargin{:}] = ft_selectdata(tmpcfg, varargin{:}); +% restore the provenance information and put back cfg.channel +tmpchannel = cfg.channel; +[cfg, varargin{:}] = rollback_provenance(cfg, varargin{:}); +cfg.channel = tmpchannel; + +if isfield(tmpvar, cfg.maskparameter) && ~isfield(varargin{1}, cfg.maskparameter) + % the mask parameter is not present after ft_selectdata, because it is + % not included in all input arguments. Make the same selection and copy + % it over + tmpvar = ft_selectdata(tmpcfg, tmpvar); + varargin{1}.(cfg.maskparameter) = tmpvar.(cfg.maskparameter); +end -% check for bivariate metric with a labelcmb -haslabelcmb = isfield(varargin{1}, 'labelcmb'); +clear tmpvar tmpcfg dimord dimtok hastime hasfreq hasrpt -if (isfull || haslabelcmb) && (isfield(varargin{1}, cfg.parameter) && ~strcmp(cfg.parameter, 'powspctrm')) - % a reference channel is required: - if ~isfield(cfg, 'refchannel') - error('no reference channel is specified'); - end +% ensure that the preproc specific options are located in the cfg.preproc +% substructure, but also ensure that the field 'refchannel' remains at the +% highest level in the structure. This is a little hack by JM because the field +% refchannel can relate to connectivity or to an EEg reference. - % check for refchannel being part of selection - if ~strcmp(cfg.refchannel,'gui') - if haslabelcmb - cfg.refchannel = ft_channelselection(cfg.refchannel, unique(varargin{1}.labelcmb(:))); - else - cfg.refchannel = ft_channelselection(cfg.refchannel, varargin{1}.label); - end - if (isfull && ~any(ismember(varargin{1}.label, cfg.refchannel))) || ... - (haslabelcmb && ~any(ismember(varargin{1}.labelcmb(:), cfg.refchannel))) - error('cfg.refchannel is a not present in the (selected) channels)') - end - end +if isfield(cfg, 'refchannel'), refchannelincfg = cfg.refchannel; cfg = rmfield(cfg, 'refchannel'); end +cfg = ft_checkconfig(cfg, 'createsubcfg', {'preproc'}); +if exist('refchannelincfg', 'var'), cfg.refchannel = refchannelincfg; end - % interactively select the reference channel - if strcmp(cfg.refchannel, 'gui') - error('cfg.refchannel = ''gui'' is not supported in ft_singleplotER'); +if ~isempty(cfg.preproc) + % preprocess the data, i.e. apply filtering, baselinecorrection, etc. + fprintf('applying preprocessing options\n'); + if ~isfield(cfg.preproc, 'feedback') + cfg.preproc.feedback = cfg.interactive; end - for i=1:Ndata - if ~isfull, - % convert 2-dimensional channel matrix to a single dimension: - if isempty(cfg.directionality) - sel1 = find(strcmp(cfg.refchannel, varargin{i}.labelcmb(:,2))); - sel2 = find(strcmp(cfg.refchannel, varargin{i}.labelcmb(:,1))); - elseif strcmp(cfg.directionality, 'outflow') - sel1 = []; - sel2 = find(strcmp(cfg.refchannel, varargin{i}.labelcmb(:,1))); - elseif strcmp(cfg.directionality, 'inflow') - sel1 = find(strcmp(cfg.refchannel, varargin{i}.labelcmb(:,2))); - sel2 = []; - end - fprintf('selected %d channels for %s\n', length(sel1)+length(sel2), cfg.parameter); - if length(sel1)+length(sel2)==0 - error('there are no channels selected for plotting: you may need to look at the specification of cfg.directionality'); - end - varargin{i}.(cfg.parameter) = varargin{i}.(cfg.parameter)([sel1;sel2],:,:); - varargin{i}.label = [varargin{i}.labelcmb(sel1,1);varargin{i}.labelcmb(sel2,2)]; - varargin{i}.labelcmb = varargin{i}.labelcmb([sel1;sel2],:); - varargin{i} = rmfield(varargin{i}, 'labelcmb'); - else - % general case - sel = match_str(varargin{i}.label, cfg.refchannel); - siz = [size(varargin{i}.(cfg.parameter)) 1]; - if strcmp(cfg.directionality, 'inflow') || isempty(cfg.directionality) - %the interpretation of 'inflow' and 'outflow' depend on - %the definition in the bivariate representation of the data - %data.(cfg.parameter) = reshape(mean(data.(cfg.parameter)(:,sel,:),2),[siz(1) 1 siz(3:end)]); - sel1 = 1:siz(1); - sel2 = sel; - meandir = 2; - elseif strcmp(cfg.directionality, 'outflow') - %data.(cfg.parameter) = reshape(mean(data.(cfg.parameter)(sel,:,:),1),[siz(1) 1 siz(3:end)]); - sel1 = sel; - sel2 = 1:siz(1); - meandir = 1; - - elseif strcmp(cfg.directionality, 'ff-fd') - error('cfg.directionality = ''ff-fd'' is not supported anymore, you have to manually subtract the two before the call to ft_singleplotER'); - elseif strcmp(cfg.directionality, 'fd-ff') - error('cfg.directionality = ''fd-ff'' is not supported anymore, you have to manually subtract the two before the call to ft_singleplotER'); - end %if directionality - end %if ~isfull - end %for i -end %handle the bivariate data - -% get physical min/max range of x -if strcmp(cfg.xlim,'maxmin') - % find maxmin throughout all varargins: + varargin{i} = ft_preprocessing(cfg.preproc, varargin{i}); + end +end + +% Handle the bivariate case +dimord = getdimord(varargin{1}, cfg.parameter); +if startsWith(dimord, 'chan_chan_') || startsWith(dimord, 'chancmb_') + % convert the bivariate data to univariate and call this plotting function again + cfg.originalfunction = 'ft_singleplotER'; + cfg.trials = 'all'; % trial selection has been taken care off + bivariate_common(cfg, varargin{:}); + return +end + +% Apply channel-type specific scaling +tmpcfg = keepfields(cfg, {'parameter', 'chanscale', 'ecgscale', 'eegscale', 'emgscale', 'eogscale', 'gradscale', 'magscale', 'megscale', 'mychan', 'mychanscale'}); +for i=1:Ndata + varargin{i}= chanscale_common(tmpcfg, varargin{i}); +end + + +%% Section 3: select the data to be plotted and determine min/max range + +% Take the desided subselection of channels, this is the same in all datasets +[selchan] = match_str(varargin{1}.label, cfg.channel); + +% Get physical min/max range of x, i.e. time or frequency +if strcmp(cfg.xlim, 'maxmin') + % Find maxmin throughout all varargins: xmin = []; xmax = []; for i=1:Ndata @@ -430,155 +380,73 @@ xmax = cfg.xlim(2); end -% get the index of the nearest bin -for i=1:Ndata - xidmin(i,1) = nearest(varargin{i}.(xparam), xmin); - xidmax(i,1) = nearest(varargin{i}.(xparam), xmax); -end - -if strcmp('freq', yparam) && strcmp('freq', dtype) - tmpcfg = keepfields(cfg, {'parameter'}); - tmpcfg.avgoverfreq = 'yes'; - tmpcfg.frequency = cfg.frequency;%cfg.zlim; - [varargin{:}] = ft_selectdata(tmpcfg, varargin{:}); - % restore the provenance information - [cfg, varargin{:}] = rollback_provenance(cfg, varargin{:}); -elseif strcmp('time', yparam) && strcmp('freq', dtype) - tmpcfg = keepfields(cfg, {'parameter'}); - tmpcfg.avgovertime = 'yes'; - tmpcfg.latency = cf.latency;%cfg.zlim; - [varargin{:}] = ft_selectdata(tmpcfg, varargin{:}); - % restore the provenance information - [cfg, varargin{:}] = rollback_provenance(cfg, varargin{:}); +% Get the index of the nearest bin, this is the same in all datasets +xminindx = nearest(varargin{1}.(xparam), xmin); +xmaxindx = nearest(varargin{1}.(xparam), xmax); +xmin = varargin{1}.(xparam)(xminindx); +xmax = varargin{1}.(xparam)(xmaxindx); +selx = xminindx:xmaxindx; +xval = varargin{1}.(xparam)(selx); + +% Get physical y-axis range, i.e. parameter to be plotted +if ~isnumeric(cfg.ylim) + % Find maxmin throughout all varargins + ymin = []; + ymax = []; + for i=1:Ndata + % Select the channels in the data that match with the layout and that are selected for plotting + dat = mean(varargin{i}.(cfg.parameter)(selchan,selx),1); % mean over channels, as that is what will be plotted + ymin = min([ymin min(min(min(dat)))]); + ymax = max([ymax max(max(max(dat)))]); + end + if strcmp(cfg.ylim, 'maxabs') % handle maxabs, make y-axis center on 0 + ymax = max([abs(ymax) abs(ymin)]); + ymin = -ymax; + elseif strcmp(cfg.ylim, 'zeromax') + ymin = 0; + elseif strcmp(cfg.ylim, 'minzero') + ymax = 0; + end +else + ymin = cfg.ylim(1); + ymax = cfg.ylim(2); end -cla -hold on; -colorlabels = []; - -% plot each data set: +% Gather the data from all input data structures +datamatrix = zeros(Ndata, length(selchan), length(selx)); for i=1:Ndata - if isfield(varargin{1}, 'label') - selchannel = ft_channelselection(cfg.channel, varargin{i}.label); - elseif isfield(varargin{1}, 'labelcmb') - selchannel = ft_channelselection(cfg.channel, unique(varargin{i}.labelcmb(:))); - else - error('the input data does not contain a label or labelcmb-field'); - end + datamatrix(i,:,:) = varargin{i}.(cfg.parameter)(selchan, selx); +end - % make vector dat with one value for each channel - dat = varargin{i}.(cfg.parameter); - % get dimord dimensions - dims = textscan(varargin{i}.dimord,'%s', 'Delimiter', '_'); - dims = dims{1}; - ydim = find(strcmp(yparam, dims)); - xdim = find(strcmp(xparam, dims)); - zdim = setdiff(1:ndims(dat), [ydim xdim]); - % and permute to make sure that dimensions are in the correct order - dat = permute(dat, [zdim(:)' ydim xdim]); - - - xval = varargin{i}.(xparam); - - % take subselection of channels - % this works for bivariate data with labelcmb because at this point the - % data has a label-field - sellab = match_str(varargin{i}.label, selchannel); - - % if ~isempty(yparam) - % if isfull - % dat = dat(sel1, sel2, ymin:ymax, xidmin(i):xidmax(i)); - % dat = nanmean(nanmean(dat, meandir), 3); - % siz = size(dat); - % %fixmedat = reshape(dat, [siz(1:2) siz(4)]); - % dat = reshape(dat, [siz(1) siz(3)]); - % dat = dat(sellab, :); - % elseif haslabelcmb - % dat = dat(sellab, ymin:ymax, xidmin(i):xidmax(i)); - % dat = nanmean(dat, 2); - % siz = size(dat); - % dat = reshape(dat, [siz(1) siz(3)]); - % else - % dat = dat(sellab, ymin:ymax, xidmin(i):xidmax(i)); - % dat = nanmean(nanmean(dat, 3), 2); - % siz = size(dat); - % dat = reshape(dat, [siz(1) siz(3)]); - % end - % else - if isfull - dat = dat(sel1, sel2, xidmin(i):xidmax(i)); - dat = nanmean(dat, meandir); - siz = size(dat); - siz(find(siz(1:2)==1)) = []; - dat = reshape(dat, siz); - dat = dat(sellab, :); - elseif haslabelcmb - dat = dat(sellab, xidmin(i):xidmax(i)); - else - dat = dat(sellab, xidmin(i):xidmax(i)); - end - % end - xval = xval(xidmin(i):xidmax(i)); - datavector = reshape(mean(dat, 1), [1 numel(xval)]); % average over channels - - % make mask - if ~isempty(cfg.maskparameter) - datmask = varargin{i}.(cfg.maskparameter)(sellab,:); - if size(datmask,2)>1 - datmask = datmask(:,xidmin(i):xidmax(i)); - else - datmask = datmask(xidmin(i):xidmax(i)); - end - maskdatavector = reshape(mean(datmask,1), [1 numel(xval)]); - else - maskdatavector = []; - end +if ~isempty(cfg.maskparameter) + % one value for each channel, or one value for each channel-time point + maskmatrix = varargin{1}.(cfg.maskparameter)(selchan, selx); +else + % create an Nx0 matrix + maskmatrix = zeros(length(selchan), 0); +end - if Ndata > 1 - if ischar(graphcolor); colorlabels = [colorlabels iname{i+1} '=' graphcolor(i+1) '\n']; - elseif isnumeric(graphcolor); colorlabels = [colorlabels iname{i+1} '=' num2str(graphcolor(i+1,:)) '\n']; - end - end +%% Section 4: do the actual plotting - if ischar(graphcolor); color = graphcolor(i+1); - elseif isnumeric(graphcolor); color = graphcolor(i+1,:); - end +cla +hold on - % update ymin and ymax for the current data set: - if ischar(cfg.ylim) - if i==1 - ymin = []; - ymax = []; - end - if strcmp(cfg.ylim,'maxmin') - % select the channels in the data that match with the layout: - ymin = min([ymin min(datavector)]); - ymax = max([ymax max(datavector)]); - elseif strcmp(cfg.ylim,'maxabs') - ymax = max([ymax max(abs(datavector))]); - ymin = -ymax; - elseif strcmp(cfg.ylim,'zeromax') - ymin = 0; - ymax = max([ymax max(datavector)]); - elseif strcmp(cfg.ylim,'minzero') - ymin = min([ymin min(datavector)]); - ymax = 0; - end; - else - ymin = cfg.ylim(1); - ymax = cfg.ylim(2); - end +yval = mean(datamatrix, 2); % over channels +yval = reshape(yval, size(yval,1), size(yval,3)); +mask = squeeze(mean(maskmatrix, 1)); % over channels +ft_plot_vector(xval, yval, 'style', cfg.linestyle{i}, 'color', graphcolor, ... + 'highlight', mask, 'highlightstyle', cfg.maskstyle, 'linewidth', cfg.linewidth, ... + 'hlim', [xmin xmax], 'vlim', [ymin ymax]); - % only plot the mask once, for the first line (it's the same anyway for - % all lines, and if plotted multiple times, it will overlay the others - if i>1 && strcmp(cfg.maskstyle, 'box') - ft_plot_vector(xval, datavector, 'style', cfg.linestyle{i}, 'color', color, ... - 'linewidth', cfg.linewidth, 'hlim', cfg.xlim, 'vlim', cfg.ylim); - else - ft_plot_vector(xval, datavector, 'style', cfg.linestyle{i}, 'color', color, ... - 'highlight', maskdatavector, 'highlightstyle', cfg.maskstyle, 'linewidth', cfg.linewidth, ... - 'hlim', cfg.xlim, 'vlim', cfg.ylim); +colorLabels = []; +if Ndata > 1 + for i=1:Ndata + if ischar(graphcolor) + colorLabels = [colorLabels '\n' dataname{i} '=' graphcolor(i) ]; + elseif isnumeric(graphcolor) + colorLabels = [colorLabels '\n' dataname{i} '=' num2str(graphcolor(i, :)) ]; + end end end @@ -588,42 +456,46 @@ % adjust mask box extents to ymin/ymax if ~isempty(cfg.maskparameter) - ptchs = findobj(gcf,'type','patch'); + ptchs = findobj(gcf, 'type', 'patch'); for i = 1:length(ptchs) - YData = get(ptchs(i),'YData'); + YData = get(ptchs(i), 'YData'); YData(YData == min(YData)) = ymin; YData(YData == max(YData)) = ymax; - set(ptchs(i),'YData',YData); + set(ptchs(i), 'YData',YData); end end -if strcmp('yes',cfg.hotkeys) +% Set callback to adjust axes +if strcmp('yes', cfg.hotkeys) % attach data and cfg to figure and attach a key listener to the figure - set(gcf, 'keypressfcn', {@key_sub, xmin, xmax, ymin, ymax}) + set(gcf, 'KeyPressFcn', {@key_sub, xmin, xmax, ymin, ymax}) end -if isfield(cfg, 'dataname') - dataname = cfg.dataname; -elseif nargin > 1 - dataname = inputname(2); - cfg.dataname = {inputname(2)}; - for k = 2:Ndata - dataname = [dataname ', ' inputname(k+1)]; - cfg.dataname{end+1} = inputname(k+1); - end +% Create axis title containing channel name(s) and channel number(s): +if ~isempty(cfg.title) + t = cfg.title; else - dataname = cfg.inputfile; + if length(cfg.channel) == 1 + t = [char(cfg.channel) ' / ' num2str(selchan) ]; + else + t = sprintf('mean(%0s)', join_str(', ', cfg.channel)); + end end +title(t, 'fontsize', cfg.fontsize); -% set the figure window title, add the channel labels if number is small -if isempty(get(gcf,'Name')) - if length(sellab) < 5 - chans = join_str(',', cfg.channel); +% set the figure window title, add channel labels if number is small +if isempty(get(gcf, 'Name')) + if length(selchan) < 5 + chans = join_str(', ', cfg.channel); else chans = ''; end if isempty(cfg.figurename) - set(gcf, 'Name', sprintf('%d: %s: %s (%s)', double(gcf), mfilename, join_str(', ',dataname), chans)); + if iscell(dataname) + set(gcf, 'Name', sprintf('%d: %s: %s (%s)', double(gcf), mfilename, join_str(', ', dataname), chans)); + else + set(gcf, 'Name', sprintf('%d: %s: %s (%s)', double(gcf), mfilename, dataname, chans)); + end set(gcf, 'NumberTitle', 'off'); else set(gcf, 'name', cfg.figurename); @@ -631,55 +503,27 @@ end end -% make the figure interactive -if strcmp(cfg.interactive, 'yes') - % add the dataname to the figure - % this is used in the callbacks - info = guidata(gcf); - info.dataname = dataname; - guidata(gcf, info); - % attach data to the figure with the current axis handle as a name - dataname = fixname(num2str(double(gca))); - setappdata(gcf,dataname,varargin); - set(gcf, 'windowbuttonupfcn', {@ft_select_range, 'multiple', false, 'yrange', false, 'callback', {@select_topoplotER, cfg}, 'event', 'windowbuttonupfcn'}); - set(gcf, 'windowbuttondownfcn', {@ft_select_range, 'multiple', false, 'yrange', false, 'callback', {@select_topoplotER, cfg}, 'event', 'windowbuttondownfcn'}); - set(gcf, 'windowbuttonmotionfcn', {@ft_select_range, 'multiple', false, 'yrange', false, 'callback', {@select_topoplotER, cfg}, 'event', 'windowbuttonmotionfcn'}); -end - -% create title text containing channel name(s) and channel number(s): -if length(sellab) == 1 - t = [char(cfg.channel) ' / ' num2str(sellab) ]; -else - t = sprintf('mean(%0s)', join_str(',', cfg.channel)); -end -h = title(t,'fontsize', cfg.fontsize); - % set renderer if specified if ~isempty(cfg.renderer) set(gcf, 'renderer', cfg.renderer) end -if false - % FIXME this is for testing purposes - % Define a context menu; it is not attached to anything - cmlines = uicontextmenu; - % Define the context menu items and install their callbacks - uimenu(cmlines, 'Label', 'dashed', 'Callback', 'set(gco, ''LineStyle'', ''--'')'); - uimenu(cmlines, 'Label', 'dotted', 'Callback', 'set(gco, ''LineStyle'', '':'')'); - uimenu(cmlines, 'Label', 'solid', 'Callback', 'set(gco, ''LineStyle'', ''-'')'); - % Locate line objects - hlines = findall(gca, 'Type', 'line'); - % Attach the context menu to each line - for line = 1:length(hlines) - set(hlines(line), 'uicontextmenu', cmlines) - end -end +hold off -% do the general cleanup and bookkeeping at the end of the function -ft_postamble debug -ft_postamble trackconfig -ft_postamble previous varargin -ft_postamble provenance +% Make the figure interactive +if strcmp(cfg.interactive, 'yes') + % add the cfg/data/channel information to the figure under identifier linked to this axis + ident = ['axh' num2str(round(sum(clock.*1e6)))]; % unique identifier for this axis + set(gca, 'tag', ident); + info = guidata(gcf); + info.(ident).cfg = cfg; + info.(ident).varargin = varargin; + info.(ident).dataname = dataname; + guidata(gcf, info); + set(gcf, 'windowbuttonupfcn', {@ft_select_range, 'multiple', false, 'yrange', false, 'callback', {@select_topoplotER}, 'event', 'windowbuttonupfcn'}); + set(gcf, 'windowbuttondownfcn', {@ft_select_range, 'multiple', false, 'yrange', false, 'callback', {@select_topoplotER}, 'event', 'windowbuttondownfcn'}); + set(gcf, 'windowbuttonmotionfcn', {@ft_select_range, 'multiple', false, 'yrange', false, 'callback', {@select_topoplotER}, 'event', 'windowbuttonmotionfcn'}); +end % add a menu to the figure, but only if the current figure does not have subplots % also, delete any possibly existing previous menu, this is safe because delete([]) does nothing @@ -690,44 +534,47 @@ uimenu(ftmenu, 'Label', 'About', 'Callback', @menu_about); end +% do the general cleanup and bookkeeping at the end of the function +ft_postamble debug +ft_postamble trackconfig +ft_postamble previous varargin +ft_postamble provenance + +if ~nargout + % don't return anything + clear cfg +end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % SUBFUNCTION which is called after selecting a time range %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -function select_topoplotER(cfg, varargin) -% first to last callback-input of ft_select_range is range -% last callback-input of ft_select_range is contextmenu label, if used -range = varargin{end-1}; -varargin = varargin(1:end-2); % remove range and last - -% get appdata belonging to current axis -dataname = fixname(num2str(double(gca))); -data = getappdata(gcf, dataname); - -if isfield(cfg, 'inputfile') - % the reading has already been done and varargin contains the data - cfg = rmfield(cfg, 'inputfile'); -end -if isfield(cfg, 'showlabels') - % this is not allowed in topoplotER - cfg = rmfield(cfg, 'showlabels'); -end -% make sure the topo displays all channels, not just the ones in this singleplot -cfg.channel = 'all'; -cfg.comment = 'auto'; -cfg.xlim = range(1:2); -% put data name in here, this cannot be resolved by other means -info = guidata(gcf); -cfg.dataname = info.dataname; -% if user specified a ylim, copy it over to the zlim of topoplot -if isfield(cfg, 'ylim') - cfg.zlim = cfg.ylim; - cfg = rmfield(cfg, 'ylim'); -end -fprintf('selected cfg.xlim = [%f %f]\n', cfg.xlim(1), cfg.xlim(2)); -p = get(gcf, 'position'); -f = figure; -set(f, 'position', p); -ft_topoplotER(cfg, data{:}); +function select_topoplotER(range, varargin) + +% fetch cfg/data based on axis indentifier given as tag +ident = get(gca, 'tag'); +info = guidata(gcf); +cfg = info.(ident).cfg; +varargin = info.(ident).varargin; +if ~isempty(range) + cfg = removefields(cfg, 'inputfile'); % the reading has already been done and varargin contains the data + cfg = removefields(cfg, 'showlabels'); % this is not allowed in topoplotER + cfg.baseline = 'no'; % make sure the next function does not apply a baseline correction again + cfg.dataname = info.(ident).dataname; % put data name in here, this cannot be resolved by other means + cfg.channel = 'all'; % make sure the topo displays all channels, not just the ones in this singleplot + cfg.comment = 'auto'; + cfg.trials = 'all'; % trial selection has already been taken care of + cfg.xlim = range(1:2); + % if user specified a ylim, copy it over to the zlim of topoplot + if isfield(cfg, 'ylim') + cfg.zlim = cfg.ylim; + cfg = rmfield(cfg, 'ylim'); + end + fprintf('selected cfg.xlim = [%f %f]\n', cfg.xlim(1), cfg.xlim(2)); + % ensure that the new figure appears at the same position + f = figure('position', get(gcf, 'Position')); + ft_topoplotER(cfg, varargin{:}); +end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % SUBFUNCTION which handles hot keys in the current plot @@ -738,26 +585,32 @@ function key_sub(handle, eventdata, varargin) incr_x = abs(xlimits(2) - xlimits(1)) /10; incr_y = abs(ylimits(2) - ylimits(1)) /10; -% TRANSLATE by 10% -if length(eventdata.Modifier) == 1 && strcmp(eventdata.Modifier{:},'control') && strcmp(eventdata.Key,'leftarrow') - xlim([xlimits(1)+incr_x xlimits(2)+incr_x]) -elseif length(eventdata.Modifier) == 1 && strcmp(eventdata.Modifier{:},'control') && strcmp(eventdata.Key,'rightarrow') - xlim([xlimits(1)-incr_x xlimits(2)-incr_x]) -elseif length(eventdata.Modifier) == 1 && strcmp(eventdata.Modifier{:},'control') && strcmp(eventdata.Key,'uparrow') - ylim([ylimits(1)-incr_y ylimits(2)-incr_y]) -elseif length(eventdata.Modifier) == 1 && strcmp(eventdata.Modifier{:},'control') && strcmp(eventdata.Key,'downarrow') - ylim([ylimits(1)+incr_y ylimits(2)+incr_y]) +if length(eventdata.Modifier) == 1 && strcmp(eventdata.Modifier{:}, 'control') + % TRANSLATE by 10% + switch eventdata.Key + case 'leftarrow' + xlim([xlimits(1)+incr_x xlimits(2)+incr_x]) + case 'rightarrow' + xlim([xlimits(1)-incr_x xlimits(2)-incr_x]) + case 'uparrow' + ylim([ylimits(1)-incr_y ylimits(2)-incr_y]) + case 'downarrow' + ylim([ylimits(1)+incr_y ylimits(2)+incr_y]) + end % switch +else % ZOOM by 10% -elseif strcmp(eventdata.Key,'leftarrow') - xlim([xlimits(1)-incr_x xlimits(2)+incr_x]) -elseif strcmp(eventdata.Key,'rightarrow') - xlim([xlimits(1)+incr_x xlimits(2)-incr_x]) -elseif strcmp(eventdata.Key,'uparrow') - ylim([ylimits(1)-incr_y ylimits(2)+incr_y]) -elseif strcmp(eventdata.Key,'downarrow') - ylim([ylimits(1)+incr_y ylimits(2)-incr_y]) - % resort to minmax of data for x-axis and y-axis -elseif strcmp(eventdata.Key,'m') - xlim([varargin{1} varargin{2}]) - ylim([varargin{3} varargin{4}]) -end + switch eventdata.Key + case 'leftarrow' + xlim([xlimits(1)-incr_x xlimits(2)+incr_x]) + case 'rightarrow' + xlim([xlimits(1)+incr_x xlimits(2)-incr_x]) + case 'uparrow' + ylim([ylimits(1)-incr_y ylimits(2)+incr_y]) + case 'downarrow' + ylim([ylimits(1)+incr_y ylimits(2)-incr_y]) + case 'm' + xlim([varargin{1} varargin{2}]) + ylim([varargin{3} varargin{4}]) + end % switch +end % if + diff --git a/external/fieldtrip/ft_singleplotTFR.m b/external/fieldtrip/ft_singleplotTFR.m index ffe53e53..d672c586 100644 --- a/external/fieldtrip/ft_singleplotTFR.m +++ b/external/fieldtrip/ft_singleplotTFR.m @@ -14,28 +14,29 @@ % cfg.maskparameter = field in the data to be used for masking of data % (not possible for mean over multiple channels, or when input contains multiple subjects % or trials) -% cfg.maskstyle = style used to masking, 'opacity', 'saturation' or 'outline' (default = 'opacity') +% cfg.maskstyle = style used to masking, 'opacity', 'saturation', 'outline' or 'colormix' (default = 'opacity') % use 'saturation' or 'outline' when saving to vector-format (like *.eps) to avoid all sorts of image-problems % cfg.maskalpha = alpha value between 0 (transparant) and 1 (opaque) used for masking areas dictated by cfg.maskparameter (default = 1) % cfg.masknans = 'yes' or 'no' (default = 'yes') % cfg.xlim = 'maxmin' or [xmin xmax] (default = 'maxmin') % cfg.ylim = 'maxmin' or [ymin ymax] (default = 'maxmin') % cfg.zlim = plotting limits for color dimension, 'maxmin', 'maxabs', 'zeromax', 'minzero', or [zmin zmax] (default = 'maxmin') -% cfg.baseline = 'yes','no' or [time1 time2] (default = 'no'), see FT_FREQBASELINE +% cfg.baseline = 'yes', 'no' or [time1 time2] (default = 'no'), see FT_FREQBASELINE % cfg.baselinetype = 'absolute', 'relative', 'relchange' or 'db' (default = 'absolute') % cfg.trials = 'all' or a selection given as a 1xN vector (default = 'all') % cfg.channel = Nx1 cell-array with selection of channels (default = 'all'), % see FT_CHANNELSELECTION for details +% cfg.title = string, title of plot % cfg.refchannel = name of reference channel for visualising connectivity, can be 'gui' % cfg.fontsize = font size of title (default = 8) -% cfg.hotkeys = enables hotkeys (up/down arrows) for dynamic colorbar adjustment +% cfg.hotkeys = enables hotkeys (leftarrow/rightarrow/uparrow/downarrow/pageup/pagedown/m) for dynamic zoom and translation (ctrl+) of the axes and color limits % cfg.colormap = any sized colormap, see COLORMAP % cfg.colorbar = 'yes', 'no' (default = 'yes') % cfg.interactive = Interactive plot 'yes' or 'no' (default = 'yes') % In a interactive plot you can select areas and produce a new % interactive plot when a selected area is clicked. Multiple areas % can be selected by holding down the SHIFT key. -% cfg.renderer = 'painters', 'zbuffer',' opengl' or 'none' (default = []) +% cfg.renderer = 'painters', 'zbuffer', ' opengl' or 'none' (default = []) % cfg.directionality = '', 'inflow' or 'outflow' specifies for % connectivity measures whether the inflow into a % node, or the outflow from a node is plotted. The @@ -62,7 +63,7 @@ % % See also FT_SINGLEPLOTER, FT_MULTIPLOTER, FT_MULTIPLOTTFR, FT_TOPOPLOTER, FT_TOPOPLOTTFR -% Copyright (C) 2005-2006, F.C. Donders Centre +% Copyright (C) 2005-2017, F.C. Donders Centre % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -82,6 +83,17 @@ % % $Id$ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% DEVELOPERS NOTE: This code is organized in a similar fashion for multiplot/singleplot/topoplot +% and for ER/TFR and should remain consistent over those 6 functions. +% Section 1: general cfg handling that is independent from the data +% Section 2: data handling, this also includes converting bivariate (chan_chan and chancmb) into univariate data +% Section 3: select the data to be plotted and determine min/max range +% Section 4: do the actual plotting +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Section 1: general cfg handling that is independent from the data + % these are used by the ft_preamble/ft_postamble function and scripts ft_revision = '$Id$'; ft_nargin = nargin; @@ -114,211 +126,154 @@ cfg = ft_checkconfig(cfg, 'renamed', {'zparam', 'parameter'}); cfg = ft_checkconfig(cfg, 'deprecated', {'xparam', 'yparam'}); -% Set the defaults: -cfg.baseline = ft_getopt(cfg, 'baseline', 'no'); -cfg.baselinetype = ft_getopt(cfg, 'baselinetype', 'absolute'); -cfg.trials = ft_getopt(cfg, 'trials', 'all', 1); -cfg.xlim = ft_getopt(cfg, 'xlim', 'maxmin'); -cfg.ylim = ft_getopt(cfg, 'ylim', 'maxmin'); -cfg.zlim = ft_getopt(cfg, 'zlim', 'maxmin'); -cfg.fontsize = ft_getopt(cfg, 'fontsize', 8); -cfg.colorbar = ft_getopt(cfg, 'colorbar', 'yes'); -cfg.interactive = ft_getopt(cfg, 'interactive', 'yes'); -cfg.hotkeys = ft_getopt(cfg, 'hotkeys', 'no'); -cfg.renderer = ft_getopt(cfg, 'renderer', []); -cfg.maskalpha = ft_getopt(cfg, 'maskalpha', 1); -cfg.maskparameter = ft_getopt(cfg, 'maskparameter', []); -cfg.maskstyle = ft_getopt(cfg, 'maskstyle', 'opacity'); -cfg.channel = ft_getopt(cfg, 'channel', 'all'); -cfg.masknans = ft_getopt(cfg, 'masknans', 'yes'); -cfg.directionality = ft_getopt(cfg, 'directionality',[]); -cfg.figurename = ft_getopt(cfg, 'figurename', []); -cfg.parameter = ft_getopt(cfg, 'parameter', 'powspctrm'); +% Set the defaults +cfg.baseline = ft_getopt(cfg, 'baseline', 'no'); +cfg.baselinetype = ft_getopt(cfg, 'baselinetype', 'absolute'); +cfg.trials = ft_getopt(cfg, 'trials', 'all', 1); +cfg.xlim = ft_getopt(cfg, 'xlim', 'maxmin'); +cfg.ylim = ft_getopt(cfg, 'ylim', 'maxmin'); +cfg.zlim = ft_getopt(cfg, 'zlim', 'maxmin'); +cfg.fontsize = ft_getopt(cfg, 'fontsize', 8); +cfg.colorbar = ft_getopt(cfg, 'colorbar', 'yes'); +cfg.interactive = ft_getopt(cfg, 'interactive', 'yes'); +cfg.hotkeys = ft_getopt(cfg, 'hotkeys', 'yes'); +cfg.renderer = ft_getopt(cfg, 'renderer', []); +cfg.maskalpha = ft_getopt(cfg, 'maskalpha', 1); +cfg.maskparameter = ft_getopt(cfg, 'maskparameter', []); +cfg.maskstyle = ft_getopt(cfg, 'maskstyle', 'opacity'); +cfg.channel = ft_getopt(cfg, 'channel', 'all'); +cfg.title = ft_getopt(cfg, 'title', []); +cfg.masknans = ft_getopt(cfg, 'masknans', 'yes'); +cfg.directionality = ft_getopt(cfg, 'directionality', []); +cfg.figurename = ft_getopt(cfg, 'figurename', []); +cfg.parameter = ft_getopt(cfg, 'parameter', 'powspctrm'); + +% this is needed for the figure title and correct labeling of graphcolor later on +if nargin>1 + if isfield(cfg, 'dataname') + if iscell(cfg.dataname) + dataname = cfg.dataname{1}; + else + dataname = cfg.dataname; + end + else + if ~isempty(inputname(2)) + dataname = inputname(2); + else + dataname = ['data' num2str(1, '%02d')]; + end + end +else % data provided through cfg.inputfile + dataname = cfg.inputfile; +end + + +%% Section 2: data handling, this also includes converting bivariate (chan_chan and chancmb) into univariate data + +hastime = isfield(data, 'time'); +hasfreq = isfield(data, 'freq'); + +assert((hastime && hasfreq), 'please use ft_singleplotER for time-only or frequency-only data'); +xparam = 'time'; +yparam = 'freq'; + +% check whether rpt/subj is present and remove if necessary dimord = getdimord(data, cfg.parameter); dimtok = tokenize(dimord, '_'); +hasrpt = any(ismember(dimtok, {'rpt' 'subj'})); -% Set x/y/parameter defaults -if ~any(ismember(dimtok, 'time')) - error('input data needs a time dimension'); +if ~hasrpt + assert(isequal(cfg.trials, 'all') || isequal(cfg.trials, 1), 'incorrect specification of cfg.trials for data without repetitions'); else - xparam = 'time'; - yparam = 'freq'; + assert(~isempty(cfg.trials), 'empty specification of cfg.trials for data with repetitions'); end +% parse cfg.channel if isfield(cfg, 'channel') && isfield(data, 'label') cfg.channel = ft_channelselection(cfg.channel, data.label); elseif isfield(cfg, 'channel') && isfield(data, 'labelcmb') cfg.channel = ft_channelselection(cfg.channel, unique(data.labelcmb(:))); end -if isempty(cfg.channel) - error('no channels selected'); -end - -if ~isfield(data, cfg.parameter) - error('data has no field ''%s''', cfg.parameter); -end - -% check whether rpt/subj is present and remove if necessary and whether -hasrpt = any(ismember(dimtok, {'rpt' 'subj'})); -if hasrpt, - % this also deals with fourier-spectra in the input - % or with multiple subjects in a frequency domain stat-structure - % on the fly computation of coherence spectrum is not supported - if isfield(data, 'crsspctrm'), - data = rmfield(data, 'crsspctrm'); - end - - tmpcfg = []; - tmpcfg.trials = cfg.trials; - tmpcfg.jackknife = 'no'; +% Apply baseline correction: +if ~strcmp(cfg.baseline, 'no') % keep mask-parameter if it is set if ~isempty(cfg.maskparameter) tempmask = data.(cfg.maskparameter); end - if isfield(cfg, 'parameter') && ~strcmp(cfg.parameter,'powspctrm') - % freqdesctiptives will only work on the powspctrm field - % hence a temporary copy of the data is needed - tempdata.dimord = data.dimord; - tempdata.freq = data.freq; - tempdata.label = data.label; - tempdata.time = data.time; - tempdata.powspctrm = data.(cfg.parameter); - if isfield(data, 'cfg') tempdata.cfg = data.cfg; end - tempdata = ft_freqdescriptives(tmpcfg, tempdata); - data.(cfg.parameter) = tempdata.powspctrm; - clear tempdata - else - data = ft_freqdescriptives(tmpcfg, data); - end + data = ft_freqbaseline(cfg, data); % put mask-parameter back if it is set if ~isempty(cfg.maskparameter) data.(cfg.maskparameter) = tempmask; end - dimord = data.dimord; - dimtok = tokenize(dimord, '_'); -end % if hasrpt +end -% Handle the bivariate case +% channels should NOT be selected and averaged here, since a topoplot might follow in interactive mode +tmpcfg = keepfields(cfg, {'showcallinfo', 'trials'}); +if hasrpt + tmpcfg.avgoverrpt = 'yes'; +else + tmpcfg.avgoverrpt = 'no'; +end +tmpvar = data; +[data] = ft_selectdata(tmpcfg, data); +% restore the provenance information and put back cfg.channel +tmpchannel = cfg.channel; +[cfg, data] = rollback_provenance(cfg, data); +cfg.channel = tmpchannel; + + +if isfield(tmpvar, cfg.maskparameter) && ~isfield(data, cfg.maskparameter) + % the mask parameter is not present after ft_selectdata, because it is + % not included in all input arguments. Make the same selection and copy + % it over + tmpvar = ft_selectdata(tmpcfg, tmpvar); + data.(cfg.maskparameter) = tmpvar.(cfg.maskparameter); +end -% Check for bivariate metric with 'chan_chan' in the dimord -selchan = strmatch('chan', dimtok); -isfull = length(selchan)>1; - -% Check for bivariate metric with a labelcmb -haslabelcmb = isfield(data, 'labelcmb'); - -% check whether the bivariate metric is the one requested to plot -%shouldPlotCmb = (haslabelcmb && ... -% size(data.(cfg.parameter),selchan(1)) == size(data.labelcmb,1)) ... -% || isfull; % this should work because if dimord has multiple chans (so isfull=1) -% % then we can never plot anything without reference channel -% % this is different when haslabelcmb=1; then the parameter -% % requested to plot might well be a simple powspctrm -%if (isfull || haslabelcmb) && shouldPlotCmb - -if (isfull || haslabelcmb) && (isfield(data, cfg.parameter) && ~strcmp(cfg.parameter, 'powspctrm')) - % A reference channel is required: - if ~isfield(cfg, 'refchannel') - error('no reference channel is specified'); - end +clear tmpvar tmpcfg dimord dimtok hastime hasfreq hasrpt - % check for refchannel being part of selection - if ~strcmp(cfg.refchannel,'gui') - if haslabelcmb - cfg.refchannel = ft_channelselection(cfg.refchannel, unique(data.labelcmb(:))); - else - cfg.refchannel = ft_channelselection(cfg.refchannel, data.label); - end - if (isfull && ~any(ismember(data.label, cfg.refchannel))) || ... - (haslabelcmb && ~any(ismember(data.labelcmb(:), cfg.refchannel))) - error('cfg.refchannel is a not present in the (selected) channels)') - end - end +% ensure that the preproc specific options are located in the cfg.preproc +% substructure, but also ensure that the field 'refchannel' remains at the +% highest level in the structure. This is a little hack by JM because the field +% refchannel can relate to connectivity or to an EEg reference. - % Interactively select the reference channel - if strcmp(cfg.refchannel, 'gui') - error('coh.refchannel = ''gui'' is not supported at the moment for ft_singleplotTFR'); -% -% % Open a single figure with the channel layout, the user can click on a reference channel -% h = clf; -% ft_plot_lay(lay, 'box', false); -% title('Select the reference channel by dragging a selection window, more than 1 channel can be selected...'); -% % add the channel information to the figure -% info = guidata(gcf); -% info.x = lay.pos(:,1); -% info.y = lay.pos(:,2); -% info.label = lay.label; -% guidata(h, info); -% %set(gcf, 'WindowButtonUpFcn', {@ft_select_channel, 'callback', {@select_topoplotER, cfg, data}}); -% set(gcf, 'WindowButtonUpFcn', {@ft_select_channel, 'multiple', true, 'callback', {@select_multiplotTFR, cfg, data}, 'event', 'WindowButtonUpFcn'}); -% set(gcf, 'WindowButtonDownFcn', {@ft_select_channel, 'multiple', true, 'callback', {@select_multiplotTFR, cfg, data}, 'event', 'WindowButtonDownFcn'}); -% set(gcf, 'WindowButtonMotionFcn', {@ft_select_channel, 'multiple', true, 'callback', {@select_multiplotTFR, cfg, data}, 'event', 'WindowButtonMotionFcn'}); -% return +if isfield(cfg, 'refchannel'), refchannelincfg = cfg.refchannel; cfg = rmfield(cfg, 'refchannel'); end +cfg = ft_checkconfig(cfg, 'createsubcfg', {'preproc'}); +if exist('refchannelincfg', 'var'), cfg.refchannel = refchannelincfg; end + +if ~isempty(cfg.preproc) + % preprocess the data, i.e. apply filtering, baselinecorrection, etc. + fprintf('applying preprocessing options\n'); + if ~isfield(cfg.preproc, 'feedback') + cfg.preproc.feedback = cfg.interactive; end + data = ft_preprocessing(cfg.preproc, data); +end - if ~isfull, - % Convert 2-dimensional channel matrix to a single dimension: - if isempty(cfg.directionality) - sel1 = find(strcmp(cfg.refchannel, data.labelcmb(:,2))); - sel2 = find(strcmp(cfg.refchannel, data.labelcmb(:,1))); - elseif strcmp(cfg.directionality, 'outflow') - sel1 = []; - sel2 = find(strcmp(cfg.refchannel, data.labelcmb(:,1))); - elseif strcmp(cfg.directionality, 'inflow') - sel1 = find(strcmp(cfg.refchannel, data.labelcmb(:,2))); - sel2 = []; - end - fprintf('selected %d channels for %s\n', length(sel1)+length(sel2), cfg.parameter); - if length(sel1)+length(sel2)==0 - error('there are no channels selected for plotting: you may need to look at the specification of cfg.directionality'); - end - data.(cfg.parameter) = data.(cfg.parameter)([sel1;sel2],:,:); - data.label = [data.labelcmb(sel1,1);data.labelcmb(sel2,2)]; - data.labelcmb = data.labelcmb([sel1;sel2],:); - data = rmfield(data, 'labelcmb'); - else - % General case - sel = match_str(data.label, cfg.refchannel); - siz = [size(data.(cfg.parameter)) 1]; - if strcmp(cfg.directionality, 'inflow') || isempty(cfg.directionality) - %the interpretation of 'inflow' and 'outflow' depend on - %the definition in the bivariate representation of the data - %data.(cfg.parameter) = reshape(mean(data.(cfg.parameter)(:,sel,:),2),[siz(1) 1 siz(3:end)]); - sel1 = 1:siz(1); - sel2 = sel; - meandir = 2; - elseif strcmp(cfg.directionality, 'outflow') - %data.(cfg.parameter) = reshape(mean(data.(cfg.parameter)(sel,:,:),1),[siz(1) 1 siz(3:end)]); - sel1 = sel; - sel2 = 1:siz(1); - meandir = 1; - - elseif strcmp(cfg.directionality, 'ff-fd') - error('cfg.directionality = ''ff-fd'' is not supported anymore, you have to manually subtract the two before the call to ft_singleplotTFR'); - elseif strcmp(cfg.directionality, 'fd-ff') - error('cfg.directionality = ''fd-ff'' is not supported anymore, you have to manually subtract the two before the call to ft_singleplotTFR'); - end %if directionality - end %if ~isfull -end %handle the bivariate data +% Handle the bivariate case +dimord = getdimord(data, cfg.parameter); +if startsWith(dimord, 'chan_chan_') || startsWith(dimord, 'chancmb_') + % convert the bivariate data to univariate and call this plotting function again + cfg.originalfunction = 'ft_singleplotTFR'; + cfg.trials = 'all'; % trial selection has been taken care off + bivariate_common(cfg, data); + return +end -% Apply baseline correction: +% Apply channel-type specific scaling +tmpcfg = keepfields(cfg, {'parameter', 'chanscale', 'ecgscale', 'eegscale', 'emgscale', 'eogscale', 'gradscale', 'magscale', 'megscale', 'mychan', 'mychanscale'}); +[data] = chanscale_common(tmpcfg, data); -if ~strcmp(cfg.baseline, 'no') - % keep mask-parameter if it is set - if ~isempty(cfg.maskparameter) - tempmask = data.(cfg.maskparameter); - end - data = ft_freqbaseline(cfg, data); - % put mask-parameter back if it is set - if ~isempty(cfg.maskparameter) - data.(cfg.maskparameter) = tempmask; - end -end -% Get physical x-axis range: -if strcmp(cfg.xlim,'maxmin') +%% Section 3: select the data to be plotted and determine min/max range + +% Take the subselection of channels that is contained in the layout, this is the same in all datasets +[selchan] = match_str(data.label, cfg.channel); + +% Get physical min/max range of x, i.e. time +if strcmp(cfg.xlim, 'maxmin') xmin = min(data.(xparam)); xmax = max(data.(xparam)); else @@ -326,14 +281,16 @@ xmax = cfg.xlim(2); end -% Replace value with the index of the nearest bin -if ~isempty(xparam) - xmin = nearest(data.(xparam), xmin); - xmax = nearest(data.(xparam), xmax); -end +% Get the index of the nearest bin +xminindx = nearest(data.(xparam), xmin); +xmaxindx = nearest(data.(xparam), xmax); +xmin = data.(xparam)(xminindx); +xmax = data.(xparam)(xmaxindx); +selx = xminindx:xmaxindx; +xval = data.(xparam)(selx); -% Get physical y-axis range: -if strcmp(cfg.ylim,'maxmin') +% Get physical min/max range of y, i.e. frequency +if strcmp(cfg.ylim, 'maxmin') ymin = min(data.(yparam)); ymax = max(data.(yparam)); else @@ -341,194 +298,141 @@ ymax = cfg.ylim(2); end -% Replace value with the index of the nearest bin -if ~isempty(yparam) - ymin = nearest(data.(yparam), ymin); - ymax = nearest(data.(yparam), ymax); +% Get the index of the nearest bin +yminindx = nearest(data.(yparam), ymin); +ymaxindx = nearest(data.(yparam), ymax); +ymin = data.(yparam)(yminindx); +ymax = data.(yparam)(ymaxindx); +sely = yminindx:ymaxindx; +yval = data.(yparam)(sely); + +% test if X and Y are linearly spaced (to within 10^-12): % FROM UIMAGE +dx = min(diff(xval)); % smallest interval for X +dy = min(diff(yval)); % smallest interval for Y +evenx = all(abs(diff(xval)/dx-1)<1e-12); % true if X is linearly spaced +eveny = all(abs(diff(yval)/dy-1)<1e-12); % true if Y is linearly spaced + +if ~evenx || ~eveny + ft_warning('(one of the) axis is/are not evenly spaced, but plots are made as if axis are linear') end -% % test if X and Y are linearly spaced (to within 10^-12): % FROM UIMAGE -% x = data.(xparam)(xmin:xmax); -% y = data.(yparam)(ymin:ymax); -% dx = min(diff(x)); % smallest interval for X -% dy = min(diff(y)); % smallest interval for Y -% evenx = all(abs(diff(x)/dx-1)<1e-12); % true if X is linearly spaced -% eveny = all(abs(diff(y)/dy-1)<1e-12); % true if Y is linearly spaced -% -% % masking only possible for evenly spaced axis -% if strcmp(cfg.masknans, 'yes') && (~evenx || ~eveny) -% warning('(one of the) axis are not evenly spaced -> nans cannot be masked out -> cfg.masknans is set to ''no'';') -% cfg.masknans = 'no'; -% end -% -% if ~isempty(cfg.maskparameter) && (~evenx || ~eveny) -% warning('(one of the) axis are not evenly spaced -> no masking possible -> cfg.maskparameter cleared') -% cfg.maskparameter = []; -% end - -% perform channel selection -selchannel = ft_channelselection(cfg.channel, data.label); -sellab = match_str(data.label, selchannel); - -% cfg.maskparameter only possible for single channel -if length(sellab) > 1 && ~isempty(cfg.maskparameter) - warning('no masking possible for average over multiple channels -> cfg.maskparameter cleared') - cfg.maskparameter = []; +% masking is only possible for evenly spaced axis +if strcmp(cfg.masknans, 'yes') && (~evenx || ~eveny) + ft_warning('(one of the) axis are not evenly spaced -> nans cannot be masked out -> cfg.masknans is set to ''no'';') + cfg.masknans = 'no'; end -% get dimord dimensions -ydim = find(strcmp(yparam, dimtok)); -xdim = find(strcmp(xparam, dimtok)); -zdim = setdiff(1:length(dimtok), [ydim xdim]); % all other dimensions - -% and permute -dat = data.(cfg.parameter); -dat = permute(dat, [zdim(:)' ydim xdim]); -if isfull - dat = dat(sel1, sel2, ymin:ymax, xmin:xmax); - dat = nanmean(dat, meandir); - siz = size(dat); - dat = reshape(dat, [max(siz(1:2)) siz(3) siz(4)]); - dat = dat(sellab, :, :); -elseif haslabelcmb - dat = dat(sellab, ymin:ymax, xmin:xmax); -else - dat = dat(sellab, ymin:ymax, xmin:xmax); -end +% the usual data is chan_freq_time, but other dimords should also work +dimtok = tokenize(dimord, '_'); +datamatrix = data.(cfg.parameter); +[c, ia, ib] = intersect(dimtok, {'chan', yparam, xparam}); +datamatrix = permute(datamatrix, ia); +datamatrix = datamatrix(selchan, sely, selx); if ~isempty(cfg.maskparameter) - mask = data.(cfg.maskparameter); - if isfull && cfg.maskalpha == 1 - mask = mask(sel1, sel2, ymin:ymax, xmin:xmax); - mask = nanmean(mask, meandir); - siz = size(mask); - mask = reshape(mask, [max(siz(1:2)) siz(3) siz(4)]); - mask = reshape(mask(sellab, :, :), [siz(3) siz(4)]); - elseif haslabelcmb && cfg.maskalpha == 1 - mask = squeeze(mask(sellab, ymin:ymax, xmin:xmax)); - elseif cfg.maskalpha == 1 - mask = squeeze(mask(sellab, ymin:ymax, xmin:xmax)); - elseif isfull && cfg.maskalpha ~= 1 %% check me - maskl = mask(sel1, sel2, ymin:ymax, xmin:xmax); - maskl = nanmean(maskl, meandir); - siz = size(maskl); - maskl = reshape(maskl, [max(siz(1:2)) siz(3) siz(4)]); - maskl = squeeze(reshape(maskl(sellab, :, :), [siz(3) siz(4)])); - mask = zeros(size(maskl)); - mask(maskl) = 1; - mask(~maskl) = cfg.maskalpha; - elseif haslabelcmb && cfg.maskalpha ~= 1 - maskl = squeeze(mask(sellab, ymin:ymax, xmin:xmax)); - mask = zeros(size(maskl)); - mask(maskl) = 1; - mask(~maskl) = cfg.maskalpha; - elseif cfg.maskalpha ~= 1 - maskl = squeeze(mask(sellab, ymin:ymax, xmin:xmax)); - mask = zeros(size(maskl)); - mask(maskl) = 1; - mask(~maskl) = cfg.maskalpha; + maskmatrix = data.(cfg.maskparameter)(selchan, sely, selx); + if cfg.maskalpha ~= 1 + maskmatrix( maskmatrix) = 1; + maskmatrix(~maskmatrix) = cfg.maskalpha; end +else + % create an Nx0x0 matrix + maskmatrix = zeros(length(selchan), 0, 0); end -siz = size(dat); -datamatrix = reshape(mean(dat, 1), [siz(2:end) 1]); -xvector = data.(xparam)(xmin:xmax); -yvector = data.(yparam)(ymin:ymax); + +%% Section 4: do the actual plotting + +cla +hold on + +zval = mean(datamatrix, 1); % over channels +zval = reshape(zval, size(zval,2), size(zval,3)); +mask = squeeze(mean(maskmatrix, 1)); % over channels % Get physical z-axis range (color axis): -if strcmp(cfg.zlim,'maxmin') - zmin = min(datamatrix(:)); - zmax = max(datamatrix(:)); -elseif strcmp(cfg.zlim,'maxabs') - zmin = -max(abs(datamatrix(:))); - zmax = max(abs(datamatrix(:))); -elseif strcmp(cfg.zlim,'zeromax') +if strcmp(cfg.zlim, 'maxmin') + zmin = nanmin(zval(:)); + zmax = nanmax(zval(:)); +elseif strcmp(cfg.zlim, 'maxabs') + zmin = -nanmax(abs(zval(:))); + zmax = nanmax(abs(zval(:))); +elseif strcmp(cfg.zlim, 'zeromax') zmin = 0; - zmax = max(datamatrix(:)); -elseif strcmp(cfg.zlim,'minzero') - zmin = min(datamatrix(:)); + zmax = nanmax(zval(:)); +elseif strcmp(cfg.zlim, 'minzero') + zmin = nanmin(zval(:)); zmax = 0; else zmin = cfg.zlim(1); zmax = cfg.zlim(2); end -% set colormap -if isfield(cfg,'colormap') - if size(cfg.colormap,2)~=3, error('singleplotTFR(): Colormap must be a n x 3 matrix'); end - set(gcf,'colormap',cfg.colormap); -end - -% Draw plot (and mask NaN's if requested): -cla -if isequal(cfg.masknans,'yes') && isempty(cfg.maskparameter) - nans_mask = ~isnan(datamatrix); +% Draw the data and mask NaN's if requested +if isequal(cfg.masknans, 'yes') && isempty(cfg.maskparameter) + nans_mask = ~isnan(zval); mask = double(nans_mask); - ft_plot_matrix(xvector, yvector, datamatrix, 'clim',[zmin,zmax],'tag','cip','highlightstyle',cfg.maskstyle,'highlight', mask) -elseif isequal(cfg.masknans,'yes') && ~isempty(cfg.maskparameter) - nans_mask = ~isnan(datamatrix); + ft_plot_matrix(xval, yval, zval, 'clim', [zmin zmax], 'tag', 'cip', 'highlightstyle', cfg.maskstyle, 'highlight', mask) +elseif isequal(cfg.masknans, 'yes') && ~isempty(cfg.maskparameter) + nans_mask = ~isnan(zval); mask = mask .* nans_mask; mask = double(mask); - ft_plot_matrix(xvector, yvector, datamatrix, 'clim',[zmin,zmax],'tag','cip','highlightstyle',cfg.maskstyle,'highlight', mask) -elseif isequal(cfg.masknans,'no') && ~isempty(cfg.maskparameter) + ft_plot_matrix(xval, yval, zval, 'clim', [zmin zmax], 'tag', 'cip', 'highlightstyle', cfg.maskstyle, 'highlight', mask) +elseif isequal(cfg.masknans, 'no') && ~isempty(cfg.maskparameter) mask = double(mask); - ft_plot_matrix(xvector, yvector, datamatrix, 'clim',[zmin,zmax],'tag','cip','highlightstyle',cfg.maskstyle,'highlight', mask) + ft_plot_matrix(xval, yval, zval, 'clim', [zmin zmax], 'tag', 'cip', 'highlightstyle', cfg.maskstyle, 'highlight', mask) else - ft_plot_matrix(xvector, yvector, datamatrix, 'clim',[zmin,zmax],'tag','cip') + ft_plot_matrix(xval, yval, zval, 'clim', [zmin zmax], 'tag', 'cip') +end + +% set colormap +if isfield(cfg, 'colormap') + if ~isnumeric(cfg.colormap) + cfg.colormap = colormap(cfg.colormap); + end + if size(cfg.colormap,2)~=3 + ft_error('colormap must be a Nx3 matrix'); + else + set(gcf, 'colormap', cfg.colormap); + end +end + +% Set renderer if specified +if ~isempty(cfg.renderer) + set(gcf, 'renderer', cfg.renderer) end -hold on -axis xy; -% set(gca,'Color','k') -if isequal(cfg.colorbar,'yes') +axis xy + +if isequal(cfg.colorbar, 'yes') % tag the colorbar so we know which axes are colorbars colorbar('tag', 'ft-colorbar'); end -% Set adjust color axis -if strcmp('yes',cfg.hotkeys) +% Set callback to adjust color axis +if strcmp('yes', cfg.hotkeys) % Attach data and cfg to figure and attach a key listener to the figure - set(gcf, 'KeyPressFcn', {@key_sub, zmin, zmax}) -end - -% Make the figure interactive: -if strcmp(cfg.interactive, 'yes') - % first, attach data to the figure with the current axis handle as a name - dataname = fixname(num2str(double(gca))); - setappdata(gcf,dataname,data); - set(gcf, 'WindowButtonUpFcn', {@ft_select_range, 'multiple', false, 'callback', {@select_topoplotTFR, cfg}, 'event', 'WindowButtonUpFcn'}); - set(gcf, 'WindowButtonDownFcn', {@ft_select_range, 'multiple', false, 'callback', {@select_topoplotTFR, cfg}, 'event', 'WindowButtonDownFcn'}); - set(gcf, 'WindowButtonMotionFcn', {@ft_select_range, 'multiple', false, 'callback', {@select_topoplotTFR, cfg}, 'event', 'WindowButtonMotionFcn'}); - % set(gcf, 'WindowButtonUpFcn', {@ft_select_range, 'multiple', false, 'callback', {@select_topoplotTFR, cfg, data}, 'event', 'WindowButtonUpFcn'}); - % set(gcf, 'WindowButtonDownFcn', {@ft_select_range, 'multiple', false, 'callback', {@select_topoplotTFR, cfg, data}, 'event', 'WindowButtonDownFcn'}); - % set(gcf, 'WindowButtonMotionFcn', {@ft_select_range, 'multiple', false, 'callback', {@select_topoplotTFR, cfg, data}, 'event', 'WindowButtonMotionFcn'}); + set(gcf, 'KeyPressFcn', {@key_sub, xmin, xmax, ymin, ymax, zmin, zmax}) end -% Create title text containing channel name(s) and channel number(s): -if length(sellab) == 1 - t = [char(cfg.channel) ' / ' num2str(sellab) ]; +% Create axis title containing channel name(s) and channel number(s): +if ~isempty(cfg.title) + t = cfg.title; else - t = sprintf('mean(%0s)', join_str(',', cfg.channel)); + if length(cfg.channel) == 1 + t = [char(cfg.channel) ' / ' num2str(selchan) ]; + else + t = sprintf('mean(%0s)', join_str(', ', cfg.channel)); + end end -h = title(t,'fontsize', cfg.fontsize); +title(t, 'fontsize', cfg.fontsize); % set the figure window title, add channel labels if number is small if isempty(get(gcf, 'Name')) - if length(sellab) < 5 - chans = join_str(',', cfg.channel); + if length(selchan) < 5 + chans = join_str(', ', cfg.channel); else chans = ''; end - if isfield(cfg,'dataname') - if iscell(cfg.dataname) - dataname = cfg.dataname{1}; - else - dataname = cfg.dataname; - end - elseif nargin > 1 - dataname = inputname(2); - else % data provided through cfg.inputfile - dataname = cfg.inputfile; - end if isempty(cfg.figurename) set(gcf, 'Name', sprintf('%d: %s: %s (%s)', double(gcf), mfilename, dataname, chans)); set(gcf, 'NumberTitle', 'off'); @@ -537,19 +441,24 @@ set(gcf, 'NumberTitle', 'off'); end end -axis tight; -hold off; -% Set renderer if specified -if ~isempty(cfg.renderer) - set(gcf, 'renderer', cfg.renderer) -end +axis tight +hold off -% do the general cleanup and bookkeeping at the end of the function -ft_postamble debug -ft_postamble trackconfig -ft_postamble previous data -ft_postamble provenance +% Make the figure interactive +if strcmp(cfg.interactive, 'yes') + % add the cfg/data information to the figure under identifier linked to this axis + ident = ['axh' num2str(round(sum(clock.*1e6)))]; % unique identifier for this axis + set(gca, 'tag',ident); + info = guidata(gcf); + info.(ident).dataname = dataname; + info.(ident).cfg = cfg; + info.(ident).data = data; + guidata(gcf, info); + set(gcf, 'WindowButtonUpFcn', {@ft_select_range, 'multiple', false, 'callback', {@select_topoplotTFR}, 'event', 'WindowButtonUpFcn'}); + set(gcf, 'WindowButtonDownFcn', {@ft_select_range, 'multiple', false, 'callback', {@select_topoplotTFR}, 'event', 'WindowButtonDownFcn'}); + set(gcf, 'WindowButtonMotionFcn', {@ft_select_range, 'multiple', false, 'callback', {@select_topoplotTFR}, 'event', 'WindowButtonMotionFcn'}); +end % add a menu to the figure, but only if the current figure does not have subplots % also, delete any possibly existing previous menu, this is safe because delete([]) does nothing @@ -560,58 +469,89 @@ uimenu(ftmenu, 'Label', 'About', 'Callback', @menu_about); end +% do the general cleanup and bookkeeping at the end of the function +ft_postamble debug +ft_postamble trackconfig +ft_postamble previous data +ft_postamble provenance + +if ~nargout + % don't return anything + clear cfg +end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % SUBFUNCTION which is called after selecting a time range %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -function select_topoplotTFR(cfg, varargin) -% first to last callback-input of ft_select_range is range -% last callback-input of ft_select_range is contextmenu label, if used -range = varargin{end-1}; -varargin = varargin(1:end-2); % remove range and last - -% get appdata belonging to current axis -dataname = fixname(num2str(double(gca))); -data = getappdata(gcf, dataname); - -if isfield(cfg, 'inputfile') - % the reading has already been done and varargin contains the data - cfg = rmfield(cfg, 'inputfile'); +function select_topoplotTFR(range, varargin) +% fetch cfg/data based on axis indentifier given as tag +ident = get(gca, 'tag'); +info = guidata(gcf); +cfg = info.(ident).cfg; +data = info.(ident).data; +if ~isempty(range) + cfg = removefields(cfg, 'inputfile'); % the reading has already been done and varargin contains the data + cfg = removefields(cfg, 'showlabels'); % this is not allowed in topoplotER + cfg.trials = 'all'; % trial selection has already been taken care of + cfg.baseline = 'no'; % make sure the next function does not apply a baseline correction again + cfg.channel = 'all'; % make sure the topo displays all channels, not just the ones in this singleplot + cfg.comment = 'auto'; + cfg.dataname = info.(ident).dataname; % put data name in here, this cannot be resolved by other means + cfg.xlim = range(1:2); + cfg.ylim = range(3:4); + fprintf('selected cfg.xlim = [%f %f]\n', cfg.xlim(1), cfg.xlim(2)); + fprintf('selected cfg.ylim = [%f %f]\n', cfg.ylim(1), cfg.ylim(2)); + % ensure that the new figure appears at the same position + f = figure('Position', get(gcf, 'Position')); + ft_topoplotTFR(cfg, data); end -% make sure the topo displays all channels, not just the ones in this -% singleplot -cfg.channel = 'all'; - -cfg.comment = 'auto'; -cfg.xlim = range(1:2); -cfg.ylim = range(3:4); -% compatibility fix for new ft_topoplotER/TFR cfg options -if isfield(cfg,'showlabels') && strcmp(cfg.showlabels,'yes') - cfg = rmfield(cfg,'showlabels'); - cfg.marker = 'labels'; -elseif isfield(cfg,'showlabels') && strcmp(cfg.showlabels,'no') - cfg = rmfield(cfg,'showlabels'); - cfg.marker = 'on'; -end -fprintf('selected cfg.xlim = [%f %f]\n', cfg.xlim(1), cfg.xlim(2)); -fprintf('selected cfg.ylim = [%f %f]\n', cfg.ylim(1), cfg.ylim(2)); -p = get(gcf, 'Position'); -f = figure; -set(f, 'Position', p); -ft_topoplotTFR(cfg, data); - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % SUBFUNCTION which handles hot keys in the current plot %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function key_sub(handle, eventdata, varargin) -incr = (max(caxis)-min(caxis)) /10; -% symmetrically scale color bar down by 10 percent -if strcmp(eventdata.Key,'uparrow') - caxis([min(caxis)-incr max(caxis)+incr]); -% symmetrically scale color bar up by 10 percent -elseif strcmp(eventdata.Key,'downarrow') - caxis([min(caxis)+incr max(caxis)-incr]); -% resort to minmax of data for colorbar -elseif strcmp(eventdata.Key,'m') - caxis([varargin{1} varargin{2}]); -end +xlimits = xlim; +ylimits = ylim; +climits = caxis; +incr_x = abs(xlimits(2) - xlimits(1)) /10; +incr_y = abs(ylimits(2) - ylimits(1)) /10; +incr_c = abs(climits(2) - climits(1)) /10; + +if length(eventdata.Modifier) == 1 && strcmp(eventdata.Modifier{:}, 'control') + % TRANSLATE by 10% + switch eventdata.Key + case 'pageup' + caxis([min(caxis)+incr_c max(caxis)+incr_c]); + case 'pagedown' + caxis([min(caxis)-incr_c max(caxis)-incr_c]); + case 'leftarrow' + xlim([xlimits(1)+incr_x xlimits(2)+incr_x]) + case 'rightarrow' + xlim([xlimits(1)-incr_x xlimits(2)-incr_x]) + case 'uparrow' + ylim([ylimits(1)-incr_y ylimits(2)-incr_y]) + case 'downarrow' + ylim([ylimits(1)+incr_y ylimits(2)+incr_y]) + end % switch +else + % ZOOM by 10% + switch eventdata.Key + case 'pageup' + caxis([min(caxis)-incr_c max(caxis)+incr_c]); + case 'pagedown' + caxis([min(caxis)+incr_c max(caxis)-incr_c]); + case 'leftarrow' + xlim([xlimits(1)-incr_x xlimits(2)+incr_x]) + case 'rightarrow' + xlim([xlimits(1)+incr_x xlimits(2)-incr_x]) + case 'uparrow' + ylim([ylimits(1)-incr_y ylimits(2)+incr_y]) + case 'downarrow' + ylim([ylimits(1)+incr_y ylimits(2)-incr_y]) + case 'm' + xlim([varargin{1} varargin{2}]) + ylim([varargin{3} varargin{4}]) + caxis([varargin{5} varargin{6}]); + end % switch +end % if diff --git a/external/fieldtrip/ft_sliceinterp.m b/external/fieldtrip/ft_sliceinterp.m index 95c655e7..179ccbfb 100644 --- a/external/fieldtrip/ft_sliceinterp.m +++ b/external/fieldtrip/ft_sliceinterp.m @@ -83,7 +83,7 @@ % % See also FT_SOURCEANALYSIS, FT_VOLUMERESLICE -% Copyright (C) 2004, Markus Siegel, markus.siegel@fcdonders.kun.nl +% Copyright (C) 2004, Markus Siegel % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -170,14 +170,14 @@ if isfield(ininterp,'anatomy'); interp.anatomy = reshape(ininterp.anatomy, ininterp.dim); else - error('no anatomical data supplied'); + ft_error('no anatomical data supplied'); end % check functional data if ~isempty(cfg.funparameter) interp.source = double(reshape(getsubfield(ininterp, cfg.funparameter), ininterp.dim)); else - error('no functional data supplied'); + ft_error('no functional data supplied'); end % check mask data @@ -484,14 +484,14 @@ function getcoords(h,eventdata,handles,varargin) co(2,1) = round(mod(yi,size(data.out,1))); co(3,1) = round(mod(xi,size(data.out,2))); switch mod(data.cfg.rotate,4) -case 1, +case 1 t1 = co(2); co(2) = co(3); co(3) = data.sin(3)-t1; -case 2, +case 2 co(2) = data.sin(2)-co(2); co(3) = data.sin(3)-co(3); -case 3, +case 3 t1 = co(3); co(3) = co(2); co(2) = data.sin(2)-t1; @@ -518,7 +518,7 @@ function getcoords(h,eventdata,handles,varargin) siz = [size(a,1) size(a,2) size(a,4)]; nn = sqrt(prod(siz))/siz(2); mm = siz(3)/nn; -if (ceil(nn)-nn) < (ceil(mm)-mm), +if (ceil(nn)-nn) < (ceil(mm)-mm) nn = ceil(nn); mm = ceil(siz(3)/nn); else mm = ceil(mm); nn = ceil(siz(3)/mm); @@ -527,10 +527,10 @@ function getcoords(h,eventdata,handles,varargin) b(1,1) = 0; b = repmat(b, [mm*siz(1), nn*siz(2), size(a,3), 1]); rows = 1:siz(1); cols = 1:siz(2); -for i=0:mm-1, - for j=0:nn-1, +for i=0:mm-1 + for j=0:nn-1 k = j+i*nn+1; - if k<=siz(3), + if k<=siz(3) b(rows+i*siz(1),cols+j*siz(2),:) = a(:,:,:,k); end end diff --git a/external/fieldtrip/ft_sourceanalysis.m b/external/fieldtrip/ft_sourceanalysis.m index 7fa3d4bd..e8bde478 100644 --- a/external/fieldtrip/ft_sourceanalysis.m +++ b/external/fieldtrip/ft_sourceanalysis.m @@ -3,17 +3,17 @@ % FT_SOURCEANALYSIS performs beamformer dipole analysis on EEG or MEG data % after preprocessing and a timelocked or frequency analysis % -% Use as either +% Use as % [source] = ft_sourceanalysis(cfg, freq) +% or % [source] = ft_sourceanalysis(cfg, timelock) % -% where the data in freq or timelock should be organised in a structure +% where the second input argument with the data should be organised in a structure % as obtained from the FT_FREQANALYSIS or FT_TIMELOCKANALYSIS function. The -% configuration "cfg" is a structure containing information about -% source positions and other options. +% configuration "cfg" is a structure containing information about source positions +% and other options. % -% The different source reconstruction algorithms that are implemented -% are +% The different source reconstruction algorithms that are implemented are % cfg.method = 'lcmv' linear constrained minimum variance beamformer % 'sam' synthetic aperture magnetometry % 'dics' dynamic imaging of coherent sources @@ -123,7 +123,7 @@ % cfg.trialweight = 'equal' or 'proportional' % cfg.powmethod = 'lambda1' or 'trace' -% Copyright (c) 2003-2008, Robert Oostenveld, F.C. Donders Centre +% Copyright (c) 2003-2008, F.C. Donders Centre, Robert Oostenveld % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -191,7 +191,7 @@ iscomp = ft_datatype(data, 'comp'); istimelock = ft_datatype(data, 'timelock'); if all(~[isfreq iscomp istimelock]) - error('input data is not recognized'); + ft_error('input data is not recognized'); end % set the defaults @@ -241,9 +241,9 @@ cfg.(cfg.method).reducerank = ft_getopt(cfg.(cfg.method), 'reducerank', []); % the default for this is handled below if hasbaseline && (strcmp(cfg.randomization, 'no') && strcmp(cfg.permutation, 'no')) - error('input of two conditions only makes sense if you want to randomize or permute'); + ft_error('input of two conditions only makes sense if you want to randomize or permute'); elseif ~hasbaseline && (strcmp(cfg.randomization, 'yes') || strcmp(cfg.permutation, 'yes')) - error('randomization or permutation requires that you give two conditions as input'); + ft_error('randomization or permutation requires that you give two conditions as input'); end if isfield(cfg, 'latency') && ischar(cfg.latency) && strcmp(cfg.latency, 'all') && istimelock @@ -251,11 +251,11 @@ end if sum([strcmp(cfg.jackknife, 'yes'), strcmp(cfg.bootstrap, 'yes'), strcmp(cfg.pseudovalue, 'yes'), strcmp(cfg.singletrial, 'yes'), strcmp(cfg.rawtrial, 'yes'), strcmp(cfg.randomization, 'yes'), strcmp(cfg.permutation, 'yes')])>1 - error('jackknife, bootstrap, pseudovalue, singletrial, rawtrial, randomization and permutation are mutually exclusive'); + ft_error('jackknife, bootstrap, pseudovalue, singletrial, rawtrial, randomization and permutation are mutually exclusive'); end if strcmp(cfg.rawtrial,'yes') && isfield(cfg,'grid') && ~isfield(cfg.grid,'filter') - warning('Using each trial to compute its own filter is not currently recommended. Use this option only with precomputed filters in grid.filter'); + ft_warning('Using each trial to compute its own filter is not currently recommended. Use this option only with precomputed filters in grid.filter'); end % start with an empty output structure @@ -263,7 +263,7 @@ if istimelock % add the time axis to the output - tmpcfg = keepfields(cfg, {'channel', 'latency'}); + tmpcfg = keepfields(cfg, {'channel', 'latency', 'showcallinfo'}); tmpcfg.avgovertime = 'no'; data = ft_selectdata(tmpcfg, data); % restore the provenance information @@ -273,7 +273,7 @@ source = copyfields(data, source, {'time'}); elseif isfreq - tmpcfg = keepfields(cfg, {'channel', 'latency', 'frequency', 'refchan'}); + tmpcfg = keepfields(cfg, {'channel', 'latency', 'frequency', 'refchan', 'nanmean', 'showcallinfo'}); % ensure that the refchan is kept, if present if isfield(tmpcfg, 'refchan') && ~isempty(tmpcfg.refchan) && isempty(match_str(tmpcfg.channel, tmpcfg.refchan)) @@ -282,7 +282,7 @@ hasrefchan = 0; end - if hasrefchan, + if hasrefchan if ischar(tmpcfg.refchan), tmpcfg.refchan = {tmpcfg.refchan}; end tmpchannel = ft_channelselection(tmpcfg.channel, data.label); % the channels needed for the spatial filter tmpcfg.channel = cat(1, tmpchannel, tmpcfg.refchan); @@ -311,7 +311,7 @@ elseif iscomp % FIXME, select the components here % FIXME, add the component numbers to the output - error('the use of component data in ft_sourceanalysis is disabled for the time being: if you encounter this error message and you need this functionality please contact the FieldTrip development team'); + ft_error('the use of component data in ft_sourceanalysis is disabled for the time being: if you encounter this error message and you need this functionality please contact the FieldTrip development team'); end convertcomp = false; @@ -378,7 +378,7 @@ % only prepare the dipole grid positions, the leadfield will be computed on the fly if not present % copy all options that are potentially used in ft_prepare_sourcemodel - tmpcfg = keepfields(cfg, {'grid' 'mri' 'headshape' 'symmetry' 'smooth' 'threshold' 'spheremesh' 'inwardshift'}); + tmpcfg = keepfields(cfg, {'grid' 'mri' 'headshape' 'symmetry' 'smooth' 'threshold' 'spheremesh' 'inwardshift', 'showcallinfo'}); tmpcfg.headmodel = headmodel; tmpcfg.grad = sens; % this can be electrodes or gradiometers grid = ft_prepare_sourcemodel(tmpcfg); @@ -411,7 +411,7 @@ % HACK: use some experimental code if hasbaseline - error('not supported') + ft_error('not supported') end tmpcfg = cfg; @@ -447,12 +447,12 @@ fbin = nearest(data.freq, cfg.frequency); if strcmp(data.dimord, 'chan_freq') avg = data.fourierspctrm(datchanindx, fbin); - elseif strcmp(data.dimord, 'rpt_chan_freq') || strcmp(data.dimord, 'rpttap_chan_freq'), + elseif strcmp(data.dimord, 'rpt_chan_freq') || strcmp(data.dimord, 'rpttap_chan_freq') avg = transpose(data.fourierspctrm(:, datchanindx, fbin)); elseif strcmp(data.dimord, 'chan_freq_time') tbin = nearest(data.time, cfg.latency); avg = data.fourierspctrm(datchanindx, fbin, tbin); - elseif strcmp(data.dimord, 'rpt_chan_freq_time') || strcmp(data.dimord, 'rpttap_chan_freq_time'), + elseif strcmp(data.dimord, 'rpt_chan_freq_time') || strcmp(data.dimord, 'rpttap_chan_freq_time') tbin = nearest(data.time, cfg.latency); avg = transpose(data.fourierspctrm(:, datchanindx, fbin, tbin)); end @@ -470,12 +470,12 @@ fbin = nearest(data.freq, cfg.frequency); if strcmp(data.dimord, 'chan_freq') avg = data.fourierspctrm(datchanindx, fbin); - elseif strcmp(data.dimord, 'rpt_chan_freq') || strcmp(data.dimord, 'rpttap_chan_freq'), + elseif strcmp(data.dimord, 'rpt_chan_freq') || strcmp(data.dimord, 'rpttap_chan_freq') avg = transpose(data.fourierspctrm(:, datchanindx, fbin)); elseif strcmp(data.dimord, 'chan_freq_time') tbin = nearest(data.time, cfg.latency); avg = data.fourierspctrm(datchanindx, fbin, tbin); - elseif strcmp(data.dimord, 'rpt_chan_freq_time') || strcmp(data.dimord, 'rpttap_chan_freq_time'), + elseif strcmp(data.dimord, 'rpt_chan_freq_time') || strcmp(data.dimord, 'rpttap_chan_freq_time') tbin = nearest(data.time, cfg.latency); avg = transpose(data.fourierspctrm(:, datchanindx, fbin, tbin)); end @@ -524,7 +524,7 @@ end if ~isequal(i1(:), (1:numel(cfg.channel))') % this is not so easy to deal with, throw an error - error('There''s a mismatch between the number/order of channels in the data, with respect to the channels in the precomputed leadfield/filter. This is not easy to solve automatically. Please look into this.'); + ft_error('There''s a mismatch between the number/order of channels in the data, with respect to the channels in the precomputed leadfield/filter. This is not easy to solve automatically. Please look into this.'); end end @@ -552,7 +552,7 @@ % prepare the resampling of the trials, or average the data if multiple trials are present and no resampling is neccessary if (Ntrials<=1) && (strcmp(cfg.jackknife, 'yes') || strcmp(cfg.bootstrap, 'yes') || strcmp(cfg.pseudovalue, 'yes') || strcmp(cfg.singletrial, 'yes') || strcmp(cfg.rawtrial, 'yes') || strcmp(cfg.randomization, 'yes') || strcmp(cfg.permutation, 'yes')) - error('multiple trials required in the data\n'); + ft_error('multiple trials required in the data\n'); elseif strcmp(cfg.permutation, 'yes') % compute the cross-spectral density matrix without resampling @@ -612,7 +612,7 @@ % filter and applies it to the single trial covariance/csd. The problem % is that beamformer will use the averaged covariance/csd to estimate the % power and not the single trial covariance/csd - error('this option contains a bug, and is therefore not supported at the moment'); + ft_error('this option contains a bug, and is therefore not supported at the moment'); Cf = Cf; % FIXME, should be averaged and repeated for each trial Cr = Cr; % FIXME, should be averaged and repeated for each trial Pr = Pr; % FIXME, should be averaged and repeated for each trial @@ -657,15 +657,15 @@ optarg = ft_cfg2keyval(tmpcfg); if Nrepetitions > 1 - ft_progress('init', 'text'); + ft_progress('init', cfg.(cfg.method).feedback, 'scanning repetition...'); end for i=1:Nrepetitions size_Cf = size(Cf); - squeeze_Cf = reshape(Cf(i,:,:), size_Cf(2:end)); + squeeze_Cf = reshape(Cf(i,:,:), size_Cf(2:end)); if Nrepetitions > 1 - ft_progress(i/Nrepetitions, 'scanning repetition %d of %d', i, Nrepetitions); + ft_progress(i/Nrepetitions, 'scanning repetition %d from %d', i, Nrepetitions); end switch cfg.method @@ -682,7 +682,7 @@ % FIXME added by jansch because an appropriate subselection of avg % should be done first (i.e. select the tapers that belong to this % repetition - error('rawtrial in combination with pcc has been temporarily disabled'); + ft_error('rawtrial in combination with pcc has been temporarily disabled'); else dip(i) = beamformer_pcc(grid, sens, headmodel, avg, squeeze_Cf, optarg{:}, 'refdip', cfg.refdip, 'refchan', refchanindx, 'supdip', cfg.supdip, 'supchan', supchanindx); end @@ -692,11 +692,11 @@ dip(i) = minimumnormestimate(grid, sens, headmodel, avg, optarg{:}); case 'harmony' dip(i) = harmony(grid, sens, headmodel, avg, optarg{:}); - % error(sprintf('method ''%s'' is unsupported for source reconstruction in the frequency domain', cfg.method)); + % ft_error(sprintf('method ''%s'' is unsupported for source reconstruction in the frequency domain', cfg.method)); case {'rv'} dip(i) = residualvariance(grid, sens, headmodel, avg, optarg{:}) ; case {'music'} - error(sprintf('method ''%s'' is currently unsupported for source reconstruction in the frequency domain', cfg.method)); + ft_error('method ''%s'' is currently unsupported for source reconstruction in the frequency domain', cfg.method); otherwise end @@ -711,7 +711,7 @@ elseif istimelock && any(strcmp(cfg.method, {'lcmv', 'sam', 'mne','harmony', 'rv', 'music', 'pcc', 'mvl', 'sloreta', 'eloreta'})) % determine the size of the data - Nsamples = size(data.avg,2); + Nsamples = length(data.time); Nchans = length(data.label); if isfield(data, 'cov') && length(size(data.cov))==3 Ntrials = size(data.cov,1); @@ -746,7 +746,7 @@ % HACK: experimental code if hasbaseline - error('not supported') + ft_error('not supported') end tmpcfg = []; @@ -764,7 +764,6 @@ data.avg = data.avg(datchanindx,:); data.cov = data.cov(datchanindx,datchanindx); else - data.avg = data.avg(datchanindx,:); data.cov = data.cov(:,datchanindx,datchanindx); data.trial = data.trial(:,datchanindx,:); end @@ -793,10 +792,11 @@ data.avg = data.avg(datchanindx,:); %data.cov = reshape(data.cov, length(datchanindx), length(datchanindx)); data.cov = data.cov(datchanindx,datchanindx); - else - data.avg = data.avg(datchanindx,:); + elseif strcmp(data.dimord, 'rpt_chan_time') data.cov = data.cov(:,datchanindx,datchanindx); data.trial = data.trial(:,datchanindx,:); + else + ft_error('unexpected dimord'); end data.label = data.label(datchanindx); Nchans = length(data.label); @@ -815,7 +815,7 @@ % prepare the resampling of the trials, or average the data if multiple trials are present and no resampling is neccessary if (strcmp(cfg.jackknife, 'yes') || strcmp(cfg.bootstrap, 'yes') || strcmp(cfg.pseudovalue, 'yes') || strcmp(cfg.singletrial, 'yes') || strcmp(cfg.rawtrial, 'yes') || strcmp(cfg.randomization, 'yes')) && ~strcmp(data.dimord, 'rpt_chan_time') - error('multiple trials required in the data\n'); + ft_error('multiple trials required in the data\n'); elseif strcmp(cfg.permutation, 'yes') % compute the average and covariance without resampling @@ -871,7 +871,7 @@ % filter and applies it to the single trial covariance/csd. The problem % is that beamformer will use the averaged covariance/csd to estimate the % power and not the single trial covariance/csd - error('this option contains a bug, and is therefore not supported at the moment'); + ft_error('this option contains a bug, and is therefore not supported at the moment'); % average the single-trial covariance matrices Cy = mean(data.cov,1); % copy the average covariance matrix for every individual trial @@ -890,8 +890,8 @@ elseif Ntrials>1 % average the single-trial covariance matrices Cy = reshape(mean(data.cov,1), [Nchans Nchans]); - % select the average ERF - avg = data.avg; + % compute the average ERF + avg = shiftdim(mean(data.trial,1),1); Nrepetitions = 1; elseif Ntrials==1 @@ -936,13 +936,13 @@ end if ~isequal(i1(:), (1:numel(cfg.channel))') % this is not so easy to deal with, throw an error - error('There''s a mismatch between the number/order of channels in the data, with respect to the channels in the precomputed leadfield/filter. This is not easy to solve automatically. Please look into this.'); + ft_error('There''s a mismatch between the number/order of channels in the data, with respect to the channels in the precomputed leadfield/filter. This is not easy to solve automatically. Please look into this.'); end end size_avg = [size(avg) 1]; size_Cy = [size(Cy) 1]; - if strcmp(cfg.method, 'lcmv')% && ~isfield(grid, 'filter'), + if strcmp(cfg.method, 'lcmv')% && ~isfield(grid, 'filter') for i = 1:Nrepetitions squeeze_avg = reshape(avg(i,:,:),[size_avg(2) size_avg(3)]); squeeze_Cy = reshape(Cy(i,:,:), [size_Cy(2) size_Cy(3)]); @@ -955,14 +955,14 @@ % elseif 0 && strcmp(cfg.method, 'lcmv') % %don't loop over repetitions (slow), but reshape the input data to obtain single trial timecourses efficiently % %in the presence of filters pre-computed on the average (or whatever) - % tmpdat = reshape(permute(avg,[2 3 1]),[siz(2) siz(3)*siz(1)]); + % tmpdat = reshape(permute(avg,[2 3 1]),[size_avg(2) size_avg(3)*size_avg(1)]); % tmpdip = beamformer_lcmv(grid, sens, headmodel, tmpdat, squeeze(mean(Cy,1)), optarg{:}); % tmpmom = tmpdip.mom{tmpdip.inside(1)}; % sizmom = size(tmpmom); % % for i=1:length(tmpdip.inside) % indx = tmpdip.inside(i); - % tmpdip.mom{indx} = permute(reshape(tmpdip.mom{indx}, [sizmom(1) siz(3) siz(1)]), [3 1 2]); + % tmpdip.mom{indx} = permute(reshape(tmpdip.mom{indx}, [sizmom(1) size_avg(3) size_avg(1)]), [3 1 2]); % end % try, tmpdip = rmfield(tmpdip, 'pow'); end % try, tmpdip = rmfield(tmpdip, 'cov'); end @@ -979,7 +979,7 @@ % dip(i).pow = nan(size(tmpdip.pos,1),1); % for ii=1:length(tmpdip.inside) % indx = tmpdip.inside(ii); - % tmpmom = reshape(tmpdip.mom{indx}(i,:,:),[sizmom(1) siz(3)]); + % tmpmom = reshape(tmpdip.mom{indx}(i,:,:),[sizmom(1) size_avg(3)]); % dip(i).mom{indx} = tmpmom; % if isfield(tmpdip, 'ori') % dip(i).ori{indx} = tmpdip.ori{indx}; @@ -990,7 +990,7 @@ % % latency of the event-related field in the input and not the % % latency of the covariance window, which can differ from the % % former - % dip(i).cov{indx} = (tmpmom*tmpmom')./siz(3); + % dip(i).cov{indx} = (tmpmom*tmpmom')./size_avg(3); % if isempty(cfg.lcmv.powmethod) || strcmp(cfg.lcmv.powmethod, 'trace') % dip(i).pow(indx) = trace(dip(i).cov{indx}); % else @@ -1008,7 +1008,7 @@ dip(i) = ft_sloreta(grid, sens, headmodel, squeeze_avg, squeeze_Cy, optarg{:}); end - elseif strcmp(cfg.method, 'eloreta'), + elseif strcmp(cfg.method, 'eloreta') for i=1:Nrepetitions squeeze_avg = reshape(avg(i,:,:),[size_avg(2) size_avg(3)]); squeeze_Cy = reshape(Cy(i,:,:), [size_Cy(2) size_Cy(3)]); @@ -1020,7 +1020,7 @@ squeeze_avg = reshape(avg(i,:,:),[size_avg(2) size_avg(3)]); squeeze_Cy = reshape(Cy(i,:,:), [size_Cy(2) size_Cy(3)]); fprintf('scanning repetition %d\n', i); - squeeze_avg=reshape(avg(i,:,:),[siz(2) siz(3)]); + squeeze_avg=reshape(avg(i,:,:),[size_avg(2) size_avg(3)]); dip(i) = beamformer_sam(grid, sens, headmodel, squeeze_avg, squeeze_Cy, optarg{:}); end elseif strcmp(cfg.method, 'pcc') @@ -1028,7 +1028,7 @@ squeeze_avg = reshape(avg(i,:,:),[size_avg(2) size_avg(3)]); squeeze_Cy = reshape(Cy(i,:,:), [size_Cy(2) size_Cy(3)]); fprintf('scanning repetition %d\n', i); - squeeze_avg=reshape(avg(i,:,:),[siz(2) siz(3)]); + squeeze_avg=reshape(avg(i,:,:),[size_avg(2) size_avg(3)]); dip(i) = beamformer_pcc(grid, sens, headmodel, squeeze_avg, squeeze_Cy, optarg{:}, 'refdip', cfg.refdip, 'refchan', refchanindx, 'supchan', supchanindx); end elseif strcmp(cfg.method, 'mne') @@ -1085,32 +1085,20 @@ dip(i) = mvlestimate(grid, sens, headmodel, squeeze_avg, optarg{:}); end else - error(sprintf('method ''%s'' is unsupported for source reconstruction in the time domain', cfg.method)); + ft_error('method ''%s'' is unsupported for source reconstruction in the time domain', cfg.method); end elseif iscomp - error('the use of component data in ft_sourceanalysis is disabled for the time being: if you encounter this error message and you need this functionality please contact the FieldTrip development team'); + ft_error('the use of component data in ft_sourceanalysis is disabled for the time being: if you encounter this error message and you need this functionality please contact the FieldTrip development team'); else - error('the specified method ''%s'' combined with the input data of type ''%s'' are not supported', cfg.method, ft_datatype(data)); + ft_error('the specified method ''%s'' combined with the input data of type ''%s'' are not supported', cfg.method, ft_datatype(data)); end % if freq or timelock or comp data %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % clean up and collect the results %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -if isfield(grid, 'dim') - % the source reconstruction was perfomed on a regular 3d volume, remember the dimensions of the volume - source.dim = grid.dim; -end - -if isfield(grid, 'tri') - % the source reconstruction was perfomed on a tesselated cortical sheet, remember the triangles - source.tri = grid.tri; -end - -if exist('grid', 'var') - source = copyfields(grid, source, {'pos', 'inside', 'leadfield', 'leadfielddimord', 'label'});%, 'filter'}); -end +source = copyfields(grid, source, {'pos', 'tri', 'dim', 'inside', 'leadfield', 'leadfielddimord', 'label'});%, 'filter'}); if exist('dip', 'var') % the fields in the dip structure might be more recent than those in the grid structure diff --git a/external/fieldtrip/ft_sourcedescriptives.m b/external/fieldtrip/ft_sourcedescriptives.m index 5534f573..6cf9c61e 100644 --- a/external/fieldtrip/ft_sourcedescriptives.m +++ b/external/fieldtrip/ft_sourcedescriptives.m @@ -82,7 +82,7 @@ % check if the input data is valid for this function % source = ft_checkdata(source, 'datatype', 'source', 'feedback', 'yes'); -cfg = ft_checkconfig(cfg, 'forbidden', {'trials'}); % trial selection is not implented here, you may want to consider ft_selectdata +% cfg = ft_checkconfig(cfg, 'forbidden', {'trials'}); % trial selection is not implented here, you may want to consider ft_selectdata % DEPRECATED by roboos on 13 June 2013 % see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2199 for more details @@ -102,6 +102,7 @@ cfg.fa = ft_getopt(cfg, 'fa', 'no'); cfg.kurtosis = ft_getopt(cfg, 'kurtosis', 'no'); cfg.keeptrials = ft_getopt(cfg, 'keeptrials', 'no'); +cfg.trials = ft_getopt(cfg, 'trials', 'all'); cfg.keepcsd = ft_getopt(cfg, 'keepcsd', 'no'); cfg.keepmom = ft_getopt(cfg, 'keepmom', 'yes'); cfg.keepnoisecsd = ft_getopt(cfg, 'keepnoisecsd', 'no'); @@ -120,6 +121,22 @@ zscore = strcmp(cfg.zscore, 'yes'); demean = strcmp(cfg.demean, 'yes'); +if ischar(cfg.trials) && strcmp(cfg.trials,'all') + % do nothing +elseif ischar(cfg.trials) + ft_error('only ''all'' is allowed for string input for cfg.trials'); +else + % check whether there's a trial field in the source structure, and + % subselect, otherwise error + if isfield(source, 'trial') + source.trial = source.trial(cfg.trials); + if isfield(source, 'cumtapcnt'), source.cumtapcnt = source.cumtapcnt(cfg.trials,:); end + else + ft_error('subselecting trials in ft_sourcedescriptives is currently only possible with a ''trial'' field'); + end +end + + % get desired method from source structure source.method = ft_getopt(source,'method',[]); @@ -143,12 +160,12 @@ if isempty(cfg.powmethod) cfg.powmethod = 'regular'; % set the default elseif ~strcmp(cfg.powmethod, 'regular') - error('unsupported powmethod in combination with projectmom'); + ft_error('unsupported powmethod in combination with projectmom'); end if isempty(cfg.cohmethod) cfg.cohmethod = 'regular';% set the default elseif ~strcmp(cfg.cohmethod, 'regular') - error('unsupported cohmethod in combination with projectmom'); + ft_error('unsupported cohmethod in combination with projectmom'); end else if isempty(cfg.powmethod) @@ -165,24 +182,24 @@ % do a validity check on the input data and specified options if strcmp(cfg.resolutionmatrix, 'yes') if ~isfield(source.avg, 'filter') - error('The computation of the resolution matrix requires keepfilter=''yes'' in sourceanalysis.'); + ft_error('The computation of the resolution matrix requires keepfilter=''yes'' in sourceanalysis.'); elseif ~isfield(source, 'leadfield') - error('The computation of the resolution matrix requires keepleadfield=''yes'' in sourceanalysis.'); + ft_error('The computation of the resolution matrix requires keepleadfield=''yes'' in sourceanalysis.'); end end if strcmp(cfg.fwhm, 'yes') if ~isfield(source.avg, 'filter') - error('The computation of the fwhm requires keepfilter=''yes'' in sourceanalysis.'); + ft_error('The computation of the fwhm requires keepfilter=''yes'' in sourceanalysis.'); end end -if strcmp(cfg.eta, 'yes') && strcmp(cfg.cohmethod, 'svdfft'), - error('eta cannot be computed in combination with the application of svdfft'); +if strcmp(cfg.eta, 'yes') && strcmp(cfg.cohmethod, 'svdfft') + ft_error('eta cannot be computed in combination with the application of svdfft'); end -if strcmp(cfg.keeptrials, 'yes') && ~strcmp(cfg.supmethod, 'none'), - error('you cannot keep trials when you want to partialize something'); +if strcmp(cfg.keeptrials, 'yes') && ~strcmp(cfg.supmethod, 'none') + ft_error('you cannot keep trials when you want to partialize something'); end % set some flags for convenience @@ -201,7 +218,7 @@ case 'none' powmethodfun = []; otherwise - error('unsupported powmethod'); + ft_error('unsupported powmethod'); end % represent the selection of sources in the brain as a row-vector with indices @@ -213,7 +230,7 @@ Ndipole = size(source.pos,1); if ischar(source.avg.csdlabel{1}), source.avg.csdlabel = {source.avg.csdlabel}; end - if numel(source.avg.csdlabel)==1, + if numel(source.avg.csdlabel)==1 source.avg.csdlabel = repmat(source.avg.csdlabel, [Ndipole 1]); end @@ -225,7 +242,7 @@ % cannot handle reference channels and reference dipoles simultaneously if numel(refchansel)>0 && numel(refdipsel)>0 - error('cannot simultaneously handle reference channels and reference dipole'); + ft_error('cannot simultaneously handle reference channels and reference dipole'); end % these are only used to count the number of reference/suppression dipoles and channels @@ -240,7 +257,7 @@ for i=insideindx ft_progress(i/length(insideindx), 'projecting dipole moment %d/%d\n', i, length(insideindx)); - if numel(source.avg.csdlabel)>1, + if numel(source.avg.csdlabel)>1 dipsel = find(strcmp(source.avg.csdlabel{i}, 'scandip')); refchansel = find(strcmp(source.avg.csdlabel{i}, 'refchan')); refdipsel = find(strcmp(source.avg.csdlabel{i}, 'refdip')); @@ -270,13 +287,13 @@ % create rotation-matrix rotmat = zeros(0, length(source.avg.csdlabel{i})); - if ~isempty(rmom), + if ~isempty(rmom) rotmat = [rotmat; rmom zeros(numel(refsel)+numel(supsel),1)]; end - if ~isempty(rref), + if ~isempty(rref) rotmat = [rotmat; zeros(1, numel(dipsel)), rref, zeros(1,numel(refchansel)+numel(supsel))]; end - if ~isempty(rsup), + if ~isempty(rsup) rotmat = [rotmat; zeros(1, numel(dipsel)+numel(refdipsel)), rsup, zeros(1,numel(refchansel)+numel(supchansel))]; end for j=1:length(supchansel) @@ -294,7 +311,7 @@ if isfield(source.avg, 'noisecsd'), source.avg.noisecsd{i} = rotmat * source.avg.noisecsd{i} * rotmat'; end % compute rotated filter if isfield(source.avg, 'filter'), source.avg.filter{i} = rotmat * source.avg.filter{i}; end - if isfield(source.avg, 'csdlabel'), + if isfield(source.avg, 'csdlabel') % remember what the interpretation is of all CSD output components scandiplabel = repmat({'scandip'}, 1, cfg.numcomp); % only one dipole orientation remains refdiplabel = repmat({'refdip'}, 1, length(refdipsel)>0); % for svdfft at max. only one dipole orientation remains @@ -307,7 +324,7 @@ % compute rotated leadfield % FIXME in the presence of a refdip and/or supdip, this does not work; leadfield is Nx3 - if isfield(source, 'leadfield'), + if isfield(source, 'leadfield') %FIXME this is a proposed dirty fix n1 = size(source.leadfield{i},2); %n2 = size(rotmat,2) - n1; @@ -390,7 +407,7 @@ if keeptrials % do the processing of the CSD matrices for each trial if ~strcmp(cfg.supmethod, 'none') - error('suppression is only supported for average CSD'); + ft_error('suppression is only supported for average CSD'); end %dipselcell = mat2cell(repmat(dipsel(:)', [Ndipole 1]), ones(Ndipole,1), length(dipsel)); %if hasrefdip, refdipselcell = mat2cell(repmat(refdipsel(:)', [Ndipole 1]), ones(Ndipole,1), length(refdipsel)); end @@ -414,7 +431,7 @@ if hasrefchan, source.trial(triallop).refchanpow(source.inside) = cellfun(powmethodfun,source.trial(triallop).csd(source.inside), refchanselcell(source.inside)); end if hassupchan, source.trial(triallop).supchanpow(source.inside) = cellfun(powmethodfun,source.trial(triallop).csd(source.inside), supchanselcell(source.inside)); end %FIXME kan volgens mij niet - if isnoise && isfield(source.trial(triallop), 'noisecsd'), + if isnoise && isfield(source.trial(triallop), 'noisecsd') % compute the power of the noise projected on each source component source.trial(triallop).noise = cellfun(powmethodfun,source.trial(triallop).csd, dipselcell); if hasrefdip, source.trial(triallop).refdipnoise = cellfun(powmethodfun,source.trial(triallop).noisecsd, refdipselcell); end @@ -470,15 +487,15 @@ if hassupchan, source.avg.supchannoise = nan(Ndipole, 1); end end % if isnoise if hasrefdip||hasrefchan, source.avg.coh = nan(Ndipole, 1); end - if strcmp(cfg.eta, 'yes'), + if strcmp(cfg.eta, 'yes') source.avg.eta = nan(Ndipole, 1); source.avg.ori = cell(1, Ndipole); end - if strcmp(cfg.eta, 'yes') && ~isempty(refsel), + if strcmp(cfg.eta, 'yes') && ~isempty(refsel) source.avg.etacsd = nan(Ndipole, 1); source.avg.ucsd = cell(1, Ndipole); end - if strcmp(cfg.fa, 'yes'), + if strcmp(cfg.fa, 'yes') source.avg.fa = nan(Ndipole, 1); end @@ -487,7 +504,7 @@ refsel = [refchanselcell{i} refdipselcell{i}]; % compute the power of each source component - if strcmp(cfg.projectmom, 'yes') && cfg.numcomp>1, + if strcmp(cfg.projectmom, 'yes') && cfg.numcomp>1 source.avg.pow(i) = powmethodfun(source.avg.csd{i}(dipselcell{i},dipselcell{i}), 1); else source.avg.pow(i) = powmethodfun(source.avg.csd{i}(dipselcell{i},dipselcell{i})); @@ -499,7 +516,7 @@ if hassupchan, source.avg.supchanpow(i) = powmethodfun(source.avg.csd{i}(supchansel,supchansel)); end if isnoise % compute the power of the noise projected on each source component - if strcmp(cfg.projectmom, 'yes') && cfg.numcomp>1, + if strcmp(cfg.projectmom, 'yes') && cfg.numcomp>1 source.avg.noise(i) = powmethodfun(source.avg.noisecsd{i}(dipselcell{i},dipselcell{i}), 1); else source.avg.noise(i) = powmethodfun(source.avg.noisecsd{i}(dipselcell{i},dipselcell{i})); @@ -531,14 +548,14 @@ [cmax, indmax] = max(ccoh); source.avg.coh(i) = ccoh(indmax); otherwise - error('unsupported cohmethod'); + ft_error('unsupported cohmethod'); end % cohmethod end % compute eta if strcmp(cfg.eta, 'yes') [source.avg.eta(i), source.avg.ori{i}] = csd2eta(source.avg.csd{i}(dipselcell{i},dipselcell{i})); - if ~isempty(refsel), + if ~isempty(refsel) %FIXME this only makes sense when only a reference signal OR a dipole is selected [source.avg.etacsd(i), source.avg.ucsd{i}] = csd2eta(source.avg.csd{i}(dipsel,refsel)); end @@ -641,7 +658,7 @@ for diplop=1:length(insideindx) mom = source.avg.mom{insideindx(diplop)}; if length(mom)~=prod(size(mom)) - error('kurtosis can only be computed for projected dipole moment'); + ft_error('kurtosis can only be computed for projected dipole moment'); end source.avg.k2(insideindx(diplop)) = kurtosis(mom); end @@ -679,7 +696,7 @@ for diplop=1:length(insideindx) mom = source.avg.mom{insideindx(diplop)}; if length(mom)~=prod(size(mom)) - error('kurtosis can only be computed for projected dipole moment'); + ft_error('kurtosis can only be computed for projected dipole moment'); end source.avg.k2(insideindx(diplop)) = kurtosis(mom); end @@ -750,7 +767,7 @@ for diplop=1:length(insideindx) mom = source.trial(trllop).mom{insideindx(diplop)}; if length(mom)~=numel(mom) - error('kurtosis can only be computed for projected dipole moment'); + ft_error('kurtosis can only be computed for projected dipole moment'); end source.trial(trllop).k2(insideindx(diplop)) = kurtosis(mom); end @@ -948,7 +965,7 @@ bias = Ntrials; elseif strcmp(source.method, 'pseudovalue') % note that I have not put any thought in this aspect yet - warning('don''t know how to compute bias for pseudovalue resampling'); + ft_warning('don''t know how to compute bias for pseudovalue resampling'); bias = 1; end @@ -1028,7 +1045,7 @@ switch cfg.fwhmmethod case 'barnes' if ~isfield(source, 'dim') - error('computation of fwhm is not possible with method ''barnes'' is not possible when the dipoles are not defined on a regular 3D grid'); + ft_error('computation of fwhm is not possible with method ''barnes'' is not possible when the dipoles are not defined on a regular 3D grid'); end fprintf('computing fwhm of spatial filters using method ''barnes''\n'); source = estimate_fwhm1(source, cfg.fwhmremovecenter); @@ -1036,7 +1053,7 @@ fprintf('computing fwhm of spatial filters using method ''gaussfit''\n'); source = estimate_fwhm2(source, cfg.fwhmmaxdist); otherwise - error('unknown method for fwhm estimation'); + ft_error('unknown method for fwhm estimation'); end end @@ -1072,7 +1089,7 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function p = powmethod_lambda1(x, ind) -if nargin==1, +if nargin==1 ind = 1:size(x,1); end s = svd(x(ind,ind)); @@ -1083,7 +1100,7 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function p = powmethod_trace(x, ind) -if nargin==1, +if nargin==1 ind = 1:size(x,1); end p = trace(x(ind,ind)); @@ -1093,7 +1110,7 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function p = powmethod_regular(x, ind) -if nargin==1, +if nargin==1 ind = 1:size(x,1); end p = abs(x(ind,ind)); diff --git a/external/fieldtrip/ft_sourcegrandaverage.m b/external/fieldtrip/ft_sourcegrandaverage.m index e742ba98..2c4ab9af 100644 --- a/external/fieldtrip/ft_sourcegrandaverage.m +++ b/external/fieldtrip/ft_sourcegrandaverage.m @@ -31,7 +31,7 @@ % input/output structure. For this particular function, the input data % should be structured as a single cell array. % -% See also FT_SOURCEANALYSIS, FT_VOLUMENORMALISE, FT_SOURCESTATISTICS +% See also FT_SOURCEANALYSIS, FT_SOURCEDESCRIPTIVES, FT_SOURCESTATISTICS, FT_MATH % Undocumented local options % You can also use FT_SOURCEGRANDAVERAGE to compute averages after @@ -113,14 +113,14 @@ for i=2:length(varargin) tmpvar2 = varargin{i}.(tmpstr); if any(size(tmpvar1)~=size(tmpvar2)) || any(tmpvar1(:)~=tmpvar2(:)) - error('the input sources vary in the field %s', tmpstr); + ft_error('the input sources vary in the field %s', tmpstr); end end end end % ensure a consistent selection of the data over all inputs -tmpcfg = keepfields(cfg, {'parameter', 'trials', 'latency', 'frequency', 'foilim'}); +tmpcfg = keepfields(cfg, {'parameter', 'trials', 'latency', 'frequency', 'foilim', 'showcallinfo'}); [varargin{:}] = ft_selectdata(tmpcfg, varargin{:}); % restore the provenance information [cfg, varargin{:}] = rollback_provenance(cfg, varargin{:}); diff --git a/external/fieldtrip/ft_sourceinterpolate.m b/external/fieldtrip/ft_sourceinterpolate.m index 7dd7f522..a7a3c0e8 100644 --- a/external/fieldtrip/ft_sourceinterpolate.m +++ b/external/fieldtrip/ft_sourceinterpolate.m @@ -63,8 +63,8 @@ % files should contain only a single variable, corresponding with the % input/output structure. % -% See also FT_READ_MRI, FT_SOURCEANALYSIS, FT_SOURCESTATISTICS, -% FT_READ_HEADSHAPE, FT_SOURCEPLOT, FT_SOURCEWRITE +% See also FT_READ_MRI, FT_READ_HEADSHAPE, FT_SOURCEPLOT, FT_SOURCEANALYSIS, +% FT_SOURCEWRITE % Copyright (C) 2003-2007, Robert Oostenveld % Copyright (C) 2011-2014, Jan-Mathijs Schoffelen @@ -106,8 +106,8 @@ end % this is not supported any more as of 26/10/2011 -if ischar(anatomical), - error('please use cfg.inputfile instead of specifying the input variable as a sting'); +if ischar(anatomical) + ft_error('please use cfg.inputfile instead of specifying the input variable as a sting'); end % check if the input cfg is valid for this function @@ -119,9 +119,9 @@ cfg = ft_checkconfig(cfg, 'renamedval', {'parameter', 'avg.mom', 'mom'}); % set the defaults -cfg.downsample = ft_getopt(cfg, 'downsample', 1); -cfg.feedback = ft_getopt(cfg, 'feedback', 'text'); -% cfg.interpmethod depends on how the interpolation should be done and will be specified below +cfg.downsample = ft_getopt(cfg, 'downsample', 1); +cfg.feedback = ft_getopt(cfg, 'feedback', 'text'); +cfg.interpmethod = ft_getopt(cfg, 'interpmethod', []); % cfg.interpmethod depends on how the interpolation should be done and actual defaults will be specified below % replace pnt by pos anatomical = fixpos(anatomical); @@ -130,6 +130,13 @@ % ensure the functional data to be in double precision functional = ft_struct2double(functional); +if strcmp(cfg.interpmethod, 'nearest') && (ft_datatype(functional, 'volume+label') || ft_datatype(functional, 'source+label')) + % the first input argument describes a parcellation or segmentation with tissue labels + isAtlasFun = true; +else + isAtlasFun = false; +end + if isfield(anatomical, 'transform') && isfield(anatomical, 'dim') % anatomical volume isUnstructuredAna = false; @@ -152,9 +159,9 @@ end if isUnstructuredAna - anatomical = ft_checkdata(anatomical, 'datatype', 'source', 'inside', 'logical', 'feedback', 'yes', 'hasunit', 'yes'); + anatomical = ft_checkdata(anatomical, 'datatype', {'source', 'source+label', 'mesh'}, 'inside', 'logical', 'feedback', 'yes', 'hasunit', 'yes'); else - anatomical = ft_checkdata(anatomical, 'datatype', 'volume', 'inside', 'logical', 'feedback', 'yes', 'hasunit', 'yes'); + anatomical = ft_checkdata(anatomical, 'datatype', {'volume', 'volume+label'}, 'inside', 'logical', 'feedback', 'yes', 'hasunit', 'yes'); end if isUnstructuredFun @@ -186,13 +193,13 @@ if isfield(functional, 'coordsys') && isfield(anatomical, 'coordsys') && ~isequal(functional.coordsys, anatomical.coordsys) % FIXME is this different when smudged or not? - % warning('the coordinate systems are not aligned'); - % error('the coordinate systems are not aligned'); + % ft_warning('the coordinate systems are not aligned'); + % ft_error('the coordinate systems are not aligned'); end if ~isUnstructuredAna && cfg.downsample~=1 % downsample the anatomical volume - tmpcfg = keepfields(cfg, {'downsample'}); + tmpcfg = keepfields(cfg, {'downsample', 'showcallinfo'}); orgcfg.parameter = cfg.parameter; tmpcfg.parameter = 'anatomy'; anatomical = ft_volumedownsample(tmpcfg, anatomical); @@ -563,7 +570,7 @@ if any(dimf(4:end)>1) && ~strcmp(cfg.feedback, 'none') % this is needed to prevent feedback to be displayed for every time-frequency point - warning('disabling feedback'); + ft_warning('disabling feedback'); cfg.feedback = 'none'; end @@ -609,6 +616,19 @@ end end +if isAtlasFun + for i=1:numel(dat_name) + % keep the labels that describe the different tissue types + interp = copyfields(functional, interp, [dat_name{i} 'label']); + % replace NaNs that fall outside the labeled area with zero + tmp = interp.(dat_name{i}); + tmp(isnan(tmp)) = 0; + interp.(dat_name{i}) = tmp; + end + % remove the inside field if present + interp = removefields(interp, 'inside'); +end + if exist('interpmat', 'var') cfg.interpmat = interpmat; cfg.interpmat; % access it once to fool the cfg-tracking diff --git a/external/fieldtrip/ft_sourcemovie.m b/external/fieldtrip/ft_sourcemovie.m index bd65a4ab..775aa5eb 100644 --- a/external/fieldtrip/ft_sourcemovie.m +++ b/external/fieldtrip/ft_sourcemovie.m @@ -8,7 +8,7 @@ % where the input source data is obtained from FT_SOURCEANALYSIS and cfg is % a configuratioun structure that should contain % -% cfg.funparameter = string, functional parameter that is color coded (default = 'pow') +% cfg.funparameter = string, functional parameter that is color coded % cfg.maskparameter = string, functional parameter that is used for opacity (default = []) % % To facilitate data-handling and distributed computing you can use @@ -17,7 +17,7 @@ % file on disk. This mat files should contain only a single variable named 'data', % corresponding to the input structure. % -% See also FT_SOURCEPLOT, FT_SOURCEINTERPOLATE +% See also FT_SOURCEPLOT, FT_SOURCEINTERPOLATE, FT_MOVIEPLOTER, FT_MOVIEPLOTTFR % Undocumented options: % cfg.parcellation @@ -72,9 +72,10 @@ source = ft_checkdata(source, 'datatype', 'source', 'feedback', 'yes'); % check if the input cfg is valid for this function -cfg = ft_checkconfig(cfg, 'renamed', {'zparam', 'cfg.funparameter'}); -cfg = ft_checkconfig(cfg, 'renamed', {'parameter', 'cfg.funparameter'}); +cfg = ft_checkconfig(cfg, 'renamed', {'zparam', 'funparameter'}); +cfg = ft_checkconfig(cfg, 'renamed', {'parameter', 'funparameter'}); cfg = ft_checkconfig(cfg, 'renamed', {'mask', 'maskparameter'}); +cfg = ft_checkconfig(cfg, 'required', 'funparameter'); % these are not needed any more, once the source structure has a proper dimord % cfg = ft_checkconfig(cfg, 'deprecated', 'xparam'); @@ -90,39 +91,51 @@ cfg.funparameter = ft_getopt(cfg, 'funparameter'); cfg.maskparameter = ft_getopt(cfg, 'maskparameter'); cfg.renderer = ft_getopt(cfg, 'renderer', 'opengl'); -cfg.title = ft_getopt(cfg, 'title', ''); +cfg.title = ft_getopt(cfg, 'title'); cfg.parcellation = ft_getopt(cfg, 'parcellation'); % select the functional and the mask parameter cfg.funparameter = parameterselection(cfg.funparameter, source); cfg.maskparameter = parameterselection(cfg.maskparameter, source); + % only a single parameter should be selected -try, cfg.funparameter = cfg.funparameter{1}; end -try, cfg.maskparameter = cfg.maskparameter{1}; end +if ~isempty(cfg.funparameter) && iscell(cfg.funparameter), cfg.funparameter = cfg.funparameter{1}; end +if ~isempty(cfg.maskparameter) && iscell(cfg.maskparameter), cfg.maskparameter = cfg.maskparameter{1}; end dimord = getdimord(source, cfg.funparameter); dimtok = tokenize(dimord, '_'); -if isempty(cfg.xparam) && numel(dimtok)>1 - cfg.xparam = dimtok{2}; -end - -if isempty(cfg.xparam) && numel(dimtok)>2 - cfg.yparam = dimtok{3}; +if numel(dimtok)==2 + % for example pos_freq or pos_time + if isempty(cfg.xparam), cfg.xparam = dimtok{2}; end +elseif numel(dimtok)==3 + % for example pos_freq_time + if isempty(cfg.yparam), cfg.yparam = dimtok{2}; end % frequency along vertical axis by default + if isempty(cfg.xparam), cfg.xparam = dimtok{3}; end % time along horizontal axis by default, this is also the time dimension in the movie end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % the actual computation is done in the middle part %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% the user specifies xparam and yparam, it may be needed to permute the dimensions +[dum, order] = match_str(dimtok, {'pos', cfg.xparam, cfg.yparam}); + if ~hassource2 fun = getsubfield(source, cfg.funparameter); -elseif hassource2 && isfield(source2, 'pos'), + fun = permute(fun, order); + +elseif hassource2 && isfield(source2, 'pos') fun = getsubfield(source, cfg.funparameter); fun2 = getsubfield(source2, cfg.funparameter); + fun = permute(fun, order); + fun2 = permute(fun2, order); + elseif hassource2 % assume the first data argument to be a parcellation, and the second a parcellated structure tmp = getsubfield(source2, cfg.funparameter); + tmp = permute(tmp, order); + siz = [size(tmp) 1]; fun = zeros([size(source.pos, 1), siz(2:end)]); parcels = source.(cfg.parcellation); @@ -141,28 +154,29 @@ end if size(source.pos)~=size(fun,1) - error('inconsistent number of vertices in the cortical mesh'); + ft_error('inconsistent number of vertices in the cortical mesh'); end if ~isfield(source, 'tri') - error('source.tri missing, this function requires a triangulated cortical sheet as source model'); + ft_error('source.tri missing, this function requires a triangulated cortical sheet as source model'); end if ~isempty(cfg.maskparameter) && ischar(cfg.maskparameter) mask = double(getsubfield(source, cfg.maskparameter)); + mask = permute(mask, order); else mask = 0.5*ones(size(fun)); end xparam = source.(cfg.xparam); if length(xparam)~=size(fun,2) - error('inconsistent size of "%s" compared to "%s"', cfg.funparameter, cfg.xparam); + ft_error('inconsistent size of "%s" compared to "%s"', cfg.funparameter, cfg.xparam); end if ~isempty(cfg.yparam) yparam = source.(cfg.yparam); if length(yparam)~=size(fun,3) - error('inconsistent size of "%s" compared to "%s"', cfg.funparameter, cfg.yparam); + ft_error('inconsistent size of "%s" compared to "%s"', cfg.funparameter, cfg.yparam); end else yparam = []; @@ -201,7 +215,7 @@ xparam = xparam(xbeg:xend); yparam = yparam(ybeg:yend); fun = fun(:,xbeg:xend,ybeg:yend); -if hassource2 && isfield(source2, 'pos'), +if hassource2 && isfield(source2, 'pos') fun2 = fun2(:,xbeg:xend,ybeg:yend); end mask = mask(:,xbeg:xend,ybeg:yend); @@ -277,49 +291,49 @@ playbutton = uicontrol('parent', h, 'units', 'normalized', 'style', 'pushbutton', 'string', 'play', 'userdata', 'p'); recordbutton = uicontrol('parent', h, 'units', 'normalized', 'style', 'pushbutton', 'string', 'record', 'userdata', 'r'); quitbutton = uicontrol('parent', h, 'units', 'normalized', 'style', 'pushbutton', 'string', 'quit', 'userdata', 'q'); -if isfield(opt, 'dat2'), +if isfield(opt, 'dat2') displaybutton = uicontrol('parent', h, 'units', 'normalized', 'style', 'pushbutton', 'string', 'display: var1', 'userdata', 'f'); end -thrmin = uicontrol('parent', h, 'units', 'normalized', 'style', 'pushbutton', 'string', '<', 'userdata', 'downarrow'); -thr = uicontrol('parent', h, 'units', 'normalized', 'style', 'pushbutton', 'string', 'threshold', 'userdata', 't'); -thrplus = uicontrol('parent', h, 'units', 'normalized', 'style', 'pushbutton', 'string', '>', 'userdata', 'uparrow'); -spdmin = uicontrol('parent', h, 'units', 'normalized', 'style', 'pushbutton', 'string', '<', 'userdata', 'shift+downarrow'); -spd = uicontrol('parent', h, 'units', 'normalized', 'style', 'pushbutton', 'string', 'speed','userdata', 's'); -spdplus = uicontrol('parent', h, 'units', 'normalized', 'style', 'pushbutton', 'string', '>', 'userdata', 'shift+uparrow'); -clim = uicontrol('parent', h, 'units', 'normalized', 'style', 'pushbutton', 'string', 'colorlim', 'userdata', 'z'); -climminmin = uicontrol('parent', h, 'units', 'normalized', 'style', 'pushbutton', 'string', '-', 'userdata', 'leftarrow'); -climmaxmin = uicontrol('parent', h, 'units', 'normalized', 'style', 'pushbutton', 'string', '+', 'userdata', 'shift+leftarrow'); +thrmin = uicontrol('parent', h, 'units', 'normalized', 'style', 'pushbutton', 'string', '<', 'userdata', 'downarrow'); +thr = uicontrol('parent', h, 'units', 'normalized', 'style', 'pushbutton', 'string', 'threshold', 'userdata', 't'); +thrplus = uicontrol('parent', h, 'units', 'normalized', 'style', 'pushbutton', 'string', '>', 'userdata', 'uparrow'); +spdmin = uicontrol('parent', h, 'units', 'normalized', 'style', 'pushbutton', 'string', '<', 'userdata', 'shift+downarrow'); +spd = uicontrol('parent', h, 'units', 'normalized', 'style', 'pushbutton', 'string', 'speed','userdata', 's'); +spdplus = uicontrol('parent', h, 'units', 'normalized', 'style', 'pushbutton', 'string', '>', 'userdata', 'shift+uparrow'); +clim = uicontrol('parent', h, 'units', 'normalized', 'style', 'pushbutton', 'string', 'colorlim', 'userdata', 'z'); +climminmin = uicontrol('parent', h, 'units', 'normalized', 'style', 'pushbutton', 'string', '-', 'userdata', 'leftarrow'); +climmaxmin = uicontrol('parent', h, 'units', 'normalized', 'style', 'pushbutton', 'string', '+', 'userdata', 'shift+leftarrow'); climminplus = uicontrol('parent', h, 'units', 'normalized', 'style', 'pushbutton', 'string', '-', 'userdata', 'rightarrow'); climmaxplus = uicontrol('parent', h, 'units', 'normalized', 'style', 'pushbutton', 'string', '+', 'userdata', 'shift+rightarrow'); -sliderx = uicontrol('parent', h, 'units', 'normalized', 'style', 'slider', 'string', sprintf('%s = ', cfg.xparam)); -stringx = uicontrol('parent', h, 'units', 'normalized', 'style', 'text'); -slidery = uicontrol('parent', h, 'units', 'normalized', 'style', 'slider', 'string', sprintf('%s = ', cfg.yparam)); -stringy = uicontrol('parent', h, 'units', 'normalized', 'style', 'text'); -stringz = uicontrol('parent', h, 'units', 'normalized', 'style', 'text'); -stringp = uicontrol('parent', h, 'units', 'normalized', 'style', 'text'); +sliderx = uicontrol('parent', h, 'units', 'normalized', 'style', 'slider', 'string', sprintf('%s = ', cfg.xparam)); +stringx = uicontrol('parent', h, 'units', 'normalized', 'style', 'text'); +slidery = uicontrol('parent', h, 'units', 'normalized', 'style', 'slider', 'string', sprintf('%s = ', cfg.yparam)); +stringy = uicontrol('parent', h, 'units', 'normalized', 'style', 'text'); +stringz = uicontrol('parent', h, 'units', 'normalized', 'style', 'text'); +stringp = uicontrol('parent', h, 'units', 'normalized', 'style', 'text'); if isfield(opt,'dat2') set(displaybutton, 'position', [0.005 0.34 0.18 0.05], 'callback', @cb_keyboard); end -set(cambutton, 'position', [0.095 0.28 0.09 0.05], 'callback', @cb_keyboard); -set(quitbutton, 'position', [0.005 0.28 0.09 0.05], 'callback', @cb_keyboard); -set(playbutton, 'position', [0.005 0.22 0.09 0.05], 'callback', @cb_keyboard); -set(recordbutton, 'position', [0.095 0.22 0.09 0.05], 'callback', @cb_keyboard); -set(thrmin, 'position', [0.005 0.16 0.03 0.05], 'callback', @cb_keyboard); -set(thr, 'position', [0.035 0.16 0.12 0.05], 'callback', @cb_keyboard); -set(thrplus, 'position', [0.155 0.16 0.03 0.05], 'callback', @cb_keyboard); +set(cambutton, 'position', [0.095 0.28 0.09 0.05], 'callback', @cb_keyboard); +set(quitbutton, 'position', [0.005 0.28 0.09 0.05], 'callback', @cb_keyboard); +set(playbutton, 'position', [0.005 0.22 0.09 0.05], 'callback', @cb_keyboard); +set(recordbutton, 'position', [0.095 0.22 0.09 0.05], 'callback', @cb_keyboard); +set(thrmin, 'position', [0.005 0.16 0.03 0.05], 'callback', @cb_keyboard); +set(thr, 'position', [0.035 0.16 0.12 0.05], 'callback', @cb_keyboard); +set(thrplus, 'position', [0.155 0.16 0.03 0.05], 'callback', @cb_keyboard); set(climminmin, 'position', [0.005 0.10 0.03 0.025], 'callback', @cb_keyboard); set(climmaxmin, 'position', [0.005 0.125 0.03 0.025], 'callback', @cb_keyboard); -set(clim, 'position', [0.035 0.10 0.12 0.05], 'callback', @cb_keyboard); +set(clim, 'position', [0.035 0.10 0.12 0.05], 'callback', @cb_keyboard); set(climminplus, 'position', [0.155 0.10 0.03 0.025], 'callback', @cb_keyboard); set(climmaxplus, 'position', [0.155 0.125 0.03 0.025], 'callback', @cb_keyboard); -set(spdmin, 'position', [0.005 0.04 0.03 0.05], 'callback', @cb_keyboard); -set(spd, 'position', [0.035 0.04 0.12 0.05], 'callback', @cb_keyboard); -set(spdplus, 'position', [0.155 0.04 0.03 0.05], 'callback', @cb_keyboard); -set(sliderx, 'position', [0.02 0.4 0.3 0.03], 'callback', @cb_slider);%[0.200 0.04 0.78 0.03], 'callback', @cb_slider); -set(slidery, 'position', [0.350 0.5 0.03 0.35], 'callback', @cb_slider); +set(spdmin, 'position', [0.005 0.04 0.03 0.05], 'callback', @cb_keyboard); +set(spd, 'position', [0.035 0.04 0.12 0.05], 'callback', @cb_keyboard); +set(spdplus, 'position', [0.155 0.04 0.03 0.05], 'callback', @cb_keyboard); +set(sliderx, 'position', [0.02 0.4 0.3 0.03], 'callback', @cb_slider); % [0.200 0.04 0.78 0.03], 'callback', @cb_slider); +set(slidery, 'position', [0.350 0.5 0.03 0.35], 'callback', @cb_slider); set(stringx, 'position', [0.800 0.93 0.18 0.03]); set(stringy, 'position', [0.800 0.90 0.18 0.03]); set(stringz, 'position', [0.650 0.96 0.33 0.03]); @@ -366,11 +380,11 @@ abc = axis; axis([opt.xparam(1) opt.xparam(end) abc(3:4)]); vline = plot(opt.xparam(1)*[1 1], abc(3:4), 'r'); - + if hassource2 && isfield(source2, 'pos') tline2 = plot(opt.xparam, mean(opt.dat2(opt.vindx,:)), 'r'); hold on; end - + else tline = imagesc(opt.xparam, opt.yparam, shiftdim(mean(opt.dat(opt.vindx,:,:)),1)'); axis xy; hold on; abc = [opt.xparam([1 end]) opt.yparam([1 end])]; @@ -391,7 +405,7 @@ if exist('hline', 'var') opt.hline = hline; end -if hassource2 && isfield(source2, 'pos'), +if hassource2 && isfield(source2, 'pos') opt.tline2 = tline2; end opt.playbutton = playbutton; % handle to the playbutton @@ -421,7 +435,7 @@ setappdata(h, 'opt', opt); -while opt.cleanup==0 +while opt.cleanup==false uiwait(h); opt = getappdata(h, 'opt'); end @@ -473,11 +487,11 @@ function cb_slider(h, eventdata) % update strings set(opt.stringx, 'string', sprintf('%s = %3.3f\n', opt.cfg.xparam, opt.xparam(valx))); set(opt.stringy, 'string', sprintf('%s = %3.3f\n', opt.cfg.yparam, opt.yparam(valy))); - + % update data in mesh set(opt.hs, 'FaceVertexCData', opt.dat(:,valx,valy)); set(opt.hs, 'FaceVertexAlphaData', mask); - + set(opt.vline, 'xdata', [1 1]*opt.xparam(valx)); if isfield(opt, 'hline') set(opt.hline, 'ydata', [1 1]*opt.yparam(valy)); @@ -501,17 +515,17 @@ function cb_slider(h, eventdata) end %set(opt.hy, 'ylim', [min(tmp(:)) max(tmp(:))]); %set(opt.vline, 'ydata', [min(tmp(:)) max(tmp(:))]); - + if isfield(opt, 'dat2') tmp = mean(opt.dat1(opt.vindx,:,valy),1); set(opt.tline, 'ydata', tmp); tmp = mean(opt.dat2(opt.vindx,:,valy),1); set(opt.tline2, 'ydata', tmp); end - + set(opt.hy, 'yaxislocation', 'right'); set(opt.stringz, 'string', sprintf('position = [%2.1f, %2.1f, %2.1f]', opt.pos(opt.vindx,:))); - if isfield(opt, 'parcellation'), + if isfield(opt, 'parcellation') set(opt.stringp, 'string', sprintf('parcel = %s', opt.parcellationlabel{opt.parcellation(opt.vindx)})); end end @@ -550,6 +564,7 @@ function cb_quitbutton(h, eventdata) opt = getappdata(h, 'opt'); opt.cleanup = 1; setappdata(h, 'opt', opt); +uiresume(h); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % SUBFUNCTION @@ -614,17 +629,16 @@ function cb_getposition(h, eventdata) set(opt.slidery, 'value', nearest(opt.yparam, pos(1,2))./numel(opt.yparam)); end elseif strcmp(get(get(h, 'currentaxes'), 'tag'), 'mesh') - % get the current point, which is defined as the intersection through the - % axis-box (in 3D) + % get the current point, which is defined as the intersection through the axis-box (in 3D) pos = get(opt.hx, 'currentpoint'); - + % get the intersection with the mesh [ipos, d] = intersect_line(opt.pos, opt.tri, pos(1,:), pos(2,:)); [md, ix] = min(abs(d)); - + dpos = opt.pos - ipos(ix*ones(size(opt.pos,1),1),:); opt.vindx = nearest(sum(dpos.^2,2),0); - + end setappdata(h, 'opt', opt); cb_slider(h); @@ -635,7 +649,7 @@ function cb_getposition(h, eventdata) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function cb_keyboard(h, eventdata) -if isempty(eventdata) +if (isempty(eventdata) && ft_platform_supports('matlabversion', -Inf, '2014a')) || isa(eventdata, 'matlab.ui.eventdata.ActionData') % determine the key that corresponds to the uicontrol element that was activated key = get(h, 'userdata'); else @@ -658,25 +672,25 @@ function cb_keyboard(h, eventdata) setappdata(h, 'opt', opt); caxis(opt.cfg.zlim); set(opt.hx, 'Clim', opt.cfg.zlim); - + case 'shift+leftarrow' % change colorlim opt.cfg.zlim(1) = opt.cfg.zlim(1)+0.1*abs(opt.cfg.zlim(1)); setappdata(h, 'opt', opt); caxis(opt.cfg.zlim); set(opt.hx, 'Clim', opt.cfg.zlim); - + case 'rightarrow' opt.cfg.zlim(2) = opt.cfg.zlim(2)-0.1*abs(opt.cfg.zlim(2)); setappdata(h, 'opt', opt); caxis(opt.cfg.zlim); set(opt.hx, 'Clim', opt.cfg.zlim); - + case 'shift+rightarrow' opt.cfg.zlim(2) = opt.cfg.zlim(2)+0.1*abs(opt.cfg.zlim(2)); setappdata(h, 'opt', opt); caxis(opt.cfg.zlim); set(opt.hx, 'Clim', opt.cfg.zlim); - + case 'uparrow' % enhance threshold opt.threshold = opt.threshold+0.01.*max(opt.dat(:)); setappdata(h, 'opt', opt); @@ -726,11 +740,11 @@ function cb_keyboard(h, eventdata) end case 'f' if isfield(opt, 'dat2') - if isequalwithequalnans(opt.dat,opt.dat2), + if isequaln(opt.dat,opt.dat2) opt.dat = opt.dat1; set(opt.displaybutton, 'string', 'display: var1'); end - if isequalwithequalnans(opt.dat,opt.dat1), + if isequaln(opt.dat,opt.dat1) opt.dat = opt.dat2; set(opt.displaybutton, 'string', 'display: var2'); end diff --git a/external/fieldtrip/ft_sourceparcellate.m b/external/fieldtrip/ft_sourceparcellate.m index bb184689..3a5e8825 100644 --- a/external/fieldtrip/ft_sourceparcellate.m +++ b/external/fieldtrip/ft_sourceparcellate.m @@ -1,6 +1,7 @@ function parcel = ft_sourceparcellate(cfg, source, parcellation) -% FT_SOURCEPARCELLATE combines the source-reconstruction parameters over the parcels. +% FT_SOURCEPARCELLATE combines the source-reconstruction parameters over the parcels, for +% example by averaging all the values in the anatomically or functionally labeled parcel. % % Use as % output = ft_sourceparcellate(cfg, source, parcellation) @@ -11,14 +12,12 @@ % individual subject. The output is a channel-based representation with the combined (e.g. % averaged) representation of the source parameters per parcel. % -% The configuration "cfg" is a structure that can contain the following -% fields +% The configuration "cfg" is a structure that can contain the following fields % cfg.method = string, method to combine the values, see below (default = 'mean') % cfg.parcellation = string, fieldname that contains the desired parcellation % cfg.parameter = cell-array with strings, fields that should be parcellated (default = 'all') % -% The values within a parcel or parcel-combination can be combined using -% the following methods: +% The values within a parcel or parcel-combination can be combined with different methods: % 'mean' compute the mean % 'median' compute the median (unsupported for fields that are represented in a cell-array) % 'eig' compute the largest eigenvector @@ -53,7 +52,7 @@ ft_nargin = nargin; ft_nargout = nargout; -% do the general setup of the function +% do the general setup of the function ft_defaults ft_preamble init ft_preamble debug @@ -105,8 +104,8 @@ source = ft_checkdata(source, 'datatype', 'source', 'inside', 'logical'); % ensure that the source and the parcellation are anatomically consistent -if ~isequalwithequalnans(source.pos, parcellation.pos) - error('the source positions are not consistent with the parcellation, please use FT_SOURCEINTERPOLATE'); +if ~isequaln(source.pos, parcellation.pos) + ft_error('the source positions are not consistent with the parcellation, please use FT_SOURCEINTERPOLATE'); end if isempty(cfg.parcellation) @@ -114,7 +113,7 @@ fn = fieldnames(parcellation); for i=1:numel(fn) if isfield(parcellation, [fn{i} 'label']) - warning('using "%s" for the parcellation', fn{i}); + ft_warning('using "%s" for the parcellation', fn{i}); cfg.parcellation = fn{i}; break end @@ -122,7 +121,7 @@ end if isempty(cfg.parcellation) - error('you should specify the field containing the parcellation'); + ft_error('you should specify the field containing the parcellation'); end % determine the fields and corresponding dimords to work on @@ -141,7 +140,7 @@ [inside, i1, i2] = intersect(cfg.parameter, fn); [outside ] = setdiff(cfg.parameter, fn); if ~isempty(outside) - warning('\nparameter "%s" cannot be parcellated', outside{:}); + ft_warning('\nparameter "%s" cannot be parcellated', outside{:}); end cfg.parameter = fn(i2); fn = fn(i2); @@ -154,7 +153,7 @@ dimord = dimord(sel); if numel(fn)==0 - error('there are no source parameters that can be parcellated'); + ft_error('there are no source parameters that can be parcellated'); end % get the parcellation and the labels that go with it @@ -176,19 +175,13 @@ end % start preparing the output data structure -parcel = []; +parcel = keepfields(source, {'freq','time','cumtapcnt'}); parcel.label = seglabel; -if isfield(source, 'time') - parcel.time = source.time; -end -if isfield(source, 'freq') - parcel.freq = source.freq; -end for i=1:numel(fn) % parcellate each of the desired parameters dat = source.(fn{i}); - + if strncmp('{pos_pos}', dimord{i}, 9) fprintf('creating %d*%d parcel combinations for parameter %s by taking the %s\n', numel(seglabel), numel(seglabel), fn{i}, cfg.method); tmp = cell(nseg, nseg); @@ -203,20 +196,20 @@ case 'mean' tmp{j1,j2} = cellmean2(dat(seg==j1,seg==j2,:)); case 'median' - error('taking the median from data in a cell-array is not yet implemented'); + tmp{j1,j2} = cellmedian2(dat(seg==j1,seg==j2,:)); case 'min' tmp{j1,j2} = cellmin2(dat(seg==j1,seg==j2,:)); case 'max' tmp{j1,j2} = cellmax2(dat(seg==j1,seg==j2,:)); - % case 'eig' - % tmp{j1,j2} = celleig2(dat(seg==j1,seg==j2,:)); + case 'eig' + tmp{j1,j2} = celleig2(dat(seg==j1,seg==j2,:)); otherwise - error('method %s not implemented for %s', cfg.method, dimord{i}); + ft_error('method %s not implemented for %s', cfg.method, dimord{i}); end % switch end % for j2 end % for j1 ft_progress('close'); - + elseif strncmp('{pos}', dimord{i}, 5) fprintf('creating %d parcels for parameter %s by taking the %s\n', numel(seglabel), fn{i}, cfg.method); tmp = cell(nseg, 1); @@ -227,19 +220,19 @@ case 'mean' tmp{j} = cellmean1(dat(seg==j)); case 'median' - error('taking the median from data in a cell-array is not yet implemented'); + tmp{j} = cellmedian1(dat(seg==j)); case 'min' tmp{j} = cellmin1(dat(seg==j)); case 'max' tmp{j} = cellmax1(dat(seg==j)); - % case 'eig' - % tmp{j} = celleig1(dat(seg==j)); + case 'eig' + tmp{j} = celleig1(dat(seg==j)); otherwise - error('method %s not implemented for %s', cfg.method, dimord{i}); + ft_error('method %s not implemented for %s', cfg.method, dimord{i}); end % switch end % for ft_progress('close'); - + elseif strncmp('pos_pos', dimord{i}, 7) fprintf('creating %d*%d parcel combinations for parameter %s by taking the %s\n', numel(seglabel), numel(seglabel), fn{i}, cfg.method); siz = size(dat); @@ -267,12 +260,12 @@ case 'maxabs' tmp(j1,j2,:) = arraymaxabs2(dat(seg==j1,seg==j2,:)); otherwise - error('method %s not implemented for %s', cfg.method, dimord{i}); + ft_error('method %s not implemented for %s', cfg.method, dimord{i}); end % switch end % for j2 end % for j1 ft_progress('close'); - + elseif strncmp('pos', dimord{i}, 3) fprintf('creating %d parcels for %s by taking the %s\n', numel(seglabel), fn{i}, cfg.method); siz = size(dat); @@ -286,8 +279,8 @@ tmp(j,:) = arraymean1(dat(seg==j,:)); case 'mean_thresholded' cfg.mean = ft_getopt(cfg, 'mean', struct('threshold', [])); - if isempty(cfg.mean.threshold), - error('when cfg.method = ''mean_thresholded'', you should specify a cfg.mean.threshold'); + if isempty(cfg.mean.threshold) + ft_error('when cfg.method = ''mean_thresholded'', you should specify a cfg.mean.threshold'); end if numel(cfg.mean.threshold)==size(dat,1) % assume one threshold per vertex @@ -307,16 +300,16 @@ case 'eig' tmp(j,:) = arrayeig1(dat(seg==j,:)); otherwise - error('method %s not implemented for %s', cfg.method, dimord{i}); + ft_error('method %s not implemented for %s', cfg.method, dimord{i}); end % switch end % for ft_progress('close'); - + else - error('unsupported dimord %s', dimord{i}) - + ft_error('unsupported dimord %s', dimord{i}) + end % if pos, pos_pos, {pos}, etc. - + % update the dimord, use chan rather than pos % this makes it look just like timelock or freq data tok = tokenize(dimord{i}, '_'); @@ -326,11 +319,11 @@ tok(strcmp(tok, 'pos}')) = { 'chan}'}; % replace pos by chan tmpdimord = sprintf('%s_', tok{:}); tmpdimord = tmpdimord(1:end-1); % exclude the last _ - + % store the results in the output structure parcel.(fn{i}) = tmp; parcel.([fn{i} 'dimord']) = tmpdimord; - + % to avoid confusion clear dat tmp tmpdimord j j1 j2 end % for each of the fields that should be parcellated @@ -448,6 +441,15 @@ end y = y/n; +function y = cellmedian1(x) +siz = size(x); +if siz(1)==1 && siz(2)>1 + siz([2 1]) = siz([1 2]); + x = reshape(x, siz); +end +x = cat(1,x{:}); +y = median(x, 1); + function y = cellmin1(x) siz = size(x); if siz(1)==1 && siz(2)>1 @@ -470,20 +472,45 @@ y = max(x{i}, y); end +function y = celleig1(x) +% FIXME this does not work for TFR representations +siz = size(x); +if siz(1)==1 && siz(2)>1 + siz([2 1]) = siz([1 2]); + x = reshape(x, siz); +end +x = cat(1,x{:}); +% [u, s, v] = svds(real(x), 1); % x = u * s * v' +% y = s(1,1) * v(:,1); % retain the largest eigenvector with appropriate scaling + +% this is computationally more efficient and returns a complex-valued output, following a real valued svd +[u, s] = svds(real(x*x'), 1); +y = u(:,1)'*x; + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % SUBFUNCTIONS to compute something over the first two dimensions of a cell array %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function y = cellmean2(x) siz = size(x); -x = reshape(x, [siz(1)*siz(2) siz(3:end) 1]); % simplify it into a single dimension +x = reshape(x, [siz(1)*siz(2) siz(3:end) 1]); % represent the first two as a single dimension y = cellmean1(x); +function y = cellmedian2(x) +siz = size(x); +x = reshape(x, [siz(1)*siz(2) siz(3:end) 1]); % represent the first two as a single dimension +y = cellmedian1(x); + function y = cellmin2(x) siz = size(x); -x = reshape(x, [siz(1)*siz(2) siz(3:end) 1]); % simplify it into a single dimension +x = reshape(x, [siz(1)*siz(2) siz(3:end) 1]); % represent the first two as a single dimension y = cellmin1(x); function y = cellmax2(x) siz = size(x); -x = reshape(x, [siz(1)*siz(2) siz(3:end) 1]); % simplify it into a single dimension +x = reshape(x, [siz(1)*siz(2) siz(3:end) 1]); % represent the first two as a single dimension y = cellmax1(x); + +function y = celleig2(x) +siz = size(x); +x = reshape(x, [siz(1)*siz(2) siz(3:end) 1]); % represent the first two as a single dimension +y = celleig1(x); diff --git a/external/fieldtrip/ft_sourceplot.m b/external/fieldtrip/ft_sourceplot.m index f1a3fc5b..fdb03607 100644 --- a/external/fieldtrip/ft_sourceplot.m +++ b/external/fieldtrip/ft_sourceplot.m @@ -1,25 +1,28 @@ function ft_sourceplot(cfg, functional, anatomical) -% FT_SOURCEPLOT plots functional source reconstruction data on slices or on a -% surface, optionally as an overlay on anatomical MRI data, where statistical data -% can be used to determine the opacity of the mask. Input data comes from -% FT_SOURCEANALYSIS, FT_SOURCEGRANDAVERAGE or statistical values from -% FT_SOURCESTATISTICS. +% FT_SOURCEPLOT plots functional source reconstruction data on slices or on a surface, +% optionally as an overlay on anatomical MRI data, where statistical data can be used to +% determine the opacity of the mask. Input data comes from FT_SOURCEANALYSIS, +% FT_SOURCEGRANDAVERAGE or statistical values from FT_SOURCESTATISTICS. % % Use as -% ft_sourceplot(cfg, data) -% where the input data can contain an anatomical MRI, functional source -% reconstruction results and/or statistical data. If both anatomical and -% functional/statistical data is provided as input, they should be represented or -% interpolated on the same same 3-D grid, e.g. using FT_SOURCEINTERPOLATE. +% ft_sourceplot(cfg, anatomical) +% ft_sourceplot(cfg, functional) +% ft_sourceplot(cfg, functional, anatomical) +% where the input data can contain either anatomical, functional or statistical data, +% or a combination of them. % -% The slice and ortho visualization plot the data in the input data voxel -% arrangement, i.e. the three ortho views are the 1st, 2nd and 3rd dimension of -% the 3-D data matrix, not of the head coordinate system. The specification of the -% coordinate for slice intersection is specified in head coordinates, i.e. -% relative to the fiducials and in mm or cm. If you want the visualisation to be -% consistent with the head coordinate system, you can reslice the data using -% FT_VOLUMERESLICE. +% The input data can be in a 3-D volumetric representation or in a 2-D cortical sheet +% representation. If both anatomical and functional/statistical data is provided as input, +% they should be represented in the same coordinate system or interpolated on the same +% geometrical representation, e.g. using FT_SOURCEINTERPOLATE. +% +% The slice and ortho visualization plot the data in the input data voxel arrangement, i.e. +% the three ortho views are the 1st, 2nd and 3rd dimension of the 3-D data matrix, not of +% the head coordinate system. The specification of the coordinate for slice intersection +% is specified in head coordinates, i.e. relative to anatomical landmarks or fiducials and +% expressed in mm or cm. If you want the visualisation to be consistent with the head +% coordinate system, you can reslice the data using FT_VOLUMERESLICE. See http://bit.ly/1OkDlVF % % The configuration should contain: % cfg.method = 'slice', plots the data on a number of slices in the same plane @@ -27,6 +30,8 @@ function ft_sourceplot(cfg, functional, anatomical) % 'surface', plots the data on a 3D brain surface % 'glassbrain', plots a max-projection through the brain % 'vertex', plots the grid points or vertices scaled according to the functional value +% 'cloud', plot the data as point clouds scaled according to the functional value +% % % cfg.anaparameter = string, field in data with the anatomical data (default = 'anatomy' if present in data) % cfg.funparameter = string, field in data with the functional parameter of interest (default = []) @@ -44,7 +49,8 @@ function ft_sourceplot(cfg, functional, anatomical) % The following parameters can be used in all methods: % cfg.downsample = downsampling for resolution reduction, integer value (default = 1) (orig: from surface) % cfg.atlas = string, filename of atlas to use (default = []) see FT_READ_ATLAS -% for ROI masking (see "masking" below) or in "ortho-plotting" mode (see "ortho-plotting" below) +% for ROI masking (see 'masking' below) or for orthogonal plots (see method='ortho' below) +% cfg.visible = string, 'on' or 'off', whether figure will be visible (default = 'on') % % The following parameters can be used for the functional data: % cfg.funcolormap = colormap for functional data, see COLORMAP (default = 'auto') @@ -62,7 +68,20 @@ function ft_sourceplot(cfg, functional, anatomical) % all negative: 'minzero', both possitive and negative: 'maxabs' % cfg.colorbar = 'yes' or 'no' (default = 'yes') % +% The 'ortho' method can also plot time and/or frequency, the other methods can not. +% If your functional data has a time and/or frequency dimension, you can use +% cfg.latency = scalar or string, can be 'all', 'prestim', 'poststim', or [beg end], specify time range in seconds +% cfg.avgovertime = string, can be 'yes' or 'no' (default = 'no') +% cfg.frequency = scalar or string, can be 'all', or [beg end], specify frequency range in Hz +% cfg.avgoverfreq = string, can be 'yes' or 'no' (default = 'no') +% % The following parameters can be used for the masking data: +% cfg.maskstyle = 'opacity', or 'colormix'. If 'opacity', low-level +% graphics opacity masking is applied, if +% 'colormix', the color data is explicitly +% expressed as a single RGB value, incorporating +% the opacitymask. Yields faster and more robust +% rendering in general. % cfg.opacitymap = opacitymap for mask data, see ALPHAMAP (default = 'auto') % 'auto', depends structure maskparameter, or on opacitylim % - maskparameter: only positive values, or opacitylim:'zeromax' -> 'rampup' @@ -76,11 +95,17 @@ function ft_sourceplot(cfg, functional, anatomical) % 'zeromax', from 0 to max(abs(maskparameter)) % 'minzero', from min(abs(maskparameter)) to 0 % 'auto', if maskparameter values are all positive: 'zeromax', -% all negative: 'minzero', both possitive and negative: 'maxabs' +% all negative: 'minzero', both positive and negative: 'maxabs' % cfg.roi = string or cell of strings, region(s) of interest from anatomical atlas (see cfg.atlas above) % everything is masked except for ROI % -% The following parameters apply for ortho-plotting +% When cfg.method='ortho', three orthogonal slices will be rendered. You can click in any +% of the slices to update the display in the other two. You can also use the arrow keys on +% your keyboard to navigate in one-voxel steps. Note that the slices are along the first, +% second and third voxel dimension, which do not neccessarily correspond to the axes of the +% head coordinate system. See http://bit.ly/1OkDlVF +% +% The following parameters apply when cfg.method='ortho' % cfg.location = location of cut, (default = 'auto') % 'auto', 'center' if only anatomy, 'max' if functional data % 'min' and 'max' position of min/max funparameter @@ -92,9 +117,12 @@ function ft_sourceplot(cfg, functional, anatomical) % cfg.crosshair = 'yes' or 'no' (default = 'yes') % cfg.axis = 'on' or 'off' (default = 'on') % cfg.queryrange = number, in atlas voxels (default 3) +% cfg.clim = lower and upper anatomical MRI limits (default = [0 1]) % +% When cfg.method='slice', a NxM montage with a large number of slices will be rendered. +% All slices are evenly spaced and along the same dimension. % -% The following parameters apply for slice-plotting +% The following parameters apply for cfg.method='slice' % cfg.nslices = number of slices, (default = 20) % cfg.slicerange = range of slices in data, (default = 'auto') % 'auto', full range of data @@ -102,15 +130,14 @@ function ft_sourceplot(cfg, functional, anatomical) % cfg.slicedim = dimension to slice 1 (x-axis) 2(y-axis) 3(z-axis) (default = 3) % cfg.title = string, title of the figure window % -% When cfg.method = 'surface', the functional data will be rendered onto a cortical -% mesh (can be an inflated mesh). If the input source data contains a tri-field (i.e. -% a description of a mesh), no interpolation is needed. If the input source data does -% not contain a tri-field, an interpolation is performed onto a specified surface. -% Note that the coordinate system in which the surface is defined should be the same -% as the coordinate system that is represented in source.pos. +% When cfg.method='surface', the functional data will be rendered onto a cortical mesh +% (can be an inflated mesh). If the input source data contains a tri-field (i.e. a +% description of a mesh), no interpolation is needed. If the input source data does not +% contain a tri-field, an interpolation is performed onto a specified surface. Note that +% the coordinate system in which the surface is defined should be the same as the coordinate +% system that is represented in the pos-field. % -% The following parameters apply to surface-plotting when an interpolation -% is required +% The following parameters apply to cfg.method='surface' when an interpolation is required % cfg.surffile = string, file that contains the surface (default = 'surface_white_both.mat') % 'surface_white_both.mat' contains a triangulation that corresponds with the % SPM anatomical template in MNI coordinates @@ -129,11 +156,35 @@ function ft_sourceplot(cfg, functional, anatomical) % included in the sphere projection methods, expressed in mm % cfg.distmat = precomputed distance matrix (default = []) % -% The following parameters apply to surface-plotting independent of whether -% an interpolation is required +% The following parameters apply to cfg.method='surface' irrespective of whether an interpolation is required % cfg.camlight = 'yes' or 'no' (default = 'yes') % cfg.renderer = 'painters', 'zbuffer', ' opengl' or 'none' (default = 'opengl') % note that when using opacity the OpenGL renderer is required. +% cfg.facecolor = [r g b] values or string, for example 'brain', 'cortex', 'skin', 'black', 'red', 'r', +% or an Nx3 or Nx1 array where N is the number of faces +% cfg.vertexcolor = [r g b] values or string, for example 'brain', 'cortex', 'skin', 'black', 'red', 'r', +% or an Nx3 or Nx1 array where N is the number of vertices +% cfg.edgecolor = [r g b] values or string, for example 'brain', 'cortex', 'skin', 'black', 'red', 'r' +% +% When cfg.method = 'cloud', the functional data will be rendered as +% point clouds around the sensor positions. These point clouds can either +% be viewed in 3D or as 2D slices. The 'anatomical' input may also consist of +% a single or multiple triangulated surface mesh(es) in an Nx1 cell-array +% to be plotted with the interpolated functional data (see FT_PLOT_CLOUD) +% +% The following parameters apply to cfg.method='cloud' +% cfg.radius = scalar, maximum radius of cloud (default = 4) +% cfg.colorgrad = 'white' or a scalar (e.g. 1), degree to which color of points in cloud +% changes from its center +% cfg.slice = requires 'anatomical' as input (default = 'none') +% '2d', plots 2D slices through the cloud with an outline of the mesh +% '3d', draws an outline around the mesh at a particular slice +% cfg.ori = 'x', 'y', or 'z', specifies the orthogonal plane which will be plotted (default = 'y') +% cfg.slicepos = 'auto' or Nx1 vector specifying the position of the +% slice plane along the orientation axis (default = 'auto': chooses slice(s) with +% the most data) +% cfg.nslices = scalar, number of slices to plot if 'slicepos' = 'auto (default = 1) +% cfg.minspace = scalar, minimum spacing between slices if nslices>1 (default = 1) % % To facilitate data-handling and distributed computing you can use % cfg.inputfile = ... @@ -141,8 +192,8 @@ function ft_sourceplot(cfg, functional, anatomical) % disk. This mat files should contain only a single variable corresponding to the % input structure. % -% See also FT_SOURCEMOVIE, FT_SOURCEANALYSIS, FT_SOURCEGRANDAVERAGE, -% FT_SOURCESTATISTICS, FT_VOLUMELOOKUP, FT_READ_ATLAS, FT_READ_MRI +% See also FT_SOURCEMOVIE, FT_SOURCEANALYSIS, FT_SOURCEGRANDAVERAGE, FT_SOURCESTATISTICS, +% FT_VOLUMELOOKUP, FT_READ_ATLAS, FT_READ_MRI % TODO have to be built in: % cfg.marker = [Nx3] array defining N marker positions to display (orig: from sliceinterp) @@ -195,7 +246,7 @@ function ft_sourceplot(cfg, functional, anatomical) % this is not supported any more as of 26/10/2011 if ischar(functional) - error('please use cfg.inputfile instead of specifying the input variable as a sting'); + ft_error('please use cfg.inputfile instead of specifying the input variable as a sting'); end % ensure that old and unsupported options are not being relied on by the end-user's script @@ -207,23 +258,24 @@ function ft_sourceplot(cfg, functional, anatomical) cfg = ft_checkconfig(cfg, 'renamedval', {'maskparameter', 'avg.mom', 'mom'}); cfg = ft_checkconfig(cfg, 'renamedval', {'location', 'interactive', 'auto'}); % instead of specifying cfg.coordsys, the user should specify the coordsys in the functional data -cfg = ft_checkconfig(cfg, 'forbidden', {'units', 'inputcoordsys', 'coordinates'}); +cfg = ft_checkconfig(cfg, 'forbidden', {'units', 'inputcoordsys', 'coordinates', 'TTlookup'}); cfg = ft_checkconfig(cfg, 'deprecated', 'coordsys'); % see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2837 cfg = ft_checkconfig(cfg, 'renamed', {'viewdim', 'axisratio'}); if isfield(cfg, 'atlas') && ~isempty(cfg.atlas) % the atlas lookup requires the specification of the coordsys - functional = ft_checkdata(functional, 'datatype', {'volume', 'source'}, 'feedback', 'yes', 'hasunit', 'yes', 'hascoordsys', 'yes'); + functional = ft_checkdata(functional, 'datatype', {'source', 'volume'}, 'feedback', 'yes', 'hasunit', 'yes', 'hascoordsys', 'yes'); else % check if the input functional is valid for this function, a coordsys is not directly needed - functional = ft_checkdata(functional, 'datatype', {'volume', 'source'}, 'feedback', 'yes', 'hasunit', 'yes'); + functional = ft_checkdata(functional, 'datatype', {'source', 'volume'}, 'feedback', 'yes', 'hasunit', 'yes'); end % set the defaults for all methods cfg.method = ft_getopt(cfg, 'method', 'ortho'); cfg.funparameter = ft_getopt(cfg, 'funparameter', []); cfg.maskparameter = ft_getopt(cfg, 'maskparameter', []); +cfg.maskstyle = ft_getopt(cfg, 'maskstyle', 'opacity'); cfg.downsample = ft_getopt(cfg, 'downsample', 1); cfg.title = ft_getopt(cfg, 'title', ''); cfg.atlas = ft_getopt(cfg, 'atlas', []); @@ -234,6 +286,8 @@ function ft_sourceplot(cfg, functional, anatomical) cfg.colorbar = ft_getopt(cfg, 'colorbar', 'yes'); cfg.voxelratio = ft_getopt(cfg, 'voxelratio', 'data'); % display size of the voxel, 'data' or 'square' cfg.axisratio = ft_getopt(cfg, 'axisratio', 'data'); % size of the axes of the three orthoplots, 'square', 'voxel', or 'data' +cfg.visible = ft_getopt(cfg, 'visible', 'on'); +cfg.clim = ft_getopt(cfg, 'clim', [0 1]); % this is used to scale the orthoplot if ~isfield(cfg, 'anaparameter') if isfield(functional, 'anatomy') @@ -251,10 +305,7 @@ function ft_sourceplot(cfg, functional, anatomical) cfg.opacitymap = ft_getopt(cfg, 'opacitymap', 'auto'); cfg.opacitylim = ft_getopt(cfg, 'opacitylim', 'auto'); cfg.roi = ft_getopt(cfg, 'roi', []); - -if isfield(cfg, 'TTlookup'), - error('TTlookup is old; now specify cfg.atlas, see help!'); -end +cfg.maskstyle = ft_getopt(cfg, 'maskstyle', 'opacity'); % select the functional and the mask parameter cfg.funparameter = parameterselection(cfg.funparameter, functional); @@ -263,19 +314,26 @@ function ft_sourceplot(cfg, functional, anatomical) try, cfg.funparameter = cfg.funparameter{1}; end try, cfg.maskparameter = cfg.maskparameter{1}; end +if isfield(functional, 'time') || isfield(functional, 'freq') + % make a selection of the time and/or frequency dimension + tmpcfg = keepfields(cfg, {'frequency', 'avgoverfreq', 'keepfreqdim', 'latency', 'avgovertime', 'keeptimedim', 'showcallinfo'}); + functional = ft_selectdata(tmpcfg, functional); + % restore the provenance information + [cfg, functional] = rollback_provenance(cfg, functional); +end % the data can be passed as input argument or can be read from disk hasanatomical = exist('anatomical', 'var'); -if hasanatomical +if hasanatomical && ~strcmp(cfg.method, 'cloud') % cloud method should be able to take multiple surfaces and does not require interpolation % interpolate on the fly, this also does the downsampling if requested - tmpcfg = keepfields(cfg, {'downsample', 'interpmethod'}); + tmpcfg = keepfields(cfg, {'downsample', 'interpmethod', 'sphereradius', 'showcallinfo'}); tmpcfg.parameter = cfg.funparameter; functional = ft_sourceinterpolate(tmpcfg, functional, anatomical); [cfg, functional] = rollback_provenance(cfg, functional); elseif ~hasanatomical && cfg.downsample~=1 % optionally downsample the functional volume - tmpcfg = keepfields(cfg, {'downsample'}); + tmpcfg = keepfields(cfg, {'downsample', 'showcallinfo'}); tmpcfg.parameter = {cfg.funparameter, cfg.maskparameter, cfg.anaparameter}; functional = ft_volumedownsample(tmpcfg, functional); [cfg, functional] = rollback_provenance(cfg, functional); @@ -303,7 +361,6 @@ function ft_sourceplot(cfg, functional, anatomical) %% get the elements that will be plotted - hasatlas = ~isempty(cfg.atlas); if hasatlas if ischar(cfg.atlas) @@ -314,12 +371,24 @@ function ft_sourceplot(cfg, functional, anatomical) else atlas = cfg.atlas; end + % ensure that the atlas is formatted properly + atlas = ft_checkdata(atlas, 'hasunit', isfield(functional, 'unit'), 'hascoordsys', isfield(functional, 'coordsys')); + if isfield(functional, 'unit') + % ensure that the units are consistent, convert the units if required + atlas = ft_convert_units(atlas, functional.unit); + end + if isfield(functional, 'coordsys') + % ensure that the coordinate systems match + functional = fixcoordsys(functional); + atlas = fixcoordsys(atlas); + assert(isequal(functional.coordsys, atlas.coordsys), 'coordinate systems do not match'); + end end hasroi = ~isempty(cfg.roi); if hasroi if ~hasatlas - error('specify cfg.atlas which specifies cfg.roi') + ft_error('specify cfg.atlas which specifies cfg.roi') else % get the mask tmpcfg = []; @@ -347,10 +416,10 @@ function ft_sourceplot(cfg, functional, anatomical) hasfun = isfield(functional, cfg.funparameter); if hasfun fun = getsubfield(functional, cfg.funparameter); - + dimord = getdimord(functional, cfg.funparameter); dimtok = tokenize(dimord, '_'); - + % replace the cell-array functional with a normal array if strcmp(dimtok{1}, '{pos}') tmpdim = getdimsiz(functional, cfg.funparameter); @@ -364,13 +433,13 @@ function ft_sourceplot(cfg, functional, anatomical) dimtok{1} = 'pos'; % update the description of the dimensions dimord([1 5]) = []; % remove the { and } end - + % ensure that the functional data is real if ~isreal(fun) - warning('functional data is complex, taking absolute value'); + ft_warning('functional data is complex, taking absolute value'); fun = abs(fun); end - + if strcmp(dimord, 'pos_rgb') % treat functional data as rgb values if any(fun(:)>1 | fun(:)<0) @@ -387,11 +456,11 @@ function ft_sourceplot(cfg, functional, anatomical) qi = 1; hasfreq = 0; hastime = 0; - + doimage = 1; fcolmin = 0; fcolmax = 1; - + else % determine scaling min and max (fcolmin fcolmax) and funcolormap if ~isa(fun, 'logical') @@ -416,17 +485,17 @@ function ft_sourceplot(cfg, functional, anatomical) if isequal(cfg.funcolorlim, 'maxabs') fcolmin = -max(abs([funmin,funmax])); fcolmax = max(abs([funmin,funmax])); - if isequal(cfg.funcolormap, 'auto'); cfg.funcolormap = 'default'; end; + if isequal(cfg.funcolormap, 'auto'); cfg.funcolormap = 'default'; end elseif isequal(cfg.funcolorlim, 'zeromax') fcolmin = 0; fcolmax = funmax; - if isequal(cfg.funcolormap, 'auto'); cfg.funcolormap = 'hot'; end; + if isequal(cfg.funcolormap, 'auto'); cfg.funcolormap = 'hot'; end elseif isequal(cfg.funcolorlim, 'minzero') fcolmin = funmin; fcolmax = 0; - if isequal(cfg.funcolormap, 'auto'); cfg.funcolormap = 'cool'; end; + if isequal(cfg.funcolormap, 'auto'); cfg.funcolormap = 'cool'; end else - error('do not understand cfg.funcolorlim'); + ft_error('do not understand cfg.funcolorlim'); end else % limits are numeric @@ -446,28 +515,29 @@ function ft_sourceplot(cfg, functional, anatomical) end end % if ischar clear funmin funmax - + % what if fun is 4D? if ndims(fun)>3 || prod(dim)==size(fun,1) - if strcmp(dimord, 'pos_freq_time') + if strcmp(dimord, 'pos_freq_time') || strcmp(dimord, 'dim1_dim2_dim3_freq_time') % functional contains time-frequency representation qi = [1 1]; hasfreq = numel(functional.freq)>1; hastime = numel(functional.time)>1; fun = reshape(fun, [dim numel(functional.freq) numel(functional.time)]); - elseif strcmp(dimord, 'pos_time') + elseif strcmp(dimord, 'pos_time') || strcmp(dimord, 'dim1_dim2_dim3_time') % functional contains evoked field qi = 1; hasfreq = 0; hastime = numel(functional.time)>1; fun = reshape(fun, [dim numel(functional.time)]); - elseif strcmp(dimord, 'pos_freq') + elseif strcmp(dimord, 'pos_freq') || strcmp(dimord, 'dim1_dim2_dim3_freq') % functional contains frequency spectra qi = 1; hasfreq = numel(functional.freq)>1; hastime = 0; fun = reshape(fun, [dim numel(functional.freq)]); else + % functional contains scalar value for each position qi = 1; hasfreq = 0; hastime = 0; @@ -479,10 +549,10 @@ function ft_sourceplot(cfg, functional, anatomical) hasfreq = 0; hastime = 0; end - + doimage = 0; end % if dimord has rgb or something else - + else % there is no functional data qi = 1; @@ -496,7 +566,7 @@ function ft_sourceplot(cfg, functional, anatomical) hasmsk = issubfield(functional, cfg.maskparameter); if hasmsk if ~hasfun - error('you can not have a mask without functional data') + ft_error('you can not have a mask without functional data') else msk = getsubfield(functional, cfg.maskparameter); if islogical(msk) % otherwise sign() not posible @@ -516,7 +586,7 @@ function ft_sourceplot(cfg, functional, anatomical) else msk = reshape(msk, dim); end - + % determine scaling and opacitymap mskmin = min(msk(:)); mskmax = max(msk(:)); @@ -541,17 +611,17 @@ function ft_sourceplot(cfg, functional, anatomical) case 'zeromax' opacmin = 0; opacmax = mskmax; - if isequal(cfg.opacitymap, 'auto'), cfg.opacitymap = 'rampup'; end; + if isequal(cfg.opacitymap, 'auto'), cfg.opacitymap = 'rampup'; end case 'minzero' opacmin = mskmin; opacmax = 0; - if isequal(cfg.opacitymap, 'auto'), cfg.opacitymap = 'rampdown'; end; + if isequal(cfg.opacitymap, 'auto'), cfg.opacitymap = 'rampdown'; end case 'maxabs' opacmin = -max(abs([mskmin, mskmax])); opacmax = max(abs([mskmin, mskmax])); - if isequal(cfg.opacitymap, 'auto'), cfg.opacitymap = 'vdown'; end; + if isequal(cfg.opacitymap, 'auto'), cfg.opacitymap = 'vdown'; end otherwise - error('incorrect specification of cfg.opacitylim'); + ft_error('incorrect specification of cfg.opacitylim'); end % switch opacitylim else % limits are numeric @@ -604,14 +674,13 @@ function ft_sourceplot(cfg, functional, anatomical) opacmin = []; opacmax = []; % has to be defined elseif hasroi - error('you can not have a roi without functional data') + ft_error('you can not have a roi without functional data') end %% give some feedback - if ~hasfun && ~hasana % this seems to be a problem that people often have due to incorrect specification of the cfg - error('no anatomy is present and no functional data is selected, please check your cfg.funparameter'); + ft_error('no anatomy is present and no functional data is selected, please check your cfg.funparameter'); end if ~hasana fprintf('not plotting anatomy\n'); @@ -629,17 +698,15 @@ function ft_sourceplot(cfg, functional, anatomical) fprintf('not using a region-of-interest\n'); end - %% start building the figure -h = figure; +h = figure('visible', cfg.visible); set(h, 'color', [1 1 1]); -set(h, 'visible', 'on'); set(h, 'renderer', cfg.renderer); if ~isempty(cfg.title) title(cfg.title); end -%%% set color and opacity mapping for this figure +%% set color and opacity mapping for this figure if hasfun colormap(cfg.funcolormap); cfg.funcolormap = colormap; @@ -655,21 +722,22 @@ function ft_sourceplot(cfg, functional, anatomical) switch cfg.method case 'slice' + assert(~hastime, 'method "%s" does not support time', cfg.method); + assert(~hasfreq, 'method "%s" does not support freq', cfg.method); + % set the defaults for method=slice cfg.nslices = ft_getopt(cfg, 'nslices', 20); cfg.slicedim = ft_getopt(cfg, 'slicedim', 3); cfg.slicerange = ft_getopt(cfg, 'slicerange', 'auto'); - - - + % white BG => mskana - + % TODO: HERE THE FUNCTION THAT MAKES TO SLICE DIMENSION ALWAYS THE THIRD DIMENSION, AND ALSO KEEP TRANSFORMATION MATRIX UP TO DATE % zoiets - % if hasana; ana = shiftdim(ana,cfg.slicedim-1); end; - % if hasfun; fun = shiftdim(fun,cfg.slicedim-1); end; - % if hasmsk; msk = shiftdim(msk,cfg.slicedim-1); end; - + % if hasana; ana = shiftdim(ana,cfg.slicedim-1); end + % if hasfun; fun = shiftdim(fun,cfg.slicedim-1); end + % if hasmsk; msk = shiftdim(msk,cfg.slicedim-1); end + % ADDED BY JM: allow for slicedim different than 3 switch cfg.slicedim case 1 @@ -687,7 +755,7 @@ function ft_sourceplot(cfg, functional, anatomical) otherwise % nothing needed end - + %%%%% select slices if ~ischar(cfg.slicerange) ind_fslice = cfg.slicerange(1); @@ -695,10 +763,10 @@ function ft_sourceplot(cfg, functional, anatomical) elseif isequal(cfg.slicerange, 'auto') if hasfun % default if isfield(functional, 'inside') - + insideMask = false(size(fun)); insideMask(functional.inside) = true; - + ind_fslice = min(find(max(max(insideMask,[],1),[],2))); ind_lslice = max(find(max(max(insideMask,[],1),[],2))); else @@ -709,49 +777,49 @@ function ft_sourceplot(cfg, functional, anatomical) ind_fslice = min(find(max(max(ana,[],1),[],2))); ind_lslice = max(find(max(max(ana,[],1),[],2))); else - error('no functional parameter and no anatomical parameter, can not plot'); + ft_error('no functional parameter and no anatomical parameter, can not plot'); end else - error('do not understand cfg.slicerange'); + ft_error('do not understand cfg.slicerange'); end ind_allslice = linspace(ind_fslice,ind_lslice,cfg.nslices); ind_allslice = round(ind_allslice); % make new ana, fun, msk, mskana with only the slices that will be plotted (slice dim is always third dimension) - if hasana; new_ana = ana(:,:,ind_allslice); clear ana; ana=new_ana; clear new_ana; end; - if hasfun; new_fun = fun(:,:,ind_allslice); clear fun; fun=new_fun; clear new_fun; end; - if hasmsk; new_msk = msk(:,:,ind_allslice); clear msk; msk=new_msk; clear new_msk; end; - % if hasmskana; new_mskana = mskana(:,:,ind_allslice); clear mskana; mskana=new_mskana; clear new_mskana; end; - + if hasana; new_ana = ana(:,:,ind_allslice); clear ana; ana=new_ana; clear new_ana; end + if hasfun; new_fun = fun(:,:,ind_allslice); clear fun; fun=new_fun; clear new_fun; end + if hasmsk; new_msk = msk(:,:,ind_allslice); clear msk; msk=new_msk; clear new_msk; end + % if hasmskana; new_mskana = mskana(:,:,ind_allslice); clear mskana; mskana=new_mskana; clear new_mskana; end + % update the dimensions of the volume - if hasana; dim=size(ana); else dim=size(fun); end; - + if hasana; dim=size(ana); else dim=size(fun); end + %%%%% make a "quilt", that contain all slices on 2D patched sheet % Number of patches along sides of Quilt (M and N) % Size (in voxels) of side of patches of Quilt (m and n) - + % take care of a potential singleton 3rd dimension if numel(dim)<3 dim(end+1:3) = 1; end - + %if cfg.slicedim~=3 - % error('only supported for slicedim=3'); + % ft_error('only supported for slicedim=3'); %end - - + + m = dim(1); n = dim(2); M = ceil(sqrt(dim(3))); N = ceil(sqrt(dim(3))); num_patch = N*M; - + num_slice = (dim(cfg.slicedim)); num_empt = num_patch-num_slice; % put empty slides on ana, fun, msk, mskana to fill Quilt up - if hasana; ana(:,:,end+1:num_patch)=0; end; - if hasfun; fun(:,:,end+1:num_patch)=0; end; - if hasmsk; msk(:,:,end+1:num_patch)=0; end; - % if hasmskana; mskana(:,:,end:num_patch)=0; end; + if hasana; ana(:,:,end+1:num_patch)=0; end + if hasfun; fun(:,:,end+1:num_patch)=0; end + if hasmsk; msk(:,:,end+1:num_patch)=0; end + % if hasmskana; mskana(:,:,end:num_patch)=0; end % put the slices in the quilt for iSlice = 1:num_slice xbeg = floor((iSlice-1)./M); @@ -770,16 +838,16 @@ function ft_sourceplot(cfg, functional, anatomical) % end end % make vols and scales, containes volumes to be plotted (fun, ana, msk), added by ingnie - if hasana; vols2D{1} = quilt_ana; scales{1} = []; end; % needed when only plotting ana - if hasfun; vols2D{2} = quilt_fun; scales{2} = [fcolmin fcolmax]; end; - if hasmsk; vols2D{3} = quilt_msk; scales{3} = [opacmin opacmax]; end; - + if hasana; vols2D{1} = quilt_ana; scales{1} = []; end % needed when only plotting ana + if hasfun; vols2D{2} = quilt_fun; scales{2} = [fcolmin fcolmax]; end + if hasmsk; vols2D{3} = quilt_msk; scales{3} = [opacmin opacmax]; end + % the transpose is needed for displaying the matrix using the MATLAB image() function - if hasana; ana = vols2D{1}'; end; - if hasfun && ~doimage; fun = vols2D{2}'; end; - if hasfun && doimage; fun = permute(vols2D{2},[2 1 3]); end; - if hasmsk; msk = vols2D{3}'; end; - + if hasana; ana = vols2D{1}'; end + if hasfun && ~doimage; fun = vols2D{2}'; end + if hasfun && doimage; fun = permute(vols2D{2},[2 1 3]); end + if hasmsk; msk = vols2D{3}'; end + if hasana % scale anatomy between 0 and 1 fprintf('scaling anatomy\n'); @@ -792,9 +860,9 @@ function ft_sourceplot(cfg, functional, anatomical) ha = imagesc(ana); end hold on - + if hasfun - + if doimage hf = image(fun); else @@ -813,25 +881,25 @@ function ft_sourceplot(cfg, functional, anatomical) elseif hasana set(hf, 'AlphaData', 0.5) end - + end end - + axis equal axis tight axis xy axis off - + if istrue(cfg.colorbar) if hasfun % use a normal MATLAB coorbar hc = colorbar; set(hc, 'YLim', [fcolmin fcolmax]); else - warning('no colorbar possible without functional data') + ft_warning('no colorbar possible without functional data') end end - + case 'ortho' % set the defaults for method=ortho cfg.location = ft_getopt(cfg, 'location', 'auto'); @@ -839,7 +907,7 @@ function ft_sourceplot(cfg, functional, anatomical) cfg.crosshair = ft_getopt(cfg, 'crosshair', 'yes'); cfg.axis = ft_getopt(cfg, 'axis', 'on'); cfg.queryrange = ft_getopt(cfg, 'queryrange', 3); - + if ~ischar(cfg.location) if strcmp(cfg.locationcoordinates, 'head') % convert the headcoordinates location into voxel coordinates @@ -849,38 +917,38 @@ function ft_sourceplot(cfg, functional, anatomical) % the location is already in voxel coordinates loc = round(cfg.location(1:3)); else - error('you should specify cfg.locationcoordinates'); + ft_error('you should specify cfg.locationcoordinates'); end else if isequal(cfg.location, 'auto') if hasfun - if isequal(cfg.funcolorlim, 'maxabs'); + if isequal(cfg.funcolorlim, 'maxabs') loc = 'max'; - elseif isequal(cfg.funcolorlim, 'zeromax'); + elseif isequal(cfg.funcolorlim, 'zeromax') loc = 'max'; - elseif isequal(cfg.funcolorlim, 'minzero'); + elseif isequal(cfg.funcolorlim, 'minzero') loc = 'min'; else % if numerical loc = 'max'; end else loc = 'center'; - end; + end else loc = cfg.location; end end - + % determine the initial intersection of the cursor (xi yi zi) if ischar(loc) && strcmp(loc, 'min') if isempty(cfg.funparameter) - error('cfg.location is min, but no functional parameter specified'); + ft_error('cfg.location is min, but no functional parameter specified'); end [dummy, minindx] = min(fun(:)); [xi, yi, zi] = ind2sub(dim, minindx); elseif ischar(loc) && strcmp(loc, 'max') if isempty(cfg.funparameter) - error('cfg.location is max, but no functional parameter specified'); + ft_error('cfg.location is max, but no functional parameter specified'); end [dummy, maxindx] = max(fun(:)); [xi, yi, zi] = ind2sub(dim, maxindx); @@ -894,11 +962,11 @@ function ft_sourceplot(cfg, functional, anatomical) yi = nearest(1:dim(2), loc(2)); zi = nearest(1:dim(3), loc(3)); end - + xi = round(xi); xi = max(xi, 1); xi = min(xi, dim(1)); yi = round(yi); yi = max(yi, 1); yi = min(yi, dim(2)); zi = round(zi); zi = max(zi, 1); zi = min(zi, dim(3)); - + % axes settings if strcmp(cfg.axisratio, 'voxel') % determine the number of voxels to be plotted along each axis @@ -917,7 +985,7 @@ function ft_sourceplot(cfg, functional, anatomical) axlen2 = 1; axlen3 = 1; end - + % this is the size reserved for subplot h1, h2 and h3 h1size(1) = 0.82*axlen1/(axlen1 + axlen2); h1size(2) = 0.82*axlen3/(axlen2 + axlen3); @@ -925,7 +993,7 @@ function ft_sourceplot(cfg, functional, anatomical) h2size(2) = 0.82*axlen3/(axlen2 + axlen3); h3size(1) = 0.82*axlen1/(axlen1 + axlen2); h3size(2) = 0.82*axlen2/(axlen2 + axlen3); - + if strcmp(cfg.voxelratio, 'square') voxlen1 = 1; voxlen2 = 1; @@ -937,31 +1005,31 @@ function ft_sourceplot(cfg, functional, anatomical) voxlen2 = norm(cp_head(4,:)-cp_head(1,:))/norm(cp_voxel(4,:)-cp_voxel(1,:)); voxlen3 = norm(cp_head(5,:)-cp_head(1,:))/norm(cp_voxel(5,:)-cp_voxel(1,:)); end - + %% the figure is interactive, add callbacks set(h, 'windowbuttondownfcn', @cb_buttonpress); set(h, 'windowbuttonupfcn', @cb_buttonrelease); set(h, 'windowkeypressfcn', @cb_keyboard); set(h, 'CloseRequestFcn', @cb_cleanup); - + % ensure that this is done in interactive mode set(h, 'renderer', cfg.renderer); - + %% create figure handles - + % axis handles will hold the anatomical functional if present, along with labels etc. h1 = axes('position',[0.06 0.06+0.06+h3size(2) h1size(1) h1size(2)]); h2 = axes('position',[0.06+0.06+h1size(1) 0.06+0.06+h3size(2) h2size(1) h2size(2)]); h3 = axes('position',[0.06 0.06 h3size(1) h3size(2)]); - + set(h1, 'Tag', 'ik', 'Visible', cfg.axis, 'XAxisLocation', 'top'); set(h2, 'Tag', 'jk', 'Visible', cfg.axis, 'YAxisLocation', 'right'); % after rotating in ft_plot_ortho this becomes top set(h3, 'Tag', 'ij', 'Visible', cfg.axis); - + set(h1, 'DataAspectRatio',1./[voxlen1 voxlen2 voxlen3]); set(h2, 'DataAspectRatio',1./[voxlen1 voxlen2 voxlen3]); set(h3, 'DataAspectRatio',1./[voxlen1 voxlen2 voxlen3]); - + % create structure to be passed to gui opt = []; opt.dim = dim; @@ -1001,23 +1069,26 @@ function ft_sourceplot(cfg, functional, anatomical) opt.fcolmax = fcolmax; opt.opacmin = opacmin; opt.opacmax = opacmax; - opt.clim = []; % contrast limits for the anatomy, see ft_volumenormalise + opt.clim = cfg.clim; % contrast limits for the anatomy, see ft_volumenormalise opt.colorbar = cfg.colorbar; opt.queryrange = cfg.queryrange; opt.funcolormap = cfg.funcolormap; opt.crosshair = istrue(cfg.crosshair); - + %% do the actual plotting setappdata(h, 'opt', opt); cb_redraw(h); - + fprintf('\n'); fprintf('click left mouse button to reposition the cursor\n'); fprintf('click and hold right mouse button to update the position while moving the mouse\n'); fprintf('use the arrowkeys to navigate in the current axis\n'); - - + + case 'surface' + assert(~hastime, 'method "%s" does not support time', cfg.method); + assert(~hasfreq, 'method "%s" does not support freq', cfg.method); + % set the defaults for method=surface cfg.downsample = ft_getopt(cfg, 'downsample', 1); cfg.surfdownsample = ft_getopt(cfg, 'surfdownsample', 1); @@ -1031,7 +1102,10 @@ function ft_sourceplot(cfg, functional, anatomical) cfg.projmethod = ft_getopt(cfg, 'projmethod', 'nearest'); cfg.distmat = ft_getopt(cfg, 'distmat', []); cfg.camlight = ft_getopt(cfg, 'camlight', 'yes'); - + cfg.facecolor = ft_getopt(cfg, 'facecolor', []); + cfg.vertexcolor = ft_getopt(cfg, 'vertexcolor', 'curv'); % curvature-dependent mix of cortex_light and cortex_dark + cfg.edgecolor = ft_getopt(cfg, 'edgecolor', 'none'); + % determine whether the source functional already contains a triangulation interpolate2surf = 0; if ~isUnstructuredFun @@ -1046,23 +1120,34 @@ function ft_sourceplot(cfg, functional, anatomical) functional.transform = pos2transform(functional.pos); interpolate2surf = 1; end - - if interpolate2surf, + + if interpolate2surf % deal with the interpolation % FIXME this should be dealt with by ft_sourceinterpolate - + % read the triangulated cortical surface from file surf = ft_read_headshape(cfg.surffile); - - if isfield(surf, 'transform'), - % compute the surface vertices in head coordinates + if isfield(surf, 'transform') + % compute the vertex positions in head coordinates surf.pos = ft_warp_apply(surf.transform, surf.pos); end - + % ensure that the surface is formatted properly + surf = ft_checkdata(surf, 'hasunit', isfield(functional, 'unit'), 'hascoordsys', isfield(functional, 'coordsys')); + if isfield(functional, 'unit') + % ensure that the units are consistent, convert the units if required + surf = ft_convert_units(surf, functional.unit); + end + if isfield(functional, 'coordsys') + % ensure that the coordinate systems match + functional = fixcoordsys(functional); + surf = fixcoordsys(surf); + assert(isequal(functional.coordsys, surf.coordsys), 'coordinate systems do not match'); + end + % downsample the cortical surface if cfg.surfdownsample > 1 if ~isempty(cfg.surfinflated) - error('downsampling the surface is not possible in combination with an inflated surface'); + ft_error('downsampling the surface is not possible in combination with an inflated surface'); end fprintf('downsampling surface from %d vertices\n', size(surf.pos,1)); [temp.tri, temp.pos] = reducepatch(surf.tri, surf.pos, 1/cfg.surfdownsample); @@ -1077,15 +1162,15 @@ function ft_sourceplot(cfg, functional, anatomical) if isfield(surf, 'sulc'), surf.sulc = surf.sulc(idx); end if isfield(surf, 'hemisphere'), surf.hemisphere = surf.hemisphere(idx); end end - + % these are required if ~isfield(functional, 'inside') functional.inside = true(dim); end - + fprintf('%d voxels in functional data\n', prod(dim)); fprintf('%d vertices in cortical surface\n', size(surf.pos,1)); - + tmpcfg = []; tmpcfg.parameter = {cfg.funparameter}; if ~isempty(cfg.maskparameter) @@ -1104,150 +1189,147 @@ function ft_sourceplot(cfg, functional, anatomical) tmpcfg.projweight = cfg.projweight; tmpcfg.projthresh = cfg.projthresh; tmpdata = ft_sourceinterpolate(tmpcfg, functional, surf); - + if hasfun, val = getsubfield(tmpdata, cfg.funparameter); val = val(:); end if hasmsk, maskval = getsubfield(tmpdata, maskparameter); maskval = maskval(:); end - - if ~isempty(cfg.projthresh), + + if ~isempty(cfg.projthresh) maskval(abs(val) < cfg.projthresh*max(abs(val(:)))) = 0; end - + else surf = []; surf.pos = functional.pos; surf.tri = functional.tri; - + % if hasfun, val = fun(functional.inside(:)); end % if hasmsk, maskval = msk(functional.inside(:)); end if hasfun, val = fun(:); end if hasmsk, maskval = msk(:); end - + end - + if ~isempty(cfg.surfinflated) if ~isstruct(cfg.surfinflated) % read the inflated triangulated cortical surface from file surf = ft_read_headshape(cfg.surfinflated); else surf = cfg.surfinflated; - if isfield(surf, 'transform'), + if isfield(surf, 'transform') % compute the surface vertices in head coordinates surf.pos = ft_warp_apply(surf.transform, surf.pos); end end end - + %------do the plotting - cortex_light = [0.781 0.762 0.664]; - cortex_dark = [0.781 0.762 0.664]/2; - if isfield(surf, 'curv') - % the curvature determines the color of gyri and sulci - color = surf.curv(:) * cortex_dark + (1-surf.curv(:)) * cortex_light; - else - color = repmat(cortex_light, size(surf.pos,1), 1); - end - - h1 = patch('Vertices', surf.pos, 'Faces', surf.tri, 'FaceVertexCData', color, 'FaceColor', 'interp'); - set(h1, 'EdgeColor', 'none'); - axis off; - axis vis3d; - axis equal; - - if hasfun - h2 = patch('Vertices', surf.pos, 'Faces', surf.tri, 'FaceVertexCData', val, 'FaceColor', 'interp'); - set(h2, 'EdgeColor', 'none'); - try - caxis(gca,[fcolmin fcolmax]); - end - colormap(cfg.funcolormap); - if hasmsk - set(h2, 'FaceVertexAlphaData', maskval); - set(h2, 'FaceAlpha', 'interp'); - set(h2, 'AlphaDataMapping', 'scaled'); - try - alim(gca, [opacmin opacmax]); - end - alphamap(cfg.opacitymap); + if ~hasfun + ft_plot_mesh(surf,'edgecolor', cfg.edgecolor, 'facecolor', cfg.facecolor, 'vertexcolor', cfg.vertexcolor); + + elseif hasfun + if ~hasmsk || all(maskval(:)==1) + ft_plot_mesh(surf,'edgecolor', cfg.edgecolor, 'facecolor', cfg.facecolor, 'vertexcolor', val, 'clim', [fcolmin fcolmax], 'colormap', cfg.funcolormap); + + elseif hasmsk + switch cfg.maskstyle + case 'opacity' + % this needs to be handled here, rather than in ft_plot_mesh, + % because the latter function needs to be called twice: once + % for drawing the background, with possibly a user-specified + % background color, and the second time for the functional data + ft_plot_mesh(surf, 'edgecolor', cfg.edgecolor, 'facecolor', cfg.facecolor, 'vertexcolor', cfg.vertexcolor); + ft_plot_mesh(surf, 'edgecolor', cfg.edgecolor, 'facecolor', cfg.facecolor, 'vertexcolor', val, 'facealpha', maskval, 'clim', [fcolmin fcolmax], 'alphalim', [opacmin opacmax], 'alphamap', cfg.opacitymap, 'colormap', cfg.funcolormap, 'maskstyle', 'opacity'); + + case 'colormix' + % convert the specification of the background color + functional + % color + opacity into a single rgb value to speed up the rendering + ft_plot_mesh(surf, 'edgecolor', cfg.edgecolor, 'facecolor', cfg.facecolor, 'vertexcolor', val, 'facealpha', maskval, 'clim', [fcolmin fcolmax], 'alphalim', [opacmin opacmax], 'alphamap', cfg.opacitymap, 'colormap', cfg.funcolormap, 'maskstyle', 'colormix'); + + end end end - + lighting gouraud - + if istrue(cfg.camlight) camlight end - + if istrue(cfg.colorbar) if hasfun % use a normal MATLAB colorbar hc = colorbar; - set(hc, 'YLim', [fcolmin fcolmax]); + if strcmp(cfg.maskstyle, 'opacity') + % functional values are according to original input values + set(hc, 'YLim', [fcolmin fcolmax]); + else + % functional values have been transformed to be scaled + set(hc,'ticks',(0:0.1:1)); + set(hc,'ticklabels',round(100*linspace(fcolmin,fcolmax,numel(get(hc,'ticks'))'))./100); + end else - warning('no colorbar possible without functional data') + ft_warning('no colorbar possible without functional data') end end - + case 'glassbrain' + assert(~hastime, 'method "%s" does not support time', cfg.method); + assert(~hasfreq, 'method "%s" does not support freq', cfg.method); + % This is implemented using a recursive call with an updated functional data % structure. The functional volume is replaced by a volume in which the maxima % are projected to the "edge" of the volume. - tmpcfg = keepfields(cfg, {'funparameter', 'funcolorlim', 'funcolormap', 'opacitylim', 'axis', 'renderer'}); - tmpcfg.method = 'ortho'; - tmpcfg.location = [1 1 1]; - tmpcfg.locationcoordinates = 'voxel'; - tmpcfg.maskparameter = 'inside'; - - if hasfun, - fun = getsubfield(functional, cfg.funparameter); - fun = reshape(fun, dim); + + tmpfunctional = keepfields(functional, {'dim', 'transform'}); + + if hasfun + if isfield(functional, 'inside') + fun(~functional.inside) = nan; + end fun(1,:,:) = max(fun, [], 1); % get the projection along the 1st dimension fun(:,1,:) = max(fun, [], 2); % get the projection along the 2nd dimension fun(:,:,1) = max(fun, [], 3); % get the projection along the 3rd dimension - functional = setsubfield(functional, cfg.funparameter, fun); + tmpfunctional.(cfg.funparameter) = fun; end - - if hasana, - ana = getsubfield(functional, cfg.anaparameter); - % this remains as it is - functional = setsubfield(functional, cfg.anaparameter, ana); - end - - if hasmsk, - msk = getsubfield(functional, 'inside'); - msk = reshape(msk, dim); - if hasana - msk(1,:,:) = fun(1,:,:)>0 & imfill(abs(ana(1,:,:)-1))>0; - msk(:,1,:) = fun(:,1,:)>0 & imfill(abs(ana(:,1,:)-1))>0; - msk(:,:,1) = fun(:,:,1)>0 & imfill(abs(ana(:,:,1)-1))>0; - else - msk(1,:,:) = fun(1,:,:)>0; - msk(:,1,:) = fun(:,1,:)>0; - msk(:,:,1) = fun(:,:,1)>0; + + if hasana + if isfield(functional, 'inside') + % ana(~functional.inside) = nan; end - functional = setsubfield(functional, 'inside', msk); + ana(1,:,:) = max(ana, [], 1); % get the projection along the 1st dimension + ana(:,1,:) = max(ana, [], 2); % get the projection along the 2nd dimension + ana(:,:,1) = max(ana, [], 3); % get the projection along the 3rd dimension + tmpfunctional.(cfg.anaparameter) = ana; end - - ft_sourceplot(tmpcfg, functional); - + + tmpcfg = keepfields(cfg, {'anaparameter', 'funparameter', 'funcolorlim', 'funcolormap', 'opacitylim', 'axis', 'renderer', 'showcallinfo'}); + tmpcfg.method = 'ortho'; + tmpcfg.location = [1 1 1]; + tmpcfg.locationcoordinates = 'voxel'; + ft_sourceplot(tmpcfg, tmpfunctional); + case 'vertex' + assert(~hastime, 'method "%s" does not support time', cfg.method); + assert(~hasfreq, 'method "%s" does not support freq', cfg.method); + if isUnstructuredFun pos = functional.pos; else [X, Y, Z] = ndgrid(1:dim(1), 1:dim(2), 1:dim(3)); pos = ft_warp_apply(functional.transform, [X(:) Y(:) Z(:)]); end - + if isfield(functional, 'inside') pos = pos(functional.inside,:); if hasfun fun = fun(functional.inside); end end - + % scale the functional data between -30 and 30 fun = 30*fun/max(abs(fun(:))); if any(fun<=0) - warning('using red for positive and blue for negative functional values') + ft_warning('using red for positive and blue for negative functional values') col = zeros(numel(fun), 3); % RGB col(fun>0,1) = 1; % red col(fun<0,3) = 1; % blue @@ -1256,12 +1338,78 @@ function ft_sourceplot(cfg, functional, anatomical) else ft_plot_mesh(pos, 'vertexsize', fun, 'vertexcolor', 'k'); end - + % ensure that the axes don't change if you rotate axis vis3d - + + case 'cloud' + assert(~hastime, 'method "%s" does not support time', cfg.method); + assert(~hasfreq, 'method "%s" does not support freq', cfg.method); + + % some defaults depend on the geometrical units + scale = ft_scalingfactor('mm', functional.unit); + % set the defaults for method=cloud + cfg.radius = ft_getopt(cfg, 'radius', 4*scale); + cfg.rmin = ft_getopt(cfg, 'rmin', 1*scale); + cfg.scalerad = ft_getopt(cfg, 'scalerad', 'yes'); + cfg.ptsize = ft_getopt(cfg, 'ptsize', 1); + cfg.ptdensity = ft_getopt(cfg, 'ptdensity', 20); + cfg.ptgradient = ft_getopt(cfg, 'ptgradient', .5); + cfg.colorgrad = ft_getopt(cfg, 'colorgrad', 'white'); + cfg.slice = ft_getopt(cfg, 'slice', 'none'); + cfg.slicetype = ft_getopt(cfg, 'slicetype', 'point'); + cfg.ori = ft_getopt(cfg, 'ori', 'y'); + cfg.slicepos = ft_getopt(cfg, 'slicepos', 'auto'); + cfg.nslices = ft_getopt(cfg, 'nslices', 1); + cfg.minspace = ft_getopt(cfg, 'minspace', 1); + cfg.intersectcolor = ft_getopt(cfg, 'intersectcolor', {'k'}); + cfg.intersectlinestyle = ft_getopt(cfg, 'intersectlinestyle', {'-'}); + cfg.intersectlinewidth = ft_getopt(cfg, 'intersectlinewidth', 2); + cfg.ncirc = ft_getopt(cfg, 'ncirc', 15); + cfg.scalealpha = ft_getopt(cfg, 'scalealpha', 'no'); + cfg.facecolor = ft_getopt(cfg, 'facecolor', [0.781 0.762 0.664]); + cfg.edgecolor = ft_getopt(cfg, 'edgecolor', 'none'); + cfg.facealpha = ft_getopt(cfg, 'facealpha', 1); + cfg.edgealpha = ft_getopt(cfg, 'edgealpha', 0); + if ~hasanatomical; anatomical = {}; end + + if isUnstructuredFun + pos = functional.pos; + else + [X, Y, Z] = ndgrid(1:dim(1), 1:dim(2), 1:dim(3)); + pos = ft_warp_apply(functional.transform, [X(:) Y(:) Z(:)]); + end + + if hasmsk + pos = pos(logical(msk),:); + if hasfun + fun = fun(logical(msk)); + end + end + + ft_plot_cloud(pos, fun, 'mesh', anatomical,... + 'radius', cfg.radius, 'rmin', cfg.rmin, 'scalerad', cfg.scalerad, ... + 'ptsize', cfg.ptsize, 'ptdensity', cfg.ptdensity, 'ptgradient', cfg.ptgradient,... + 'colorgrad', cfg.colorgrad, 'colormap', cfg.funcolormap, 'clim', [fcolmin fcolmax], ... + 'unit', functional.unit, 'slice', cfg.slice, 'slicetype', cfg.slicetype, ... + 'ori', cfg.ori, 'slicepos', cfg.slicepos, 'nslices', cfg.nslices, 'minspace', cfg.minspace,... + 'intersectcolor', cfg.intersectcolor, 'intersectlinestyle', cfg.intersectlinestyle, ... + 'intersectlinewidth', cfg.intersectlinewidth, 'ncirc', cfg.ncirc, ... + 'scalealpha', cfg.scalealpha, 'facecolor', cfg.facecolor, 'edgecolor', cfg.edgecolor,... + 'facealpha', cfg.facealpha, 'edgealpha', cfg.edgealpha); + + if istrue(cfg.colorbar) + if ~strcmp(cfg.slice, '2d') + colorbar; + else % position the colorbar so that it does not change the axis of the last subplot + subplotpos = get(subplot(cfg.nslices,1,cfg.nslices), 'Position'); % position of the bottom or rightmost subplot + colorbar('Position', [subplotpos(1)+subplotpos(3)+0.01 subplotpos(2) .03 subplotpos(2)+subplotpos(4)*(cfg.nslices+.1)]); + end + end + + otherwise - error('unsupported method "%s"', cfg.method); + ft_error('unsupported method "%s"', cfg.method); end % do the general cleanup and bookkeeping at the end of the function @@ -1327,11 +1475,11 @@ function cb_redraw(h, eventdata) str2 = ''; end -if opt.hasfreq && opt.hastime, +if opt.hasfreq && opt.hastime str3 = sprintf('%.1f s, %.1f Hz', functional.time(opt.qi(2)), functional.freq(opt.qi(1))); -elseif ~opt.hasfreq && opt.hastime, +elseif ~opt.hasfreq && opt.hastime str3 = sprintf('%.1f s', functional.time(opt.qi(1))); -elseif opt.hasfreq && ~opt.hastime, +elseif opt.hasfreq && ~opt.hastime str3 = sprintf('%.1f Hz', functional.freq(opt.qi(1))); else str3 = ''; @@ -1377,7 +1525,7 @@ function cb_redraw(h, eventdata) if opt.init tmph = [h1 h2 h3]; ft_plot_ortho(opt.ana, 'transform', eye(4), 'location', opt.ijk, 'style', 'subplot', 'parents', tmph, 'update', opt.update, 'doscale', false, 'clim', opt.clim); - + opt.anahandles = findobj(opt.handlesfigure, 'type', 'surface')'; for i=1:length(opt.anahandles) opt.parenttag{i} = get(get(opt.anahandles(i), 'parent'), 'tag'); @@ -1400,8 +1548,7 @@ function cb_redraw(h, eventdata) 'style', 'subplot', 'parents', tmph, 'update', opt.update, ... 'colormap', opt.funcolormap, 'clim', [opt.fcolmin opt.fcolmax], ... 'opacitylim', [opt.opacmin opt.opacmax]); - - + else tmpqi = [opt.qi 1]; tmph = [h1 h2 h3]; @@ -1409,9 +1556,8 @@ function cb_redraw(h, eventdata) 'style', 'subplot', 'parents', tmph, 'update', opt.update, ... 'colormap', opt.funcolormap, 'clim', [opt.fcolmin opt.fcolmax]); end - % after the first call, the handles to the functional surfaces - % exist. create a variable containing this, and sort according to - % the parents + % After the first call, the handles to the functional surfaces exist. + % Create a variable containing these, and sort according to the parents. opt.funhandles = findobj(opt.handlesfigure, 'type', 'surface'); opt.funtag = get(opt.funhandles, 'tag'); opt.funhandles = opt.funhandles(~strcmp('ana', opt.funtag)); @@ -1422,13 +1568,13 @@ function cb_redraw(h, eventdata) opt.funhandles = opt.funhandles(i3(i2)); % seems like swapping the order opt.funhandles = opt.funhandles(:)'; set(opt.funhandles, 'tag', 'fun'); - + if ~opt.hasmsk && opt.hasfun && opt.hasana set(opt.funhandles(1), 'facealpha',0.5); set(opt.funhandles(2), 'facealpha',0.5); set(opt.funhandles(3), 'facealpha',0.5); end - + else if opt.hasmsk tmpqi = [opt.qi 1]; @@ -1450,23 +1596,23 @@ function cb_redraw(h, eventdata) set(opt.handlesaxes(2), 'Visible',opt.axis); set(opt.handlesaxes(3), 'Visible',opt.axis); -if opt.hasfreq && opt.hastime && opt.hasfun, +if opt.hasfreq && opt.hastime && opt.hasfun h4 = subplot(2,2,4); tmpdat = double(shiftdim(opt.fun(xi,yi,zi,:,:),3)); uimagesc(double(functional.time), double(functional.freq), tmpdat); axis xy; xlabel('time'); ylabel('freq'); set(h4, 'tag', 'TF1'); caxis([opt.fcolmin opt.fcolmax]); -elseif opt.hasfreq && opt.hasfun, +elseif opt.hasfreq && opt.hasfun h4 = subplot(2,2,4); plot(functional.freq, shiftdim(opt.fun(xi,yi,zi,:),3)); xlabel('freq'); axis([functional.freq(1) functional.freq(end) opt.fcolmin opt.fcolmax]); set(h4, 'tag', 'TF2'); -elseif opt.hastime && opt.hasfun, +elseif opt.hastime && opt.hasfun h4 = subplot(2,2,4); plot(functional.time, shiftdim(opt.fun(xi,yi,zi,:),3)); xlabel('time'); set(h4, 'tag', 'TF3', 'xlim',functional.time([1 end]), 'ylim',[opt.fcolmin opt.fcolmax], 'layer', 'top'); -elseif strcmp(opt.colorbar, 'yes') && ~isfield(opt, 'hc'), +elseif strcmp(opt.colorbar, 'yes') && ~isfield(opt, 'hc') if opt.hasfun % vectorcolorbar = linspace(fscolmin, fcolmax,length(cfg.funcolormap)); % imagesc(vectorcolorbar,1,vectorcolorbar);colormap(cfg.funcolormap); @@ -1477,7 +1623,7 @@ function cb_redraw(h, eventdata) opt.hc = colorbar; set(opt.hc, 'location', 'southoutside'); set(opt.hc, 'position',[0.06+0.06+opt.h1size(1) 0.06-0.06+opt.h3size(2) opt.h2size(1) 0.06]); - + try set(opt.hc, 'XLim', [opt.fcolmin opt.fcolmax]); end @@ -1511,14 +1657,14 @@ function cb_redraw(h, eventdata) end if opt.crosshair if opt.init - hch1 = crosshair([xi 1 zi], 'parent', opt.handlesaxes(1)); - hch3 = crosshair([xi yi opt.dim(3)], 'parent', opt.handlesaxes(3)); - hch2 = crosshair([opt.dim(1) yi zi], 'parent', opt.handlesaxes(2)); + hch1 = ft_plot_crosshair([xi 1 zi], 'parent', opt.handlesaxes(1)); + hch3 = ft_plot_crosshair([xi yi opt.dim(3)], 'parent', opt.handlesaxes(3)); + hch2 = ft_plot_crosshair([opt.dim(1) yi zi], 'parent', opt.handlesaxes(2)); opt.handlescross = [hch1(:)';hch2(:)';hch3(:)']; else - crosshair([xi 1 zi], 'handle', opt.handlescross(1, :)); - crosshair([opt.dim(1) yi zi], 'handle', opt.handlescross(2, :)); - crosshair([xi yi opt.dim(3)], 'handle', opt.handlescross(3, :)); + ft_plot_crosshair([xi 1 zi], 'handle', opt.handlescross(1, :)); + ft_plot_crosshair([opt.dim(1) yi zi], 'handle', opt.handlescross(2, :)); + ft_plot_crosshair([xi yi opt.dim(3)], 'handle', opt.handlescross(3, :)); end end @@ -1563,20 +1709,20 @@ function cb_keyboard(h, eventdata) switch key case {'' 'shift+shift' 'alt-alt' 'control+control' 'command-0'} % do nothing - + case '1' subplot(opt.handlesaxes(1)); - + case '2' subplot(opt.handlesaxes(2)); - + case '3' subplot(opt.handlesaxes(3)); - + case 'q' setappdata(h, 'opt', opt); cb_cleanup(h); - + case {'i' 'j' 'k' 'm' 28 29 30 31 'leftarrow' 'rightarrow' 'uparrow' 'downarrow'} % TODO FIXME use leftarrow rightarrow uparrow downarrow % update the view to a new position if strcmp(tag, 'ik') && (strcmp(key, 'i') || strcmp(key, 'uparrow') || isequal(key, 30)), opt.ijk(3) = opt.ijk(3)+1; opt.update = [0 0 1]; @@ -1593,10 +1739,10 @@ function cb_keyboard(h, eventdata) elseif strcmp(tag, 'jk') && (strcmp(key, 'm') || strcmp(key, 'downarrow') || isequal(key, 31)), opt.ijk(3) = opt.ijk(3)-1; opt.update = [0 0 1]; else % do nothing - end; + end setappdata(h, 'opt', opt); cb_redraw(h); - + % contrast scaling case {43 'shift+equal'} % numpad + if isempty(opt.clim) @@ -1608,7 +1754,7 @@ function cb_keyboard(h, eventdata) opt.clim(2) = opt.clim(2)-cscalefactor; setappdata(h, 'opt', opt); cb_redraw(h); - + case {45 'shift+hyphen'} % numpad - if isempty(opt.clim) opt.clim = [min(opt.ana(:)) max(opt.ana(:))]; @@ -1619,9 +1765,9 @@ function cb_keyboard(h, eventdata) opt.clim(2) = opt.clim(2)+cscalefactor; setappdata(h, 'opt', opt); cb_redraw(h); - + otherwise - + end % switch key %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/external/fieldtrip/ft_sourcestatistics.m b/external/fieldtrip/ft_sourcestatistics.m index 4e69be08..7c1174f6 100644 --- a/external/fieldtrip/ft_sourcestatistics.m +++ b/external/fieldtrip/ft_sourcestatistics.m @@ -23,7 +23,8 @@ % for the corresponding configuration options and for a detailed % explanation of each method. % -% See also FT_SOURCEANALYSIS, FT_SOURCEDESCRIPTIVES, FT_SOURCEGRANDAVERAGE +% See also FT_SOURCEANALYSIS, FT_SOURCEDESCRIPTIVES, FT_SOURCEGRANDAVERAGE, FT_MATH, +% FT_STATISTICS_MONTECARLO, FT_STATISTICS_ANALYTIC, FT_STATISTICS_CROSSVALIDATE, FT_STATISTICS_STATS % Deprecated cfg.method options: % 'parametric' uses the MATLAB statistics toolbox (very similar to 'stats'), @@ -118,7 +119,7 @@ end % ensure that the data in all inputs has the same channels, time-axis, etc. -tmpcfg = keepfields(cfg, {'frequency', 'avgoverfreq', 'latency', 'avgovertime'}); +tmpcfg = keepfields(cfg, {'frequency', 'avgoverfreq', 'latency', 'avgovertime', 'showcallinfo'}); [varargin{:}] = ft_selectdata(tmpcfg, varargin{:}); % restore the provenance information [cfg, varargin{:}] = rollback_provenance(cfg, varargin{:}); @@ -147,6 +148,18 @@ end end +if isfield(varargin{1}, 'inside'), + cfg.inside = varargin{1}.inside; +else + cfg.inside = true(size(varargin{1}.pos,1),1); +end + +% also create an inside vector for the reshaped data, which is needed +% when there are multiple values per grid position +cfg.originside = cfg.inside; +cfg.inside = repmat(cfg.inside, prod(cfg.dim)./numel(cfg.inside), 1); + + if numel(cfg.dim)==1 cfg.dim(2) = 1; % add a trailing singleton dimensions end @@ -172,6 +185,7 @@ dat = cat(1, dat{:}); % repetitions along 1st dimension dat = dat'; % repetitions along 2nd dimension end +dat = dat(cfg.inside,:); if size(cfg.design,2)~=size(dat,2) cfg.design = transpose(cfg.design); @@ -183,13 +197,13 @@ if exist(['ft_statistics_' cfg.method], 'file') statmethod = str2func(['ft_statistics_' cfg.method]); else - error('could not find the corresponding function for cfg.method="%s"\n', cfg.method); + ft_error('could not find the corresponding function for cfg.method="%s"\n', cfg.method); end fprintf('using "%s" for the statistical testing\n', func2str(statmethod)); % check that the design completely describes the data if size(dat,2) ~= size(cfg.design,2) - error('the length of the design matrix (%d) does not match the number of observations in the data (%d)', size(cfg.design,2), size(dat,2)); + ft_error('the length of the design matrix (%d) does not match the number of observations in the data (%d)', size(cfg.design,2), size(dat,2)); end % determine the number of output arguments @@ -217,6 +231,12 @@ fn = fieldnames(stat); for i=1:length(fn) + if numel(stat.(fn{i}))==sum(cfg.inside) + % get the data back onto the inside positions + tmp = nan+zeros(numel(cfg.inside),1); + tmp(cfg.inside) = stat.(fn{i}); + stat.(fn{i}) = tmp; + end if numel(stat.(fn{i}))==prod(datsiz) % reformat into the same dimensions as the input data stat.(fn{i}) = reshape(stat.(fn{i}), [datsiz 1]); @@ -227,7 +247,7 @@ stat.dimord = cfg.dimord; % copy the descripive fields into the output -stat = copyfields(varargin{1}, stat, {'freq', 'time', 'pos', 'dim', 'transform', 'tri'}); +stat = copyfields(varargin{1}, stat, {'freq', 'time', 'pos', 'dim', 'transform', 'tri', 'inside'}); % these were only present to inform the low-level functions cfg = removefields(cfg, {'dim', 'dimord', 'tri', 'inside'}); diff --git a/external/fieldtrip/ft_sourcewrite.m b/external/fieldtrip/ft_sourcewrite.m index d4d0a42a..c680b92d 100644 --- a/external/fieldtrip/ft_sourcewrite.m +++ b/external/fieldtrip/ft_sourcewrite.m @@ -20,7 +20,7 @@ function ft_sourcewrite(cfg, source) % file on disk. This mat file should contain only a single variable, % corresponding with the input data structure. % -% See also FT_SOURCEANALYSIS FT_SOURCEDESCRIPTIVES FT_VOLUMEWRITE +% See also FT_SOURCEANALYSIS, FT_SOURCEDESCRIPTIVES, FT_VOLUMEWRITE % Copyright (C) 2011, Jan-Mathijs Schoffelen % Copyright (C) 2011-2014, Jan-Mathijs Schoffelen, Robert Oostenveld @@ -116,7 +116,7 @@ function ft_sourcewrite(cfg, source) % there is a specification of a 2D cortical sheet, save as gifti cfg.filetype = 'gifti'; else - error('the input data does not look like a 2D sheet, nor as a 3D regular volume'); + ft_error('the input data does not look like a 2D sheet, nor as a 3D regular volume'); end end @@ -151,7 +151,7 @@ function ft_sourcewrite(cfg, source) ft_write_cifti(cfg.filename, source, 'parameter', cfg.parameter, 'brainstructure', cfg.brainstructure, 'parcellation', cfg.parcellation, 'precision', cfg.precision); otherwise - error('unsupported output format (%s)', cfg.filetype); + ft_error('unsupported output format (%s)', cfg.filetype); end % switch filetype ft_postamble debug diff --git a/external/fieldtrip/ft_statistics_analytic.m b/external/fieldtrip/ft_statistics_analytic.m index 34b471dd..eac6e085 100644 --- a/external/fieldtrip/ft_statistics_analytic.m +++ b/external/fieldtrip/ft_statistics_analytic.m @@ -73,7 +73,7 @@ % fetch function handle to the low-level statistics function statfun = ft_getuserfun(cfg.statistic, 'statfun'); if isempty(statfun) - error('could not locate the appropriate statistics function'); + ft_error('could not locate the appropriate statistics function'); else fprintf('using "%s" for the single-sample statistics\n', func2str(statfun)); end @@ -94,7 +94,7 @@ cfg = rmfield(cfg, 'computecritval'); if ~isfield(stat, 'prob') - warning('probability was not computed'); + ft_warning('probability was not computed'); else switch lower(cfg.correctm) case 'bonferroni' @@ -127,6 +127,6 @@ fprintf('not performing a correction for multiple comparisons\n'); stat.mask = stat.prob<=cfg.alpha; otherwise - error('unsupported option "%s" for cfg.correctm', cfg.correctm); + ft_error('unsupported option "%s" for cfg.correctm', cfg.correctm); end end diff --git a/external/fieldtrip/ft_statistics_crossvalidate.m b/external/fieldtrip/ft_statistics_crossvalidate.m index 9e5b8b53..a189f62f 100644 --- a/external/fieldtrip/ft_statistics_crossvalidate.m +++ b/external/fieldtrip/ft_statistics_crossvalidate.m @@ -20,8 +20,9 @@ % stat.statistic = the statistics to report % stat.model = the models associated with this multivariate analysis % +% See also FT_TIMELOCKSTATISTICS, FT_FREQSTATISTICS, FT_SOURCESTATISTICS -% Copyright (c) 2007-2011, Marcel van Gerven, F.C. Donders Centre +% Copyright (c) 2007-2011, F.C. Donders Centre, Marcel van Gerven % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -58,12 +59,12 @@ 'resample', cfg.resample, 'compact', true, 'verbose', true); if any(isinf(dat(:))) - warning('Inf encountered; replacing by zeros'); + ft_warning('Inf encountered; replacing by zeros'); dat(isinf(dat(:))) = 0; end if any(isnan(dat(:))) - warning('Nan encountered; replacing by zeros'); + ft_warning('Nan encountered; replacing by zeros'); dat(isnan(dat(:))) = 0; end @@ -80,19 +81,19 @@ stat.model = cv.model; fn = fieldnames(stat.model{1}); -if any(strcmp(fn, 'weights')), +if any(strcmp(fn, 'weights')) % create the 'encoding' matrix from the weights, as per Haufe 2014. covdat = cov(dat'); for i=1:length(stat.model) W = stat.model{i}.weights; M = dat'*W; covM = cov(M); - stat.model{i}.weightsinv = covdat*W*inv(covM); + stat.model{i}.weightsinv = covdat*W/covM; end end +fn = fieldnames(stat.model{1}); % may now also contain weightsinv for i=1:length(stat.model) - for k=1:length(fn) if numel(stat.model{i}.(fn{k}))==prod(cfg.dim) stat.model{i}.(fn{k}) = reshape(stat.model{i}.(fn{k}),cfg.dim); diff --git a/external/fieldtrip/ft_statistics_montecarlo.m b/external/fieldtrip/ft_statistics_montecarlo.m index 2169e7dc..52e1d45e 100644 --- a/external/fieldtrip/ft_statistics_montecarlo.m +++ b/external/fieldtrip/ft_statistics_montecarlo.m @@ -100,7 +100,8 @@ % % $Id$ -ft_preamble randomseed; % deal with the user specified random seed +% deal with the user specified random seed +ft_preamble randomseed % check if the input cfg is valid for this function cfg = ft_checkconfig(cfg, 'renamed', {'factor', 'ivar'}); @@ -131,7 +132,7 @@ % explicit check for option 'yes' in cfg.correctail. if strcmp(cfg.correcttail,'yes') - error('cfg.correcttail = ''yes'' is not allowed, use either ''prob'', ''alpha'' or ''no''') + ft_error('cfg.correcttail = ''yes'' is not allowed, use either ''prob'', ''alpha'' or ''no''') end if strcmp(cfg.correctm, 'cluster') @@ -149,9 +150,9 @@ % input data can be reshaped into a 3D volume, use bwlabeln/spm_bwlabel rather than clusterstat fprintf('using connectivity of voxels in 3-D volume\n'); cfg.connectivity = nan; - if isfield(cfg, 'inside') - cfg = fixinside(cfg, 'index'); - end + %if isfield(cfg, 'inside') + % cfg = fixinside(cfg, 'index'); + %end elseif isfield(cfg, 'tri') % input data describes a surface along which neighbours can be defined fprintf('using connectivity of vertices along triangulated surface\n'); @@ -180,7 +181,7 @@ % for backward compatibility and other warnings relating correcttail if isfield(cfg,'correctp') && strcmp(cfg.correctp,'yes') - warning('cfg.correctp has been renamed to cfg.correcttail and the options have been changed') + ft_warning('cfg.correctp has been renamed to cfg.correcttail and the options have been changed') disp('setting cfg.correcttail to ''prob''') cfg.correcttail = 'prob'; cfg = rmfield(cfg,'correctp'); @@ -188,7 +189,7 @@ cfg = ft_checkconfig(cfg, 'renamed', {'correctp', 'correcttail'}); end if strcmp(cfg.correcttail,'no') && cfg.tail==0 && cfg.alpha==0.05 - warning('doing a two-sided test without correcting p-values or alpha-level, p-values and alpha-level will reflect one-sided tests per tail') + ft_warning('doing a two-sided test without correcting p-values or alpha-level, p-values and alpha-level will reflect one-sided tests per tail') end % for backward compatibility @@ -203,7 +204,7 @@ % fetch function handle to the low-level statistics function statfun = ft_getuserfun(cfg.statistic, 'statfun'); if isempty(statfun) - error('could not locate the appropriate statistics function'); + ft_error('could not locate the appropriate statistics function'); else fprintf('using "%s" for the single-sample statistics\n', func2str(statfun)); end @@ -239,7 +240,7 @@ cfg.clustercritval = getfield(statfun(tmpcfg, dat, design), 'critval'); catch disp(lasterr); - error('could not determine the parametric critical value for clustering'); + ft_error('could not determine the parametric critical value for clustering'); end elseif strcmp(cfg.clusterthreshold, 'parametric') && ~isempty(cfg.clustercritval) fprintf('using the specified parametric threshold for clustering\n'); @@ -259,13 +260,13 @@ num = 1; end -if num==1, +if num==1 % only the statistic is returned [statobs] = statfun(cfg, dat, design); -elseif num==2, +elseif num==2 % both the statistic and the (updated) configuration are returned [statobs, cfg] = statfun(cfg, dat, design); -elseif num==3, +elseif num==3 % both the statistic and the (updated) configuration and the (updated) data are returned tmpcfg = cfg; if strcmp(cfg. precondition, 'before'), tmpcfg.preconditionflag = 1; end @@ -292,7 +293,7 @@ prb_neg = zeros(size(statobs)); end -if strcmp(cfg.precondition, 'after'), +if strcmp(cfg.precondition, 'after') tmpcfg = cfg; tmpcfg.preconditionflag = 1; [tmpstat, tmpcfg, dat] = statfun(tmpcfg, dat, design); @@ -413,7 +414,7 @@ stat.posclusters(i).stddev = sqrt(stat.posclusters(i).prob.*(1-stat.posclusters(i).prob)/Nrand); stat.posclusters(i).cirange = 1.96*stat.posclusters(i).stddev; if i==1 && stat.posclusters(i).prob=cfg.alpha - warning('FieldTrip:posCluster_exceeds_alpha', sprintf('The p-value confidence interval of positive cluster #%i includes %.3f - consider increasing the number of permutations!', i, cfg.alpha)); + ft_warning('FieldTrip:posCluster_exceeds_alpha', sprintf('The p-value confidence interval of positive cluster #%i includes %.3f - consider increasing the number of permutations!', i, cfg.alpha)); end end end @@ -422,13 +423,13 @@ stat.negclusters(i).stddev = sqrt(stat.negclusters(i).prob.*(1-stat.negclusters(i).prob)/Nrand); stat.negclusters(i).cirange = 1.96*stat.negclusters(i).stddev; if i==1 && stat.negclusters(i).prob=cfg.alpha - warning('FieldTrip:negCluster_exceeds_alpha', sprintf('The p-value confidence interval of negative cluster #%i includes %.3f - consider increasing the number of permutations!', i, cfg.alpha)); + ft_warning('FieldTrip:negCluster_exceeds_alpha', sprintf('The p-value confidence interval of negative cluster #%i includes %.3f - consider increasing the number of permutations!', i, cfg.alpha)); end end end if ~isfield(stat, 'prob') - warning('probability was not computed'); + ft_warning('probability was not computed'); else switch lower(cfg.correctm) case 'max' @@ -480,7 +481,7 @@ stat.stat = statobs; end -if exist('statrand', 'var'), +if exist('statrand', 'var') stat.ref = mean(statrand,2); end @@ -492,7 +493,8 @@ end end -ft_postamble randomseed; % deal with the potential user specified randomseed +% deal with the potential user specified randomseed +ft_postamble randomseed warning(ws); % revert to original state diff --git a/external/fieldtrip/ft_statistics_stats.m b/external/fieldtrip/ft_statistics_stats.m index 041cd4c9..fa3926ca 100644 --- a/external/fieldtrip/ft_statistics_stats.m +++ b/external/fieldtrip/ft_statistics_stats.m @@ -60,7 +60,7 @@ ft_hastoolbox('stats', 1); % set the defaults that are common to all methods -if ~isfield(cfg, 'feedback'), cfg.feedback = 'textbar'; end +cfg.feedback = ft_getopt(cfg, 'feedback', 'textbar'); switch cfg.statistic @@ -68,16 +68,16 @@ case {'ttest', 'ttest_samples_vs_const'} % set the defaults - if ~isfield(cfg, 'alpha'), cfg.alpha = 0.05; end - if ~isfield(cfg, 'constantvalue'), cfg.constantvalue = 0; end - if ~isfield(cfg, 'tail'), cfg.tail = 0; end + cfg.alpha = ft_getopt(cfg, 'alpha', 0.05); + cfg.tail = ft_getopt(cfg, 'tail', 0); + cfg.constantvalue = ft_getopt(cfg, 'constantvalue', 0); if ~any(size(design)==1) - error('design matrix should only contain one factor (i.e. one row)'); + ft_error('design matrix should only contain one factor (i.e. one row)'); end Ncond = length(unique(design)); if Ncond>1 - error(sprintf('%s method is only supported for one condition at a time', cfg.statistic)); + ft_error('method "%s" is only supported for one condition', cfg.statistic); end Nobs = size(dat, 1); Nrepl = size(dat, 2); % over all conditions @@ -101,15 +101,15 @@ case {'ttest2', 'ttest_2samples_by_timepoint'} % set the defaults - if ~isfield(cfg, 'alpha'), cfg.alpha = 0.05; end - if ~isfield(cfg, 'tail'), cfg.tail = 0; end + cfg.alpha = ft_getopt(cfg, 'alpha', 0.05); + cfg.tail = ft_getopt(cfg, 'tail', 0); if size(design,1)~=1 - error('design matrix should only contain one factor (i.e. one row)'); + ft_error('design matrix should only contain one factor (i.e. one row)'); end Ncond = length(unique(design)); if Ncond~=2 - error(sprintf('%s method is only supported for two condition', cfg.statistic)); + ft_error('%s method is only supported for two conditions', cfg.statistic); end Nobs = size(dat, 1); selA = find(design==design(1)); @@ -135,28 +135,32 @@ case {'paired-ttest'} % set the defaults - if ~isfield(cfg, 'alpha'), cfg.alpha = 0.05; end - if ~isfield(cfg, 'tail'), cfg.tail = 0; end + cfg.alpha = ft_getopt(cfg, 'alpha', 0.05); + cfg.tail = ft_getopt(cfg, 'tail', 0); if ~any(size(design)==1) - error('design matrix should only contain one factor (i.e. one row)'); + ft_error('design matrix should only contain one factor (i.e. one row)'); end Ncond = length(unique(design)); if Ncond~=2 - error(sprintf('%s method is only supported for two condition', cfg.statistic)); + ft_error('method "%s" is only supported for two conditions', cfg.statistic); end Nobs = size(dat, 1); selA = find(design==design(1)); selB = find(design~=design(1)); Nrepl = [length(selA), length(selB)]; if Nrepl(1)~=Nrepl(2) - error('number of replications per condition should be the same'); + ft_error('number of replications per condition should be the same'); end h = zeros(Nobs, 1); p = zeros(Nobs, 1); s = zeros(Nobs, 1); ci = zeros(Nobs, 2); + df = zeros(Nobs, 1); + md = zeros(Nobs, 1); + sd = zeros(Nobs, 1); + cohens_d = zeros(Nobs, 1); fprintf('number of observations %d\n', Nobs); fprintf('number of replications %d and %d\n', Nrepl(1), Nrepl(2)); @@ -165,6 +169,10 @@ ft_progress(chan/Nobs, 'Processing observation %d/%d\n', chan, Nobs); [h(chan), p(chan), ci(chan, :), stats] = ttest_wrapper(dat(chan, selA)-dat(chan, selB), 0, cfg.alpha, cfg.tail); s(chan) = stats.tstat; + df(chan) = stats.df; + md(chan) = mean(dat(chan, selA)-dat(chan, selB)); + sd(chan) = stats.sd; + cohens_d(chan) = md(chan)/sd(chan); end ft_progress('close'); @@ -172,7 +180,7 @@ case {'anova1'} if ~any(size(design)==1) - error('design matrix should only contain one factor (i.e. one row)'); + ft_error('design matrix should only contain one factor (i.e. one row)'); end Ncond = length(unique(design)); Nobs = size(dat, 1); @@ -195,7 +203,7 @@ case {'kruskalwallis'} if ~any(size(design)==1) - error('design matrix should only contain one factor (i.e. one row)'); + ft_error('design matrix should only contain one factor (i.e. one row)'); end Ncond = length(unique(design)); Nobs = size(dat, 1); @@ -246,13 +254,13 @@ % this used to be a feature of the timelockanalysis as it was % originally implemented by Jens Schwartzbach, but it has been % superseded by the use of ft_selectdata for data selection - error(sprintf('%s is not supported any more, use cfg.avgovertime=''yes'' instead', cfg.statistic)); + ft_error('%s is not supported any more, use cfg.avgovertime=''yes'' instead', cfg.statistic); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% case {'signtest'} % set the defaults - if ~isfield(cfg, 'alpha'), cfg.alpha = 0.05; end - if ~isfield(cfg, 'tail'), cfg.tail = 0; end + cfg.alpha = ft_getopt(cfg, 'alpha', 0.05); + cfg.tail = ft_getopt(cfg, 'tail', 0); switch cfg.tail case 0 @@ -261,14 +269,14 @@ cfg.tail = 'left'; case 1 cfg.tail = 'right'; - end; + end if size(design,1)~=1 - error('design matrix should only contain one factor (i.e. one row)'); + ft_error('design matrix should only contain one factor (i.e. one row)'); end Ncond = length(unique(design)); if Ncond~=2 - error(sprintf('%s method is only supported for two condition', cfg.statistic)); + ft_error('method "%s" is only supported for two conditions', cfg.statistic); end Nobs = size(dat, 1); selA = find(design==design(1)); @@ -292,8 +300,8 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% case {'signrank'} % set the defaults - if ~isfield(cfg, 'alpha'), cfg.alpha = 0.05; end - if ~isfield(cfg, 'tail'), cfg.tail = 0; end + cfg.alpha = ft_getopt(cfg, 'alpha', 0.05); + cfg.tail = ft_getopt(cfg, 'tail', 0); switch cfg.tail case 0 @@ -302,14 +310,14 @@ cfg.tail = 'left'; case 1 cfg.tail = 'right'; - end; + end if size(design,1)~=1 - error('design matrix should only contain one factor (i.e. one row)'); + ft_error('design matrix should only contain one factor (i.e. one row)'); end Ncond = length(unique(design)); if Ncond~=2 - error(sprintf('%s method is only supported for two condition', cfg.statistic)); + ft_error('method ''%s'' is only supported for two conditions', cfg.statistic); end Nobs = size(dat, 1); selA = find(design==design(1)); @@ -332,14 +340,19 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% otherwise - error(sprintf('Statistical method ''%s'' is not implemented', cfg.statistic)); + ft_error('method ''%s'' is not implemented', cfg.statistic); end % assign the output variable stat = []; -try, stat.mask = h; end -try, stat.prob = p; end -try, stat.stat = s; end +try, stat.mask = h; end +try, stat.prob = p; end +try, stat.stat = s; end +try, stat.ci = ci; end +try, stat.df = df; end +try, stat.md = md; end +try, stat.sd = sd; end +try, stat.cohens_d = cohens_d; end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % helper functions for ttest and ttest2 diff --git a/external/fieldtrip/ft_steadystatesimulation.m b/external/fieldtrip/ft_steadystatesimulation.m new file mode 100644 index 00000000..4c52b3d3 --- /dev/null +++ b/external/fieldtrip/ft_steadystatesimulation.m @@ -0,0 +1,397 @@ +function data = ft_steadystatesimulation(cfg) + +% FT_STEADYSTATESIMULATION creates a simulated EEG/MEG dataset. This function +% allows to simulate the effect of several independent stimulus trains. These can +% be presented as a periodic sequence, or as single (or few) transient stimuli. +% This function creates a single block of data. You can call it repeatedly and use +% FT_APPENDDATA to combine different blocks. +% +% Use as +% data = ft_steadystatesimulation(cfg) +% where cfg is a configuration structure that should contain +% cfg.fsample = scalar, sampling frequency in Hz (default = 512) +% cfg.duration = scalar, trial length in seconds (default = 4.56) +% cfg.baseline = scalar, baseline length in seconds (default = 0) +% cfg.ntrials = integer N, number of trials (default = 320) +% cfg.iti = scalar, inter-trial interval in seconds (default = 1) +% +% Each trial can contain multiple nested experimental manipulations +% cfg.level1.condition = scalar, or vector of length L1 (default = 1) +% cfg.level1.gain = scalar, or vector of length L1 (default = 1) +% cfg.level2.condition = scalar, or vector of length L2 (default = 1) +% cfg.level2.gain = scalar, or vector of length L2 (default = 1) +% cfg.level3.condition = scalar, or vector of length L3 (default = 1) +% cfg.level3.gain = scalar, or vector of length L3 (default = 1) +% If you don't need level 2 and up, specify the condition and gain as empty. +% Idem for level 3 and up. +% +% Stimuli are created at the lowest experimental level, and are modulated according to the product of the gain of all levels. +% Each trial can contain one or multiple stimuli. +% The behaviour of each stimuli is specified with +% cfg.stimulus1.mode = 'periodic', 'transient' or 'off' (default = 'periodic') +% cfg.stimulus2.mode = 'periodic', 'transient' or 'off' (default = 'transient') +% +% If the stimulus is periodic (below as example for stimulus1), the following options apply +% cfg.stimulus1.number = does not apply for periodic stimuli +% cfg.stimulus1.onset = in seconds, first stimulus relative to the start of the trial (default = 0) +% cfg.stimulus1.onsetjitter = in seconds, max jitter that is added to the onset (default = 0) +% cfg.stimulus1.isi = in seconds, i.e. for 10Hz you would specify 0.1 seconds as the interstimulus interval (default = 0.1176) +% cfg.stimulus1.isijitter = in seconds, max jitter relative to the previous stimulus (default = 0) +% cfg.stimulus2.condition = does not apply for periodic stimuli +% cfg.stimulus2.gain = does not apply for periodic stimuli +% cfg.stimulus1.kernelshape = 'sine' +% cfg.stimulus1.kernelduration = in seconds (default = isi) +% +% If the stimulus is transient (below as example for stimulus2), the following options apply +% cfg.stimulus2.number = scalar M, how many transients are to be presented per trial (default = 4) +% cfg.stimulus2.onset = in seconds, first stimulus relative to the start of the trial (default = 0.7) +% cfg.stimulus2.onsetjitter = in seconds, max jitter that is added to the onset (default = 0.2) +% cfg.stimulus2.isi = in seconds as the interstimulus interval (default = 0.7) +% cfg.stimulus2.isijitter = in seconds, max jitter relative to the previous stimulus ((default = 0.2) +% cfg.stimulus2.condition = 1xM vector with condition codes for each transient within a trial (default = [1 1 2 2]) +% cfg.stimulus2.gain = 1xM vector with gain for each condition for each transient within a trial(default = [1 1 1 1]) +% cfg.stimulus2.kernelshape = 'hanning' +% cfg.stimulus2.kernelduration = in seconds (default = 0.75*isi) +% +% RANDOMIZATIONS: +% - The onsetjitter is randomized between 0 and the value given, and is always added to the onset. +% - The isijitter is randomized between 0 and the value given, and is always added to the interstimulus interval (isi). +% - For periodic stimuli, which are constant within a trial, the condition code and gain are shuffled over all trials. +% - For transient stimuli, the condition code and gain are shuffled within each trial. +% +% Using the default settings, we model a peripherally presented flickering stimulus +% that appears at different excentricities together with a centrally presented +% transient stimulus that appears 4x per trial. To simulate the experiment described +% at , you have to call this 4 times with a different cfg.configuration and +% cfg.gain to model the task load and use FT_APPENDDATA to concatenate the trials. In +% this case cfg.condition models the factor "task load" (2 levels, low and high), +% cfg.stimulus1.condition models the factor "excentricity" (4 levels), and +% cfg.stimulation2.condition models the factor "stimulus type" (2 levels, non-target +% or target). +% +% See also FT_DIPOLESIMULATION, FT_TIMELOCKSIMULATION, FT_FREQSIMULATION, +% FT_CONNECTIVITYSIMULATION, FT_APPENDDATA + +% Copyright (C) 2017, Stefan Wiens, Malina Szychowska, Robert Oostenveld +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% the initial part deals with parsing the input options and data +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% these are used by the ft_preamble/ft_postamble function and scripts +ft_revision = '$Id$'; +ft_nargin = nargin; +ft_nargout = nargout; + +% do the general setup of the function +ft_defaults +ft_preamble init +ft_preamble debug +ft_preamble provenance +ft_preamble trackconfig + +% the ft_abort variable is set to true or false in ft_preamble_init +if ft_abort + % do not continue function execution in case the outputfile is present and the user indicated to keep it + return +end + +% get the options or set the defaults +cfg.level1 = ft_getopt(cfg, 'level1'); +cfg.level2 = ft_getopt(cfg, 'level2'); +cfg.level3 = ft_getopt(cfg, 'level3'); +cfg.level1.condition = ft_getopt(cfg.level1, 'condition', 1); +cfg.level2.condition = ft_getopt(cfg.level2, 'condition', []); +cfg.level3.condition = ft_getopt(cfg.level3, 'condition', []); +cfg.level1.gain = ft_getopt(cfg.level1, 'gain', 1); +cfg.level2.gain = ft_getopt(cfg.level2, 'gain', []); +cfg.level3.gain = ft_getopt(cfg.level3, 'gain', []); + +cfg.ntrials = ft_getopt(cfg, 'ntrials', 320); +cfg.fsample = ft_getopt(cfg, 'fsample', 512); +cfg.duration = ft_getopt(cfg, 'duration', 4.5); +cfg.baseline = ft_getopt(cfg, 'baseline', 0); +cfg.iti = ft_getopt(cfg, 'iti', 1); + +cfg.stimulus1 = ft_getopt(cfg, 'stimulus1'); +cfg.stimulus2 = ft_getopt(cfg, 'stimulus2'); + +cfg.stimulus1.mode = ft_getopt(cfg.stimulus1, 'mode', 'periodic'); +cfg.stimulus1.number = ft_getopt(cfg.stimulus1, 'number', 0); +cfg.stimulus1.onset = ft_getopt(cfg.stimulus1, 'onset', 0); +cfg.stimulus1.onsetjitter = ft_getopt(cfg.stimulus1, 'onsetjitter', 0); +cfg.stimulus1.isi = ft_getopt(cfg.stimulus1, 'isi', 0.1176); +cfg.stimulus1.isijitter = ft_getopt(cfg.stimulus1, 'isijitter', 0); +cfg.stimulus1.condition = ft_getopt(cfg.stimulus1, 'condition'); +cfg.stimulus1.gain = ft_getopt(cfg.stimulus1, 'gain'); +cfg.stimulus1.kernelshape = ft_getopt(cfg.stimulus1, 'kernelshape', 'sine'); +cfg.stimulus1.kernelduration = ft_getopt(cfg.stimulus1, 'kernelduration', cfg.stimulus1.isi); + +cfg.stimulus2.mode = ft_getopt(cfg.stimulus2, 'mode', 'transient'); +cfg.stimulus2.number = ft_getopt(cfg.stimulus2, 'number', 4); +cfg.stimulus2.onset = ft_getopt(cfg.stimulus2, 'onset', 0.7); +cfg.stimulus2.onsetjitter = ft_getopt(cfg.stimulus2, 'onsetjitter', 0); +cfg.stimulus2.isi = ft_getopt(cfg.stimulus2, 'isi', 0.7); +cfg.stimulus2.isijitter = ft_getopt(cfg.stimulus2, 'isijitter', 0); +cfg.stimulus2.condition = ft_getopt(cfg.stimulus2, 'condition', [1 2 3 4]); +cfg.stimulus2.gain = ft_getopt(cfg.stimulus2, 'gain', [1 1 1 1]); +cfg.stimulus2.kernelshape = ft_getopt(cfg.stimulus2, 'kernelshape', 'hanning'); +cfg.stimulus2.kernelduration = ft_getopt(cfg.stimulus2, 'kernelduration', 0.75*cfg.stimulus2.isi); + +ncondition1 = length(cfg.level1.condition); +ncondition2 = length(cfg.level2.condition); +ncondition3 = length(cfg.level3.condition); + +switch cfg.stimulus1.mode + case 'off' + cfg.stimulus1.number = 0; + cfg.stimulus1.condition = []; + cfg.stimulus1.gain = []; + case 'transient' + assert(numel(cfg.stimulus1.condition)==cfg.stimulus1.number); + assert(numel(cfg.stimulus1.gain)==cfg.stimulus1.number); +end + +switch cfg.stimulus2.mode + case 'off' + cfg.stimulus2.number = 0; + cfg.stimulus2.condition = []; + cfg.stimulus2.gain = []; + case 'transient' + assert(numel(cfg.stimulus2.condition)==cfg.stimulus2.number); + assert(numel(cfg.stimulus2.gain)==cfg.stimulus2.number); +end + +% they cannot be the same, as that would confuse the trialinfo +assert(~isequal(cfg.stimulus1.mode, cfg.stimulus2.mode)); + +% determine which levels are being used +level1 = ncondition1>0; +level2 = ncondition2>0; +level3 = ncondition3>0; + +% count the number of blocks and number of trials per block +nblock = max(ncondition1,1) * max(ncondition2,1) * max(ncondition3,1); +ntrial = cfg.ntrials / nblock; + +assert(ntrial==round(ntrial), 'number of trials inconsistent'); + +% the time (followinf onset) and baseline are the same for each trial +baseline = (-cfg.baseline):(1/cfg.fsample):0; +baseline(end) = []; % remove the last sample +time = 0:(1/cfg.fsample):cfg.duration; + +% construct a sine-wave kernel, feval fails on this one +sine = @(n) sin(2*pi*((1:n)-1)/n); + +% construct the kernels for the response to each stimulus +if strcmp(cfg.stimulus1.kernelshape, 'sine') + kernel1 = sine(round(cfg.stimulus1.kernelduration*cfg.fsample)); +else + kernel1 = feval(cfg.stimulus1.kernelshape, round(cfg.stimulus1.kernelduration*cfg.fsample)); +end +if strcmp(cfg.stimulus2.kernelshape, 'sine') + kernel2 = sine(round(cfg.stimulus2.kernelduration*cfg.fsample)); +else + kernel2 = feval(cfg.stimulus2.kernelshape, round(cfg.stimulus2.kernelduration*cfg.fsample)); +end +% these should be row-vectors +kernel1 = kernel1(:)'; +kernel2 = kernel2(:)'; + +% start with empty data +data = []; + +% this keeps track of the trials +k = 1; + +shuffle = randperm(ncondition3); +tmpcondition3 = cfg.level3.condition(shuffle); +tmpgain3 = cfg.level3.gain(shuffle); +for cond3=1:max(ncondition3, 1) + if level3 + trialgain = tmpgain3(cond3); + else + trialgain = 1; + end + + shuffle = randperm(ncondition2); + tmpcondition2 = cfg.level2.condition(shuffle); + tmpgain2 = cfg.level2.gain(shuffle); + for cond2=1:max(ncondition2, 1) + if level2 + trialgain = trialgain * tmpgain2(cond2); + end + + shuffle = randperm(ncondition1); + tmpcondition1 = cfg.level1.condition(shuffle); + tmpgain1 = cfg.level1.gain(shuffle); + for cond1=1:max(ncondition1, 1) + if level1 + trialgain = trialgain * tmpgain1(cond1); + end + + for trial=1:ntrial + trialinfo = k; % start with the trial number + varname = {'trial'}; + + if level1 + trialinfo = [trialinfo tmpcondition1(cond1)]; + varname(end+1) = {'l1_cond'}; + end + if level2>0 + trialinfo = [trialinfo tmpcondition2(cond2)]; + varname(end+1) = {'l2_cond'}; + end + if level3>0 + trialinfo = [trialinfo tmpcondition3(cond3)]; + varname(end+1) = {'l3_cond'}; + end + + dat = []; + + stimcfg = cfg.stimulus1; + signal = zeros(size(time)); % the baseline will be added later + + switch stimcfg.mode + case 'periodic' + sample = nearest(time, stimcfg.onset + rand(1)*stimcfg.onsetjitter); + for i=1:ceil((cfg.duration-stimcfg.onset)/stimcfg.isi) + sample = sample + round(cfg.fsample*(stimcfg.isi + stimcfg.isijitter*rand(1))); + if sample>length(signal) + % this periodic stimulus falls outside the trial + sample = nan; + else + signal(sample) = 1; + end + trialinfo = [trialinfo sample+length(baseline)]; + varname(end+1) = {sprintf('p%d_sample', i)}; + end % while + + case 'transient' + shuffle = randperm(numel(stimcfg.gain)); + sample = nearest(time, stimcfg.onset + rand(1)*stimcfg.onsetjitter); + transientgain = stimcfg.gain(shuffle); + transientcondition = stimcfg.condition(shuffle); + for i=1:stimcfg.number + sample = sample + round(cfg.fsample*(stimcfg.isi + stimcfg.isijitter*rand(1))); + if sample>length(signal) + warning('transient stimulus falls outside of trial'); + sample = nan; + else + signal(sample) = transientgain(i); + end + trialinfo = [trialinfo transientcondition(i)]; + varname(end+1) = {sprintf('t%d_cond', i)}; + trialinfo = [trialinfo sample+length(baseline)]; + varname(end+1) = {sprintf('t%d_sample', i)}; + + end % while + end % switch mode + + dat(2,:) = [zeros(size(baseline)) signal*trialgain ]; + dat(3,:) = [zeros(size(baseline)) erpconvolve(signal*trialgain, kernel1)]; + + stimcfg = cfg.stimulus2; + signal = zeros(size(time)); % the baseline will be added later + + switch stimcfg.mode + case 'periodic' + sample = nearest(time, stimcfg.onset + rand(1)*stimcfg.onsetjitter); + for i=1:ceil((cfg.duration-stimcfg.onset)/stimcfg.isi) + sample = sample + round(cfg.fsample*(stimcfg.isi + stimcfg.isijitter*rand(1))); + if sample>length(signal) + % this periodic stimulus falls outside the trial + sample = nan; + else + signal(sample) = 1; + end + trialinfo = [trialinfo sample+length(baseline)]; + varname(end+1) = {sprintf('p%d_sample', i)}; + end % while + + case 'transient' + shuffle = randperm(numel(stimcfg.gain)); + sample = nearest(time, stimcfg.onset + rand(1)*stimcfg.onsetjitter); + transientgain = stimcfg.gain(shuffle); + transientcondition = stimcfg.condition(shuffle); + for i=1:stimcfg.number + sample = sample + round(cfg.fsample*(stimcfg.isi + stimcfg.isijitter*rand(1))); + if sample>length(signal) + warning('transient stimulus falls outside of trial'); + sample = nan; + else + signal(sample) = transientgain(i); + end + trialinfo = [trialinfo transientcondition(i)]; + varname(end+1) = {sprintf('t%d_cond', i)}; + trialinfo = [trialinfo sample+length(baseline)]; + varname(end+1) = {sprintf('t%d_sample', i)}; + end % while + + end % switch mode + + dat(4,:) = [zeros(size(baseline)) signal*trialgain ]; + dat(5,:) = [zeros(size(baseline)) erpconvolve(signal*trialgain, kernel2)]; + + % the first channel contains the sum of the two convolved signals + dat(1,:) = sum(dat([3 5],:), 1); + + data.trial{k} = dat; + data.time{k} = [baseline time]; + data.trialinfo(k,:) = trialinfo; + + k = k+1; + end % for each trial in each block + end % for all conditions in level 1 + end % for all conditions in level 2 +end % for all conditions in level 3 + +data.trialinfo = array2table(data.trialinfo, 'VariableNames', varname); +data.fsample = cfg.fsample; +data.label = { + 'combined' + 'stickfunction1' + 'convolved1' + 'stickfunction2' + 'convolved2' + }; + +% construct the sample information, start with consecutive segments +nsample = length(baseline) + length(time); +data.sampleinfo(:,1) = ((1:ntrial)-1)*nsample + 1; +data.sampleinfo(:,2) = ((1:ntrial) )*nsample; +% add the inter-trial-interval +data.sampleinfo(:,1) = data.sampleinfo(:,1) + transpose((1:ntrial)-1)*round(cfg.iti*cfg.fsample); +data.sampleinfo(:,2) = data.sampleinfo(:,2) + transpose((1:ntrial)-1)*round(cfg.iti*cfg.fsample); + +ft_postamble debug +ft_postamble trackconfig +ft_postamble provenance data +ft_postamble history data +ft_postamble savevar data + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function dat = erpconvolve(stickfunction, kernel) +dat = convn(stickfunction, kernel, 'full'); +dat = dat(1:length(stickfunction)); diff --git a/external/fieldtrip/ft_stratify.m b/external/fieldtrip/ft_stratify.m index 0a118293..74b9c294 100644 --- a/external/fieldtrip/ft_stratify.m +++ b/external/fieldtrip/ft_stratify.m @@ -37,8 +37,10 @@ % The following options apply only to the equatespike method. % cfg.pairtrials = 'spikesort', 'linkage' or 'no' (default = 'spikesort') % cfg.channel = 'all' or list with indices ( default = 'all') +% +% See also FT_FREQSTATISTICS, FT_TIMELOCKSTATISTICS, FT_SOURCESTATISTICS -% Copyright (C) 2007 F.C.Donders Centre, Jan-Mathijs Schoffelen & Robert Oostenveld +% Copyright (C) 2007 Jan-Mathijs Schoffelen & Robert Oostenveld % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -73,36 +75,38 @@ end % input1 and input2 are the to be stratified with respect to each other -% dimensionality of input1 (2) = chan x rpt. if nchan>1, do a "double" +% dimensionality of input1 (2) = chan x rpt. If nchan>1, do a "double" % stratification -if ~isfield(cfg, 'method'), cfg.method = 'histogram'; end -if ~isfield(cfg, 'equalbinavg'), cfg.equalbinavg = 'yes'; end -if ~isfield(cfg, 'numbin'), cfg.numbin = 10; end -if ~isfield(cfg, 'numiter'), cfg.numiter = 2000; end -if ~isfield(cfg, 'binedges'), cfg.binedges = []; end -%if ~isfield(cfg, 'dimord'), error('no information about dimensionality in cfg'); end -if ~isfield(cfg, 'pairtrials'), cfg.pairtrials='spikesort'; end -if ~isfield(cfg, 'channel'), cfg.channel='all'; end -if ~isfield(cfg, 'linkage'), cfg.linkage='complete'; end % 'single', 'complete', 'average', 'weighted', 'centroid', 'median', 'ward' +% set the defaults +cfg.method = ft_getopt('method', 'histogram'); +cfg.equalbinavg = ft_getopt('equalbinavg', 'yes'); +cfg.numbin = ft_getopt('numbin', 10); +cfg.numiter = ft_getopt('numiter', 2000); +cfg.binedges = ft_getopt('binedges', []); +cfg.pairtrials = ft_getopt('pairtrials', 'spikesort'); +cfg.channel = ft_getopt('channel', 'all'); +cfg.linkage = ft_getopt('linkage', 'complete'); % 'single', 'complete', 'average', 'weighted', 'centroid', 'median', 'ward' % the input data is a cell-array containing matrices for each condition input = varargin; -if size(input{1},1)~=size(input{2},1), error('the number of channels should be the same'); end -if size(input{1},1)~=1 && strcmp(cfg.equalbinavg, 'yes'), - error('combining equalising bin-averages and simultaneous stratification of two channels is impossible'); +if size(input{1},1)~=size(input{2},1) + ft_error('the number of channels should be the same'); +end +if size(input{1},1)~=1 && strcmp(cfg.equalbinavg, 'yes') + ft_error('combining equalising bin-averages and simultaneous stratification of two channels is impossible'); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % histogram %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -if strcmp(cfg.method, 'histogram'), - +if strcmp(cfg.method, 'histogram') + nchan = size(input{1},1); ncond = length(input); - %if nchan~=2, error('number of trials ~= 2, do not know how to stratify'); end - if isfield(cfg,'cmbindx'), + % if nchan~=2, ft_error('number of trials ~= 2, do not know how to stratify'); end + if isfield(cfg,'cmbindx') [output, b] = stratify2(cfg, input{1}, input{2}); varargout{1} = output{1}; varargout{2} = output{2}; @@ -116,7 +120,7 @@ cfg.numbin = numel(cfg.binedges)-1; end end - + %------prepare some stuff if numel(cfg.numbin) ~= nchan cfg.numbin = repmat(cfg.numbin(1), [1 nchan]); @@ -125,9 +129,9 @@ tmp = []; for cndlop = 1:ncond tmp = cat(2, tmp, input{cndlop}(j,:)); - end %concatenate input-data - - %create a 'common binspace' + end % concatenate input-data + + % create a 'common binspace' [ndum,x] = hist(tmp, cfg.numbin(j)); dx = diff(x); if ~isempty(cfg.binedges) @@ -139,7 +143,7 @@ else xc = [-inf x(1:end-1)+0.5*dx(1) inf]; end - + %make histograms and compute the 'target histogram', which %will equalize the conditions while throwing away as few %repetitions as possible @@ -150,14 +154,14 @@ end binaxis(j,1:(cfg.numbin(j)+1)) = xc; end - + %------index the trials %------create n-d histo linearhisto = zeros(ncond, prod(cfg.numbin)); for cndlop = 1:ncond tmpb = zeros(1, size(b{cndlop},2)); for j = 1:nchan - if j == 1, + if j == 1 tmpb = tmpb + (b{cndlop}(j,:)).*prod(cfg.numbin(1:(j-1))); else tmpb = tmpb + (b{cndlop}(j,:)-1).*prod(cfg.numbin(1:(j-1))); @@ -168,26 +172,26 @@ linearhisto(cndlop,binlop) = sum(tmpb==binlop); end end - + %------find intersection numok = min(linearhisto,[],1); nummax = max(linearhisto,[],1); for j = 1:length(numok) minind{j} = find(linearhisto(:,j)==numok(j)); end - + %------do stratification the easy or the hard way - if strcmp(cfg.equalbinavg, 'yes'), + if strcmp(cfg.equalbinavg, 'yes') %---this is the hard way - if nchan>1, error('the option equalbinavg only works for one channel input at the moment'); end - + if nchan>1, ft_error('the option equalbinavg only works for one channel input at the moment'); end + %---first allocate some memory for cndlop = 1:ncond sel{cndlop} = zeros(1,size(b{cndlop},2)); end - + for binlop = 1:length(numok) - if numok(binlop)>0, + if numok(binlop)>0 tmpmatmin = nan(ncond,nummax(binlop)); tmpmatmax = nan(ncond,nummax(binlop)); tmpmatminind = nan(ncond,nummax(binlop)); @@ -204,15 +208,15 @@ refavg = nanmean(tmpmatmin,2); refmin = mean(tmpmatmin(:,1:numok(binlop) ),2); refmax = mean(tmpmatmax(:,end-numok(binlop)+1:end),2); - + %---determine the amount of trials in this bin, so that for all conditions %it lies between the lowest possible and highest possible realisation ok = 0; lowok = 0; hiok = 0; cnt = 0; offset = zeros(1,ncond); - while ok==0, - if numok(binlop)>0, + while ok==0 + if numok(binlop)>0 [tmpref,refind] = min(refavg(minind{binlop})); - if any(refmin - tmpref > 0), + if any(refmin - tmpref > 0) numok(binlop) = numok(binlop) - 1; offset(minind{binlop}(refind)) = offset(minind{binlop}(refind)) + 1; %correction term tmpmatmin(minind{binlop}(refind),:) = [ tmpmatmin(minind{binlop}(refind),2:end) nan]; @@ -226,7 +230,7 @@ lowok = 1; end [tmpref,refind] = min(refavg(minind{binlop})); - if any(refmax - tmpref < 0), + if any(refmax - tmpref < 0) numok(binlop) = numok(binlop) - 1; tmpmatmax(minind{binlop}(refind),:) = [nan tmpmatmax(minind{binlop}(refind),1:end-1)]; %tmpmatmaxind(minind{binlop}(refind),:) = [nan tmpmatmaxind(minind{binlop}(refind),1:end-1)]; @@ -243,11 +247,11 @@ if cnt==100, ok = 1; end cnt = cnt+1; end - + %---this is now the average that should be approximated [tmpref,refind] = min(refavg(minind{binlop})); - - if numok(binlop)>0, + + if numok(binlop)>0 for cndlop = 1:ncond pnt = tmpmatmin(cndlop, 1:linearhisto(cndlop,binlop)) - tmpref; nrow = length(pnt)-numok(binlop)+1; @@ -261,17 +265,17 @@ if indvec(end)>length(cpnt), indvec = indvec-indvec(end)+length(cpnt); end tmpmat = zeros(nrow,length(pnt)); tmpmat(:, indvec ) = 1; - if length(unique(indvec))>1 || size(pntmat,2)>nrow, + if length(unique(indvec))>1 || size(pntmat,2)>nrow tmpmat(:, setdiff(1:length(pnt),indvec)) = eye(nrow); else tmpmat = eye(nrow); end %tmpmat = [ones(nrow,numok(binlop)-1) eye(nrow)]; %tmpmat = tmpmat(:,randperm(size(tmpmat,2))); - if cndlop~=minind{binlop}(refind), + if cndlop~=minind{binlop}(refind) m = nan(1,100); for rndlop = 1:100 - if rndlop<=12 || sum(diff(m(rndlop-11:rndlop-1))==0)<10, + if rndlop<=12 || sum(diff(m(rndlop-11:rndlop-1))==0)<10 dif = abs(sum(pntmat.*tmpmat,2)./numok(binlop)); [m(rndlop),ind] = min(dif); tmpvec = tmpmat(ind,:); @@ -294,7 +298,7 @@ end end end - + else %------stratify the easy way for cndlop = 1:ncond @@ -308,7 +312,7 @@ end end end - + %------create output output = input; for cndlop = 1:ncond @@ -316,141 +320,141 @@ end varargout{1} = output; varargout{2} = binaxis; - + end %if nchan>2 - + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % histogram_shift %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -elseif strcmp(cfg.method, 'histogram_shift'), - +elseif strcmp(cfg.method, 'histogram_shift') + tmpcfg = []; tmpcfg.method = 'histogram'; tmpcfg.equalbinavg = 'no'; - + nshift = size(input{1},1); ncond = length(input); - %if nchan~=2, error('number of trials ~= 2, do not know how to stratify'); end - + %if nchan~=2, ft_error('number of trials ~= 2, do not know how to stratify'); end + for k = 1:cfg.niter tmpinput = input; for cndlop = 1:ncond sel{cndlop} = floor(abs(rand(size(input{cndlop},2),1)-eps)*nshift)+1; tmpinput{cndlop} = input{cndlop}(sel{cndlop}+6.*[0:length(sel{cndlop})-1]')'; end - + [tmpoutput, binaxis] = stratify(tmpcfg, tmpinput{:}); - if k == 1, + if k == 1 bestoutput = tmpoutput; bestaxis = binaxis; bestok = sum(~isnan(tmpoutput{1})); end - - numok = sum(~isnan(tmpoutput{1})) + + numok = sum(~isnan(tmpoutput{1})); [bestok, ind] = max([bestok numok]); - if ind>1, + if ind>1 bestoutput = tmpoutput; bestaxis = binaxis; end end - + %------create output varargout{1} = bestoutput; varargout{2} = bestaxis; varargout{3} = sel; - + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % splitxxxx %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -elseif ~isempty(strfind(cfg.method, 'split')), +elseif ~isempty(strfind(cfg.method, 'split')) ncond = length(varargin); - if ~size(varargin{1},1)==2, error('two channels required'); end + if ~size(varargin{1},1)==2, ft_error('two channels required'); end m1 = mean(varargin{1},2); m2 = mean(varargin{2},2); sel{1} = zeros(1,size(varargin{1},2)); sel{2} = zeros(1,size(varargin{2},2)); - + sel{1}(find(varargin{1}(1,:) <= m1(1) & varargin{1}(2,:) <= m1(2))) = 1; sel{1}(find(varargin{1}(1,:) <= m1(1) & varargin{1}(2,:) > m1(2))) = 2; sel{1}(find(varargin{1}(1,:) > m1(1) & varargin{1}(2,:) <= m1(2))) = 3; sel{1}(find(varargin{1}(1,:) > m1(1) & varargin{1}(2,:) > m1(2))) = 4; - + sel{2}(find(varargin{2}(1,:) <= m2(1) & varargin{2}(2,:) <= m2(2))) = 1; sel{2}(find(varargin{2}(1,:) <= m2(1) & varargin{2}(2,:) > m2(2))) = 2; sel{2}(find(varargin{2}(1,:) > m2(1) & varargin{2}(2,:) <= m2(2))) = 3; sel{2}(find(varargin{2}(1,:) > m2(1) & varargin{2}(2,:) > m2(2))) = 4; - - if ~isempty(strfind(cfg.method, 'hilo')), + + if ~isempty(strfind(cfg.method, 'hilo')) sel{1} = sel{1} == 4; sel{2} = sel{2} == 1; - elseif ~isempty(strfind(cfg.method, 'lohi')), + elseif ~isempty(strfind(cfg.method, 'lohi')) sel{1} = sel{1} == 1; sel{2} = sel{2} == 4; - elseif ~isempty(strfind(cfg.method, 'lolo')), + elseif ~isempty(strfind(cfg.method, 'lolo')) sel{1} = sel{1} == 1; sel{2} = sel{2} == 1; - elseif ~isempty(strfind(cfg.method, 'hihi')), + elseif ~isempty(strfind(cfg.method, 'hihi')) sel{1} = sel{1} == 4; sel{2} = sel{2} == 4; end - + %------create output output = input; for cndlop = 1:ncond output{cndlop}(:,find(sel{cndlop}==0))=nan; end varargout{1} = output; - + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % equatespike %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% elseif strcmp(cfg.method, 'equatespike') if length(input)~=2 - error('this requires two conditions as input'); + ft_error('this requires two conditions as input'); end datA = input{1}; datB = input{2}; - + ntrlA = length(datA); ntrlB = length(datB); nchanA = size(datA{1},1); nchanB = size(datB{1},1); nsmpA = size(datA{1},2); nsmpB = size(datB{1},2); - + if (ntrlA~=ntrlB) - error('number of trials should be the same in each condition'); + ft_error('number of trials should be the same in each condition'); end - + if (nchanA~=nchanB) - error('number of channels should be the same in each condition'); + ft_error('number of channels should be the same in each condition'); end - + if (nsmpA~=nsmpB) - error('number of samples should be the same in each condition'); + ft_error('number of samples should be the same in each condition'); end - + for i=1:ntrlA if size(datA{i},2)~=nsmpA - error('number of samples should be the same in each trial'); + ft_error('number of samples should be the same in each trial'); end end - + for i=1:ntrlB if size(datB{i},2)~=nsmpB - error('number of samples should be the same in each trial'); + ft_error('number of samples should be the same in each trial'); end end - + nchan = nchanA; % the same for each condition ntrl = ntrlA; % the same for each condition - + if isequal(cfg.channel, 'all') chansel = 1:nchan; else chansel = cfg.channel; end - + % count the number of spikes in each trial and channel numA = zeros(ntrlA, nchanA); numB = zeros(ntrlB, nchanB); @@ -462,7 +466,7 @@ end numA(:,setdiff(1:nchan, chansel)) = 0; numB(:,setdiff(1:nchan, chansel)) = 0; - + fprintf('average (over trials) of the number of spikes per channel in condition A: '); fprintf('%.0f ', mean(numA,1)); fprintf('\n'); @@ -475,13 +479,13 @@ fprintf('standard deviation (over trials) of the number of spikes per channel in condition B: '); fprintf('%.0f ', std(numB,1)); fprintf('\n'); - + if strcmp(cfg.pairtrials, 'linkage') % concatenate the spike numbers for both conditions num = [numA; numB]; % compute the distance between all possible pairs y = pdist(num, 'cityblock'); - + % remove the connections between all pairs within a single condition y = squareform(y); sel = 1:ntrlA; @@ -492,16 +496,16 @@ y(i,i) = 0; end y = squareform(y); - + % determine the pairs that are the closest z = linkage(y, cfg.linkage); - + if any(any(z(1:ntrl,:)>2*ntrl)) - error('trial pairs are not correct after hierarchical clustering'); + ft_error('trial pairs are not correct after hierarchical clustering'); else fprintf('remaining distance after hierarchical clustering is %d\n', sum(z(1:ntrl,3))); end - + % ensure that the order of the pairs is always correct z = z(1:ntrl,:); for i=1:ntrl @@ -509,7 +513,7 @@ z(i,1:2) = z(i,2:1); end end - + % figure % hold on % for i=1:ntrl @@ -517,27 +521,27 @@ % y = [num(z(i,1),2) num(z(i,2),2)]; % plot(x, y, '.-'); % end - + indxA = z(:,1); indxB = z(:,2) - ntrlA; dist = z(:,3); - + elseif strcmp(cfg.pairtrials, 'spikesort') [srtA, srtB, indxA, indxB] = spikesort(numA, numB, 'presort', 'global'); dist = sum(abs(numA(indxA,:)-numB(indxB,:)),2); - + elseif strcmp(cfg.pairtrials, 'no') % no sorting to pair the trials is required indxA = 1:ntrlA; indxB = 1:ntrlA; dist = sum(abs(numA(indxA,:)-numB(indxB,:)),2); - + else - error('incorrect value for cfg.pairtrials'); + ft_error('incorrect value for cfg.pairtrials'); end % if pairtrials - + fprintf('removing %d spikes from a total of %d spikes\n', sum(dist), sum(sum(numA))+sum(sum(numB))); - + for i=1:ntrl delta = numA(indxA(i),:) - numB(indxB(i),:); outA{i} = datA{indxA(i)}; @@ -585,24 +589,24 @@ end % for nchan end % for ntrl varargout{1} = {outA, outB}; - + elseif strcmp(cfg.method, 'lohi') %%%%%%%%%%%%%%%%% %experimental code working on single channel inputs (2) selecting the %lowest amplitude for input 1 and highest for input 2 %%%%%%%%%%%%%%%%% if length(varargin)~=2 - error('two input arguments with data required'); + ft_error('two input arguments with data required'); end if size(varargin{1},1)~=1 || size(varargin{2},1)~=1 - error('only one channel per input is allowed'); + ft_error('only one channel per input is allowed'); end if size(varargin{1},2)~=size(varargin{2},2) - error('the number of observations should be equal'); + ft_error('the number of observations should be equal'); end - - [srt1, ix1] = sort(input{1},'ascend'); - [srt2, ix2] = sort(input{2},'descend'); + + [srt1, ix1] = sort(input{1}, 'ascend'); + [srt2, ix2] = sort(input{2}, 'descend'); mx1 = -inf; mx2 = inf; cnt = 0; @@ -613,12 +617,12 @@ mx1 = mean(input{1}(sel)); mx2 = mean(input{2}(sel)); end - + varargout{1} = input{1}; varargout{2} = input{2}; - + sel = setdiff(1:numel(srt1), sel); varargout{1}(sel) = nan; varargout{2}(sel) = nan; - + end % cfg.method diff --git a/external/fieldtrip/ft_surfacerealign.m b/external/fieldtrip/ft_surfacerealign.m deleted file mode 100644 index bb30081f..00000000 --- a/external/fieldtrip/ft_surfacerealign.m +++ /dev/null @@ -1,73 +0,0 @@ -function [surface_original] = ft_surfacerealign(cfg, surface_original) -% FT_SURFACEREALIGN realigns surface -% FIDUCIAL - You can apply a rigid body realignment based on three fiducial -% locations. After realigning, the fiducials in the input surface -% (typically nose, left and right ear) are along the same axes as the -% fiducials in the template surface set. - -% cfg.method = string representing the method for aligning the surface -% 'fiducial' realign using three fiducials -% (e.g. NAS, LPA and RPA) -% -% If you want to realign the surface using fiducials, the target and the -% objective have to contain the three fiducials which relate , e.g. -% cfg.target.elecpos(1,:) = [110 0 0] % location of the nose -% cfg.target.elecpos(2,:) = [0 90 0] % location of the left ear -% cfg.target.elecpos(3,:) = [0 -90 0] % location of the right ear -% cfg.target.label = {'NAS', 'LPA', 'RPA'} -% cfg.objective.elecpos(1,:) = [0 -110 0] % location of the nose -% cfg.objective.elecpos(2,:) = [90 0 0] % location of the left ear -% cfg.objective.elecpos(3,:) = [-90 0 0] % location of the right ear -% cfg.objective.label = {'NAS', 'LPA', 'RPA'} -% -% Copyright (C) 2016, Simon Homoelle -% -% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org -% for the documentation and details. -% -% FieldTrip is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. -% -% FieldTrip is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with FieldTrip. If not, see . -% - -% these are used by the ft_preamble/ft_postamble function and scripts -ft_revision = '$Id$'; -ft_nargin = nargin; -ft_nargout = nargout; - -% do the general setup of the function -ft_defaults -ft_preamble init -ft_preamble debug -ft_preamble loadvar surface_original -ft_preamble provenance surface_original -ft_preamble trackconfig - -% the ft_abort variable is set to true or false in ft_preamble_init -if ft_abort - return -end - -usefiducial = isfield(cfg, 'target') & isfield(cfg, 'objective') & strcmp(cfg.method,'fiducial'); - -if usefiducial - cfg.elec = cfg.objective; - %use ft_electroderealign for realign the surface - surface_realigned = ft_electroderealign(cfg); - %use transformation obtained by ft_electroderealign - transform = [surface_original.pos, ones(length(surface_original.pos),1)]*surface_realigned.homogeneous'; - surface_original.pos = transform(:,1:3); - surface_original.cfg = surface_realigned.cfg; -else - error('Cannot perform ft_surfacerealign. Please read help ft_surfacerealign, and check your cfg') -end - diff --git a/external/fieldtrip/ft_timelockanalysis.m b/external/fieldtrip/ft_timelockanalysis.m index 041c2889..58a7968c 100644 --- a/external/fieldtrip/ft_timelockanalysis.m +++ b/external/fieldtrip/ft_timelockanalysis.m @@ -150,8 +150,8 @@ nchan = length(data.label); % number of channels numsamples = zeros(ntrial,1); % number of selected samples in each trial, is determined later -if ntrial==0, error('Number of trials selected in data is zero'); end -if nchan==0, error('Number of channels selected in data is zero'); end +if ntrial==0, ft_error('Number of trials selected in data is zero'); end +if nchan==0, ft_error('Number of channels selected in data is zero'); end % determine the duration of each trial begsamplatency = zeros(1,ntrial); @@ -177,7 +177,7 @@ switch cfg.vartrllength case 0 if ~all(minperlength==maxperlength) - error('data has variable trial lengths, you specified not to accept that'); + ft_error('data has variable trial lengths, you specified not to accept that'); end case 1 if all(minperlength==maxperlength) @@ -188,12 +188,12 @@ disp('processing and keeping variable length single trials'); end otherwise - error('unknown value for vartrllength'); + ft_error('unknown value for vartrllength'); end if strcmp(cfg.covariance, 'yes') if ~isfield(cfg, 'covariancewindow') - warning('the option cfg.covariancewindow is not specified, taking all time points'); + ft_warning('the option cfg.covariancewindow is not specified, taking all time points'); cfg.covariancewindow = latency; end if ischar(cfg.covariancewindow) @@ -205,11 +205,11 @@ case 'all' cfg.covariancewindow = latency; case 'minperlength' - error('cfg.covariancewindow = ''minperlength'' is not supported anymore'); + ft_error('cfg.covariancewindow = ''minperlength'' is not supported anymore'); case 'maxperlength' - error('cfg.covariancewindow = ''maxperlength'' is not supported anymore'); + ft_error('cfg.covariancewindow = ''maxperlength'' is not supported anymore'); otherwise - error('unsupported specification of cfg.covariancewindow'); + ft_error('unsupported specification of cfg.covariancewindow'); end end end @@ -249,7 +249,7 @@ % elseif strcmp(cfg.covariance,'yes') && (begsamplatency(i)>cfg.covariancewindow(1) || endsamplatency(i)cfg.covariancewindow(1) || endsamplatency(i) 1 && ~isfield(cfg, 'dataname') - cfg.dataname = {inputname(2)}; - for k = 3:nargin - cfg.dataname{end+1} = inputname(k); +if nargin>1 + if ~isfield(cfg, 'dataname') + cfg.dataname = []; + for k = 2:nargin + if isstruct(varargin{k-1}) + if ~isempty(inputname(k)) + cfg.dataname{k-1} = inputname(k); + else + cfg.dataname{k-1} = ['data' num2str(k-1,'%02d')]; + end + end + end end +else % data provided through cfg.inputfile + cfg.dataname = cfg.inputfile; end % prepare the layout, this should be done only once -cfg.layout = ft_prepare_layout(cfg, varargin{1}); +tmpcfg = removefields(cfg, 'inputfile'); +cfg.layout = ft_prepare_layout(tmpcfg, varargin{1}); % call the common function that is shared between ft_topoplotER and ft_topoplotTFR cfg = topoplot_common(cfg, varargin{:}); diff --git a/external/fieldtrip/ft_topoplotIC.m b/external/fieldtrip/ft_topoplotIC.m index f2acdaa2..3426c1de 100644 --- a/external/fieldtrip/ft_topoplotIC.m +++ b/external/fieldtrip/ft_topoplotIC.m @@ -121,20 +121,25 @@ % this will remove all time-series information comp = ft_checkdata(comp, 'datatype', 'comp'); +% set the config defaults +cfg.title = ft_getopt(cfg, 'title', 'auto'); +cfg.parameter = ft_getopt(cfg, 'parameter', 'topo'); % needed in topoplot_common + % check if the input cfg is valid for this function cfg = ft_checkconfig(cfg, 'required', 'component'); - -% set the config defaults -cfg.title = ft_getopt(cfg, 'title', 'auto'); +cfg = ft_checkconfig(cfg, 'allowedval', {'parameter' 'topo'}); % interactive plotting doesn't work for chan_comp dimord. if isfield(cfg, 'interactive') && strcmp(cfg.interactive, 'yes') - warning('Interactive plotting is not supported.'); + ft_warning('Interactive plotting is not supported.'); end cfg.interactive = 'no'; % prepare the layout, this should be done only once -cfg.layout = ft_prepare_layout(cfg, comp); +tmpcfg = removefields(cfg, 'inputfile'); +tmpcomp.label = comp.topolabel; % the input to ft_prepare_layout needs at least a data.label field +cfg.layout = ft_prepare_layout(tmpcfg, tmpcomp); +clear tmpcomp; % don't show the callinfo for each separate component cfg.showcallinfo = 'no'; diff --git a/external/fieldtrip/ft_topoplotTFR.m b/external/fieldtrip/ft_topoplotTFR.m index b475ccbd..85cb073c 100644 --- a/external/fieldtrip/ft_topoplotTFR.m +++ b/external/fieldtrip/ft_topoplotTFR.m @@ -10,14 +10,12 @@ % The input freq structrure should contain a time-resolved power or % coherence spectrum from FT_FREQANALYSIS or FT_FREQDESCRIPTIVES. % -% The configuration can have the following parameters: -% cfg.parameter = field that contains the data to be plotted as color -% 'avg', 'powspctrm' or 'cohspctrm' (default depends on data.dimord) -% cfg.maskparameter = field in the data to be used for masking of -% data. Values between 0 and 1, 0 = transparent -% cfg.xlim = selection boundaries over first dimension in data (e.g., time) -% 'maxmin' or [xmin xmax] (default = 'maxmin') -% cfg.zlim = plotting limits for color dimension, 'maxmin', 'maxabs', 'zeromax', 'minzero', or [zmin zmax] (default = 'maxmin') +% The configuration can have the following parameters +% cfg.parameter = field that contains the data to be plotted as color, for example 'avg', 'powspctrm' or 'cohspctrm' (default is automatic) +% cfg.maskparameter = field in the data to be used for masking of data. It should have alues between 0 and 1, where 0 corresponds to transparent. +% cfg.xlim = limit for 1st dimension in data (e.g., time), can be 'maxmin' or [xmin xmax] (default = 'maxmin') +% cfg.ylim = limit for 2nd dimension in data (e.g., freq), can be 'maxmin' or [ymin ymax] (default = 'maxmin') +% cfg.zlim = limits for color dimension, 'maxmin', 'maxabs', 'zeromax', 'minzero', or [zmin zmax] (default = 'maxmin') % cfg.channel = Nx1 cell-array with selection of channels (default = 'all'), see FT_CHANNELSELECTION for details % cfg.refchannel = name of reference channel for visualising connectivity, can be 'gui' % cfg.baseline = 'yes','no' or [time1 time2] (default = 'no'), see FT_TIMELOCKBASELINE or FT_FREQBASELINE @@ -29,13 +27,13 @@ % cfg.markercolor = channel marker color (default = [0 0 0] (black)) % cfg.markersize = channel marker size (default = 2) % cfg.markerfontsize = font size of channel labels (default = 8 pt) -% cfg.highlight = 'on', 'labels', 'numbers', 'off' +% cfg.highlight = 'off', 'on', 'labels', 'numbers' % cfg.highlightchannel = Nx1 cell-array with selection of channels, or vector containing channel indices see FT_CHANNELSELECTION % cfg.highlightsymbol = highlight marker symbol (default = 'o') % cfg.highlightcolor = highlight marker color (default = [0 0 0] (black)) % cfg.highlightsize = highlight marker size (default = 6) % cfg.highlightfontsize = highlight marker size (default = 8) -% cfg.hotkeys = enables hotkeys (up/down arrows) for dynamic colorbar adjustment +% cfg.hotkeys = enables hotkeys (pageup/pagedown/m) for dynamic zoom and translation (ctrl+) of the color limits % cfg.colorbar = 'yes' % 'no' (default) % 'North' inside plot box near top @@ -58,10 +56,11 @@ % 'blank' only the head shape % cfg.gridscale = scaling grid size (default = 67) % determines resolution of figure -% cfg.shading = 'flat' 'interp' (default = 'flat') -% cfg.comment = string 'no' 'auto' or 'xlim' (default = 'auto') -% 'auto': date, xparam and parameter limits are printed +% cfg.shading = 'flat' or 'interp' (default = 'flat') +% cfg.comment = 'no', 'auto' or 'xlim' (default = 'auto') +% 'auto': date, xparam, yparam and parameter limits are printed % 'xlim': only xparam limits are printed +% 'ylim': only yparam limits are printed % cfg.commentpos = string or two numbers, position of comment (default 'leftbottom') % 'lefttop' 'leftbottom' 'middletop' 'middlebottom' 'righttop' 'rightbottom' % 'title' to place comment as title @@ -139,7 +138,7 @@ % Other options: % cfg.labeloffset (offset of labels to their marker, default = 0.005) -% Copyright (C) 2005-2011, F.C. Donders Centre +% Copyright (C) 2005-2017, F.C. Donders Centre % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -159,6 +158,17 @@ % % $Id$ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% DEVELOPERS NOTE: This code is organized in a similar fashion for multiplot/singleplot/topoplot +% and for ER/TFR and should remain consistent over those 6 functions. +% Section 1: general cfg handling that is independent from the data +% Section 2: data handling, this also includes converting bivariate (chan_chan and chancmb) into univariate data +% Section 3: cfg handling that depends on the data +% Section 4: actual plotting +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Section 1: general cfg handling that is independent from the data + % these are used by the ft_preamble/ft_postamble function and scripts ft_revision = '$Id$'; ft_nargin = nargin; @@ -178,18 +188,29 @@ end % make sure figure window titles are labeled appropriately, pass this onto the actual -% plotting function if we don't specify this, the window will be called +% plotting function. if we don't specify this, the window will be called % 'ft_topoplotTFR', which is confusing to the user cfg.funcname = mfilename; -if nargin > 1 - cfg.dataname = {inputname(2)}; - for k = 3:nargin - cfg.dataname{end+1} = inputname(k); +if nargin>1 + if ~isfield(cfg, 'dataname') + cfg.dataname = []; + for k = 2:nargin + if isstruct(varargin{k-1}) + if ~isempty(inputname(k)) + cfg.dataname{k-1} = inputname(k); + else + cfg.dataname{k-1} = ['data' num2str(k-1,'%02d')]; + end + end + end end +else % data provided through cfg.inputfile + cfg.dataname = cfg.inputfile; end % prepare the layout, this should be done only once -cfg.layout = ft_prepare_layout(cfg, varargin{:}); +tmpcfg = removefields(cfg, {'inputfile', 'style'}); +cfg.layout = ft_prepare_layout(tmpcfg, varargin{1}); % call the common function that is shared between ft_topoplotER and ft_topoplotTFR [cfg] = topoplot_common(cfg, varargin{:}); diff --git a/external/fieldtrip/ft_volumebiascorrect.m b/external/fieldtrip/ft_volumebiascorrect.m new file mode 100644 index 00000000..23da2114 --- /dev/null +++ b/external/fieldtrip/ft_volumebiascorrect.m @@ -0,0 +1,174 @@ +function mri_unbias = ft_volumebiascorrect(cfg, mri) + +% FT_VOLUMEBIASCORRECT corrects the image inhomogeneity bias in an anatomical MRI +% +% Use as +% mri_unbias = ft_volumebiascorrect(cfg, mri) +% where the input mri should be a single anatomical volume that was for example read with +% FT_READ_MRI. +% +% The configuration structure can contain +% cfg.spmversion = string, 'spm8', 'spm12' (default = 'spm8') +% cfg.opts = struct, containing spmversion specific options. +% See the code below and the SPM-documentation for +% more information. +% +% See also FT_VOLUMEREALIGN FT_VOLUMESEGMENT FT_VOLUMENORMALISE + +ft_revision = '$Id$'; +ft_nargin = nargin; +ft_nargout = nargout; + +% do the general setup of the function + +% the ft_preamble function works by calling a number of scripts from +% fieldtrip/utility/private that are able to modify the local workspace + +ft_defaults % this ensures that the path is correct and that the ft_defaults global variable is available +ft_preamble init +ft_preamble debug +ft_preamble loadvar mri +ft_preamble provenance mri +ft_preamble trackconfig + +if ft_abort + % do not continue function execution in case the outputfile is present and the user indicated to keep it + return +end + +% ensure that the input data is valid for this function +mri = ft_checkdata(mri, 'datatype', {'volume'}); + +% set the defaults +cfg.spmversion = ft_getopt(cfg, 'spmversion', 'spm12'); +cfg.keepintermediate = ft_getopt(cfg, 'keepintermediate', 'no'); +cfg.opts = ft_getopt(cfg, 'opts'); + +if ~isfield(cfg, 'intermediatename') + cfg.intermediatename = tempname; +end + +% check that the preferred SPM version is on the path +ft_hastoolbox(cfg.spmversion, 1); + +% check whether the input has an anatomy +if ~isfield(mri, 'anatomy') + ft_error('no anatomical information available, this is required for bias correction'); +end + +% do an approximate alignment +mri_acpc = ft_convert_coordsys(mri, 'acpc'); + +% flip and permute the 3D volume itself, so that the voxel and +% headcoordinates approximately correspond this improves the convergence +% of the segmentation algorithm +[mri_acpc, permutevec, flipflags] = align_ijk2xyz(mri_acpc); + +% create an spm-compatible file for the anatomical volume data +V = ft_write_mri([cfg.intermediatename '_anatomy.nii'], mri_acpc.anatomy, 'transform', mri_acpc.transform, 'spmversion', cfg.spmversion, 'dataformat', 'nifti_spm'); + +% get the options from hte cfg +opts = cfg.opts; +switch cfg.spmversion + case 'spm8' + + opts.nbins = ft_getopt(opts, 'nbins', 256); + opts.reg = ft_getopt(opts, 'reg', 0.01); + opts.cutoff = ft_getopt(opts, 'cutoff', 30); + opts.niter = ft_getopt(opts, 'niter', 128); + + T = spm_bias_estimate(V, opts); + VO = spm_bias_apply(V,T); + + mri_unbias = keepfields(mri, {'coordsys', 'dim', 'transform', 'unit', 'inside'}); + mri_unbias.anatomy = VO.dat.*scale; + + % if strcmp(cfg.keepintermediate, 'no') + % % remove the intermediate files + % for flop=1:length(files) + % [p, f, x] = fileparts(files{flop}); + % delete(fullfile(p, [f, '.*'])); + % [p, f, x] = fileparts(wfiles{flop}); + % delete(fullfile(p, [f, '.*'])); + % end + % end + case 'spm12' + if ~isfield(cfg, 'tpm') || isempty(cfg.tpm) + cfg.tpm = fullfile(spm('dir'),'tpm','TPM.nii'); + end + + % create the structure that is required for spm_preproc8 + opts.image = V; + opts.tpm = spm_load_priors8(cfg.tpm); + opts.biasreg = ft_getopt(opts, 'biasreg', 0.0001); + opts.biasfwhm = ft_getopt(opts, 'biasfwhm', 60); + opts.lkp = ft_getopt(opts, 'lkp', [1 1 2 2 3 3 4 4 4 5 5 5 5 6 6 ]); + opts.reg = ft_getopt(opts, 'reg', [0 0.001 0.5 0.05 0.2]); + opts.samp = ft_getopt(opts, 'samp', 3); + opts.fwhm = ft_getopt(opts, 'fwhm', 1); + + Affine = spm_maff8(opts.image(1),3,32,opts.tpm,eye(4),'mni'); + Affine = spm_maff8(opts.image(1),3, 1,opts.tpm,Affine,'mni'); + opts.Affine = Affine; + + % run the segmentation + fprintf('Estimating the bias field etc..\n'); + p = spm_preproc8(opts); + + % this writes the 'native' segmentations + spm_preproc_write8(p, [ones(6,1) zeros(6,3)], [0 1], [0 1], 0, 0, nan(2,3), nan); + + + [pathname,name,ext] = fileparts([cfg.intermediatename '_anatomy.nii']); + filename = fullfile(pathname, ['m' name ext]); + + VO = spm_vol(filename); + VO.dat = spm_read_vols(VO); + + tmp = zeros([size(VO.dat) 6]); + for k = 1:6 + cfilename = fullfile(pathname, ['c' num2str(k) name ext]); + Vtmp = spm_vol(cfilename); + tmp(:,:,:,k) = spm_read_vols(Vtmp); + end + tmp_tc = false(size(tmp)); + for k = 1:6 + notk = setdiff(1:6,k); + for m = notk(:)' + tmp_tc(:,:,:,k) = tmp(:,:,:,m)3, +if length(source.dim)>3 downsample.dim = [downsample.dim source.dim(4:end)]; end @@ -115,15 +116,9 @@ downsample = grid2transform(downsample); % smooth functional parameters, excluding anatomy and inside -if isfield(cfg, 'smooth') && ~strcmp(cfg.smooth, 'no'), - % check that SPM is on the path, try to add the preferred version - if strcmpi(cfg.spmversion, 'spm2'), - ft_hastoolbox('SPM2',1); - elseif strcmpi(cfg.spmversion, 'spm8'), - ft_hastoolbox('SPM8',1); - elseif strcmpi(cfg.spmversion, 'spm12'), - ft_hastoolbox('SPM12',1); - end +if isfield(cfg, 'smooth') && ~strcmp(cfg.smooth, 'no') + % check that the preferred SPM version is on the path + ft_hastoolbox(cfg.spmversion, 1); for j = 1:length(cfg.parameter) if strcmp(cfg.parameter{j}, 'inside') diff --git a/external/fieldtrip/ft_volumelookup.m b/external/fieldtrip/ft_volumelookup.m index c7604eb0..dbbc5412 100644 --- a/external/fieldtrip/ft_volumelookup.m +++ b/external/fieldtrip/ft_volumelookup.m @@ -1,18 +1,17 @@ function [output] = ft_volumelookup(cfg, volume) -% FT_VOLUMELOOKUP can be used in to combine an anatomical or functional -% atlas with source reconstruction. You can use it for forward and reverse -% lookup. +% FT_VOLUMELOOKUP can be used in to combine an anatomical or functional atlas with +% the source reconstruction results. You can use it for forward and reverse lookup. % -% Given the anatomical or functional label, it looks up the locations and -% creates a mask (as a binary volume) based on the label, or creates a -% sphere or box around a point of interest. In this case the function is to -% be used as: +% Given the ROI as anatomical or functional label, it looks up the locations and +% creates a mask (as a binary volume) based on the label. Given the ROI as point in +% the brain, it creates a sphere or box around that point. In these two case the +% function is to be used as: % mask = ft_volumelookup(cfg, volume) % -% Given a binary volume that indicates a region of interest, it looks up -% the corresponding anatomical or functional labels from a given atlas. In -% this case the function is to be used as follows: +% Given a binary volume that indicates a region of interest or a point of +% interest, it looks up the corresponding anatomical or functional labels +% from the atlas. In this case the function is to be used as: % labels = ft_volumelookup(cfg, volume) % % In both cases the input volume can be: @@ -21,44 +20,53 @@ % stat is the output of FT_SOURCESTATISTICS % % The configuration options for a mask according to an atlas: -% cfg.inputcoord = 'mni' or 'tal', coordinate system of the mri/source/stat -% cfg.atlas = string, filename of atlas to use, either the AFNI -% brik file that is available from http://afni.nimh.nih.gov/afni/doc/misc/ttatlas_tlrc, -% or the WFU atlasses available from http://fmri.wfubmc.edu. see FT_READ_ATLAS -% cfg.roi = string or cell of strings, region(s) of interest from anatomical atlas +% cfg.inputcoord = 'mni' or 'tal', coordinate system of the mri/source/stat +% cfg.atlas = string, filename of atlas to use, see FT_READ_ATLAS +% cfg.roi = string or cell-array of strings, region(s) of interest from anatomical atlas % % The configuration options for a spherical/box mask around a point of interest: -% cfg.roi = Nx3 vector, coordinates of the points of interest -% cfg.sphere = radius of each sphere in cm/mm dep on unit of input -% cfg.box = Nx3 vector, size of each box in cm/mm dep on unit of input -% cfg.round2nearestvoxel = 'yes' or 'no' (default = 'no'), voxel closest to point of interest is calculated +% cfg.roi = Nx3 vector, coordinates of the points of interest +% cfg.sphere = radius of each sphere in cm/mm dep on unit of input +% cfg.box = Nx3 vector, size of each box in cm/mm dep on unit of input +% cfg.round2nearestvoxel = 'yes' or 'no' (default = 'no'), voxel closest to point of interest is calculated % and box/sphere is centered around coordinates of that voxel % % The configuration options for labels from a mask: -% cfg.inputcoord = 'mni' or 'tal', coordinate system of the mri/source/stat -% cfg.atlas = string, filename of atlas to use, either the AFNI -% brik file that is available from http://afni.nimh.nih.gov/afni/doc/misc/afni_ttatlas/, -% or the WFU atlasses available from http://fmri.wfubmc.edu. see FT_READ_ATLAS -% cfg.maskparameter = string, field in volume to be lookedup, data in field should be logical -% cfg.maxqueryrange = number, should be 1, 3, 5 (default = 1) +% cfg.inputcoord = 'mni' or 'tal', coordinate system of the mri/source/stat +% cfg.atlas = string, filename of atlas to use, see FT_READ_ATLAS +% cfg.maskparameter = string, field in volume to be looked up, data in field should be logical +% cfg.maxqueryrange = number, should be odd (default = 1) % -% The label output has a field "names", a field "count" and a field "usedqueryrange" +% The configuration options for labels around a point of interest: +% cfg.output = 'label' +% cfg.roi = Nx3 vector, coordinates of the points of interest +% cfg.inputcoord = 'mni' or 'tal', coordinate system of the mri/source/stat +% cfg.atlas = string, filename of atlas to use, see FT_READ_ATLAS +% cfg.maxqueryrange = number, should be 1, 3, 5 (default = 1) +% cfg.querymethod = 'sphere' searches voxels around the roi in a sphere (default) +% = 'cube' searches voxels around the roi in a sphere +% cfg.round2nearestvoxel = 'yes' or 'no', voxel closest to point of interest is calculated (default = 'yes') +% +% The label output has a field "names", a field "count" and a field "usedqueryrange". % To get a list of areas of the given mask you can do for instance: % [tmp ind] = sort(labels.count,1,'descend'); % sel = find(tmp); % for j = 1:length(sel) % found_areas{j,1} = [num2str(labels.count(ind(j))) ': ' labels.name{ind(j)}]; % end -% in found_areas you can then see how many times which labels are found -% NB in the AFNI brick one location can have 2 labels! +% In the "found_areas" variable you can then see how many times which labels are +% found. Note that in the AFNI brick one location can have 2 labels. % % Dependent on the input coordinates and the coordinates of the atlas, the % input MRI is transformed betweem MNI and Talairach-Tournoux coordinates % See http://www.mrc-cbu.cam.ac.uk/Imaging/Common/mnispace.shtml for more details. % +% See http://www.fieldtriptoolbox.org/template/atlas for a list of templates and +% atlasses that are included in the FieldTrip release. +% % See also FT_READ_ATLAS, FT_SOURCEPLOT -% Copyright (C) 2008-2013, Robert Oostenveld, Ingrid Nieuwenhuis +% Copyright (C) 2008-2017, Robert Oostenveld, Ingrid Nieuwenhuis % Copyright (C) 2013, Jan-Mathijs Schoffelen % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org @@ -101,48 +109,53 @@ % the checking of the input data is done further down cfg.maxqueryrange = ft_getopt(cfg,'maxqueryrange', 1); +cfg.output = ft_getopt(cfg,'output', []); % in future, cfg.output could be extended to support both 'label' and 'mask' roi2mask = 0; mask2label = 0; -if isfield(cfg, 'roi'); +roi2label = 0; +if isfield(cfg, 'roi') && strcmp(cfg.output, 'label') + roi2label = 1; +elseif isfield(cfg, 'roi') roi2mask = 1; elseif isfield(cfg, 'maskparameter') mask2label = 1; else - error('either specify cfg.roi, or cfg.maskparameter') + ft_error('you should either specify cfg.roi, or cfg.maskparameter') end if roi2mask % only for volume data volume = ft_checkdata(volume, 'datatype', 'volume'); - + cfg.round2nearestvoxel = ft_getopt(cfg, 'round2nearestvoxel', 'no'); - + isatlas = iscell(cfg.roi) || ischar(cfg.roi); ispoi = isnumeric(cfg.roi); if isatlas+ispoi ~= 1 - error('do not understand cfg.roi') + ft_error('do not understand cfg.roi') end - + if isatlas - ft_checkconfig(cfg, 'forbidden', {'sphere' 'box'}, ... - 'required', {'atlas' 'inputcoord'}); + ft_checkconfig(cfg, 'forbidden', {'sphere', 'box'}, 'required', {'atlas', 'inputcoord'}); elseif ispoi ft_checkconfig(cfg, 'forbidden', {'atlas' 'inputcoord'}); if isempty(ft_getopt(cfg, 'sphere')) && isempty(ft_getopt(cfg, 'box')) - % either needs to be there - error('either specify cfg.sphere or cfg.box') + ft_error('you should either specify cfg.sphere or cfg.box') end end - -elseif mask2label + +elseif mask2label || roi2label % convert to source representation (easier to work with) volume = ft_checkdata(volume, 'datatype', 'source'); - ft_checkconfig(cfg, 'required', {'atlas' 'inputcoord'}); - - if isempty(intersect(cfg.maxqueryrange, [1 3 5])) - error('incorrect query range, should be one of [1 3 5]'); + ft_checkconfig(cfg, 'required', {'atlas', 'inputcoord'}); + + if isempty(intersect(cfg.maxqueryrange, 1:2:cfg.maxqueryrange)) + ft_error('incorrect query range, should be an odd number'); end + + cfg.round2nearestvoxel = ft_getopt(cfg, 'round2nearestvoxel', 'yes'); + cfg.querymethod = ft_getopt(cfg, 'querymethod', 'sphere'); end @@ -156,9 +169,9 @@ ijk = [I(:) J(:) K(:) ones(prod(dim),1)]'; % determine location of each anatomical voxel in head coordinates xyz = volume.transform * ijk; % note that this is 4xN - + if isatlas - if ischar(cfg.atlas), + if ischar(cfg.atlas) % assume it to represent a filename atlas = ft_read_atlas(cfg.atlas); else @@ -166,7 +179,7 @@ % into a config object atlas = struct(cfg.atlas); end - + % determine which field(s) to use to look up the labels, % and whether these are boolean or indexed fn = fieldnames(atlas); @@ -188,12 +201,12 @@ fn = fn(isboolean); isindexed = 0; end - + if ischar(cfg.roi) cfg.roi = {cfg.roi}; end - - if isindexed, + + if isindexed sel = zeros(0,2); for m = 1:length(fn) for i = 1:length(cfg.roi) @@ -202,13 +215,13 @@ end end fprintf('found %d matching anatomical labels\n', size(sel,1)); - + % this is to accommodate for multiple parcellations: % the brick refers to the parcellationname % the value refers to the value within the given parcellation brick = sel(:,2); value = sel(:,1); - + % convert between MNI head coordinates and TAL head coordinates % coordinates should be expressed compatible with the atlas if strcmp(cfg.inputcoord, 'mni') && strcmp(atlas.coordsys, 'tal') @@ -220,47 +233,47 @@ elseif strcmp(cfg.inputcoord, 'tal') && strcmp(atlas.coordsys, 'mni') xyz(1:3,:) = tal2mni(xyz(1:3,:)); elseif ~strcmp(cfg.inputcoord, atlas.coordsys) - error('there is a mismatch between the coordinate system in the atlas and the coordinate system in the data, which cannot be resolved'); + ft_error('there is a mismatch between the coordinate system in the atlas and the coordinate system in the data, which cannot be resolved'); end - + % determine location of each anatomical voxel in atlas voxel coordinates ijk = atlas.transform \ xyz; ijk = round(ijk(1:3,:))'; - + inside_vol = ijk(:,1)>=1 & ijk(:,1)<=atlas.dim(1) & ... ijk(:,2)>=1 & ijk(:,2)<=atlas.dim(2) & ... ijk(:,3)>=1 & ijk(:,3)<=atlas.dim(3); inside_vol = find(inside_vol); - + % convert the selection inside the atlas volume into linear indices ind = sub2ind(atlas.dim, ijk(inside_vol,1), ijk(inside_vol,2), ijk(inside_vol,3)); - + brick_val = cell(1,numel(brick)); % search the bricks for the value of each voxel for i=1:numel(brick_val) brick_val{i} = zeros(prod(dim),1); brick_val{i}(inside_vol) = atlas.(fn{brick(i)})(ind); end - + mask = zeros(prod(dim),1); for i=1:numel(brick_val) %fprintf('constructing mask for %s\n', atlas.descr.name{sel(i)}); mask = mask | (brick_val{i}==value(i)); end else - error('support for atlases that have a probabilistic segmentationstyle is not supported yet'); + ft_error('support for atlases that have a probabilistic segmentationstyle is not supported yet'); % NOTE: this may be very straightforward indeed: the mask is just the % logical or of the specified rois. end - + elseif ispoi - + if istrue(cfg.round2nearestvoxel) for i=1:size(cfg.roi,1) cfg.roi(i,:) = poi2voi(cfg.roi(i,:), xyz); end end - + % sphere(s) if isfield(cfg, 'sphere') mask = zeros(1,prod(dim)); @@ -279,13 +292,13 @@ end end end - + mask = reshape(mask, dim); fprintf('%i voxels in mask, which is %.3f %% of total volume\n', sum(mask(:)), 100*mean(mask(:))); output = mask; - -elseif mask2label - if ischar(cfg.atlas), + +elseif mask2label || roi2label + if ischar(cfg.atlas) % assume it to represent a filename atlas = ft_read_atlas(cfg.atlas); else @@ -293,7 +306,7 @@ % into a config object atlas = struct(cfg.atlas); end - + % determine which field(s) to use to look up the labels, % and whether these are boolean or indexed fn = fieldnames(atlas); @@ -315,7 +328,7 @@ fn = fn(isboolean); isindexed = 0; end - sel = find(volume.(cfg.maskparameter)(:)); + labels.name = cell(0,1); for k = 1:numel(fn) % ensure that they are concatenated as column @@ -327,30 +340,45 @@ for iLab = 1:length(labels.name) labels.usedqueryrange{iLab} = []; end - + + if mask2label + sel = find(volume.(cfg.maskparameter)(:)); + elseif roi2label + if istrue(cfg.round2nearestvoxel) + % determine location of each anatomical voxel in head coordinates + xyz = [volume.pos ones(size(volume.pos,1),1)]'; % note that this is 4xN + for i=1:size(cfg.roi,1) + cfg.roi(i,:) = poi2voi(cfg.roi(i,:), xyz); + end + end % round2nearestvoxel + sel = find(ismember(volume.pos, cfg.roi, 'rows')==1); + end for iVox = 1:length(sel) - usedQR = 1; - label = atlas_lookup(atlas, [volume.pos(sel(iVox),1) volume.pos(sel(iVox),2) volume.pos(sel(iVox),3)], 'inputcoord', cfg.inputcoord, 'queryrange', 1); - if isempty(label) && cfg.maxqueryrange > 1 - label = atlas_lookup(atlas, [volume.pos(sel(iVox),1) volume.pos(sel(iVox),2) volume.pos(sel(iVox),3)], 'inputcoord', cfg.inputcoord, 'queryrange', 3); - usedQR = 3; - end - if isempty(label) && cfg.maxqueryrange > 3 - label = atlas_lookup(atlas, [volume.pos(sel(iVox),1) volume.pos(sel(iVox),2) volume.pos(sel(iVox),3)], 'inputcoord', cfg.inputcoord, 'queryrange', 5); - usedQR = 5; + label = {}; + for qr = 1:2:cfg.maxqueryrange + if isempty(label) + label = atlas_lookup(atlas, [volume.pos(sel(iVox),1) volume.pos(sel(iVox),2) volume.pos(sel(iVox),3)], 'inputcoord', cfg.inputcoord, 'queryrange', qr, 'method', cfg.querymethod); + usedQR = qr; + end end + if isempty(label) label = {'no_label_found'}; elseif length(label) == 1 label = {label}; end - + ind_lab = []; for iLab = 1:length(label) - ind_lab = [ind_lab find(strcmp(label{iLab}, labels.name))]; + ind_lab = find(strcmp(label{iLab}, labels.name)); + labels.count(ind_lab) = labels.count(ind_lab)+1; % labels.count should give the number of times a label was found within a query range end - - labels.count(ind_lab) = labels.count(ind_lab) + (1/length(ind_lab)); + +% labels.count(ind_lab) = labels.count(ind_lab) + (1/length(ind_lab)); +% ^this gives each label a weight depending on the number of +% labels found within the query range. Using this method, all labels +% that were found will have the same number listed for labels.count, +% which defeats the point of the labels.count field as I understand it for iFoundLab = 1:length(ind_lab) if isempty(labels.usedqueryrange{ind_lab(iFoundLab)}) labels.usedqueryrange{ind_lab(iFoundLab)} = usedQR; @@ -359,9 +387,9 @@ end end end %iVox - + output = labels; - + end % do the general cleanup and bookkeeping at the end of the function @@ -378,7 +406,7 @@ ymin = min(abs(xyz(2,:) - poi(2))); ycl = round(abs(xyz(2,:) - poi(2))) == round(ymin); zmin = min(abs(xyz(3,:) - poi(3))); zcl = round(abs(xyz(3,:) - poi(3))) == round(zmin); xyzcls = xcl + ycl + zcl; ind_voi = xyzcls == 3; -if sum(ind_voi) > 1; +if sum(ind_voi) > 1 fprintf('%i voxels at same distance of poi, taking first voxel\n', sum(ind_voi)) ind_voi_temp = find(ind_voi); ind_voi_temp = ind_voi_temp(1); ind_voi = zeros(size(ind_voi)); diff --git a/external/fieldtrip/ft_volumenormalise.m b/external/fieldtrip/ft_volumenormalise.m index 80cc8842..2ca4a728 100644 --- a/external/fieldtrip/ft_volumenormalise.m +++ b/external/fieldtrip/ft_volumenormalise.m @@ -8,8 +8,8 @@ % where the input mri should be a single anatomical volume that was for % example read with FT_READ_MRI. % -% Configuration options are: -% cfg.spmversion = string, 'spm2' or 'spm8' (default = 'spm8') +% Configuration options are +% cfg.spmversion = string, 'spm2', 'spm8', 'spm12' (default = 'spm8') % cfg.template = string, filename of the template anatomical MRI (default = 'T1.mnc' % for spm2 or 'T1.nii' for spm8) % cfg.parameter = cell-array with the functional data to be normalised (default = 'all') @@ -81,8 +81,8 @@ end % this is not supported any more as of 26/10/2011 -if ischar(mri), - error('please use cfg.inputfile instead of specifying the input variable as a sting'); +if ischar(mri) + ft_error('please use cfg.inputfile instead of specifying the input variable as a sting'); end % ensure that old and unsupported options are not being relied on by the end-user's script @@ -99,6 +99,7 @@ % set the defaults cfg.spmversion = ft_getopt(cfg, 'spmversion', 'spm8'); +cfg.spmmethod = ft_getopt(cfg, 'spmmethod', 'old'); % in case of spm12, use the old-style cfg.parameter = ft_getopt(cfg, 'parameter', 'all'); cfg.downsample = ft_getopt(cfg, 'downsample', 1); cfg.write = ft_getopt(cfg, 'write', 'no'); @@ -107,23 +108,23 @@ cfg.nonlinear = ft_getopt(cfg, 'nonlinear', 'yes'); cfg.smooth = ft_getopt(cfg, 'smooth', 'no'); -% check if the required spm is in your path: -ft_hastoolbox(upper(cfg.spmversion),1); +% check that the preferred SPM version is on the path +ft_hastoolbox(cfg.spmversion, 1); % check whether the input has an anatomy -if ~isfield(mri,'anatomy'), - error('no anatomical information available, this is required for normalisation'); +if ~isfield(mri, 'anatomy') + ft_error('no anatomical information available, this is required for normalisation'); end % ensure that the data has interpretable units and that the coordinate -% system is in approximate spm space and keep track of an initial transformation +% system is in approximate ACPC space and keep track of an initial transformation % matrix that approximately does the co-registration -mri = ft_convert_units(mri, 'mm'); +mri = ft_convert_units(mri, 'mm'); orig = mri.transform; if isdeployed - mri = ft_convert_coordsys(mri, 'spm', 2, cfg.template); + mri = ft_convert_coordsys(mri, 'acpc', 2, cfg.template); else - mri = ft_convert_coordsys(mri, 'spm'); + mri = ft_convert_coordsys(mri, 'acpc'); end initial = mri.transform / orig; @@ -131,32 +132,33 @@ % in deployed mode, FieldTrip cannot use the template in the release version, because these are not compiled cfg = ft_checkconfig(cfg, 'required', 'template'); else - if ~isfield(cfg, 'template'), + if ~isfield(cfg, 'template') spmpath = spm('dir'); - if strcmpi(cfg.spmversion, 'spm8'), cfg.template = [spmpath,filesep,'templates',filesep,'T1.nii']; end - if strcmpi(cfg.spmversion, 'spm2'), cfg.template = [spmpath,filesep,'templates',filesep,'T1.mnc']; end + if strcmpi(cfg.spmversion, 'spm2'), cfg.template = fullfile(spmpath, filesep, 'templates', filesep, 'T1.mnc'); end + if strcmpi(cfg.spmversion, 'spm8'), cfg.template = fullfile(spmpath, filesep, 'templates', filesep, 'T1.nii'); end + if strcmpi(cfg.spmversion, 'spm12'), cfg.template = fullfile(spmpath, filesep, 'toolbox', filesep, 'OldNorm', filesep, 'T1.nii'); end end end if strcmp(cfg.keepinside, 'yes') % add inside to the list of parameters - if ~iscell(cfg.parameter), + if ~iscell(cfg.parameter) cfg.parameter = {cfg.parameter 'inside'}; else cfg.parameter(end+1) = {'inside'}; end end -if ~isfield(cfg,'intermediatename') +if ~isfield(cfg, 'intermediatename') cfg.intermediatename = tempname; end -if ~isfield(cfg,'name') && strcmp(cfg.write,'yes') - error('you must specify the output filename in cfg.name'); +if ~isfield(cfg, 'name') && strcmp(cfg.write, 'yes') + ft_error('you must specify the output filename in cfg.name'); end -if isempty(cfg.template), - error('you must specify a template anatomical MRI'); +if isempty(cfg.template) + ft_error('you must specify a template anatomical MRI'); end % the template anatomy should always be stored in a SPM-compatible file @@ -165,7 +167,7 @@ % based on the filetype assume that the coordinates correspond with MNI/SPM convention % this is ok else - error('the head coordinate system of the template does not seem to be correspond with the mni/spm convention'); + ft_error('the head coordinate system of the template does not seem to be correspond with the mni/spm convention'); end % select the parameters that should be normalised @@ -182,37 +184,37 @@ if cfg.downsample~=1 % optionally downsample the anatomical and/or functional volumes - tmpcfg = keepfields(cfg, {'downsample', 'parameter', 'smooth'}); + tmpcfg = keepfields(cfg, {'downsample', 'parameter', 'smooth', 'showcallinfo'}); mri = ft_volumedownsample(tmpcfg, mri); % restore the provenance information [cfg, mri] = rollback_provenance(cfg, mri); end -ws = warning('off'); +ws = ft_warning('off'); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % here the normalisation starts %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % create an spm-compatible header for the anatomical volume data -VF = ft_write_mri([cfg.intermediatename,'_anatomy.img'], mri.anatomy, 'transform', mri.transform, 'spmversion', cfg.spmversion); +VF = ft_write_mri([cfg.intermediatename '_anatomy.img'], mri.anatomy, 'transform', mri.transform, 'spmversion', cfg.spmversion); % create an spm-compatible file for each of the functional volumes for parlop=2:length(cfg.parameter) % skip the anatomy tmp = cfg.parameter{parlop}; data = reshape(getsubfield(mri, tmp), mri.dim); tmp(tmp=='.') = '_'; - ft_write_mri([cfg.intermediatename,'_' tmp '.img'], data, 'transform', mri.transform, 'spmversion', cfg.spmversion); + ft_write_mri([cfg.intermediatename '_' tmp '.img'], data, 'transform', mri.transform, 'spmversion', cfg.spmversion); end % read the template anatomical volume switch template_ftype case 'minc' VG = spm_vol_minc(cfg.template); - case {'analyze_img', 'analyze_hdr', 'nifti'}, + case {'analyze_img', 'analyze_hdr', 'nifti'} VG = spm_vol(cfg.template); otherwise - error('Unknown template'); + ft_error('Unknown template'); end fprintf('performing the normalisation\n'); @@ -221,21 +223,21 @@ % step 2: compute transformation parameters % step 3: write the results to a file with prefix 'w' -if ~isfield(cfg, 'spmparams') && strcmp(cfg.nonlinear, 'yes'), +if ~isfield(cfg, 'spmparams') && strcmp(cfg.nonlinear, 'yes') fprintf('warping the individual anatomy to the template anatomy\n'); % compute the parameters by warping the individual anatomy - VF = spm_vol([cfg.intermediatename,'_anatomy.img']); + VF = spm_vol([cfg.intermediatename '_anatomy.img']); params = spm_normalise(VG,VF); -elseif ~isfield(cfg, 'spmparams') && strcmp(cfg.nonlinear, 'no'), +elseif ~isfield(cfg, 'spmparams') && strcmp(cfg.nonlinear, 'no') fprintf('warping the individual anatomy to the template anatomy, using only linear transformations\n'); % compute the parameters by warping the individual anatomy - VF = spm_vol([cfg.intermediatename,'_anatomy.img']); - flags.nits = 0; %put number of non-linear iterations to zero + VF = spm_vol([cfg.intermediatename '_anatomy.img']); + flags.nits = 0; % put number of non-linear iterations to zero params = spm_normalise(VG,VF,[],[],[],flags); else fprintf('using the parameters specified in the configuration, skipping the parameter estimation\n'); % use the externally specified parameters - VF = spm_vol([cfg.intermediatename,'_anatomy.img']); + VF = spm_vol([cfg.intermediatename '_anatomy.img']); params = cfg.spmparams; end flags.vox = [cfg.downsample,cfg.downsample,cfg.downsample]; @@ -256,7 +258,7 @@ end spm_write_sn(char(files),params,flags); % this creates the 'w' prefixed files -% spm_figure('Create','Graphics'); +% spm_figure('Create', 'Graphics'); % spm_normalise_disp(params,VF); normalised = []; @@ -281,17 +283,17 @@ % flip and permute the dimensions to align the volume with the headcoordinate axes normalised = align_ijk2xyz(normalised); -if strcmp(cfg.write,'yes') +if strcmp(cfg.write, 'yes') % create an spm-compatible file for each of the normalised volumes for parlop=1:length(cfg.parameter) % include the anatomy tmp = cfg.parameter{parlop}; data = reshape(getsubfield(normalised, tmp), normalised.dim); tmp(tmp=='.') = '_'; - ft_write_mri([cfg.name,'_' tmp '.img'], data, 'transform', normalised.transform, 'spmversion', cfg.spmversion); + ft_write_mri([cfg.name '_' tmp '.img'], data, 'transform', normalised.transform, 'spmversion', cfg.spmversion); end end -if strcmp(cfg.keepintermediate,'no') +if strcmp(cfg.keepintermediate, 'no') % remove the intermediate files for flop=1:length(files) [p, f, x] = fileparts(files{flop}); @@ -311,6 +313,9 @@ cfg.spmparams = params; cfg.final = final; +% restore the previous warning state +warning(ws); + ft_postamble previous mri ft_postamble provenance normalised ft_postamble history normalised diff --git a/external/fieldtrip/ft_volumerealign.m b/external/fieldtrip/ft_volumerealign.m index e9adbde8..c7d90d0e 100644 --- a/external/fieldtrip/ft_volumerealign.m +++ b/external/fieldtrip/ft_volumerealign.m @@ -14,29 +14,32 @@ % implemented, which are described in detail below: % % INTERACTIVE - Use a graphical user interface to click on the location of anatomical -% fiducials. The coordinate system is updated according to the definition of the -% coordinates of these fiducials. +% landmarks or fiducials. The anatomical data can be displayed as three orthogonal +% MRI slices or as a rendering of the head surface. The coordinate system is updated +% according to the definition of the coordinates of these fiducials. % % FIDUCIAL - The coordinate system is updated according to the definition of the -% coordinates of fiducials that are specified in the configuration. +% coordinates of anatomical landmarks or fiducials that are specified in the +% configuration. % % HEADSHAPE - Match the head surface from the MRI with a measured head surface using % an iterative closest point procedure. The MRI will be updated to match the measured -% head surface. This includes an optional manual coregistration of the two head +% head surface. You can optionally do an initial manual coregistration of the two head % surfaces. % -% SPM - align the individual MRI to the coordinate system of a target or template MRI +% SPM - Align the individual MRI to the coordinate system of a target or template MRI % by matching the two volumes. % -% FSL - align the individual MRI to the coordinate system of a target or template MRI +% FSL - Align the individual MRI to the coordinate system of a target or template MRI % by matching the two volumes. % % Use as % [mri] = ft_volumerealign(cfg, mri) % or % [mri] = ft_volumerealign(cfg, mri, target) -% where the input MRI should be an anatomical or functional MRI volume and the third -% input argument is the the target anatomical MRI for SPM or FSL. +% where the first input is the configuration structure, the second input should be an +% anatomical or functional MRI volume and the third input is the the target anatomical MRI +% for SPM or FSL. % % The configuration can contain the following options % cfg.method = string representing the method for aligning @@ -47,8 +50,8 @@ % 'fsl' match to template anatomical MRI % cfg.coordsys = string specifying the origin and the axes of the coordinate % system. Supported coordinate systems are 'ctf', '4d', -% 'bti', 'yokogawa', 'asa', 'itab', 'neuromag', 'spm', -% 'tal' and 'paxinos'. See http://tinyurl.com/ojkuhqz +% 'bti', 'yokogawa', 'asa', 'itab', 'neuromag', 'acpc', +% and 'paxinos'. See http://tinyurl.com/ojkuhqz % cfg.clim = [min max], scaling of the anatomy color (default % is to adjust to the minimum and maximum) % cfg.parameter = 'anatomy' the parameter which is used for the @@ -70,7 +73,7 @@ % handed, the volume is flipped to yield right handed voxel % axes. % -% When cfg.method = 'fiducial' and cfg.coordsys = 'spm' or 'tal', the following +% When cfg.method = 'fiducial' and cfg.coordsys = 'acpc', the following % is required to specify the voxel indices of the fiducials: % cfg.fiducial.ac = [i j k], position of anterior commissure % cfg.fiducial.pc = [i j k], position of posterior commissure @@ -133,12 +136,15 @@ % resliced conform the target image (default = 'yes') % % When cfg.method = 'spm', a third input argument is required. The input volume is -% coregistered to this target volume, using SPM. Additional options pertaining -% to this method should be defined in the sub-structure cfg.spm and can include: +% coregistered to this target volume, using SPM. You can specify the version of +% the SPM toolbox to use with +% cfg.spmversion = string, 'spm2', 'spm8', 'spm12' (default = 'spm8') +% Additional options pertaining to SPM2 and SPM8 should be defined in the +% sub-structure cfg.spm and can include: % cfg.spm.regtype = 'subj', 'rigid' % cfg.spm.smosrc = scalar value % cfg.spm.smoref = scalar value -% When cfg.spmversion is 'spm12', the following options apply: +% Additional options pertaining to SPM12 are % cfg.spm.sep = optimisation sampling steps (mm), default: [4 2] % cfg.spm.params = starting estimates (6 elements), default: [0 0 0 0 0 0] % cfg.spm.cost_fun = cost function string: @@ -165,8 +171,8 @@ % file. These mat files should contain only a single variable, % corresponding with the input/output structure. % -% See also FT_READ_MRI, FT_ELECTRODEREALIGN, FT_DETERMINE_COORDSYS, SPM_AFFREG, -% SPM_NORMALISE, SPM_COREG +% See also FT_READ_MRI, FT_VOLUMERESLICE, FT_INTERACTIVEREALIGN, FT_ELECTRODEREALIGN, +% FT_DETERMINE_COORDSYS, SPM_AFFREG, SPM_NORMALISE, SPM_COREG % Undocumented options: % @@ -222,6 +228,10 @@ % check if the input cfg is valid for this function cfg = ft_checkconfig(cfg, 'renamedval', {'method', 'realignfiducial', 'fiducial'}); cfg = ft_checkconfig(cfg, 'renamed', {'landmark', 'fiducial'}); % cfg.landmark -> cfg.fiducial +% mni/spm/tal are to be interpreted as acpc with native scaling, see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=3304 +cfg = ft_checkconfig(cfg, 'renamedval', {'coordsys', 'mni', 'acpc'}); +cfg = ft_checkconfig(cfg, 'renamedval', {'coordsys', 'spm', 'acpc'}); +cfg = ft_checkconfig(cfg, 'renamedval', {'coordsys', 'tal', 'acpc'}); % see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2837 cfg = ft_checkconfig(cfg, 'renamed', {'viewdim', 'axisratio'}); @@ -239,7 +249,6 @@ cfg.axisratio = ft_getopt(cfg, 'axisratio', 'data'); % size of the axes of the three orthoplots, 'square', 'voxel', or 'data' cfg.viewresult = ft_getopt(cfg, 'viewresult', 'no'); -% viewresult = istrue(cfg.viewresult); if isempty(cfg.method) @@ -256,18 +265,18 @@ if isstruct(cfg.fiducial) && all(ismember(fieldnames(cfg.fiducial), {'lpa', 'rpa', 'nas', 'zpoint'})) cfg.coordsys = 'ctf'; elseif isstruct(cfg.fiducial) && all(ismember(fieldnames(cfg.fiducial), {'ac', 'pc', 'xzpoint', 'right'})) - cfg.coordsys = 'spm'; + cfg.coordsys = 'acpc'; elseif strcmp(cfg.method, 'interactive') cfg.coordsys = 'ctf'; else - error('you should specify the desired head coordinate system in cfg.coordsys') + ft_error('you should specify the desired head coordinate system in cfg.coordsys') end - warning('defaulting to %s coordinate system', cfg.coordsys); + ft_warning('defaulting to %s coordinate system', cfg.coordsys); end % these two have to be simultaneously true for a snapshot to be taken dosnapshot = istrue(cfg.snapshot); -if dosnapshot, +if dosnapshot % create an empty array of handles snap = []; end @@ -285,11 +294,11 @@ % assume anatomy to be the parameter of interest siz = size(mri.anatomy); - if all(siz(1:3)==mri.dim) && numel(siz)==4, + if all(siz(1:3)==mri.dim) && numel(siz)==4 % it's OK cfg.parameter= 'anatomy'; else - error('there''s an unexpected dimension mismatch'); + ft_error('there''s an unexpected dimension mismatch'); end end @@ -304,7 +313,7 @@ fidletter = {'n', 'l', 'r', 'z'}; fidexplanation1 = ' press n for nas, l for lpa, r for rpa\n'; fidexplanation2 = ' press z for an extra control point that should have a positive z-value\n'; - case {'spm' 'tal'} + case 'acpc' fidlabel = {'ac', 'pc', 'xzpoint', 'right'}; fidletter = {'a', 'p', 'z', 'r'}; fidexplanation1 = ' press a for ac, p for pc, z for xzpoint\n'; @@ -315,7 +324,7 @@ fidexplanation1 = ' press b for bregma, l for lambda, z for yzpoint\n'; fidexplanation2 = ''; otherwise - error('unknown coordinate system "%s"', cfg.coordsys); + ft_error('unknown coordinate system "%s"', cfg.coordsys); end for i=1:length(fidlabel) @@ -618,11 +627,11 @@ if ischar(cfg.headshape) % old-style specification, convert cfg into new representation cfg.headshape = struct('headshape', cfg.headshape); - if isfield(cfg, 'scalpsmooth'), + if isfield(cfg, 'scalpsmooth') cfg.headshape.scalpsmooth = cfg.scalpsmooth; cfg = rmfield(cfg, 'scalpsmooth'); end - if isfield(cfg, 'scalpthreshold'), + if isfield(cfg, 'scalpthreshold') cfg.headshape.scalpthreshold = cfg.scalpthreshold; cfg = rmfield(cfg, 'scalpthreshold'); end @@ -630,18 +639,18 @@ elseif isstruct(cfg.headshape) && isfield(cfg.headshape, 'pos') % old-style specification, convert into new representation cfg.headshape = struct('headshape', cfg.headshape); - if isfield(cfg, 'scalpsmooth'), + if isfield(cfg, 'scalpsmooth') cfg.headshape.scalpsmooth = cfg.scalpsmooth; cfg = rmfield(cfg, 'scalpsmooth'); end - if isfield(cfg, 'scalpthreshold'), + if isfield(cfg, 'scalpthreshold') cfg.headshape.scalpthreshold = cfg.scalpthreshold; cfg = rmfield(cfg, 'scalpthreshold'); end elseif isstruct(cfg.headshape) % new-style specification, do nothing else - error('incorrect specification of cfg.headshape'); + ft_error('incorrect specification of cfg.headshape'); end if ischar(cfg.headshape.headshape) @@ -663,6 +672,7 @@ % extract the scalp surface from the anatomical image tmpcfg = []; tmpcfg.output = 'scalp'; + tmpcfg.spmversion = cfg.spmversion; tmpcfg.scalpsmooth = cfg.headshape.scalpsmooth; tmpcfg.scalpthreshold = cfg.headshape.scalpthreshold; if isfield(cfg, 'template') @@ -677,16 +687,16 @@ tmpcfg = []; tmpcfg.tissue = 'scalp'; tmpcfg.method = 'projectmesh';%'isosurface'; + tmpcfg.spmversion = cfg.spmversion; tmpcfg.numvertices = 20000; scalp = ft_prepare_mesh(tmpcfg, seg); - if dointeractive, + if dointeractive fprintf('doing interactive realignment with headshape\n'); - tmpcfg = []; - tmpcfg.template.elec = shape; % this is the Polhemus recorded headshape - tmpcfg.template.elec.chanpos = shape.pos; % ft_interactiverealign needs the field chanpos - tmpcfg.template.elec.label = cellstr(num2str((1:size(shape.pos,1))')); - tmpcfg.individual.headshape = scalp; % this is the headshape extracted from the anatomical MRI + tmpcfg = []; + tmpcfg.template.headshape = shape; % this is the Polhemus recorded headshape + tmpcfg.template.headshapestyle = 'vertex'; + tmpcfg.individual.headshape = scalp; % this is the headshape extracted from the anatomical MRI tmpcfg.individual.headshapestyle = 'surface'; tmpcfg = ft_interactiverealign(tmpcfg); M = tmpcfg.m; @@ -702,7 +712,7 @@ % always perform an icp-step, because this will give an estimate of the % initial distance of the corresponding points. depending on the value % for doicp, deal with the output differently - if doicp, + if doicp numiter = 50; else numiter = 1; @@ -712,8 +722,8 @@ w = ones(size(shape.pos,1),1); else w = cfg.weights(:); - if numel(w)~=size(shape.pos,1), - error('number of weights should be equal to the number of points in the headshape'); + if numel(w)~=size(shape.pos,1) + ft_error('number of weights should be equal to the number of points in the headshape'); end end @@ -726,7 +736,7 @@ nrm = normals(scalp.pos, scalp.tri, 'vertex'); [R, t, err, dummy, info] = icp(scalp.pos', shape.pos', numiter, 'Minimize', 'plane', 'Normals', nrm', 'Weight', weights, 'Extrapolation', true, 'WorstRejection', 0.05); - if doicp, + if doicp fprintf('doing iterative closest points realignment with headshape\n'); % create the additional transformation matrix and compute the % distance between the corresponding points, both prior and after icp @@ -910,14 +920,8 @@ delete(tmpname4); case 'spm' - % ensure that SPM is on the path - if strcmpi(cfg.spmversion, 'spm2'), - ft_hastoolbox('SPM2',1); - elseif strcmpi(cfg.spmversion, 'spm8'), - ft_hastoolbox('SPM8',1); - elseif strcmpi(cfg.spmversion, 'spm12'), - ft_hastoolbox('SPM12',1); - end + % check that the preferred SPM version is on the path + ft_hastoolbox(cfg.spmversion, 1); if strcmpi(cfg.spmversion, 'spm2') || strcmpi(cfg.spmversion, 'spm8') @@ -926,12 +930,12 @@ cfg.spm.smosrc = ft_getopt(cfg.spm, 'smosrc', 2); cfg.spm.smoref = ft_getopt(cfg.spm, 'smoref', 2); - if ~isfield(mri, 'coordsys'), + if ~isfield(mri, 'coordsys') mri = ft_convert_coordsys(mri); else fprintf('Input volume has coordinate system ''%s''\n', mri.coordsys); end - if ~isfield(target, 'coordsys'), + if ~isfield(target, 'coordsys') target = ft_convert_coordsys(target); else fprintf('Target volume has coordinate system ''%s''\n', target.coordsys); @@ -939,12 +943,11 @@ if strcmp(mri.coordsys, target.coordsys) % this should hopefully work else - % only works when it is possible to approximately align the input to - % the target coordsys - if strcmp(target.coordsys, 'spm') - mri = ft_convert_coordsys(mri, 'spm'); + % only works when it is possible to approximately align the input to the target coordsys + if strcmp(target.coordsys, 'acpc') + mri = ft_convert_coordsys(mri, 'acpc'); else - error('The coordinate systems of the input and target volumes are different, coregistration is not possible'); + ft_error('The coordinate systems of the input and target volumes are different, coregistration is not possible'); end end @@ -979,6 +982,7 @@ transform = inv(spm_matrix(x(:)')); % from V1 to V2, to be multiplied still with the original transform (mri.transform), see below end + if isfield(target, 'coordsys') coordsys = target.coordsys; else @@ -989,7 +993,7 @@ delete(tname1); delete(tname2); otherwise - error('unsupported method "%s"', cfg.method); + ft_error('unsupported method "%s"', cfg.method); end if any(strcmp(cfg.method, {'fiducial', 'interactive'})) @@ -1027,7 +1031,7 @@ realign.transform = transform * mri.transform; realign.coordsys = coordsys; else - warning('no coordinate system realignment has been done'); + ft_warning('no coordinate system realignment has been done'); end % visualize result @@ -1607,16 +1611,16 @@ function cb_redraw(h, eventdata) if opt.init % draw the crosshairs for the first time - hch1 = crosshair([xi crossoffs(2) zi], 'parent', h1, 'color', 'yellow'); - hch2 = crosshair([crossoffs(1) yi zi], 'parent', h2, 'color', 'yellow'); - hch3 = crosshair([xi yi crossoffs(3)], 'parent', h3, 'color', 'yellow'); + hch1 = ft_plot_crosshair([xi crossoffs(2) zi], 'parent', h1, 'color', 'yellow'); + hch2 = ft_plot_crosshair([crossoffs(1) yi zi], 'parent', h2, 'color', 'yellow'); + hch3 = ft_plot_crosshair([xi yi crossoffs(3)], 'parent', h3, 'color', 'yellow'); opt.handlescross = [hch1(:)';hch2(:)';hch3(:)']; opt.handlesmarker = []; else % update the existing crosshairs, don't change the handles - crosshair([xi crossoffs(2) zi], 'handle', opt.handlescross(1, :)); - crosshair([crossoffs(1) yi zi], 'handle', opt.handlescross(2, :)); - crosshair([xi yi crossoffs(3)], 'handle', opt.handlescross(3, :)); + ft_plot_crosshair([xi crossoffs(2) zi], 'handle', opt.handlescross(1, :)); + ft_plot_crosshair([crossoffs(1) yi zi], 'handle', opt.handlescross(2, :)); + ft_plot_crosshair([xi yi crossoffs(3)], 'handle', opt.handlescross(3, :)); end % For some unknown god-awful reason, the line command 'disables' all transparency. % The below command resets it. It was the only axes property that I (=roemei) could @@ -1756,7 +1760,7 @@ function cb_keyboard(h, eventdata) elseif strcmp(tag,'jk') && (strcmp(key,'m') || strcmp(key,'downarrow') || isequal(key, 31)), opt.ijk(3) = opt.ijk(3)-1; opt.update = [0 0 1]; else % do nothing - end; + end setappdata(h, 'opt', opt); cb_redraw(h); @@ -1806,7 +1810,7 @@ function cb_keyboard(h, eventdata) % add point to a list l1 = get(get(gca, 'xlabel'), 'string'); l2 = get(get(gca, 'ylabel'), 'string'); - switch l1, + switch l1 case 'i' xc = d1; case 'j' @@ -1814,7 +1818,7 @@ function cb_keyboard(h, eventdata) case 'k' zc = d1; end - switch l2, + switch l2 case 'i' xc = d2; case 'j' diff --git a/external/fieldtrip/ft_volumereslice.m b/external/fieldtrip/ft_volumereslice.m index 895c7b47..e713c2ed 100644 --- a/external/fieldtrip/ft_volumereslice.m +++ b/external/fieldtrip/ft_volumereslice.m @@ -1,15 +1,23 @@ function [resliced] = ft_volumereslice(cfg, mri) -% FT_VOLUMERESLICE interpolates and reslices a volume along the -% principal axes of the coordinate system according to a specified -% resolution. +% FT_VOLUMERESLICE flips, permutes, interpolates and reslices a volume along the +% principal axes of the coordinate system according to a specified resolution. % % Use as % mri = ft_volumereslice(cfg, mri) -% where the input mri should be a single anatomical or functional MRI -% volume that was for example read with FT_READ_MRI. +% where the input MRI should be a single anatomical or functional MRI volume that +% results from FT_READ_MRI or FT_VOLUMEREALIGN. You can visualize the the input and +% output using FT_SOURCEPLOT. % % The configuration structure can contain +% cfg.method = string, 'flip', 'nearest', 'linear', 'cubic' or 'spline' (default = 'linear') +% cfg.downsample = integer number (default = 1, i.e. no downsampling) +% +% If you specify the method as 'flip', it will only permute and flip the volume, but +% not perform any interpolation. For the other methods the input volumetric data will +% also be interpolated on a regular voxel grid. +% +% For the interpolation methods you should specify % cfg.resolution = number, in physical units % cfg.xrange = [min max], in physical units % cfg.yrange = [min max], in physical units @@ -17,9 +25,9 @@ % or alternatively with % cfg.dim = [nx ny nz], size of the volume in each direction % -% If the input mri has a coordsys-field, the centre of the volume will be -% shifted (with respect to the origin of the coordinate system), for the -% brain to fit nicely in the box. +% If the input MRI has a coordsys-field and you don't specify explicit the +% xrange/yrange/zrange, the centre of the volume will be shifted (with respect to the +% origin of the coordinate system), for the brain to fit nicely in the box. % % To facilitate data-handling and distributed computing you can use % cfg.inputfile = ... @@ -29,12 +37,9 @@ % files should contain only a single variable, corresponding with the % input/output structure. % -% See also FT_VOLUMEDOWNSAMPLE, FT_SOURCEINTERPOLATE +% See also FT_VOLUMEREALIGN, FT_VOLUMEDOWNSAMPLE, FT_SOURCEINTERPOLATE, FT_SOURCEPLOT -% Undocumented local options: -% cfg.downsample - -% Copyright (C) 2010-2013, Robert Oostenveld & Jan-Mathijs Schoffelen +% Copyright (C) 2010-2017, Robert Oostenveld & Jan-Mathijs Schoffelen % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -63,7 +68,7 @@ ft_defaults ft_preamble init ft_preamble debug -ft_preamble loadvar mri +ft_preamble loadvar mri ft_preamble provenance mri ft_preamble trackconfig @@ -80,111 +85,141 @@ end % set the defaults -% set voxel resolution according to the input units- see bug2906 -unitcheckmm = strcmp(mri.unit,'mm'); -if unitcheckmm==1; - cfg.resolution = ft_getopt(cfg, 'resolution', 1); -end; -unitcheckcm = strcmp(mri.unit,'cm'); -if unitcheckcm==1; - cfg.resolution = ft_getopt(cfg, 'resolution', .1); -end; -unitcheckm = strcmp(mri.unit,'m'); -if unitcheckm==1; - cfg.resolution = ft_getopt(cfg, 'resolution', .001); -end; -%cfg.resolution = ft_getopt(cfg, 'resolution', 1); +cfg.method = ft_getopt(cfg, 'method', 'linear'); cfg.downsample = ft_getopt(cfg, 'downsample', 1); -cfg.xrange = ft_getopt(cfg, 'xrange', []); -cfg.yrange = ft_getopt(cfg, 'yrange', []); -cfg.zrange = ft_getopt(cfg, 'zrange', []); -cfg.dim = ft_getopt(cfg, 'dim', []); % alternatively use ceil(mri.dim./cfg.resolution) -if isfield(mri, 'coordsys') - % use some prior knowledge to optimize the location of the bounding box - % with respect to the origin of the coordinate system - switch mri.coordsys - case {'ctf' '4d' 'bti'} - xshift = 30./cfg.resolution; - yshift = 0; - zshift = 40./cfg.resolution; - case {'itab' 'neuromag'} - xshift = 0; - yshift = 30./cfg.resolution; - zshift = 40./cfg.resolution; - otherwise - xshift = 0; - yshift = 0; - zshift = 0; +if isequal(cfg.method, 'flip') + % these do not apply when flipping + cfg = ft_checkconfig(cfg, 'forbidden', {'resolution', 'xrange', 'yrange', 'zrange', 'dim'}); +else + % these only applies when interpolating + cfg.resolution = ft_getopt(cfg, 'resolution', 1 * ft_scalingfactor('mm', mri.unit)); % default is 1 mm, but the actual number depends on the units. See bug2906 + cfg.xrange = ft_getopt(cfg, 'xrange', []); + cfg.yrange = ft_getopt(cfg, 'yrange', []); + cfg.zrange = ft_getopt(cfg, 'zrange', []); + cfg.dim = ft_getopt(cfg, 'dim', []); % alternatively use ceil(mri.dim./cfg.resolution) + + if isfield(mri, 'coordsys') + % use some prior knowledge to optimize the location of the bounding box + % with respect to the origin of the coordinate system + switch mri.coordsys + case {'ctf' '4d' 'bti'} + xshift = 30./cfg.resolution; + yshift = 0; + zshift = 40./cfg.resolution; + case {'itab' 'neuromag'} + xshift = 0; + yshift = 30./cfg.resolution; + zshift = 40./cfg.resolution; + case {'acpc' 'spm' 'mni' 'tal'} + ft_warning('FIXME, the bounding box needs a better default'); + xshift = 0; + yshift = 0; + zshift = 0; + otherwise + xshift = 0; + yshift = 0; + zshift = 0; + end + else % if no coordsys is present + xshift = 0; + yshift = 0; + zshift = 0; end -else % if no coordsys is present - xshift = 0; - yshift = 0; - zshift = 0; -end - -if ~isempty(cfg.dim) - xrange = [-cfg.dim(1)/2+0.5 cfg.dim(1)/2-0.5] * cfg.resolution + xshift; - yrange = [-cfg.dim(2)/2+0.5 cfg.dim(2)/2-0.5] * cfg.resolution + yshift; - zrange = [-cfg.dim(3)/2+0.5 cfg.dim(3)/2-0.5] * cfg.resolution + zshift; -else % if no cfg.dim is specified, use defaults - range = [-127.5 127.5] * cfg.resolution; % 255 mm^3 bounding box, assuming human brain - xrange = range + xshift; - yrange = range + yshift; - zrange = range + zshift; -end - -% if ranges have not been specified by the user -if isempty(cfg.xrange) - cfg.xrange = xrange; -end -if isempty(cfg.yrange) - cfg.yrange = yrange; -end -if isempty(cfg.zrange) - cfg.zrange = zrange; -end + + if ~isempty(cfg.dim) + xrange = [-cfg.dim(1)/2+0.5 cfg.dim(1)/2-0.5] * cfg.resolution + xshift; + yrange = [-cfg.dim(2)/2+0.5 cfg.dim(2)/2-0.5] * cfg.resolution + yshift; + zrange = [-cfg.dim(3)/2+0.5 cfg.dim(3)/2-0.5] * cfg.resolution + zshift; + else % if no cfg.dim is specified, use defaults + range = [-127.5 127.5] * cfg.resolution; % 255 mm^3 bounding box, assuming human brain + xrange = range + xshift; + yrange = range + yshift; + zrange = range + zshift; + end + + % if ranges have not been specified by the user + if isempty(cfg.xrange) + cfg.xrange = xrange; + end + if isempty(cfg.yrange) + cfg.yrange = yrange; + end + if isempty(cfg.zrange) + cfg.zrange = zrange; + end + +end % if method~=fip if cfg.downsample~=1 % optionally downsample the anatomical and/or functional volumes - tmpcfg = keepfields(cfg, {'downsample'}); + tmpcfg = keepfields(cfg, {'downsample', 'showcallinfo'}); mri = ft_volumedownsample(tmpcfg, mri); % restore the provenance information [cfg, mri] = rollback_provenance(cfg, mri); end -% compute the desired grid positions -xgrid = cfg.xrange(1):cfg.resolution:cfg.xrange(2); -ygrid = cfg.yrange(1):cfg.resolution:cfg.yrange(2); -zgrid = cfg.zrange(1):cfg.resolution:cfg.zrange(2); - -resliced = []; -resliced.dim = [length(xgrid) length(ygrid) length(zgrid)]; -resliced.transform = translate([cfg.xrange(1) cfg.yrange(1) cfg.zrange(1)]) * scale([cfg.resolution cfg.resolution cfg.resolution]) * translate([-1 -1 -1]); -resliced.anatomy = zeros(resliced.dim, 'int8'); -resliced.unit = mri.unit; - -clear xgrid ygrid zgrid - -% these are the same in the resliced as in the input anatomical MRI -if isfield(mri, 'coordsys') - resliced.coordsys = mri.coordsys; +% determine the fields to reslice +fn = fieldnames(mri); +fn = setdiff(fn, {'pos', 'tri', 'inside', 'outside', 'time', 'freq', 'dim', 'transform', 'unit', 'coordsys', 'cfg', 'hdr'}); % remove fields that do not represent the data +dimord = cell(size(fn)); +for i=1:numel(fn) + dimord{i} = getdimord(mri, fn{i}); end - -fprintf('reslicing from [%d %d %d] to [%d %d %d]\n', mri.dim(1), mri.dim(2), mri.dim(3), resliced.dim(1), resliced.dim(2), resliced.dim(3)); - -% the actual work is being done by ft_sourceinterpolate, which interpolates the real mri volume -% on the resolution that is defined for the resliced volume -tmpcfg = []; -tmpcfg.parameter = 'anatomy'; -resliced = ft_sourceinterpolate(tmpcfg, mri, resliced); - -% remove fields that were not present in the input, this applies specifically to -% the 'inside' field that may have been added by ft_sourceinterpolate -resliced = rmfield(resliced, setdiff(fieldnames(resliced), fieldnames(mri))); - -% convert any non-finite values to 0 to avoid problems later on -resliced.anatomy(~isfinite(resliced.anatomy)) = 0; +fn = fn(strcmp(dimord, 'dim1_dim2_dim3')); + +if strcmp(cfg.method, 'flip') + % this uses some private functions that change the volumes and the transform + resliced = volumepermute(mri); % this makes the transform approximately diagonal + flipvec = false(1,3); + flipvec(1) = resliced.transform(1,1)<0; + flipvec(2) = resliced.transform(2,2)<0; + flipvec(3) = resliced.transform(3,3)<0; + resliced = volumeflip(resliced, flipvec); % this flips along each of the dimensions + +else + % compute the desired grid positions + xgrid = cfg.xrange(1):cfg.resolution:cfg.xrange(2); + ygrid = cfg.yrange(1):cfg.resolution:cfg.yrange(2); + zgrid = cfg.zrange(1):cfg.resolution:cfg.zrange(2); + + resliced = []; + resliced.dim = [length(xgrid) length(ygrid) length(zgrid)]; + resliced.transform = translate([cfg.xrange(1) cfg.yrange(1) cfg.zrange(1)]) * scale([cfg.resolution cfg.resolution cfg.resolution]) * translate([-1 -1 -1]); + resliced.anatomy = zeros(resliced.dim, 'int8'); + resliced.unit = mri.unit; + + % these take a lot of memory + clear xgrid ygrid zgrid + + % these are the same in the resliced as in the input anatomical MRI + if isfield(mri, 'coordsys') + resliced.coordsys = mri.coordsys; + end + + fprintf('reslicing from [%d %d %d] to [%d %d %d]\n', mri.dim(1), mri.dim(2), mri.dim(3), resliced.dim(1), resliced.dim(2), resliced.dim(3)); + + % the actual work is being done by ft_sourceinterpolate + % this interpolates the real volume on the resolution that is defined for the resliced volume + tmpcfg = []; + tmpcfg.parameter = fn; + tmpcfg.interpmethod = cfg.method; + resliced = ft_sourceinterpolate(tmpcfg, mri, resliced); + resliced.cfg.previous = resliced.cfg.previous{1}; % the 2nd input is a dummy variable + cfg.method = resliced.cfg.interpmethod; % remember the method that was used + % restore the provenance information + [cfg, resliced] = rollback_provenance(cfg, resliced); + + % remove fields that were not present in the input + % this applies specifically to the 'inside' field that may have been added by ft_sourceinterpolate + resliced = keepfields(resliced, fieldnames(mri)); + + % convert any non-finite values to 0 to avoid problems later on + for i=1:numel(fn) + resliced.(fn{i})(~isfinite((fn{i}))) = 0; + end + +end % if method=flip or interpolate % do the general cleanup and bookkeeping at the end of the function ft_postamble debug diff --git a/external/fieldtrip/ft_volumesegment.m b/external/fieldtrip/ft_volumesegment.m index 3e1d8448..a2f9ba4a 100644 --- a/external/fieldtrip/ft_volumesegment.m +++ b/external/fieldtrip/ft_volumesegment.m @@ -13,29 +13,47 @@ % % The configuration structure can contain % cfg.output = string or cell-array of strings, see below (default = 'tpm') -% cfg.spmversion = string, 'spm2' or 'spm8' (default = 'spm8') +% cfg.spmversion = string, 'spm2', 'spm8', 'spm12' (default = 'spm12') +% cfg.spmmethod = string, 'old', 'new', 'mars' (default = 'old'). This pertains +% to the algorithm used when cfg.spmversion='spm12', see below. +% cfg.opts = struct, containing spm-version specific options. See +% the code and/or the SPM-documentation for more detail. % cfg.template = filename of the template anatomical MRI (default = '/spm2/templates/T1.mnc' % or '/spm8/templates/T1.nii') % cfg.tpm = cell-array containing the filenames of the tissue probability maps % cfg.name = string for output filename % cfg.write = 'no' or 'yes' (default = 'no'), % writes the probabilistic tissue maps to SPM compatible analyze (spm2), -% or nifti (spm8) files, +% or nifti (spm8/spm12) files, % with the suffix (spm2) -% _seg1, for the gray matter segmentation -% _seg2, for the white matter segmentation -% _seg3, for the csf segmentation -% or with the prefix (spm8) -% c1, for the gray matter segmentation -% c2, for the white matter segmentation -% c3, for the csf segmentation +% _seg1, for the gray matter segmentation +% _seg2, for the white matter segmentation +% _seg3, for the csf segmentation +% or with the prefix (spm8, and spm12 with spmmethod='old') +% c1, for the gray matter segmentation +% c2, for the white matter segmentation +% c3, for the csf segmentation +% when using spm12 with spmmethod='new' there'll be 3 additional tissue types +% c4, for the bone segmentation +% c5, for the soft tissue segmentation +% c6, for the air segmentation +% when using spm12 with spmmethod='mars' the tpms will be +% postprocessed with the mars toolbox, yielding smoother% segmentations in general. % cfg.brainsmooth = 'no', or scalar, the FWHM of the gaussian kernel in voxels, (default = 5) % cfg.scalpsmooth = 'no', or scalar, the FWHM of the gaussian kernel in voxels, (default = 5) +% cfg.skullsmooth = 'no', or scalar, the FWHM of the gaussian kernel in voxels, (default = 5) +% this parameter is only used when the segmentation +% contains 6 tisuse types, including 'bone' % cfg.brainthreshold = 'no', or scalar, relative threshold value which is used to threshold the % tpm in order to create a volumetric brainmask (see below), (default = 0.5) % cfg.scalpthreshold = 'no', or scalar, relative threshold value which is used to threshold the % anatomical data in order to create a volumetric scalpmask (see below), % (default = 0.1) +% cfg.skullthreshold = 'no', or scalar, relative threshold value which is used to threshold the +% anatomical data in order to create a volumetric scalpmask (see below), +% (default = 0.5). this parameter is only used when +% the segmetnation contains 6 tissue types, +% including 'bone', % cfg.downsample = integer, amount of downsampling before segmentation % (default = 1; i.e., no downsampling) % @@ -107,10 +125,7 @@ % % See also FT_READ_MRI, FT_DETERMINE_COORDSYS, FT_PREPARE_HEADMODEL -% undocumented options -% cfg.keepintermediate = 'yes' or 'no' - -% Copyright (C) 2007-2012, Jan-Mathijs Schoffelen, Robert Oostenveld +% Copyright (C) 2007-2017, Jan-Mathijs Schoffelen, Robert Oostenveld % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -149,34 +164,34 @@ end % this is not supported any more as of 26/10/2011 -if ischar(mri), - error('please use cfg.inputfile instead of specifying the input variable as a string'); +if ischar(mri) + ft_error('please use cfg.inputfile instead of specifying the input variable as a string'); end % ensure that old and unsupported options are not being relied on by the end-user's script % instead of specifying cfg.coordsys, the user should specify the coordsys in the data cfg = ft_checkconfig(cfg, 'forbidden', {'units', 'inputcoordsys', 'coordinates'}); -cfg = ft_checkconfig(cfg, 'deprecated', 'coordsys'); -%if isfield(cfg, 'coordsys') && ~isfield(mri, 'coordsys') -% % from revision 8680 onward (Oct 2013) it is not recommended to use cfg.coordsys to specify the coordinate system of the data. -% mri.coordsys = cfg.coordsys; -%end +cfg = ft_checkconfig(cfg, 'deprecated',{'coordsys', 'keepintermediate'}); +% as of march 2017 keepintermediate is deprecated, does not seem to be +% used, nor sensible. If result files are to be kept, use cfg.write % check if the input data is valid for this function mri = ft_checkdata(mri, 'datatype', 'volume', 'feedback', 'yes', 'hasunit', 'yes', 'hascoordsys', 'yes'); % set the defaults -cfg.output = ft_getopt(cfg, 'output', 'tpm'); -cfg.downsample = ft_getopt(cfg, 'downsample', 1); -cfg.spmversion = ft_getopt(cfg, 'spmversion', 'spm8'); -cfg.write = ft_getopt(cfg, 'write', 'no'); -cfg.keepintermediate = ft_getopt(cfg, 'keepintermediate', 'no'); +cfg.output = ft_getopt(cfg, 'output', 'tpm'); +cfg.downsample = ft_getopt(cfg, 'downsample', 1); +cfg.spmversion = ft_getopt(cfg, 'spmversion', 'spm12'); +cfg.write = ft_getopt(cfg, 'write', 'no'); +cfg.spmmethod = ft_getopt(cfg, 'spmmethod', 'old'); % doing old-style in case of spm12 % set default for smooth and threshold -cfg.brainsmooth = ft_getopt(cfg, 'brainsmooth', ''); % see also below -cfg.scalpsmooth = ft_getopt(cfg, 'scalpsmooth', ''); % see also below -cfg.brainthreshold = ft_getopt(cfg, 'brainthreshold', ''); % see also below -cfg.scalpthreshold = ft_getopt(cfg, 'scalpthreshold', ''); % see also below +cfg.brainsmooth = ft_getopt(cfg, 'brainsmooth', ''); % see also below +cfg.scalpsmooth = ft_getopt(cfg, 'scalpsmooth', ''); % see also below +cfg.skullsmooth = ft_getopt(cfg, 'skullsmooth', ''); % see also below +cfg.brainthreshold = ft_getopt(cfg, 'brainthreshold', ''); % see also below +cfg.scalpthreshold = ft_getopt(cfg, 'scalpthreshold', ''); % see also below + % earlier version of smooth and threshold specification cfg.smooth = ft_getopt(cfg, 'smooth', ''); cfg.threshold = ft_getopt(cfg, 'threshold', ''); @@ -184,47 +199,45 @@ % chech whether earlier version of smooth and threshold was specified if ~(isempty(cfg.smooth)) if isempty(cfg.brainsmooth) - cfg.brainsmooth=cfg.smooth; - warning('Smoothing can be specified separately for scalp and brain. User-specified smoothing will be applied for brainmask.') + cfg.brainsmooth = cfg.smooth; + ft_warning('Smoothing can be specified separately for scalp and brain. User-specified smoothing will be applied for brainmask.') end if isempty(cfg.scalpsmooth) - cfg.scalpsmooth=cfg.smooth; - warning('Smoothing can be specified separately for scalp and brain. User-specified smoothing will be applied for scalpmask.') + cfg.scalpsmooth = cfg.smooth; + ft_warning('Smoothing can be specified separately for scalp and brain. User-specified smoothing will be applied for scalpmask.') end end if ~(isempty(cfg.threshold)) if isempty(cfg.brainthreshold) - cfg.brainthreshold=cfg.threshold; - warning('Threshold can be specified separately for scalp and brain. User-specified threshold will be applied for brainmask.') + cfg.brainthreshold = cfg.threshold; + ft_warning('Threshold can be specified separately for scalp and brain. User-specified threshold will be applied for brainmask.') end if isempty(cfg.scalpthreshold) - cfg.scalpthreshold=cfg.threshold; - warning('Threshold can be specified separately for scalp and brain. User-specified threshold will be applied for scalpmask.') + cfg.scalpthreshold = cfg.threshold; + ft_warning('Threshold can be specified separately for scalp and brain. User-specified threshold will be applied for scalpmask.') end end % then set defaults again cfg.brainsmooth = ft_getopt(cfg, 'brainsmooth', 5); cfg.scalpsmooth = ft_getopt(cfg, 'scalpsmooth', 5); +cfg.skullsmooth = ft_getopt(cfg, 'skullsmooth', 5); cfg.brainthreshold = ft_getopt(cfg, 'brainthreshold', 0.5); cfg.scalpthreshold = ft_getopt(cfg, 'scalpthreshold', 0.1); +cfg.skullthreshold = ft_getopt(cfg, 'skullthreshold', 0.5); -% check if the required version of SPM is on your path -if strcmpi(cfg.spmversion, 'spm2'), - ft_hastoolbox('SPM2',1); -elseif strcmpi(cfg.spmversion, 'spm8'), - ft_hastoolbox('SPM8',1); -elseif strcmpi(cfg.spmversion, 'spm12'), - ft_hastoolbox('SPM12',1); -end +% check that the preferred SPM version is on the path +ft_hastoolbox(cfg.spmversion, 1); if ~isfield(cfg, 'name') if ~strcmp(cfg.write, 'yes') tmp = tempname; cfg.name = tmp; else - error('you must specify the output filename in cfg.name'); + ft_error('you must specify the output filename in cfg.name'); end end +[pathstr, name, ~] = fileparts(cfg.name); +cfg.name = fullfile(pathstr, name); % remove any possible file extension, to be added later if ~iscell(cfg.output) % ensure it to be cell, to allow for multiple outputs @@ -238,8 +251,16 @@ needtpm = any(ismember(cfg.output, {'tpm' 'gray' 'white' 'csf' 'brain' 'skull' 'skullstrip'})); end -if all(isfield(mri,{'gray', 'white', 'csf'})) - hastpm = ~islogical(mri.gray) && ~islogical(mri.white) && ~islogical(mri.csf); % tpm is probabilistic and not binary! +tissue = isfield(mri, {'gray', 'white', 'csf', 'bone', 'softtissue', 'air'}); +ntissue = sum(tissue); +if ntissue==6 + % this is new-style segmentation + hastpm = ~islogical(mri.gray) && ~islogical(mri.white) && ~islogical(mri.csf); % tpm should be probabilistic and not binary! +elseif all(tissue(1:3)==true) + hastpm = ~islogical(mri.gray) && ~islogical(mri.white) && ~islogical(mri.csf); % tpm should be probabilistic and not binary! +elseif any(tissue) + ft_warning('the input seems to contain tissue probability maps, but is incomplete for this function'); + hastpm = false; else hastpm = false; end @@ -251,27 +272,9 @@ dotpm = 0; end -% get the names of the templates for the segmentation -if isdeployed && dotpm - cfg = ft_checkconfig(cfg, 'required', {'template' 'tpm'}); -else - if ~isfield(cfg, 'template'), - spmpath = spm('dir'); - % spm deals with the defaults for tpm, so they don't need to be specified here. - if strcmpi(cfg.spmversion, 'spm8'), cfg.template = [spmpath, filesep, 'templates', filesep, 'T1.nii']; end - if strcmpi(cfg.spmversion, 'spm2'), cfg.template = [spmpath, filesep, 'templates', filesep, 'T1.mnc']; end - end -end - -needana = any(ismember(cfg.output, {'scalp' 'skullstrip'})) || dotpm; -hasanatomy = isfield(mri, 'anatomy'); -if needana && ~hasanatomy - error('the input volume needs an anatomy-field'); -end - if cfg.downsample~=1 % optionally downsample the anatomical and/or functional volumes - tmpcfg = keepfields(cfg, {'downsample'}); + tmpcfg = keepfields(cfg, {'downsample', 'showcallinfo'}); tmpcfg.smooth = 'no'; % smoothing is done in ft_volumesegment itself mri = ft_volumedownsample(tmpcfg, mri); % restore the provenance information @@ -282,7 +285,11 @@ % create the tissue probability maps if needed %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% if dotpm - + if isdeployed + % ensure that these exist in this case, otherwise deal with the defaults below + cfg = ft_checkconfig(cfg, 'required', {'template' 'tpm'}); + end + % remember the original transformation matrix coordinate system original = []; original.transform = mri.transform; @@ -290,14 +297,14 @@ if isfield(mri, 'unit') original.unit = mri.unit; else - mri = ft_convert_units(mri); % guess the unit field if not present + mri = ft_determine_units(mri); % guess the unit field if not present original.unit = mri.unit; end mri = ft_convert_units(mri, 'mm'); if isdeployed - mri = ft_convert_coordsys(mri, 'spm', 2, cfg.template); + mri = ft_convert_coordsys(mri, 'acpc', 2, cfg.template); else - mri = ft_convert_coordsys(mri, 'spm'); + mri = ft_convert_coordsys(mri, 'acpc'); end % flip and permute the 3D volume itself, so that the voxel and @@ -305,165 +312,231 @@ % of the segmentation algorithm [mri, permutevec, flipflags] = align_ijk2xyz(mri); - % SPM can be quite noisy, this prevents the warnings from displaying on screen - % warning off; - switch lower(cfg.spmversion) case 'spm2' - Va = ft_write_mri([cfg.name, '.img'], mri.anatomy, 'transform', mri.transform, 'spmversion', cfg.spmversion, 'dataformat', 'analyze_img'); + cfg.template = ft_getopt(cfg, 'template', fullfile(spm('Dir'), 'templates', 'T1.mnc')); + opts = ft_getopt(cfg, 'opts'); + opts.estimate = ft_getopt(opts, 'estimate'); + opts.write = ft_getopt(opts, 'write'); + opts.estimate.affreg = ft_getopt(opts.estimate, 'affreg'); + + VF = ft_write_mri([cfg.name, '.img'], mri.anatomy, 'transform', mri.transform, 'spmversion', cfg.spmversion, 'dataformat', 'analyze_img'); % set the spm segmentation defaults (from /opt/spm2/spm_defaults.m script) - defaults.segmented.estimate.priors = str2mat(... - fullfile(spm('Dir'), 'apriori', 'gray.mnc'),... - fullfile(spm('Dir'), 'apriori', 'white.mnc'),... - fullfile(spm('Dir'), 'apriori', 'csf.mnc')); - defaults.segmented.estimate.reg = 0.01; - defaults.segmented.estimate.cutoff = 30; - defaults.segmented.estimate.samp = 3; - defaults.segmented.estimate.bb = [[-88 88]' [-122 86]' [-60 95]']; - defaults.segmented.estimate.affreg.smosrc = 8; - defaults.segmented.estimate.affreg.regtype = 'mni'; - %defaults.segmented.estimate.affreg.weight = fullfile(spm('Dir'), 'apriori', 'brainmask.mnc'); - defaults.segmented.estimate.affreg.weight = ''; - defaults.segmented.write.cleanup = 1; - defaults.segmented.write.wrt_cor = 1; - - flags = defaults.segmented; + opts.estimate.priors = ft_getopt(opts.estimate, 'priors', ... + char(fullfile(spm('Dir'), 'apriori', 'gray.mnc'),... + fullfile(spm('Dir'), 'apriori', 'white.mnc'),... + fullfile(spm('Dir'), 'apriori', 'csf.mnc'))); + opts.estimate.reg = ft_getopt(opts.estimate, 'reg', 0.01); + opts.estimate.cutoff = ft_getopt(opts.estimate, 'cutoff', 30); + opts.estimate.samp = ft_getopt(opts.estimate, 'samp', 3); + opts.estimate.bb = ft_getopt(opts.estimate, 'bb', [[-88 88]' [-122 86]' [-60 95]']); + opts.estimate.affreg.smosrc = ft_getopt(opts.estimate.affreg, 'smosrc', 8); + opts.estimate.affreg.regtype = ft_getopt(opts.estimate.affreg, 'regtype', 'mni'); + opts.estimate.affreg.weight = ft_getopt(opts.estimate.affreg, 'weight', ''); + opts.write.cleanup = ft_getopt(opts.write, 'cleanup', 1); + opts.write.wrt_cor = ft_getopt(opts.write, 'wrt_cor', 1); % perform the segmentation fprintf('performing the segmentation on the specified volume\n'); - spm_segment(Va, cfg.template, flags); - Vtmp = spm_vol({[cfg.name, '_seg1.img'];... - [cfg.name, '_seg2.img'];... - [cfg.name, '_seg3.img']}); - - % read the resulting volumes - for j = 1:3 - vol = spm_read_vols(Vtmp{j}); - Vtmp{j}.dat = vol; - V(j) = struct(Vtmp{j}); - end - - % keep or remove the files according to the configuration - if strcmp(cfg.keepintermediate, 'no'), - delete([cfg.name, '.img']); - delete([cfg.name, '.hdr']); - delete([cfg.name, '.mat']); - end - if strcmp(cfg.write, 'no'), - delete([cfg.name, '_seg1.hdr']); - delete([cfg.name, '_seg2.hdr']); - delete([cfg.name, '_seg3.hdr']); - delete([cfg.name, '_seg1.img']); - delete([cfg.name, '_seg2.img']); - delete([cfg.name, '_seg3.img']); - delete([cfg.name, '_seg1.mat']); - delete([cfg.name, '_seg2.mat']); - delete([cfg.name, '_seg3.mat']); - elseif strcmp(cfg.write, 'yes'), - for j = 1:3 - % put the transformation-matrix in the headers - V(j).mat = mri.transform; - % write the updated header information back to file ??????? - V(j) = spm_create_vol(V(j)); - end - end - + spm_segment(VF, cfg.template, opts); + + % generate the list of filenames that contains the segmented volumes + filenames = {[cfg.name, '_seg1.img'];... + [cfg.name, '_seg2.img'];... + [cfg.name, '_seg3.img']}; + + case 'spm8' - Va = ft_write_mri([cfg.name, '.img'], mri.anatomy, 'transform', mri.transform, 'spmversion', cfg.spmversion, 'dataformat', 'nifti_spm'); - - fprintf('performing the segmentation on the specified volume\n'); - if isfield(cfg, 'tpm') - cfg.tpm = char(cfg.tpm(:)); - px.tpm = cfg.tpm; - p = spm_preproc(Va, px); - else - p = spm_preproc(Va); + cfg.tpm = ft_getopt(cfg, 'tpm'); + cfg.tpm = char(cfg.tpm(:)); + if isempty(cfg.tpm) + cfg.tpm = char(fullfile(spm('Dir'),'tpm','grey.nii'),... + fullfile(spm('Dir'),'tpm','white.nii'),... + fullfile(spm('Dir'),'tpm','csf.nii')); end - [po, pin] = spm_prep2sn(p); + px.tpm = cfg.tpm; + + VF = ft_write_mri([cfg.name, '.img'], mri.anatomy, 'transform', mri.transform, 'spmversion', cfg.spmversion, 'dataformat', 'nifti_spm'); - % I took these settings from a batch - opts = []; + fprintf('performing the segmentation on the specified volume\n'); + p = spm_preproc(VF, px); + [po, ~] = spm_prep2sn(p); + + % this writes a mat file, may be needed for Dartel, not sure yet + save([cfg.name '_sn.mat'],'-struct','po'); + + % These settings were taken from a batch + opts = ft_getopt(cfg, 'opts'); opts.GM = [0 0 1]; opts.WM = [0 0 1]; opts.CSF = [0 0 1]; opts.biascor = 1; opts.cleanup = 0; + + % write the segmented volumes, -> this can probably be done differently spm_preproc_write(po, opts); - [pathstr, name, ext] = fileparts(cfg.name); - Vtmp = spm_vol({fullfile(pathstr,['c1', name, '.img']);... - fullfile(pathstr,['c2', name, '.img']);... - fullfile(pathstr,['c3', name, '.img'])}); - - % read the resulting volumes - for j = 1:3 - vol = spm_read_vols(Vtmp{j}); - Vtmp{j}.dat = vol; - V(j) = struct(Vtmp{j}); - end - - % keep or remove the files according to the configuration - if strcmp(cfg.keepintermediate, 'no'), - delete([cfg.name, '.img']); - delete([cfg.name, '.hdr']); - if exist([cfg.name, '.mat'], 'file'), - delete([cfg.name, '.mat']); - end %does not always exist - end - - % keep the files written to disk or remove them - % FIXME check whether this works at all - if strcmp(cfg.write, 'no'), - delete(fullfile(pathstr,['c1', name, '.hdr'])); %FIXME this may not be needed in spm8 - delete(fullfile(pathstr,['c1', name, '.img'])); - delete(fullfile(pathstr,['c2', name, '.hdr'])); - delete(fullfile(pathstr,['c2', name, '.img'])); - delete(fullfile(pathstr,['c3', name, '.hdr'])); - delete(fullfile(pathstr,['c3', name, '.img'])); - delete(fullfile(pathstr,['m', name, '.hdr'])); - delete(fullfile(pathstr,['m', name, '.img'])); - elseif strcmp(cfg.write, 'yes'), - for j = 1:3 - % put the transformation-matrix in the headers - V(j).mat = mri.transform; - % write the updated header information back to file ??????? - V(j) = spm_create_vol(V(j)); + % generate the list of filenames that contains the segmented volumes + [pathstr, name, ~] = fileparts(cfg.name); + filenames = {fullfile(pathstr,['c1', name, '.img']);... + fullfile(pathstr,['c2', name, '.img']);... + fullfile(pathstr,['c3', name, '.img'])}; + + case 'spm12' + addpath(fullfile(spm('Dir'),'toolbox/OldSeg')); + if strcmp(cfg.spmmethod, 'old') + cfg.tpm = ft_getopt(cfg, 'tpm'); + cfg.tpm = char(cfg.tpm(:)); + if isempty(cfg.tpm) + cfg.tpm = char(fullfile(spm('Dir'),'toolbox/OldSeg','grey.nii'),... + fullfile(spm('Dir'),'toolbox/OldSeg','white.nii'),... + fullfile(spm('Dir'),'toolbox/OldSeg','csf.nii')); end + px.tpm = cfg.tpm; + + VF = ft_write_mri([cfg.name, '.nii'], mri.anatomy, 'transform', mri.transform, 'spmversion', cfg.spmversion, 'dataformat', 'nifti_spm'); + + fprintf('performing the segmentation on the specified volume, using the old-style segmentation\n'); + p = spm_preproc(VF, px); + [po, ~] = spm_prep2sn(p); + + % this write a mat file, may be needed for Dartel, not sure yet + save([cfg.name '_sn.mat'],'-struct','po'); + + % These settings are taken from a batch + opts = []; + opts.GM = [0 0 1]; + opts.WM = [0 0 1]; + opts.CSF = [0 0 1]; + opts.biascor = 1; + opts.cleanup = 0; + + % write the segmented volumes, -> this can be done differently + spm_preproc_write(po, opts); + + % generate the list of filenames that contains the segmented volumes + [pathstr, name, ~] = fileparts(cfg.name); + filenames = {fullfile(pathstr,['c1', name, '.nii']);... + fullfile(pathstr,['c2', name, '.nii']);... + fullfile(pathstr,['c3', name, '.nii'])}; + + + elseif strcmp(cfg.spmmethod, 'new') || strcmp(cfg.spmmethod, 'mars') + if ~isfield(cfg, 'tpm') || isempty(cfg.tpm) + cfg.tpm = fullfile(spm('dir'),'tpm','TPM.nii'); + end + + VF = ft_write_mri([cfg.name, '.nii'], mri.anatomy, 'transform', mri.transform, 'spmversion', cfg.spmversion, 'dataformat', 'nifti_spm'); + + fprintf('performing the segmentation on the specified volume, using the new-style segmentation\n'); + + % create the structure that is required for spm_preproc8 + opts = ft_getopt(cfg, 'opts'); + opts.image = VF; + opts.tpm = ft_getopt(opts, 'tpm', spm_load_priors8(cfg.tpm)); + opts.biasreg = ft_getopt(opts, 'biasreg', 0.0001); + opts.biasfwhm = ft_getopt(opts, 'biasfwhm', 60); + opts.lkp = ft_getopt(opts, 'lkp', [1 1 2 2 3 3 4 4 4 5 5 5 5 6 6 ]); + opts.reg = ft_getopt(opts, 'reg', [0 0.001 0.5 0.05 0.2]); + opts.samp = ft_getopt(opts, 'samp', 3); + opts.fwhm = ft_getopt(opts, 'fwhm', 1); + + Affine = spm_maff8(opts.image(1),3,32,opts.tpm,eye(4),'mni'); + Affine = spm_maff8(opts.image(1),3, 1,opts.tpm,Affine,'mni'); + opts.Affine = Affine; + + % run the segmentation + p = spm_preproc8(opts); + + % this writes the 'native' segmentations + if strcmp(cfg.spmmethod, 'new') + spm_preproc_write8(p, [ones(6,2) zeros(6,2)], [0 0], [0 1], 1, 1, nan(2,3), nan); + elseif strcmp(cfg.spmmethod, 'mars') + ft_hastoolbox('mars', 1); + if ~isfield(cfg, 'mars'), cfg.mars = []; end + beta = ft_getopt(cfg.mars, 'beta', 0.1); + convergence = ft_getopt(cfg.mars, 'convergence', 0.1); + tcm{1} = fullfile(fileparts(which('spm_mars_mrf')), 'rTCM_BW20_S1.mat'); + p = spm_mars_mrf(p, [ones(6,2) zeros(6,2)], [0 0], [0 1], tcm, beta, convergence, 1); + end + + % this writes a mat file, may be needed for Dartel, not sure yet + save([cfg.name '_seg8.mat'],'-struct','p'); + + + [pathstr, name, ~] = fileparts(cfg.name); + filenames = {fullfile(pathstr,['c1', name, '.nii']);... + fullfile(pathstr,['c2', name, '.nii']);... + fullfile(pathstr,['c3', name, '.nii']);... + fullfile(pathstr,['c4', name, '.nii']);... + fullfile(pathstr,['c5', name, '.nii']);... + fullfile(pathstr,['c6', name, '.nii'])}; + + else + ft_error('cfg.spmmethod should be either ''old'', ''new'' or ''mars'''); end - + otherwise - error('unsupported SPM version'); + ft_error('unsupported SPM version'); end - + + for k = 1:numel(filenames) + Vtmp = spm_vol(filenames{k}); + dat = spm_read_vols(Vtmp); + Vtmp.dat = dat; + V(k) = Vtmp; + end + + if strcmp(cfg.write, 'no') + [pathstr, name, ~] = fileparts(cfg.name); + prefix = {'c1';'c2';'c3';'c3';'c4';'c5';'c6';'m';'y_';''}; + suffix = {'_seg1.hdr';'_seg2.hdr';'_seg3.hdr';'_seg1.img';'_seg2.img';'_seg3.img';'_seg1.mat';'_seg2.mat';'_seg3.mat';'.hdr';'.img';'.nii'}; + for k = 1:numel(prefix) + for j = 1:numel(suffix) + warning off; % delete is quite verbose in its warnings + try, delete(fullfile(pathstr,[prefix{k}, name, suffix{j}])); end + warning on; + end + end + elseif strcmp(cfg.write, 'yes') + for k= 1:numel(V) + % I am not sure whether or why this is needed + V(k).mat = mri.transform; + V(k) = spm_create_vol(V(k)); + end + end + % collect the results - segmented.dim = size(V(1).dat); - segmented.dim = segmented.dim(:)'; % enforce a row vector + segmented.dim = reshape(size(V(1).dat), 1, []); % enforce a row vector segmented.transform = original.transform; % use the original transform segmented.coordsys = original.coordsys; % use the original coordsys segmented.unit = original.unit; % use the original units segmented.gray = V(1).dat; - if length(V)>1, segmented.white = V(2).dat; end - if length(V)>2, segmented.csf = V(3).dat; end + if length(V)>1, segmented.white = V(2).dat; end + if length(V)>2, segmented.csf = V(3).dat; end + if length(V)>3, segmented.bone = V(4).dat; end + if length(V)>4, segmented.softtissue = V(5).dat; end + if length(V)>5, segmented.air = V(6).dat; end segmented.anatomy = mri.anatomy; % flip the volumes back according to the changes introduced by align_ijk2xyz + fn = fieldnames(segmented); + fn = fn(ismember(fn, {'anatomy', 'gray', 'white', 'csf', 'bone', 'softtissue', 'air'})); for k = 1:3 if flipflags(k) - segmented.gray = flipdim(segmented.gray, k); - segmented.anatomy = flipdim(segmented.anatomy, k); - if isfield(segmented, 'white'), segmented.white = flipdim(segmented.white, k); end - if isfield(segmented, 'csf'), segmented.csf = flipdim(segmented.csf, k); end + for j = 1:numel(fn) + segmented.(fn{j}) = flipdim(segmented.(fn{j}), k); + end end end if ~all(permutevec == [1 2 3]) - segmented.gray = ipermute(segmented.gray, permutevec); - segmented.anatomy = ipermute(segmented.anatomy, permutevec); - if isfield(segmented, 'white'), segmented.white = ipermute(segmented.white, permutevec); end - if isfield(segmented, 'csf'), segmented.csf = ipermute(segmented.csf, permutevec); end - segmented.dim = size(segmented.gray); + for j = 1:numel(fn) + segmented.(fn{j}) = ipermute(segmented.(fn{j}), permutevec); + end + segmented.dim = size(segmented.(fn{1})); end else @@ -477,33 +550,41 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % create the requested output fields -remove = {'anatomy' 'csf' 'gray' 'white'}; +remove = {'anatomy' 'csf' 'gray' 'white' 'bone' 'softtissue' 'air' 'skull' 'skullstrip' 'brain' 'scalp'}; % all possible tissues % check if smoothing or thresholding is required dosmooth_brain = ~strcmp(cfg.brainsmooth, 'no'); if dosmooth_brain && ischar(cfg.brainsmooth) - error('invalid value %s for cfg.brainsmooth', cfg.brainsmooth); + ft_error('invalid value %s for cfg.brainsmooth', cfg.brainsmooth); end dosmooth_scalp = ~strcmp(cfg.scalpsmooth, 'no'); if dosmooth_scalp && ischar(cfg.scalpsmooth) - error('invalid value %s for cfg.scalpsmooth', cfg.scalpsmooth); + ft_error('invalid value %s for cfg.scalpsmooth', cfg.scalpsmooth); +end +dosmooth_skull = ~strcmp(cfg.skullsmooth, 'no'); +if dosmooth_skull && ischar(cfg.skullsmooth) + ft_error('invalid value %s for cfg.skullsmooth', cfg.skullsmooth); end dothres_brain = ~strcmp(cfg.brainthreshold, 'no'); if dothres_brain && ischar(cfg.brainthreshold) - error('invalid value %s for cfg.brainthreshold', cfg.brainthreshold); + ft_error('invalid value %s for cfg.brainthreshold', cfg.brainthreshold); end dothres_scalp = ~strcmp(cfg.scalpthreshold, 'no'); if dothres_scalp && ischar(cfg.scalpthreshold) - error('invalid value %s for cfg.scalpthreshold', cfg.scalpthreshold); + ft_error('invalid value %s for cfg.scalpthreshold', cfg.scalpthreshold); +end +dothres_skull = ~strcmp(cfg.skullthreshold, 'no'); +if dothres_skull && ischar(cfg.skullthreshold) + ft_error('invalid value %s for cfg.skullthreshold', cfg.skullthreshold); end outp = cfg.output; if ~isempty(intersect(outp, 'tpm')) % output: probability tissue maps - remove = intersect(remove, {'anatomy'}); + remove = intersect(remove, {'anatomy'}); elseif ~isempty(intersect(outp, {'white' 'gray' 'csf' 'brain' 'skull' 'scalp' 'skullstrip'})) createoutputs = true; @@ -511,17 +592,28 @@ % create scalpmask - no tpm or brainmask is required to create it if any(strcmp('scalp', outp)) - fprintf('creating scalpmask\n'); - anatomy = segmented.anatomy; + fprintf('creating scalpmask ... '); + % let the softtissue mask take precedence + if isfield(segmented, 'softtissue') + fprintf('using the softtissue tpm for segmentation\n'); + fname = 'softtissue'; + anatomy = segmented.softtissue; + elseif isfield(segmented, 'anatomy') + fprintf('using the anatomy field for segmentation\n'); + fname = 'anatomy'; + anatomy = segmented.anatomy; + else + ft_error('no appropriate volume is present for the creation of a scalpmask'); + end if dosmooth_scalp - anatomy = volumesmooth(anatomy, cfg.scalpsmooth, 'anatomy'); + anatomy = volumesmooth(anatomy, cfg.scalpsmooth, fname); else - fprintf('no smoothing applied on anatomy for scalp segmentation\n'); + fprintf('no smoothing applied on %s for scalp segmentation\n',fname); end if dothres_scalp - anatomy = volumethreshold(anatomy, cfg.scalpthreshold, 'anatomy'); + anatomy = volumethreshold(anatomy, cfg.scalpthreshold, fname); else - fprintf('no threshold applied on anatomy for scalp segmentation\n') + fprintf('no threshold applied on %s for scalp segmentation\n',fname); end % fill the slices along each dimension (because using a single one is @@ -542,12 +634,13 @@ % output: scalp (cummulative) (if this is the only requested output) if numel(outp)==1 segmented.scalp = scalpmask; + remove(strcmp(remove,'scalp'))=[]; break end end % end scalp % create the brain from the tpm - fprintf('creating brainmask\n'); + fprintf('creating brainmask ... using the summation of gray, white and csf tpms\n'); brain = segmented.gray + segmented.white + segmented.csf; if dosmooth_brain brain = volumesmooth(brain, cfg.brainsmooth, 'brainmask'); @@ -562,12 +655,13 @@ % output: skullstrip if any(strcmp('skullstrip', outp)) - - fprintf('creating skullstripped anatomy\n'); + if ~isfield(segmented, 'anatomy'), ft_error('no anatomy field present'); end + fprintf('creating skullstripped anatomy ...'); brain_ss = cast(brain, class(segmented.anatomy)); segmented.anatomy = segmented.anatomy.*brain_ss; clear brain_ss - remove = intersect(remove, {'gray' 'white' 'csf'}); + remove(strcmp(remove,'skullstrip'))=[]; + remove(strcmp(remove,'anatomy'))=[]; if numel(outp)==1 break end @@ -580,43 +674,70 @@ % output: brain if any(strcmp(outp, 'brain')) segmented.brain = brainmask; - + remove(strcmp(remove,'brain'))=[]; if numel(outp)==1 break end % output: gray, white, csf elseif any(strcmp(outp, 'gray')) || any(strcmp(outp, 'white')) || any(strcmp(outp, 'csf')) - [dummy, tissuetype] = max(cat(4, segmented.csf, segmented.gray, segmented.white), [], 4); + [~, tissuetype] = max(cat(4, segmented.csf, segmented.gray, segmented.white), [], 4); clear dummy if any(strcmp(outp, 'white')) segmented.white = (tissuetype == 3) & brainmask; - remove = intersect(remove, {'anatomy' 'gray' 'csf'}); + remove(strcmp(remove,'white'))=[]; end if any(strcmp(outp, 'gray')) segmented.gray = (tissuetype == 2) & brainmask; - remove = intersect(remove, {'anatomy' 'white' 'csf'}); + remove(strcmp(remove,'gray'))=[]; end if any(strcmp(outp, 'csf')) segmented.csf = (tissuetype == 1) & brainmask; - remove = intersect(remove, {'anatomy' 'gray' 'white'}); + remove(strcmp(remove,'csf'))=[]; end end % if brain or gray/while/csf if any(strcmp('skull', outp)) || any(strcmp('scalp', outp)) % create skull from brain mask FIXME check this (e.g. strel_bol) - fprintf('creating skullmask\n'); - braindil = imdilate(brainmask>0, strel_bol(6)); - skullmask = braindil & ~brainmask; + fprintf('creating skullmask ... '); + if ~isfield(segmented, 'bone') + fprintf('using the brainmask\n'); + braindil = imdilate(brainmask>0, strel_bol(6)); + skullmask = braindil & ~brainmask; + clear braindil + elseif isfield(segmented, 'bone') + fprintf('using the bone tpm for segmentation\n'); + skull = segmented.bone + segmented.gray + segmented.white + segmented.csf; + if dosmooth_skull + skull = volumesmooth(skull, cfg.skullsmooth, 'skull'); + else + fprintf('no smoothing applied on skull tpm for skull segmentation\n'); + end + if dothres_skull + skull = volumethreshold(skull, cfg.skullthreshold, 'skull'); + else + fprintf('no threshold applied on skull tom for skull segmentation\n') + end + + a1 = volumefillholes(skull, 1); + a2 = volumefillholes(skull, 2); + a3 = volumefillholes(skull, 3); + + skullmask = a1 | a2 | a3; + skullmask = volumethreshold(skullmask); + skullmask = skullmask & ~brainmask; + + clear a1 a2 a3 + end if any(strcmp(outp, 'skull')) segmented.skull = skullmask; + remove(strcmp(remove,'skull'))=[]; if numel(outp)==1 break end end - clear braindil - + % output: scalp (exclusive type) if numel(outp) > 1 && any(strcmp('scalp', outp)) scalpmask(brainmask>0)=0; @@ -624,6 +745,7 @@ scalpmask(skullmask>0)=0; clear skullmask segmented.scalp=scalpmask; + remove(strcmp(remove,'scalp'))=[]; clear scalpmask end end @@ -632,7 +754,7 @@ end % while createoutputs else - error('unknown output %s requested\n', cfg.output{:}); + ft_error('unknown output %s requested\n', cfg.output{:}); end % remove unnecessary fields diff --git a/external/fieldtrip/ft_volumewrite.m b/external/fieldtrip/ft_volumewrite.m index 929e14a8..49dd7a17 100644 --- a/external/fieldtrip/ft_volumewrite.m +++ b/external/fieldtrip/ft_volumewrite.m @@ -20,9 +20,6 @@ function ft_volumewrite(cfg, volume) % cfg.filetype = 'analyze', 'nifti', 'nifti_img', 'analyze_spm', 'mgz', % 'vmp' or 'vmr' % cfg.vmpversion = 1 or 2 (default) version of the vmp-format to use -% cfg.coordsys = 'spm' or 'ctf', this will only affect the -% functionality in case filetype = 'analyze', 'vmp', -% or 'vmr' % % The default filetype is 'nifti', which means that a single *.nii file % will be written using the SPM8 toolbox. The 'nifti_img' filetype uses SPM8 for @@ -102,6 +99,7 @@ function ft_volumewrite(cfg, volume) volume = ft_checkdata(volume, 'datatype', 'volume', 'feedback', 'yes'); % check if the input cfg is valid for this function +cfg = ft_checkconfig(cfg, 'forbidden', {'coordsys'}); % the coordinate system should be specified in the data cfg = ft_checkconfig(cfg, 'required', {'filename', 'parameter'}); cfg = ft_checkconfig(cfg, 'renamed', {'coordinates', 'coordsys'}); @@ -133,7 +131,7 @@ function ft_volumewrite(cfg, volume) if cfg.downsample~=1 % optionally downsample the anatomical and/or functional volumes - tmpcfg = keepfields(cfg, {'downsample', 'parameter'}); + tmpcfg = keepfields(cfg, {'downsample', 'parameter', 'showcallinfo'}); volume = ft_volumedownsample(tmpcfg, volume); % restore the provenance information [cfg, volume] = rollback_provenance(cfg, volume); @@ -152,13 +150,13 @@ function ft_volumewrite(cfg, volume) lpa = cfg.fiducial.lpa; rpa = cfg.fiducial.rpa; if any(nasmaxxyz) - warning('nasion does not lie within volume, using nearest voxel'); + ft_warning('nasion does not lie within volume, using nearest voxel'); end if any(lpamaxxyz) - warning('LPA does not lie within volume, using nearest voxel'); + ft_warning('LPA does not lie within volume, using nearest voxel'); end if any(rpamaxxyz) - warning('RPA does not lie within volume, using nearest voxel'); + ft_warning('RPA does not lie within volume, using nearest voxel'); end idx_nas = [nearest(x, nas(1)) nearest(y, nas(2)) nearest(z, nas(3))]; idx_lpa = [nearest(x, lpa(1)) nearest(y, lpa(2)) nearest(z, lpa(3))]; @@ -176,7 +174,7 @@ function ft_volumewrite(cfg, volume) % FIXME determine the voxel index of the coordinate system origin ori = [0 0 0]; if any(orimaxxyz) - warning('origin does not ly within volume, using nearest voxel'); + ft_warning('origin does not ly within volume, using nearest voxel'); end idx_ori = [nearest(x, ori(1)) nearest(y, ori(2)) nearest(z, ori(3))]; fprintf('origin corresponds to voxel [%d, %d, %d]\n', idx_ori); @@ -210,7 +208,7 @@ function ft_volumewrite(cfg, volume) case 'double' data = double(data ./ maxval); otherwise - error('unknown datatype'); + ft_error('unknown datatype'); end end @@ -238,27 +236,31 @@ function ft_volumewrite(cfg, volume) switch cfg.filetype case {'vmp', 'vmr'} % the reordering for BrainVoyager has been figured out by Markus Siegel - if strcmp(cfg.coordsys, 'ctf') + if any(strcmp(volume.coordsys, {'ctf', '4d', 'bti'})) data = permute(data, [2 3 1]); - elseif strcmp(cfg.coordsys, 'spm') + elseif any(strcmp(volume.coordsys, {'acpc', 'spm', 'mni', 'tal'})) data = permute(data, [2 3 1]); data = flipdim(data, 1); data = flipdim(data, 2); + else + ft_error('unsupported coordinate system ''%s''', volume.coordsys); end siz = size(data); case 'analyze' % the reordering of the Analyze format is according to documentation from Darren Webber - if strcmp(cfg.coordsys, 'ctf') + if any(strcmp(volume.coordsys, {'ctf', '4d', 'bti'})) data = permute(data, [2 1 3]); - elseif strcmp(cfg.coordsys, 'spm') + elseif any(strcmp(volume.coordsys, {'acpc', 'spm', 'mni', 'tal'})) data = flipdim(data, 1); + else + ft_error('unsupported coordinate system ''%s''', volume.coordsys); end siz = size(data); case {'analyze_spm', 'nifti', 'nifti_img' 'mgz' 'mgh'} % this format supports a homogenous transformation matrix % nothing needs to be changed otherwise - warning('unknown fileformat\n'); + ft_warning('unknown fileformat\n'); end % write the volume data to file @@ -268,8 +270,8 @@ function ft_volumewrite(cfg, volume) % write in BrainVoyager VMP format %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% fid = fopen(sprintf('%s.vmp', cfg.filename),'w'); - if fid < 0, - error('Cannot write to file %s.vmp\n',cfg.filename); + if fid < 0 + ft_error('Cannot write to file %s.vmp\n',cfg.filename); end switch cfg.vmpversion @@ -346,8 +348,8 @@ function ft_volumewrite(cfg, volume) % write in BrainVoyager VMR format %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% fid = fopen(sprintf('%s.vmr',cfg.filename),'w'); - if fid < 0, - error('Cannot write to file %s.vmr\n',cfg.filename); + if fid < 0 + ft_error('Cannot write to file %s.vmr\n',cfg.filename); end % data should be scaled between 0 and 225 @@ -404,7 +406,7 @@ function ft_volumewrite(cfg, volume) avw.hdr.dime.datatype = 64; avw.hdr.dime.bitpix = 64; otherwise - error('unknown datatype'); + ft_error('unknown datatype'); end % write the header and image data @@ -449,7 +451,7 @@ function ft_volumewrite(cfg, volume) % this format supports a homogenous transformation matrix %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% if ispc && strcmp(cfg.filetype, 'mgz') - warning('Saving in .mgz format is not possible on a PC, saving in .mgh format instead'); + ft_warning('Saving in .mgz format is not possible on a PC, saving in .mgh format instead'); cfg.filetype = 'mgh'; end [pathstr, name, ext] = fileparts(cfg.filename); diff --git a/external/fieldtrip/inverse/beamformer_dics.m b/external/fieldtrip/inverse/beamformer_dics.m index 929e77ec..fb1a1a68 100644 --- a/external/fieldtrip/inverse/beamformer_dics.m +++ b/external/fieldtrip/inverse/beamformer_dics.m @@ -67,7 +67,7 @@ if mod(nargin-5,2) % the first 5 arguments are fixed, the other arguments should come in pairs - error('invalid number of optional arguments'); + ft_error('invalid number of optional arguments'); end % these optional settings do not have defaults @@ -119,7 +119,7 @@ end if isfield(dip, 'mom') && fixedori - error('you cannot specify a dipole orientation and fixedmom simultaneously'); + ft_error('you cannot specify a dipole orientation and fixedmom simultaneously'); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -187,10 +187,11 @@ % only compute power of a dipole at the grid positions submethod = 'dics_power'; else - error('invalid combination of input arguments for dics'); + ft_error('invalid combination of input arguments for dics'); end isrankdeficient = (rank(Cf) pi) | (angle < 0) +if (angle > pi) || (angle < 0) inv_pseudo_Z = inv_pseudo_Z*10^4; else % hold on diff --git a/external/fieldtrip/inverse/private/bounding_mesh.m b/external/fieldtrip/inverse/private/bounding_mesh.m index e0e2bb95..22b9c25c 100644 --- a/external/fieldtrip/inverse/private/bounding_mesh.m +++ b/external/fieldtrip/inverse/private/bounding_mesh.m @@ -30,12 +30,11 @@ % You should have received a copy of the GNU General Public License % along with FieldTrip. If not, see . % -% $Id$ % this can be used for printing detailled user feedback fb = false; -% this is a work-around for http://bugzilla.fcdonders.nl/show_bug.cgi?id=2369 +% this is a work-around for http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2369 pos = double(pos); pnt = double(pnt); tri = double(tri); diff --git a/external/fieldtrip/inverse/private/calctangent.m b/external/fieldtrip/inverse/private/calctangent.m index cfc3b76e..7e189ba8 100644 --- a/external/fieldtrip/inverse/private/calctangent.m +++ b/external/fieldtrip/inverse/private/calctangent.m @@ -9,7 +9,7 @@ z=RDip(3); r=sqrt(x*x+y*y+z*z); -if (x==0) & (y==0) +if (x==0) && (y==0) tanu(1)=1.0; tanu(2)=0; tanu(3)=0; tanv(1)=0; tanv(2)=1.0; tanv(3)=0; else @@ -23,6 +23,6 @@ tanv(1)= RZXY * X2Y2/r; tanv(2)= (z*y*y + r*x*x) * X2Y2/r; tanv(3)= -y/r; -end; +end + - diff --git a/external/fieldtrip/inverse/private/defaultId.m b/external/fieldtrip/inverse/private/defaultId.m new file mode 100644 index 00000000..f4e1ee99 --- /dev/null +++ b/external/fieldtrip/inverse/private/defaultId.m @@ -0,0 +1,57 @@ +function id = defaultId + +% DEFAULTID returns a string that can serve as warning or error identifier, +% for example 'FieldTip:ft_read_header:line345'. +% +% See also WARNING, ERROR, FT_NOTICE, FT_INFO, FT_DEBUG + +% Copyright (C) 2017, Robert Oostenveld +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +stack = dbstack('-completenames'); + +% remove the functions that pertain to the notification system itself +keep = true(size(stack)); +keep(strcmp({stack.name}, 'defaultId')) = false; % this function itself +keep(strcmp({stack.name}, 'ft_notification')) = false; % this one is doing the work underneath ft_error/ft_warning/ft_notice/etc. +keep(strcmp({stack.name}, 'ft_error')) = false; +keep(strcmp({stack.name}, 'ft_warning')) = false; +keep(strcmp({stack.name}, 'ft_notice')) = false; +keep(strcmp({stack.name}, 'ft_info')) = false; +keep(strcmp({stack.name}, 'ft_debug')) = false; +stack = stack(keep); + +% remove the non-FieldTrip functions from the path, these should not be part of the default message identifier +keep = true(size(stack)); +[v, p] = ft_version; +for i=1:numel(stack) + keep(i) = strncmp(p, stack(i).file, length(p)); +end +stack = stack(keep); + +if ~isempty(stack) + % it is called from within a function + stack = flipud(stack); + name = {stack.name}; + id = ['FieldTrip' sprintf(':%s', name{:}) ':line' num2str(stack(end).line)]; +else + % it is called from the command line + id = 'FieldTrip:commandline'; +end diff --git a/external/fieldtrip/inverse/private/fixdipole.m b/external/fieldtrip/inverse/private/fixdipole.m index 2d691a78..14d94b56 100644 --- a/external/fieldtrip/inverse/private/fixdipole.m +++ b/external/fieldtrip/inverse/private/fixdipole.m @@ -29,15 +29,15 @@ % the input representation is Nx3, which is what we want elseif m==3 % it is possible to translate it into a Nx3 unambiguously - warning('input dipole positions should be specified as Nx3 matrix'); + ft_warning('input dipole positions should be specified as Nx3 matrix'); dip.pos = dip.pos'; elseif m==1 % it is possible to translate it into a Nx3 unambiguously - warning('input dipole positions should be specified as Nx3 matrix'); + ft_warning('input dipole positions should be specified as Nx3 matrix'); dip.pos = reshape(dip.pos, 3, n/3)'; else % it is not clear how to convert to a Nx3 matrix - error('input dipole positions should be specified as Nx3 matrix'); + ft_error('input dipole positions should be specified as Nx3 matrix'); end if isfield(dip, 'mom') diff --git a/external/fieldtrip/inverse/private/fixname.m b/external/fieldtrip/inverse/private/fixname.m index 96a345ec..76fd5951 100644 --- a/external/fieldtrip/inverse/private/fixname.m +++ b/external/fieldtrip/inverse/private/fixname.m @@ -1,19 +1,20 @@ -function str = fixname(str) +function str = fixname(str, version) % FIXNAME changes all inappropriate characters in a sting into '_' -% such that it can be used as a filename or as a structure field name. If -% the string begins with a numeric digit, an 'x' is prepended. +% so that it can be used as a filename or as a field name in a structure. +% If the string begins with a digit, an 'x' is prepended. % % Use as % str = fixname(str) % % MATLAB 2014a introduces the matlab.lang.makeValidName and -% matlab.lang.makeUniqueStrings functions for constructing unique MATLAB identifiers, -% but this particular implementation also works with older MATLAB versions. +% matlab.lang.makeUniqueStrings functions for constructing unique +% identifiers, but this particular implementation also works with +% older MATLAB versions. % % See also DEBLANK -% Copyright (C) 2012-2016, Robert Oostenveld +% Copyright (C) 2012-2017, Robert Oostenveld % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -33,19 +34,48 @@ % % $Id$ -str = lower(str); -str(regexp(str,'\W')) = '_'; - -while(str(1) == '_'), str = str(2:end); end; % remove all underscore at the begin of the string -while(str(end) == '_'), str = str(1:end-1); end; % remove all underscore at the end of the string - -if int8(str(1))<58 && int8(str(1))>47 - % the string begins with a digit, prepend an 'x' - str = ['x' str]; +if nargin<2 + version = 'default'; end -% truncate the string if it's too long: MATLAB maximizes the string length to 63 characters (and throws a warning when truncating) -if numel(str)>63 - str = str(1:63); - ft_warning(sprintf('%s exceeds MATLAB''s maximum name length of 63 characters and has been truncated to %s', str, str(1:63))); +switch version + case 'default' + if isempty(str) + str='x'; + end + str = lower(str); + str(regexp(str,'\W')) = '_'; + while(str(1) == '_'), str = str(2:end); end % remove all underscore at the begin of the string + while(str(end) == '_'), str = str(1:end-1); end % remove all underscore at the end of the string + if int8(str(1))<58 && int8(str(1))>47 + % the string begins with a digit, prepend an 'x' + str = ['x' str]; + end + % truncate the string if it's too long: MATLAB maximizes the string length to 63 characters (and throws a warning when truncating) + if numel(str)>63 + str = str(1:63); + warning('%s exceeds MATLAB''s maximum name length of 63 characters and has been truncated to %s', str, str(1:63)); + end + + case '2014a' + str = matlab.lang.makeValidName(str); + + case 'X_base64encode_X' + % this uses some code from Mathworks file exchange + ft_hastoolbox('fileexchange', 1); + % the following is an encoding that can be reverted + str = strtrim(base64encode(str)); + str(str=='=') = '_'; % replace the '=' sign with '_' + str = ['X' str 'X']; % start and end with an 'X' + + case 'X_base64decode_X' + % this uses some code from Mathworks file exchange + ft_hastoolbox('fileexchange', 1); + % revert the encoding + str = str(2:end-1); % it starts and ends with 'X' + str(str=='_') = '='; % the '=' sign has been replaced with '_' + str = char(base64decode(str)); + + otherwise + error('unsupported version "%s"', version); end diff --git a/external/fieldtrip/inverse/private/ft_getopt.m b/external/fieldtrip/inverse/private/ft_getopt.m index 21ed892a..0d433115 100644 --- a/external/fieldtrip/inverse/private/ft_getopt.m +++ b/external/fieldtrip/inverse/private/ft_getopt.m @@ -8,19 +8,19 @@ % where the input values are % s = structure or cell-array % key = string -% default = any valid MATLAB data type +% default = any valid MATLAB data type (optional, default = []) % emptymeaningful = boolean value (optional, default = 0) % -% If the key is present as field in the structure, or as key-value -% pair in the cell-array, the corresponding value will be returned. +% If the key is present as field in the structure, or as key-value pair in the +% cell-array, the corresponding value will be returned. % -% If the key is not present, ft_getopt will return an empty array. +% If the key is not present, ft_getopt will return the default, or an empty array +% when no default was specified. % -% If the key is present but has an empty value, then the emptymeaningful -% flag specifies whether the empty value or the default value should -% be returned. If emptymeaningful==true, then an empty array will be -% returned. If emptymeaningful==false, then the specified default will -% be returned. +% If the key is present but has an empty value, then the emptymeaningful flag +% specifies whether the empty value or the default value should be returned. +% If emptymeaningful==true, then the empty array will be returned. +% If emptymeaningful==false, then the specified default will be returned. % % See also FT_SETOPT, FT_CHECKOPT @@ -60,27 +60,27 @@ else val = opt.(key); end - + elseif isa(opt, 'cell') % get the key-value from the cell-array if mod(length(opt),2) error('optional input arguments should come in key-value pairs, i.e. there should be an even number'); end - + % the 1st, 3rd, etc. contain the keys, the 2nd, 4th, etc. contain the values keys = opt(1:2:end); vals = opt(2:2:end); - + % the following may be faster than cellfun(@ischar, keys) valid = false(size(keys)); for i=1:numel(keys) valid(i) = ischar(keys{i}); end - + if ~all(valid) error('optional input arguments should come in key-value pairs, the optional input argument %d is invalid (should be a string)', i); end - + hit = find(strcmpi(key, keys)); if isempty(hit) % the requested key was not found @@ -91,7 +91,7 @@ else error('multiple input arguments with the same name'); end - + elseif isempty(opt) % no options are specified, return default val = default; diff --git a/external/fieldtrip/inverse/private/ft_getopt.mexmaci64 b/external/fieldtrip/inverse/private/ft_getopt.mexmaci64 index 1e499c9421e1062ba1178bd37b44ea26728740c3..48fecb34b3878cd01301ebf956190ce9f9db8af2 100755 GIT binary patch literal 9680 zcmeHNU2Ggz6~62II6tOd2d6cn&}peFm;BizC~4BB-r7!g!A>3Qv=Ly&v+G&!(Al5N z&ZO(eiL5v-ow`P*DWyVHu+#@C1P>r2A_3K+w3vrLO?Zhah$=*rvD`|9LO?BKIp3W- z-q|rmec%brmG3?0JLlYU&zyVbdiKt|{{A~R>lurzVT^5{8l@_&V{D2j%Ezd-)iEZ^ zgFVLvxu~{52Y(Tmd@^#w)(f31n`+6d8V3DIn_QhiW1#@Aby>Gv%O?C#mW!s9EG~5vnU$5nrlk8d`2t*a!Xn zN%;Gg2+G64yw*1fW!cI-q2)$oEtk%7Tst4*jc(6=;Q+WMJ|XvrEUOtgZ75mQl?3Bk z5dPXl2Vks`)e6>$Lsgc$V}miDmA5`tp;#yI>%}U|IbAM}Ws`YbE||uu{ycYBu>QC( zpUuAEWm#ALo4=@VG$;B1`~4xlTYdg;opGwN+?zQ3`JV2CcTY&d$O}y11>6Kw;K#rI z?qY1B9SX_4?=}!^0TxA)7`s3nuH4DkK9V6n(8sCcZA6FfW~@N^&BXUp^%vNpZuJWT z{Dn_3_UV8O@Z(f5&K*m?xNY{K{lk;j=I^`O*|eL6<9h?!NH^xDO}wvnsib1K-EckV zi?O}ZX%rMQvrE^K+0xFDF`};KL)feS4lC_T+Sw#chQB&Kt?d%YPzaxgyg**W;SPKvW-vp+F?E5-C2iF)l* zWzxX<18R@6drY1N*gQSDwbu__thAOWluGMK-j4J3G;b$(dxp1X zdHW=9pW^M)ynTkZn1xC!=C{)NEN?OGmDcBZ`vPyV&MK`~yOq}S)Y6R4eBy7kzG4HF z*0+exW*}U=R;g4nc;s6AJ-EH#E`#d>_bYIChF*LH+(~dh1~&`td*FTmZVp@--1FcT zz&!)*O>k$x{TW;dTpdl;Vh-F^a3kQ_z*`#Vn`Lv|v3YIA;#;BE5b7qm58C7~*9g~WgyrqvwNmVKq)RdOi)DcN3 zN{S?Y&1mVWVtc@gq-G1|SXNbX^t&f*={{$Qq~}Mql%h*{15v1kmXb~=x}~yIK9|-; z8R>NT<&{i5UfiSY-aBUOmQzn8gIIb1fmkWCEns->0hZEL#gGE>1N_R;no%@GwACx5 zi=sevx>WAcGSt&pQ9<@|Z$mI%iFP}A6o>FyvhhiAY7%sj#7H&y)J5>}v zrM1U@|L!4*dJYe>RKR1QHqaAxv-^}C8HO=E*#7p|I=EZ@?Griq1r{kqBhiNX4YQuSdM}Ca=hP2I8Rdx1ryzPNvW0S|mU;}MuQ)nLpFfar))Ue>QZ=0~2q~rDQN_>{%I9O6 znRz7nRXVmqw>e?ZZ!H@@{BoqZlP1kbDMdAvEs)475sXZqbkrTPaw${G=h*hNMkj3Q zaZ5AQ5v8D=P>mwwbn-jbOb1I7c(*;*{3g98W$gW{4R~|CohrwWQQ>DyMBP&-->Y&6 z8cFMY$AQlWfG5P+72Y)y^!o94vwr+=K(7SwaTik;x10&!7X$eF0sKk;|2lyG5Ws&8 z;0TTE{*i*p<^aY)tzRz%@U{TPiND{zCxDN*csch&0gUe)@S+3X>};e;Z{_*707y5E z%5I^GIfzniqPm6ZN2%go$0Xn!5zaBm_)b840!{s#yu*x#5y;C@<-Xehi z`QCuWe^ad3tVpoRHbt764GOq+Ya)q%Q*vQ-J96=gjmQ;?Er@{Fd|VFOj?3{4hqLZh X!&z^W;lSHoI1u}a|88HgWi$3~)uY>q literal 9832 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 delta 33 mcmZp0X>eJ<$YTBPQ|M$CMjxgvZ#D-pCP{(?Ht&$~U! delta 32 lcmZqhXz-ZugT=2, get_spm_version()<95}; + %This is to avoid crashes when trying to add SPM to the path + fallback_toolbox = 'SPM8'; case 'SPM5' dependency = {'spm', get_spm_version()==5}; + case 'SPM5UP' % version 5 or later, but not SPM 9X + dependency = {'spm', get_spm_version()>=5, get_spm_version()<95}; + %This is to avoid crashes when trying to add SPM to the path + fallback_toolbox = 'SPM5'; case 'SPM8' dependency = {'spm', get_spm_version()==8}; case 'SPM8UP' % version 8 or later, but not SPM 9X dependency = {'spm', get_spm_version()>=8, get_spm_version()<95}; - %This is to avoid crashes when trying to add SPM to the path fallback_toolbox = 'SPM8'; case 'SPM12' dependency = {'spm', get_spm_version()==12}; + case 'SPM12UP' % version 12 or later, but not SPM 9X + dependency = {'spm', get_spm_version()>=12, get_spm_version()<95}; + %This is to avoid crashes when trying to add SPM to the path + fallback_toolbox = 'SPM12'; case 'MEG-PD' dependency = {'rawdata', 'channames'}; case 'MEG-CALC' @@ -205,8 +220,7 @@ case 'MRI' % other functions in the mri section dependency = {'avw_hdr_read', 'avw_img_read'}; case 'NEUROSHARE' - dependency = {'ns_OpenFile', 'ns_SetLibrary', ... - 'ns_GetAnalogData'}; + dependency = {'ns_OpenFile', 'ns_SetLibrary', 'ns_GetAnalogData'}; case 'ARTINIS' dependency = {'read_artinis_oxy3'}; case 'BESA' @@ -234,21 +248,21 @@ case '4D-VERSION' dependency = {'read4d', 'read4dhdr'}; case {'STATS', 'STATISTICS'} - dependency = has_license('statistics_toolbox'); % check the availability of a toolbox license + dependency = has_license('statistics_toolbox'); % also check the availability of a toolbox license case {'OPTIM', 'OPTIMIZATION'} - dependency = has_license('optimization_toolbox'); % check the availability of a toolbox license + dependency = has_license('optimization_toolbox'); % also check the availability of a toolbox license case {'SPLINES', 'CURVE_FITTING'} - dependency = has_license('curve_fitting_toolbox'); % check the availability of a toolbox license + dependency = has_license('curve_fitting_toolbox'); % also check the availability of a toolbox license case 'COMM' dependency = {has_license('communication_toolbox'), 'de2bi'}; % also check the availability of a toolbox license case 'SIGNAL' - dependency = {has_license('signal_toolbox'), 'window'}; % also check the availability of a toolbox license - case 'IMAGE' - dependency = has_license('image_toolbox'); % check the availability of a toolbox license + dependency = {has_license('signal_toolbox'), 'window'}; % also check the availability of a toolbox license + case 'IMAGES' + dependency = has_license('image_toolbox'); % also check the availability of a toolbox license case {'DCT', 'DISTCOMP'} - dependency = has_license('distrib_computing_toolbox'); % check the availability of a toolbox license + dependency = has_license('distrib_computing_toolbox'); % also check the availability of a toolbox license case 'COMPILER' - dependency = has_license('compiler'); % check the availability of a toolbox license + dependency = has_license('compiler'); % also check the availability of a toolbox license case 'FASTICA' dependency = 'fpica'; case 'BRAINSTORM' @@ -260,8 +274,7 @@ case 'BCI2000' dependency = {'load_bcidat'}; case 'NLXNETCOM' - dependency = {'MatlabNetComClient', 'NlxConnectToServer', ... - 'NlxGetNewCSCData'}; + dependency = {'MatlabNetComClient', 'NlxConnectToServer', 'NlxGetNewCSCData'}; case 'DIPOLI' dependency = {'dipoli.maci', 'file'}; case 'MNE' @@ -323,17 +336,17 @@ dependency = {'plx_adchan_gains', 'mexPlex'}; case '35625-INFORMATION-THEORY-TOOLBOX' dependency = {'conditionalEntropy', 'entropy', 'jointEntropy',... - 'mutualInformation' 'nmi' 'nvi' 'relativeEntropy'}; + 'mutualInformation' 'nmi' 'nvi' 'relativeEntropy'}; case '29046-MUTUAL-INFORMATION' dependency = {'MI', 'license.txt'}; case '14888-MUTUAL-INFORMATION-COMPUTATION' dependency = {'condentropy', 'demo_mi', 'estcondentropy.cpp',... - 'estjointentropy.cpp', 'estpa.cpp', ... - 'findjointstateab.cpp', 'makeosmex.m',... - 'mutualinfo.m', 'condmutualinfo.m',... - 'entropy.m', 'estentropy.cpp',... - 'estmutualinfo.cpp', 'estpab.cpp',... - 'jointentropy.m' 'mergemultivariables.m' }; + 'estjointentropy.cpp', 'estpa.cpp', ... + 'findjointstateab.cpp', 'makeosmex.m',... + 'mutualinfo.m', 'condmutualinfo.m',... + 'entropy.m', 'estentropy.cpp',... + 'estmutualinfo.cpp', 'estpab.cpp',... + 'jointentropy.m' 'mergemultivariables.m' }; case 'PLOT2SVG' dependency = {'plot2svg.m', 'simulink2svg.m'}; case 'BRAINSUITE' @@ -352,11 +365,16 @@ dependency = {'write_wobj' 'read_wobj'}; case 'NEURONE' dependency = {'readneurone' 'readneuronedata' 'readneuroneevents'}; - + case 'BREWERMAP' + dependency = {'brewermap' 'brewermap_view'}; + case 'GTEC' + dependency = {'ghdf5read' 'ghdf5fileimport'}; + case 'MARS' + dependency = {'spm_mars_mrf'}; + % the following are FieldTrip modules/toolboxes case 'FILEIO' - dependency = {'ft_read_header', 'ft_read_data', ... - 'ft_read_event', 'ft_read_sens'}; + dependency = {'ft_read_header', 'ft_read_data', 'ft_read_event', 'ft_read_sens'}; case 'FORWARD' dependency = {'ft_compute_leadfield', 'ft_prepare_vol_sens'}; case 'PLOTTING' @@ -369,33 +387,35 @@ dependency = {'ft_spiketriggeredaverage', 'ft_spiketriggeredspectrum'}; case 'FILEEXCHANGE' dependency = is_subdir_in_fieldtrip_path('/external/fileexchange'); + case 'CELLFUNCTION' + dependency = {'cellmean', 'cellvecadd', 'cellcat'}; case {'INVERSE', 'REALTIME', 'SPECEST', 'PREPROC', ... - 'COMPAT', 'STATFUN', 'TRIALFUN', 'UTILITIES/COMPAT', ... - 'FILEIO/COMPAT', 'PREPROC/COMPAT', 'FORWARD/COMPAT', ... - 'PLOTTING/COMPAT', 'TEMPLATE/LAYOUT', 'TEMPLATE/ANATOMY' ,... - 'TEMPLATE/HEADMODEL', 'TEMPLATE/ELECTRODE', ... - 'TEMPLATE/NEIGHBOURS', 'TEMPLATE/SOURCEMODEL'} + 'COMPAT', 'STATFUN', 'TRIALFUN', 'UTILITIES/COMPAT', ... + 'FILEIO/COMPAT', 'PREPROC/COMPAT', 'FORWARD/COMPAT', ... + 'PLOTTING/COMPAT', 'TEMPLATE/LAYOUT', 'TEMPLATE/ANATOMY' ,... + 'TEMPLATE/HEADMODEL', 'TEMPLATE/ELECTRODE', ... + 'TEMPLATE/NEIGHBOURS', 'TEMPLATE/SOURCEMODEL'} dependency = is_subdir_in_fieldtrip_path(toolbox); otherwise - if ~silent, warning('cannot determine whether the %s toolbox is present', toolbox); end + if ~silent, ft_warning('cannot determine whether the %s toolbox is present', toolbox); end dependency = false; end status = is_present(dependency); if ~status && ~isempty(fallback_toolbox) - % in case of SPM8UP + % in case of SPMxUP toolbox = fallback_toolbox; end % try to determine the path of the requested toolbox if autoadd>0 && ~status - + % for core FieldTrip modules prefix = fileparts(which('ft_defaults')); if ~status status = myaddpath(fullfile(prefix, lower(toolbox)), silent); end - + % for external FieldTrip modules prefix = fullfile(fileparts(which('ft_defaults')), 'external'); if ~status @@ -407,37 +427,37 @@ feval(licensefile); end end - + % for contributed FieldTrip extensions prefix = fullfile(fileparts(which('ft_defaults')), 'contrib'); if ~status status = myaddpath(fullfile(prefix, lower(toolbox)), silent); licensefile = [lower(toolbox) '_license']; if status && exist(licensefile, 'file') - % this will execute openmeeg_license and mne_license - % which display the license on screen for three seconds + % this will execute openmeeg_license, mne_license and artinis_license + % which display the license on screen for a few seconds feval(licensefile); end end - + % for linux computers in the Donders Centre for Cognitive Neuroimaging prefix = '/home/common/matlab'; if ~status && isdir(prefix) status = myaddpath(fullfile(prefix, lower(toolbox)), silent); end - + % for windows computers in the Donders Centre for Cognitive Neuroimaging prefix = 'h:\common\matlab'; if ~status && isdir(prefix) status = myaddpath(fullfile(prefix, lower(toolbox)), silent); end - + % use the MATLAB subdirectory in your homedirectory, this works on linux and mac prefix = fullfile(getenv('HOME'), 'matlab'); if ~status && isdir(prefix) status = myaddpath(fullfile(prefix, lower(toolbox)), silent); end - + if ~status % the toolbox is not on the path and cannot be added sel = find(strcmp(url(:,1), toolbox)); @@ -447,7 +467,7 @@ msg = sprintf('the %s toolbox is not installed', toolbox); end if autoadd==1 - error(msg); + ft_error(msg); elseif autoadd==2 ft_warning(msg); else @@ -458,30 +478,35 @@ % this function is called many times in FieldTrip and associated toolboxes % use efficient handling if the same toolbox has been investigated before -if status - previous.(fixname(toolbox)) = status; -end +% if status +% previous.(fixname(toolbox)) = status; +% end % remember the previous path, allows us to determine on the next call % whether the path has been modified outise of this function -previouspath = path; +% previouspath = path; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % helper function %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function status = myaddpath(toolbox, silent) if isdeployed - warning('cannot change path settings for %s in a compiled application', toolbox); + ft_warning('cannot change path settings for %s in a compiled application', toolbox); status = 1; elseif exist(toolbox, 'dir') - if ~silent, - ws = warning('backtrace', 'off'); - warning('adding %s toolbox to your MATLAB path', toolbox); - warning(ws); % return to the previous warning level + if ~silent + ft_warning('off','backtrace'); + ft_warning('adding %s toolbox to your MATLAB path', toolbox); + ft_warning('on','backtrace'); + end + if any(~cellfun(@isempty, regexp(toolbox, {'spm2', 'spm5', 'spm8', 'spm12'}))) + % SPM needs to be added with the subdirectories + addpath(genpath(toolbox)); + else + addpath(toolbox); end - addpath(toolbox); status = 1; -elseif (~isempty(regexp(toolbox, 'spm5$', 'once')) || ~isempty(regexp(toolbox, 'spm8$', 'once')) || ~isempty(regexp(toolbox, 'spm12$', 'once'))) && exist([toolbox 'b'], 'dir') +elseif (~isempty(regexp(toolbox, 'spm2$', 'once')) || ~isempty(regexp(toolbox, 'spm5$', 'once')) || ~isempty(regexp(toolbox, 'spm8$', 'once')) || ~isempty(regexp(toolbox, 'spm12$', 'once'))) && exist([toolbox 'b'], 'dir') status = myaddpath([toolbox 'b'], silent); else status = 0; @@ -511,9 +536,9 @@ m = lasterror; if strcmp(m.identifier, 'MATLAB:license:checkouterror') if nargin>1 - warning('the %s toolbox is available, but you don''t have a license for it', toolbox); + ft_warning('the %s toolbox is available, but you don''t have a license for it', toolbox); else - warning('the function ''%s'' is available, but you don''t have a license for it', funname); + ft_warning('the function ''%s'' is available, but you don''t have a license for it', funname); end status = false; elseif strcmp(m.identifier, 'MATLAB:UndefinedFunction') @@ -529,65 +554,65 @@ % helper function %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function status = is_subdir_in_fieldtrip_path(toolbox_name) - fttrunkpath = unixpath(fileparts(which('ft_defaults'))); - fttoolboxpath = fullfile(fttrunkpath, lower(toolbox_name)); +fttrunkpath = unixpath(fileparts(which('ft_defaults'))); +fttoolboxpath = fullfile(fttrunkpath, lower(toolbox_name)); - needle=[pathsep fttoolboxpath pathsep]; - haystack = [pathsep path() pathsep]; +needle=[pathsep fttoolboxpath pathsep]; +haystack = [pathsep path() pathsep]; - status = ~isempty(findstr(needle, haystack)); +status = ~isempty(findstr(needle, haystack)); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % helper function %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function status = has_mex(name) - full_name=[name '.' mexext]; - status = (exist(full_name, 'file')==3); +full_name=[name '.' mexext]; +status = (exist(full_name, 'file')==3); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % helper function %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function v = get_spm_version() - if ~is_present('spm') - v=NaN; - return - end +if ~is_present('spm') + v=NaN; + return +end - version_str = spm('ver'); - token = regexp(version_str,'(\d*)','tokens'); - v = str2num([token{:}{:}]); +version_str = spm('ver'); +token = regexp(version_str,'(\d*)','tokens'); +v = str2num([token{:}{:}]); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % helper function %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function status = has_license(toolbox_name) - status = license('checkout', toolbox_name)==1; +status = license('checkout', toolbox_name)==1; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % helper function %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function status = is_present(dependency) - if iscell(dependency) - % use recursion - status = all(cellfun(@is_present,dependency)); - elseif islogical(dependency) - % boolean - status = all(dependency); - elseif ischar(dependency) - % name of a function - status = is_function_present_in_search_path(dependency); - elseif isa(dependency, 'function_handle') - status = dependency(); - else - assert(false,'this should not happen'); - end +if iscell(dependency) + % use recursion + status = all(cellfun(@is_present,dependency)); +elseif islogical(dependency) + % boolean + status = all(dependency); +elseif ischar(dependency) + % name of a function + status = is_function_present_in_search_path(dependency); +elseif isa(dependency, 'function_handle') + status = dependency(); +else + assert(false,'this should not happen'); +end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % helper function %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function status = is_function_present_in_search_path(function_name) - w = which(function_name); +w = which(function_name); - % must be in path and not a variable - status = ~isempty(w) && ~isequal(w, 'variable'); +% must be in path and not a variable +status = ~isempty(w) && ~isequal(w, 'variable'); diff --git a/external/fieldtrip/inverse/private/ft_inside_vol.m b/external/fieldtrip/inverse/private/ft_inside_vol.m index 7cefd4cd..8e1f06bf 100644 --- a/external/fieldtrip/inverse/private/ft_inside_vol.m +++ b/external/fieldtrip/inverse/private/ft_inside_vol.m @@ -17,7 +17,7 @@ % grad = structure with gradiometer information, used for localspheres % headshape = structure with headshape, used for old CTF localspheres strategy -% Copyright (C) 2003-2013, Robert Oostenveld +% Copyright (C) 2003-2016, Robert Oostenveld % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -97,7 +97,7 @@ case {'halfspace', 'halfspace_monopole'} inside = false(1,size(dippos,1)); - for i = 1:size(dippos,1); + for i = 1:size(dippos,1) pol = dippos(i,:); % condition of dipoles/monopoles falling in the non conductive halfspace inside(i) = acos(dot(headmodel.ori,(pol-headmodel.pos)./norm(pol-headmodel.pos))) >= pi/2; @@ -105,7 +105,7 @@ case 'slab_monopole' inside = false(1,size(dippos,1)); - for i=1:size(dippos,1); + for i=1:size(dippos,1) pol = dippos(i,:); % condition of dipoles/monopoles falling in the non conductive halfspace % Attention: voxels on the boundary are automatically considered outside the strip @@ -120,54 +120,93 @@ inside = bounding_mesh(dippos, pos, tri); case {'simbio'} - - brain = false(size(headmodel.tissue)); - brain = brain | headmodel.tissue == find(strcmp(headmodel.tissuelabel, 'gray')); - brain = brain | headmodel.tissue == find(strcmp(headmodel.tissuelabel, 'white')); - brain = brain | headmodel.tissue == find(strcmp(headmodel.tissuelabel, 'csf')); - - minbrain = min(headmodel.pos(headmodel.hex(brain(:)), :), [], 1); - maxbrain = max(headmodel.pos(headmodel.hex(brain(:)), :), [], 1); - - mindippos = min(dippos, [], 1); - maxdippos = max(dippos, [], 1); - - % combine the two bounding boxes - minbox = max([minbrain; mindippos], [], 1); - maxbox = min([maxbrain; maxdippos], [], 1); - - % prune the mesh to the bounding box - discard1 = true(size(headmodel.hex,1),1); - discard2 = true(size(headmodel.hex,1),1); - for i=1:8 - discard1 = discard1 & any(bsxfun(@minus, headmodel.pos(headmodel.hex(:,i),:), minbox)<0,2); - discard2 = discard2 & any(bsxfun(@minus, headmodel.pos(headmodel.hex(:,i),:), maxbox)>0,2); + % this is a model with hexaheders or tetraheders + if isfield(headmodel, 'tet') + % the subsequent code works both for tetraheders or hexaheders, but assumes the volume elements to be called "hex" + headmodel.hex = headmodel.tet; + headmodel = rmfield(headmodel, 'tet'); end - discard = discard1 | discard2; - - fprintf('pruning mesh from %d to %d elements (%d%%)\n', length(discard), sum(discard), round(100*sum(discard)/length(discard))); - headmodel.hex = headmodel.hex(~discard,:); - headmodel.tissue = headmodel.tissue(~discard); + % determine the size of the relevant elements + numhex = size(headmodel.hex,1); + numpos = size(headmodel.pos,1); + numdip = size(dippos,1); - % determine the center of each volume element - elementpos = zeros(size(headmodel.hex,1),3); - for i=1:8 - elementpos = elementpos + headmodel.pos(headmodel.hex(:,i),:); + % FIXME we have to rethink which tissue types should be flagged as inside + tissue = intersect({'gray', 'white', 'csf', 'brain'}, headmodel.tissuelabel); + + % determine all hexaheders that are labeled as brain + insidehex = false(size(headmodel.tissue)); + for i=1:numel(tissue) + fprintf('selecting dipole positions inside the ''%s'' tissue\n', tissue{i}); + insidehex = insidehex | (headmodel.tissue == find(strcmp(headmodel.tissuelabel, tissue{i}))); end - elementpos = elementpos/8; + % prune the mesh, i.e. only retain hexaheders labeled as brain + fprintf('pruning headmodel volume elements from %d to %d (%d%%)\n', numhex, sum(insidehex), round(100*sum(insidehex)/numhex)); + headmodel.hex = headmodel.hex(insidehex,:); + headmodel.tissue = headmodel.tissue(insidehex); + numhex = sum(insidehex); + clear insidehex + + % determine all vertices that are part of a hexaheder + insidepos = false(numpos,1); + insidepos(headmodel.hex) = true; + + % prune the mesh, i.e. only retain vertices that are part of a hexaheder + fprintf('pruning headmodel vertices from %d to %d (%d%%)\n', numpos, sum(insidepos), round(100*sum(insidepos)/numpos)); + headmodel.pos = headmodel.pos(insidepos,:); + numpos = sum(insidepos); + renumber = zeros(size(insidepos)); + renumber(insidepos) = 1:numpos; % determine the mapping from original to pruned vertex indices + headmodel.hex = renumber(headmodel.hex); % renumber the vertex indices + clear insidepos renumber + + % construct a sparse matrix with the mapping between all hexaheders and vertices + i = repmat(transpose(1:numhex), 1, 8); + j = headmodel.hex; + s = ones(size(i)); + hex2pos = sparse(i(:),j(:),s(:),numhex,numpos); + + % determine the bounding box + minpos = min(headmodel.pos,[],1); + maxpos = max(headmodel.pos,[],1); + insidedip = all(bsxfun(@ge, dippos, minpos),2) & all(bsxfun(@le, dippos, maxpos),2); + fprintf('pruning dipole positions from %d to %d (%d%%)\n', numdip, sum(insidedip), round(100*sum(insidedip)/numdip)); + insidedip = find( insidedip); + dippos = dippos(insidedip,:); + + % find the nearest vertex for each of the dipoles + dsearchn(headmodel.pos, dippos(1,:)); % call it once to precompile stopwatch = tic; - k = dsearchn(elementpos, dippos(1,:)); + dsearchn(headmodel.pos, dippos(1,:)); % call it once to estimate the time t = toc(stopwatch); - fprintf('determining inside points, this takes about %d seconds\n', round(size(dippos,1)*t)); - k = dsearchn(elementpos, dippos); - - % select the source positions that are inside the brain - inside = brain(k); + fprintf('determining inside points, this takes about %d seconds\n', round(numdip*t)); + posindx = dsearchn(headmodel.pos, dippos); + + % The following code is only guaranteed to work with convex elements. Regular + % hexahedra and tetrahedra are convex, and the adapted hexahedra we can use with + % SIMBIO have to be convex as well. + + inside = false(1, numdip); + % for each dipole determine whether it is inside one of the neighbouring hexaheders + % this will be the case for all vertices that are inside the middle, but not at the edges + for i=1:numel(insidedip) + hexindx = find(hex2pos(:,posindx(i))); + for j=1:numel(hexindx) + posx = headmodel.pos(headmodel.hex(hexindx(j),:),1); + posy = headmodel.pos(headmodel.hex(hexindx(j),:),2); + posz = headmodel.pos(headmodel.hex(hexindx(j),:),3); + pos = [posx posy posz]; + if isequal(convhull(pos), convhull([pos; dippos(i,:)])) + inside(insidedip(i)) = true; + break % out of the for-loop + end % if + end % for each hexaheder + end % for each of the dipole positions otherwise - error('unrecognized volume conductor model'); + ft_error('unrecognized volume conductor model'); end % ensure that it is a boolean column vector diff --git a/external/fieldtrip/inverse/private/ft_notification.m b/external/fieldtrip/inverse/private/ft_notification.m new file mode 100644 index 00000000..dc9b7369 --- /dev/null +++ b/external/fieldtrip/inverse/private/ft_notification.m @@ -0,0 +1,482 @@ +function [varargout] = ft_notification(varargin) + +% FT_NOTIFICATION works mostly like the WARNING and ERROR commands in MATLAB and +% is called by FT_ERROR, FT_WARNING, FT_NOTICE, FT_INFO, FT_DEBUG. Note that you +% should not call this function directly. +% +% Some examples: +% ft_info on +% ft_info on msgId +% ft_info off +% ft_info off msgId +% ft_info once +% ft_info once msgId +% ft_info on backtrace +% ft_info off backtrace +% ft_info on verbose +% ft_info off verbose +% +% ft_info query % shows the status of all notifications +% ft_info last % shows the last notification +% ft_info clear % clears the status of all notifications +% ft_info timeout 10 % sets the timeout (for 'once') to 10 seconds +% +% See also DEFAULTID + +% Copyright (C) 2012-2017, Robert Oostenveld, J?rn M. Horschig +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +global ft_default + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% determine who is calling + +stack = dbstack('-completenames'); +% st(1) is this function +% st(2) is the calling function +switch stack(2).name + case 'ft_debug' + level = 'debug'; + case 'ft_info' + level = 'info'; + case 'ft_notice' + level = 'notice'; + case 'ft_warning' + level = 'warning'; + case 'ft_error' + level = 'error'; + otherwise + error('this function cannot be called from %s', stack(2).name); +end + +% remove this function itself and the ft_xxx calling function +stack = stack(3:end); + +% remove the non-FieldTrip functions from the path, these should not be part of the default message identifier +keep = true(size(stack)); +p = fileparts(which('ft_defaults')); +for i=1:numel(stack) + keep(i) = strncmp(p, stack(i).file, length(p)); +end +stack = stack(keep); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% handle the defaults + +if isfield(ft_default, 'notification') && isfield(ft_default.notification, level) + % this would be error, warning, notice, info, debug + s = ft_default.notification.(level); +else + s = []; +end + +% start with an empty state structure +if isempty(s) + s = struct('identifier', {}, 'state', {}, 'timestamp', {}); +end + +% set the default notification state +if ~ismember('all', {s.identifier}) + s = setstate(s, 'all', 'on'); +end + +% set the default backtrace state +defaultbacktrace = false; +if ~ismember('backtrace', {s.identifier}) + switch level + case {'debug' 'info' 'notice'} + s = setstate(s, 'backtrace', 'off'); + case 'warning' + defaultbacktrace = true; + t = warning('query', 'backtrace'); % get the default state + s = setstate(s, 'backtrace', t.state); + case 'error' + s = setstate(s, 'backtrace', 'on'); + end % switch +end + +% set the default verbose state +defaultverbose = false; +if ~ismember('verbose', {s.identifier}) + switch level + case 'warning' + defaultverbose = true; + t = warning('query', 'verbose');% get the default state + s = setstate(s, 'verbose', t.state); + otherwise + s = setstate(s, 'verbose', 'off'); + end +end + +% set the default timeout +if ~ismember('timeout', {s.identifier}) + s = setstate(s, 'timeout', 60); +end + +% set the last notification to empty +if ~ismember('last', {s.identifier}) + state.message = ''; + state.identifier = ''; + state.stack = struct('file', {}, 'name', {}, 'line', {}); + s = setstate(s, 'last', state); +end + +if strcmp(level, 'warning') + ws = warning; + % warnings should be on in general + warning on + % the backtrace is handled by this function + warning off backtrace + % the verbose message is handled by this function + warning off verbose +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% set the notification state according to the input + +if numel(varargin)>0 && (isstruct(varargin{1}) || isempty(varargin{1})) + ft_default.notification.(level) = varargin{1}; + return +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% act according to the first input argument + +if isempty(varargin) + varargin{1} = 'query'; +end + +switch varargin{1} + case 'on' + if numel(varargin)>1 + % switch a specific item on + msgId = varargin{2}; + s = setstate(s, msgId, 'on'); + if strcmp(msgId, 'backtrace') + defaultbacktrace = false; + end + if strcmp(msgId, 'verbose') + defaultverbose = false; + end + % return the message state of all + varargout{1} = getreturnstate(s, msgId); + else + % switch all on + s = setstate(s, 'all', 'on'); + % return the message state of all + varargout{1} = getreturnstate(s); + end + + case 'off' + if numel(varargin)>1 + % switch a specific item off + msgId = varargin{2}; + s = setstate(s, msgId, 'off'); + if strcmp(msgId, 'backtrace') + defaultbacktrace = false; + end + if strcmp(msgId, 'verbose') + defaultverbose = false; + end + % return the specific message state + varargout{1} = getreturnstate(s, msgId); + else + % switch all off + s = setstate(s, 'all', 'off'); + % return the message state of all + varargout{1} = getreturnstate(s); + end + + case 'once' + if numel(varargin)>1 + % switch a specific item to once + msgId = varargin{2}; + s = setstate(s, msgId, 'once'); + % return the specific message state + varargout{1} = getreturnstate(s, msgId); + else + % switch all to once + s = setstate(s, 'all', 'once'); + % return the message state of all + varargout{1} = getreturnstate(s); + end + + case 'timeout' + % set the timeout, this is used for 'once' + if ischar(varargin{2}) + s = setstate(s, 'timeout', str2double(varargin{2})); + else + s = setstate(s, 'timeout', varargin{2}); + end + + case {'last' '-last'} + % return the last notification + varargout{1} = getstate(s, 'last'); + + case {'clear' '-clear'} + % reset the notification system + s = []; + + case {'query' '-query'} + if numel(varargin)>1 + % select a specific item + msgId = varargin{2}; + if ~ismember(msgId, {s.identifier}) + error('Unknown setting or incorrect message identifier ''%s''.', msgId); + end + msgState = getstate(s, msgId); + if nargout + varargout{1} = getreturnstate(s, msgId); + elseif strcmp(msgId, 'verbose') + if istrue(msgState) + fprintf('%s output is verbose.\n', level); + else + fprintf('%s output is terse.\n', level); + end + elseif strcmp(msgId, 'backtrace') + if istrue(msgState) + fprintf('%s backtraces are enabled.\n', level); + else + fprintf('%s backtraces are disabled.\n', level); + end + else + fprintf('The state of %s ''%s'' is ''%s''\n', level, msgId, msgState); + end + else + % return all items + r = getreturnstate(s); + + if nargout + % return the state of all items + varargout{1} = r; + else + % show the state of all items that are different from the default + default = getstate(s, 'all'); + fprintf('The default %s state is ''%s''.', level, default); + r = r(~strcmp({r.state}, default)); + % don't show these + r(strcmp('verbose', {r.identifier})) = []; + r(strcmp('backtrace', {r.identifier})) = []; + if ~isempty(r) + fprintf(' Items not set to the default are\n\n'); + end + for i=1:numel(r) + fprintf(' %4s %s\n', r(i).state, r(i).identifier); + end + fprintf('\n'); + end + end + + otherwise + + if nargout + varargout{1} = getreturnstate(s); + end + + % first input might be msgId + if numel(varargin)>1 && ~isempty(regexp(varargin{1}, '^\w*:', 'once')) + msgId = varargin{1}; + varargin = varargin(2:end); % shift them all by one + else + msgId = defaultId; + end + + % get the state for this notification, it will default to the 'all' state + msgState = getstate(s, msgId); + + % errors are always to be printed + if strcmp(level, 'error') + msgState = 'on'; + end + + if strcmp(msgState, 'once') + timeout = getstate(s, 'timeout'); + since = elapsed(gettimestamp(s, msgId)); + if (since>timeout) + % the timeout has passed, update the timestamp and print the message + s = settimestamp(s, msgId, tic); + msgState = 'on'; + else + % the timeout has not yet passed, do not print the message + msgState = 'off'; + end + end + + % use an automatically generated default identifier + if isempty(msgId) + msgId = defaultId; + end + + % store the last notification + state.message = strtrim(sprintf(varargin{:})); % remove the trailing newline + state.identifier = msgId; + state.stack = stack; + s = setstate(s, 'last', state); + + if strcmp(msgState, 'on') + + if strcmp(level, 'error') + % update the global variable, we won't return here after the error + ft_default.notification.(level) = s; + % the remainder is fully handled by the ERROR function + if ~isempty(msgId) + error(msgId, varargin{:}); + else + error(varargin{:}); + end + + elseif strcmp(level, 'warning') + if ~isempty(msgId) + warning(msgId, varargin{:}); + else + warning(varargin{:}); + end + + else + % ensure there is a line end + if isempty(regexp(varargin{1}, '\\n$', 'once')) % note the double \\ + varargin{1} = [varargin{1} '\n']; + end + fprintf(varargin{:}); + + end % if level=error, warning or otherwise + + % decide whether the stack trace should be shown + if istrue(getstate(s, 'backtrace')) + for i=1:numel(stack) + % show the deepest and lowest-level function first + [p, f, x] = fileparts(stack(i).file); + if isequal(f, stack(i).name) + funname = stack(i).name; + else + funname = sprintf('%s>%s', f, stack(i).name); + end + filename = stack(i).file; + if isempty(fileparts(filename)) + % it requires the full path + filename = fullfile(pwd, filename); + end + if ft_platform_supports('html') + fprintf(' In %s at line %d\n', filename, stack(i).line, funname, stack(i).line); + else + fprintf(' In ''%s'' at line %d\n', filename, stack(i).line); + end + end + fprintf('\n'); + end + + % decide whether a verboe message should be shown + if istrue(getstate(s, 'verbose')) + if ~isempty(msgId) + fprintf('Type "ft_%s off %s" to suppress this message.\n', level, msgId) + else + fprintf('Type "ft_%s off" to suppress this message.\n', level) + end + end + + end % if msgState is on + +end % switch varargin{1} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% update the global variable +if defaultbacktrace && ~isempty(s) + % do not keep the default, it will be determined again on the next call + s = s(~strcmp({s.identifier}, 'backtrace')); +end +if defaultverbose && ~isempty(s) + % do not keep the default, it will be determined again on the next call + s = s(~strcmp({s.identifier}, 'verbose')); +end +ft_default.notification.(level) = s; + +if strcmp(level, 'warning') + % return to the original warning state + warning(ws); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTIONS +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +function r = getreturnstate(s, msgId) +if nargin<2 + r = s; + % don't return these + r(strcmp('timeout', {r.identifier})) = []; + r(strcmp('last', {r.identifier})) = []; + % don't return the timestamps + r = rmfield(r, 'timestamp'); +else + msgState = getstate(s, msgId); + r = struct('identifier', msgId, 'state', msgState); +end + +function state = getstate(s, msgId) +identifier = {s.identifier}; +sel = find(strcmp(identifier, msgId)); +if numel(sel)==1 + state = s(sel).state; + if isempty(state) + state = getstate(s, 'all'); + end +else + state = getstate(s, 'all'); +end + +function timestamp = gettimestamp(s, msgId) +identifier = {s.identifier}; +sel = find(strcmp(identifier, msgId)); +if numel(sel)==1 + timestamp = s(sel).timestamp; +else + timestamp = nan; +end + +function s = setstate(s, msgId, state) +if isempty(msgId), return; end % this happens from the command line +identifier = {s.identifier}; +sel = find(strcmp(identifier, msgId)); +if numel(sel)==1 + s(sel).state = state; +else + s(end+1).identifier = msgId; + s(end ).state = state; + s(end ).timestamp = nan; +end + +function s = settimestamp(s, msgId, timestamp) +if isempty(msgId), return; end % this happens from the command line +identifier = {s.identifier}; +sel = find(strcmp(identifier, msgId)); +if numel(sel)==1 + s(sel).timestamp = timestamp; +else + s(end+1).identifier = msgId; + s(end ).state = []; + s(end ).timestamp = timestamp; +end + +function t = elapsed(start) +if isempty(start) || isnan(start) + t = inf; +else + t = toc(start); +end diff --git a/external/fieldtrip/inverse/private/ft_platform_supports.m b/external/fieldtrip/inverse/private/ft_platform_supports.m new file mode 100644 index 00000000..c0676b62 --- /dev/null +++ b/external/fieldtrip/inverse/private/ft_platform_supports.m @@ -0,0 +1,336 @@ +function tf = ft_platform_supports(what,varargin) + +% FT_PLATFORM_SUPPORTS returns a boolean indicating whether the current platform +% supports a specific capability +% +% Use as +% status = ft_platform_supports(what) +% or +% status = ft_platform_supports('matlabversion', min_version, max_version) +% +% The following values are allowed for the 'what' parameter, which means means that +% the specific feature explained on the right is supported: +% +% 'which-all' which(...,'all') +% 'exists-in-private-directory' exists(...) will look in the /private subdirectory to see if a file exists +% 'onCleanup' onCleanup(...) +% 'alim' alim(...) +% 'int32_logical_operations' bitand(a,b) with a, b of type int32 +% 'graphics_objects' graphics sysem is object-oriented +% 'libmx_c_interface' libmx is supported through mex in the C-language (recent MATLAB versions only support C++) +% 'images' all image processing functions in FieldTrip's external/images directory +% 'signal' all signal processing functions in FieldTrip's external/signal directory +% 'stats' all statistical functions in FieldTrip's external/stats directory +% 'program_invocation_name' program_invocation_name() (GNU Octave) +% 'singleCompThread' start MATLAB with -singleCompThread +% 'nosplash' start MATLAB with -nosplash +% 'nodisplay' start MATLAB with -nodisplay +% 'nojvm' start MATLAB with -nojvm +% 'no-gui' start GNU Octave with --no-gui +% 'RandStream.setGlobalStream' RandStream.setGlobalStream(...) +% 'RandStream.setDefaultStream' RandStream.setDefaultStream(...) +% 'rng' rng(...) +% 'rand-state' rand('state') +% 'urlread-timeout' urlread(..., 'Timeout', t) +% 'griddata-vector-input' griddata(...,...,...,a,b) with a and b vectors +% 'griddata-v4' griddata(...,...,...,...,...,'v4') with v4 interpolation support +% 'uimenu' uimenu(...) +% 'weboptions' weboptions(...) +% 'parula' parula(...) +% 'html' html rendering in desktop +% +% See also FT_VERSION, VERSION, VER, VERLESSTHAN + +if ~ischar(what) + error('first argument must be a string'); +end + +switch what + case 'matlabversion' + tf = is_matlab() && matlabversion(varargin{:}); + + case 'exists-in-private-directory' + tf = is_matlab(); + + case 'which-all' + tf = is_matlab(); + + case 'onCleanup' + tf = is_octave() || matlabversion(7.8, Inf); + + case 'alim' + tf = is_matlab(); + + case 'int32_logical_operations' + % earlier version of MATLAB don't support bitand (and similar) + % operations on int32 + tf = is_octave() || ~matlabversion(-Inf, '2012a'); + + case 'graphics_objects' + % introduced in MATLAB 2014b, graphics is handled through objects; + % previous versions use numeric handles + tf = is_matlab() && matlabversion('2014b', Inf); + + case 'libmx_c_interface' + % removed after 2013b + tf = is_matlab() && matlabversion(-Inf, '2013b'); + + case 'images' + root_dir = fileparts(which('ft_defaults')); + external_stats_dir = fullfile(root_dir, 'external', 'images'); + + tf = has_all_functions_in_dir(external_stats_dir, {}); + + case 'signal' + root_dir = fileparts(which('ft_defaults')); + external_stats_dir = fullfile(root_dir, 'external', 'signal'); + + tf = has_all_functions_in_dir(external_stats_dir, {}); + + case 'stats' + root_dir = fileparts(which('ft_defaults')); + external_stats_dir = fullfile(root_dir, 'external', 'stats'); + + % these files are only used by other functions in the external/stats directory + exclude_mfiles = { + 'common_size.m' + 'iscomplex.m' + }; + + tf = has_all_functions_in_dir(external_stats_dir, exclude_mfiles); + + case 'program_invocation_name' + % Octave supports program_invocation_name, which returns the path + % of the binary that was run to start Octave + tf = is_octave(); + + case 'singleCompThread' + tf = is_matlab() && matlabversion(7.8, Inf); + + case {'nosplash', 'nodisplay', 'nojvm'} + % Only on MATLAB + tf = is_matlab(); + + case 'no-gui' + % Only on Octave + tf = is_octave(); + + case 'RandStream.setDefaultStream' + tf = is_matlab() && matlabversion('2008b', '2011b'); + + case 'RandStream.setGlobalStream' + tf = is_matlab() && matlabversion('2012a', Inf); + + case 'randomized_PRNG_on_startup' + tf = is_octave() || ~matlabversion(-Inf, '7.3'); + + case 'rng' + % recent MATLAB versions + tf = is_matlab() && matlabversion('7.12', Inf); + + case 'rand-state' + % GNU Octave + tf = is_octave(); + + case 'urlread-timeout' + tf = is_matlab() && matlabversion('2012b', Inf); + + case 'griddata-vector-input' + tf = is_matlab(); + + case 'griddata-v4' + tf = is_matlab() && matlabversion('2009a', Inf); + + case 'uimenu' + tf = is_matlab(); + + case {'weboptions', 'webread', 'websave'} + tf = is_matlab() && matlabversion('2014b', Inf); + + case 'webwrite' + tf = is_matlab() && matlabversion('2015a', Inf); + + case 'boundary' + tf = is_matlab() && matlabversion('2014b', Inf); + + case 'parula' + tf = is_matlab() && matlabversion('2014b', Inf); + + case 'html' + tf = ~is_octave() && usejava('desktop') && desktop('-inuse'); + + otherwise + error('unsupported value for first argument: %s', what); + +end % switch + +end % function + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function tf = is_matlab() +tf = ~is_octave(); +end % function + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function tf = is_octave() +persistent cached_tf + +if isempty(cached_tf) + cached_tf = logical(exist('OCTAVE_VERSION', 'builtin')); +end + +tf = cached_tf; +end % function + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function tf = has_all_functions_in_dir(in_dir, exclude_mfiles) +% returns true if all functions in in_dir are already provided by the platform +m_files = dir(fullfile(in_dir,'*.m')); +n = numel(m_files); + +for k = 1:n + m_filename = m_files(k).name; + if isempty(which(m_filename)) && isempty(strmatch(m_filename,exclude_mfiles)) + tf = false; + return; + end +end + +tf = true; + +end % function + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function [inInterval] = matlabversion(min, max) + +% MATLABVERSION checks if the current MATLAB version is within the interval +% specified by min and max. +% +% Use as +% if matlabversion(7.0, 7.9) +% % do something +% end +% +% Both strings and numbers, as well as infinities, are supported, eg.: +% matlabversion(7.1, 7.9) % is version between 7.1 and 7.9? +% matlabversion(6, '7.10') % is version between 6 and 7.10? (note: '7.10', not 7.10) +% matlabversion(-Inf, 7.6) % is version <= 7.6? +% matlabversion('2009b') % exactly 2009b +% matlabversion('2008b', '2010a') % between two versions +% matlabversion('2008b', Inf) % from a version onwards +% etc. +% +% See also VERSION, VER, VERLESSTHAN + +% Copyright (C) 2006, Robert Oostenveld +% Copyright (C) 2010, Eelke Spaak +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +% the version does not change, making it persistent speeds up the subsequent calls +persistent curVer + +if nargin<2 + max = min; +end + +if isempty(curVer) + curVer = version(); +end + +if ((ischar(min) && isempty(str2num(min))) || (ischar(max) && isempty(str2num(max)))) + % perform comparison with respect to release string + + ind = strfind(curVer, '(R'); + [year, ab] = parseMatlabRelease(curVer((ind + 2):(numel(curVer) - 1))); + + [minY, minAb] = parseMatlabRelease(min); + [maxY, maxAb] = parseMatlabRelease(max); + + inInterval = orderedComparison(minY, minAb, maxY, maxAb, year, ab); + +else + % perform comparison with respect to version number + [major, minor] = parseMatlabVersion(curVer); + [minMajor, minMinor] = parseMatlabVersion(min); + [maxMajor, maxMinor] = parseMatlabVersion(max); + + inInterval = orderedComparison(minMajor, minMinor, maxMajor, maxMinor, major, minor); +end + +end % function + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function [year, ab] = parseMatlabRelease(str) +if (str == Inf) + year = Inf; ab = Inf; +elseif (str == -Inf) + year = -Inf; ab = -Inf; +else + year = str2num(str(1:4)); + ab = str(5); +end +end % function + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function [major, minor] = parseMatlabVersion(ver) +if (ver == Inf) + major = Inf; minor = Inf; +elseif (ver == -Inf) + major = -Inf; minor = -Inf; +elseif (isnumeric(ver)) + major = floor(ver); + minor = int8((ver - floor(ver)) * 10); +else % ver is string (e.g. '7.10'), parse accordingly + [major, rest] = strtok(ver, '.'); + major = str2num(major); + minor = str2num(strtok(rest, '.')); +end +end % function + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function inInterval = orderedComparison(lowerA, lowerB, upperA, upperB, testA, testB) +% checks if testA is in interval (lowerA,upperA); if at edges, checks if testB is in interval (lowerB,upperB). +if (testA < lowerA || testA > upperA) + inInterval = false; +else + inInterval = true; + if (testA == lowerA) + inInterval = inInterval && (testB >= lowerB); + end + + if (testA == upperA) + inInterval = inInterval && (testB <= upperB); + end +end +end % function diff --git a/external/fieldtrip/inverse/private/ft_progress.m b/external/fieldtrip/inverse/private/ft_progress.m index 559686aa..d7dce75e 100644 --- a/external/fieldtrip/inverse/private/ft_progress.m +++ b/external/fieldtrip/inverse/private/ft_progress.m @@ -27,6 +27,8 @@ function ft_progress(varargin) % pause(0.1); % end % ft_progress('close') +% +% See also WAITBAR % Copyright (C) 2004-2008, Robert Oostenveld % diff --git a/external/fieldtrip/inverse/private/ft_scalingfactor.m b/external/fieldtrip/inverse/private/ft_scalingfactor.m index 804871df..ad7a8512 100644 --- a/external/fieldtrip/inverse/private/ft_scalingfactor.m +++ b/external/fieldtrip/inverse/private/ft_scalingfactor.m @@ -87,7 +87,7 @@ end if ~isequal(class(old), class(new)) - error('the input arguments should be of the same class'); + ft_error('the input arguments should be of the same class'); end if iscell(old) @@ -178,7 +178,7 @@ eval(sprintf('oldunit = %s;', old)); eval(sprintf('newunit = %s;', new)); if ~isequal(oldunit, newunit) - error('cannot convert %s to %s', old, new); + ft_error('cannot convert %s to %s', old, new); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/external/fieldtrip/inverse/private/ft_senslabel.m b/external/fieldtrip/inverse/private/ft_senslabel.m index 4ab57989..85e062af 100644 --- a/external/fieldtrip/inverse/private/ft_senslabel.m +++ b/external/fieldtrip/inverse/private/ft_senslabel.m @@ -87,7 +87,7 @@ output = ft_getopt(varargin, 'output', 'normal'); % 'normal' or 'planarcombined' if ~exist(type, 'var') - error('the requested sensor type "%s" is not supported', type); + ft_error('the requested sensor type "%s" is not supported', type); elseif isempty(eval(type)) % assign the list of channels only once, keep it as persistent variable @@ -3673,7 +3673,7 @@ label = ft_senslabel(type); otherwise - error('the requested sensor type "%s" is not supported', type); + ft_error('the requested sensor type "%s" is not supported', type); end % switch @@ -3700,6 +3700,6 @@ label = [planar(:,1:2) combined]; % magnetometers are in the 3rd column for neuromag306 otherwise - error('unsupported output "%s"', output); + ft_error('unsupported output "%s"', output); end diff --git a/external/fieldtrip/inverse/private/ft_senstype.m b/external/fieldtrip/inverse/private/ft_senstype.m index 1d91722d..b6753338 100644 --- a/external/fieldtrip/inverse/private/ft_senstype.m +++ b/external/fieldtrip/inverse/private/ft_senstype.m @@ -43,18 +43,27 @@ % 'biosemi64' % 'biosemi128' % 'biosemi256' +% 'ant128' % 'neuralynx' % 'plexon' % 'artinis' -% 'ext1020' this includes eeg1020, eeg1010 and eeg1005 -% 'eeg' this was called 'electrode' in older versions -% 'meg' this was called 'magnetometer' in older versions % 'nirs' +% 'meg' +% 'eeg' +% 'ieeg' +% 'seeg' +% 'ecog' +% 'eeg1020' +% 'eeg1010' +% 'eeg1005' +% 'ext1020' in case it is a small subset of eeg1020, eeg1010 or eeg1005 % % The optional input argument for the desired type can be any of the above, or any of % the following generic classes of acquisition systems % 'eeg' +% 'ieeg' % 'ext1020' +% 'ant' % 'biosemi' % 'egi' % 'meg' @@ -81,7 +90,7 @@ % % See also FT_SENSLABEL, FT_CHANTYPE, FT_READ_SENS, FT_COMPUTE_LEADFIELD, FT_DATATYPE_SENS -% Copyright (C) 2007-2016, Robert Oostenveld +% Copyright (C) 2007-2017, Robert Oostenveld % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -146,7 +155,8 @@ iselec = (isa(input, 'struct') && isfield(input, 'label') && isfield(input, 'elecpos')) || iselec; % new style isnirs = isa(input, 'struct') && isfield(input, 'label') && isfield(input, 'transceiver'); islabel = isa(input, 'cell') && ~isempty(input) && isa(input{1}, 'char'); -haslabel = isa(input, 'struct') && isfield(input, 'label'); +haslabel = isa(input, 'struct') && isfield(input, 'label'); +haschantype = isa(input, 'struct') && isfield(input, 'chantype'); if ~(isdata || isheader || isgrad || iselec || isnirs || islabel || haslabel) && isfield(input, 'hdr') input = input.hdr; @@ -211,8 +221,8 @@ elseif haslabel % it does not resemble anything that we had expected at this location, but it does have channel labels % the channel labels can be used to determine the type of sensor array - sens.label = input.label; - islabel = true; + sens = keepfields(input, {'label' 'chantype'}); + islabel = true; else sens = []; @@ -265,21 +275,18 @@ % start with unknown, then try to determine the proper type by looking at the labels type = 'unknown'; - if isgrad && isfield(sens, 'type') - type = sens.type; - - elseif isgrad + if isgrad % this looks like MEG + % revert the component balancing that was previously applied if isfield(sens, 'balance') && strcmp(sens.balance.current, 'comp') sens = undobalancing(sens); end - % determine the type of magnetometer/gradiometer system based on the channel names alone + % determine the particular type of acquisition system based on the channel names alone % this uses a recursive call to the "islabel" section further down type = ft_senstype(sens.label); - %sens_temp.type = type; - if strcmp(type, 'unknown') %|| ~ft_senstype(sens_temp,'meg') + if strcmp(type, 'unknown') % although we don't know the type, we do know that it is MEG type = 'meg'; end @@ -287,24 +294,33 @@ elseif iselec % this looks like EEG - % determine the type of eeg/acquisition system based on the channel names alone + % determine the particular type of acquisition system based on the channel names alone % this uses a recursive call to the "islabel" section further down type = ft_senstype(sens.label); - %sens_temp.type = type; - if strcmp(type, 'unknown') %|| ~ft_senstype(sens_temp,'eeg') - % although we don't know the type, we do know that it is EEG - type = 'eeg'; + if strcmp(type, 'unknown') + % although we don't know the type, we do know that it is EEG, IEEG, SEEG, or ECOG + if haschantype && all(strcmp(sens.chantype, 'eeg')) + type = 'eeg'; + elseif haschantype && all(strcmp(sens.chantype, 'seeg')) + type = 'seeg'; + elseif haschantype && all(strcmp(sens.chantype, 'ecog')) + type = 'ecog'; + elseif haschantype && all(ismember(sens.chantype, {'ieeg' 'seeg' 'ecog'})) + type = 'ieeg'; + else + % fall back to the most generic description + type = 'eeg'; + end end elseif isnirs % this looks like NIRS - % determine the type of eeg/acquisition system based on the channel names alone + % determine the particular type of acquisition system based on the channel names alone % this uses a recursive call to the "islabel" section further down type = ft_senstype(sens.label); - %sens_temp.type = type; - if strcmp(type, 'unknown') %|| ~ft_senstype(sens_temp,'eeg') - % although we don't know the type, we do know that it is EEG + if strcmp(type, 'unknown') + % although we don't know the type, we do know that it is NIRS type = 'nirs'; end @@ -382,7 +398,7 @@ elseif (mean(ismember(ft_senslabel('egi32'), sens.label)) > 0.8) type = 'egi32'; - % the following check on the fraction of channels in the user's data rather than on the fraction of channels in the predefined set + % the following check looks at the fraction of channels in the user's data rather than the fraction in the predefined set elseif (mean(ismember(sens.label, ft_senslabel('eeg1020'))) > 0.8) type = 'eeg1020'; elseif (mean(ismember(sens.label, ft_senslabel('eeg1010'))) > 0.8) @@ -390,12 +406,14 @@ elseif (mean(ismember(sens.label, ft_senslabel('eeg1005'))) > 0.8) type = 'eeg1005'; - elseif (sum(ismember(sens.label, ft_senslabel('eeg1005'))) > 10) % Otherwise it's not even worth recognizing + % the following check looks at the fraction of channels in the user's data rather than the fraction in the predefined set + % there is a minumum number of channels, otherwise it is not worth recognizing + elseif (sum(ismember(sens.label, ft_senslabel('eeg1005'))) > 10) type = 'ext1020'; % this will also cover small subsets of eeg1020, eeg1010 and eeg1005 - elseif any(ismember(ft_senslabel('btiref'), sens.label)) - type = 'bti'; % it might be 148 or 248 channels - elseif any(ismember(ft_senslabel('ctfref'), sens.label)) - type = 'ctf'; % it might be 151 or 275 channels + elseif (sum(ismember(ft_senslabel('btiref'), sens.label)) > 10) + type = 'bti'; % 23 in the reference set, it might be 148 or 248 channels + elseif (sum(ismember(ft_senslabel('ctfref'), sens.label)) > 10) + type = 'ctf'; % 29 in the reference set, it might be 151 or 275 channels end end % look at label, ori and/or pos @@ -432,26 +450,30 @@ if ~isempty(desired) % return a boolean flag switch desired + case {'eeg'} + type = any(strcmp(type, {'eeg' 'ieeg' 'seeg' 'ecog' 'ant128' 'biosemi64' 'biosemi128' 'biosemi256' 'egi32' 'egi64' 'egi128' 'egi256' 'ext1020' 'eeg1005' 'eeg1010' 'eeg1020'})); case 'ext1020' - type = any(strcmp(type, {'eeg1005' 'eeg1010' 'eeg1020' 'ext1020'})); - case {'eeg' 'electrode'} - type = any(strcmp(type, {'eeg' 'electrode' 'ant128' 'biosemi64' 'biosemi128' 'biosemi256' 'egi32' 'egi64' 'egi128' 'egi256' 'eeg1005' 'eeg1010' 'eeg1020' 'ext1020'})); + type = any(strcmp(type, {'ext1020' 'eeg1005' 'eeg1010' 'eeg1020'})); + case {'ieeg'} + type = any(strcmp(type, {'ieeg' 'seeg' 'ecog'})); + case 'ant' + type = any(strcmp(type, {'ant' 'ant128'})); case 'biosemi' - type = any(strcmp(type, {'biosemi64' 'biosemi128' 'biosemi256'})); + type = any(strcmp(type, {'biosemi' 'biosemi64' 'biosemi128' 'biosemi256'})); case 'egi' - type = any(strcmp(type, {'egi32' 'egi64' 'egi128' 'egi256'})); + type = any(strcmp(type, {'egi' 'egi32' 'egi64' 'egi128' 'egi256'})); case 'meg' - type = any(strcmp(type, {'meg' 'magnetometer' 'ctf' 'bti' 'ctf64' 'ctf151' 'ctf275' 'ctf151_planar' 'ctf275_planar' 'neuromag122' 'neuromag306' 'neuromag306_combined' 'bti148' 'bti148_planar' 'bti248' 'bti248_planar' 'bti248grad' 'bti248grad_planar' 'yokogawa9' 'yokogawa160' 'yokogawa160_planar' 'yokogawa64' 'yokogawa64_planar' 'yokogawa440' 'itab' 'itab28' 'itab153' 'itab153_planar'})); + type = any(strcmp(type, {'meg' 'ctf' 'ctf64' 'ctf151' 'ctf275' 'ctf151_planar' 'ctf275_planar' 'neuromag' 'neuromag122' 'neuromag306' 'neuromag306_combined' 'bti' 'bti148' 'bti148_planar' 'bti248' 'bti248_planar' 'bti248grad' 'bti248grad_planar' 'yokogawa' 'yokogawa9' 'yokogawa160' 'yokogawa160_planar' 'yokogawa64' 'yokogawa64_planar' 'yokogawa440' 'itab' 'itab28' 'itab153' 'itab153_planar' 'babysquid' 'babysquid74' 'artenis123' 'magview'})); case 'ctf' type = any(strcmp(type, {'ctf' 'ctf64' 'ctf151' 'ctf275' 'ctf151_planar' 'ctf275_planar'})); case 'bti' type = any(strcmp(type, {'bti' 'bti148' 'bti148_planar' 'bti248' 'bti248_planar' 'bti248grad' 'bti248grad_planar'})); case 'neuromag' - type = any(strcmp(type, {'neuromag122' 'neuromag306'})); + type = any(strcmp(type, {'neuromag' 'neuromag122' 'neuromag306'})); case 'babysquid' - type = any(strcmp(type, {'babysquid74' 'artenis123' 'magview'})); + type = any(strcmp(type, {'babysquid' 'babysquid74' 'artenis123' 'magview'})); case 'yokogawa' - type = any(strcmp(type, {'yokogawa160' 'yokogawa160_planar' 'yokogawa64' 'yokogawa64_planar' 'yokogawa440'})); + type = any(strcmp(type, {'yokogawa' 'yokogawa160' 'yokogawa160_planar' 'yokogawa64' 'yokogawa64_planar' 'yokogawa440'})); case 'itab' type = any(strcmp(type, {'itab' 'itab28' 'itab153' 'itab153_planar'})); case 'meg_axial' diff --git a/external/fieldtrip/inverse/private/ft_warning.m b/external/fieldtrip/inverse/private/ft_warning.m new file mode 100644 index 00000000..58f3985e --- /dev/null +++ b/external/fieldtrip/inverse/private/ft_warning.m @@ -0,0 +1,65 @@ +function varargout = ft_warning(varargin) + +% FT_WARNING prints a warning message on screen, depending on the verbosity +% settings of the calling high-level FieldTrip function. This function works +% similar to the standard WARNING function, but also features the "once" mode. +% +% Use as +% ft_warning(...) +% with arguments similar to fprintf, or +% ft_warning(msgId, ...) +% with arguments similar to warning. +% +% You can switch of all warning messages using +% ft_warning off +% or for specific ones using +% ft_warning off msgId +% +% To switch them back on, you would use +% ft_warning on +% or for specific ones using +% ft_warning on msgId +% +% Warning messages are only printed once per timeout period using +% ft_warning timeout 60 +% ft_warning once +% or for specific ones using +% ft_warning once msgId +% +% You can see the most recent messages and identifier using +% ft_warning last +% +% You can query the current on/off/once state for all messages using +% ft_warning query +% +% See also FT_ERROR, FT_WARNING, FT_NOTICE, FT_warning, FT_DEBUG, ERROR, WARNING + +% Copyright (C) 2012-2017, Robert Oostenveld, J?rn M. Horschig +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +if nargout + varargout{:} = ft_notification(varargin{:}); +elseif isequal(varargin, {'last'}) + % return an answer anyway + varargout{1} = ft_notification(varargin{:}); +else + ft_notification(varargin{:}); +end + diff --git a/external/fieldtrip/inverse/private/hasyokogawa.m b/external/fieldtrip/inverse/private/hasyokogawa.m index b98d91bb..cf309aab 100644 --- a/external/fieldtrip/inverse/private/hasyokogawa.m +++ b/external/fieldtrip/inverse/private/hasyokogawa.m @@ -74,7 +74,7 @@ elseif [0 2 2 5] == [rev_ADbitInfoM rev_ChannelInfoM rev_AmpGainM rev_MatchingInfoM] version='16bitBeta6'; else - warning('The version of the installed Yokogawa toolbox cannot be determined.'); + ft_warning('The version of the installed Yokogawa toolbox cannot be determined.'); end catch m = lasterror; diff --git a/external/fieldtrip/inverse/private/keyval.m b/external/fieldtrip/inverse/private/keyval.m index b176ce8d..0043c72b 100644 --- a/external/fieldtrip/inverse/private/keyval.m +++ b/external/fieldtrip/inverse/private/keyval.m @@ -44,7 +44,7 @@ end if mod(length(varargin),2) - error('optional input arguments should come in key-value pairs, i.e. there should be an even number'); + ft_error('optional input arguments should come in key-value pairs, i.e. there should be an even number'); end % the 1st, 3rd, etc. contain the keys, the 2nd, 4th, etc. contain the values @@ -58,7 +58,7 @@ end if ~all(valid) - error('optional input arguments should come in key-value pairs, the optional input argument %d is invalid (should be a string)', i); + ft_error('optional input arguments should come in key-value pairs, the optional input argument %d is invalid (should be a string)', i); end hit = find(strcmpi(key, keys)); @@ -69,7 +69,7 @@ % the requested key was found val = vals{hit}; else - error('multiple input arguments with the same name'); + ft_error('multiple input arguments with the same name'); end if nargout>1 diff --git a/external/fieldtrip/inverse/private/quaternion.m b/external/fieldtrip/inverse/private/quaternion.m index ad8d5e06..bd34c4f6 100644 --- a/external/fieldtrip/inverse/private/quaternion.m +++ b/external/fieldtrip/inverse/private/quaternion.m @@ -48,7 +48,7 @@ % $Id$ if numel(q)~=7 - error('incorrect input vector'); + ft_error('incorrect input vector'); end % all of these quaternions are zero-offset in the original equation, but one-offset in the MATLAB vector diff --git a/external/fieldtrip/inverse/private/rigidbody.m b/external/fieldtrip/inverse/private/rigidbody.m index 8f74ee43..cd02a500 100644 --- a/external/fieldtrip/inverse/private/rigidbody.m +++ b/external/fieldtrip/inverse/private/rigidbody.m @@ -50,7 +50,7 @@ % $Id$ if numel(f)~=6 - error('incorrect input vector'); + ft_error('incorrect input vector'); end % compute the homogenous transformation matrix for the translation diff --git a/external/fieldtrip/inverse/private/rotate.m b/external/fieldtrip/inverse/private/rotate.m index d6b05256..2512a5a8 100644 --- a/external/fieldtrip/inverse/private/rotate.m +++ b/external/fieldtrip/inverse/private/rotate.m @@ -49,7 +49,7 @@ % $Id$ if numel(f)~=3 - error('incorrect input vector'); + ft_error('incorrect input vector'); end % convert degrees to radians diff --git a/external/fieldtrip/inverse/private/solid_angle.m b/external/fieldtrip/inverse/private/solid_angle.m index c984e803..47e65c67 100644 --- a/external/fieldtrip/inverse/private/solid_angle.m +++ b/external/fieldtrip/inverse/private/solid_angle.m @@ -1,4 +1,4 @@ -function [varargout] = funname(varargin) +function [varargout] = solid_angle(varargin) % SOLID_ANGLE of a planar triangle as seen from the origin % @@ -33,7 +33,6 @@ % You should have received a copy of the GNU General Public License % along with FieldTrip. If not, see . % -% $Id$ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % The first section contains the plain MATLAB implementation. The mex file @@ -79,7 +78,7 @@ % w = 2 * atan2 (nom, den); % return % else -% error('invalid input'); +% ft_error('invalid input'); % end % compile the missing mex file on the fly @@ -93,7 +92,7 @@ try % try to compile the mex file on the fly - warning('trying to compile MEX file from %s', mexsrc); + ft_warning('trying to compile MEX file from %s', mexsrc); cd(mexdir); if ispc @@ -111,7 +110,7 @@ catch % compilation failed disp(lasterr); - error('could not locate MEX file for %s', mexname); + ft_error('could not locate MEX file for %s', mexname); cd(pwdir); success = false; end diff --git a/external/fieldtrip/inverse/private/solid_angle.mexa64 b/external/fieldtrip/inverse/private/solid_angle.mexa64 index d94d91903daba7af06c027953cbd8f5bc78e29f4..a09e02e630aae3124abc1c336d5d1a1d3a101109 100755 GIT binary patch delta 1247 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 diff --git a/external/fieldtrip/inverse/private/solid_angle.mexw32 b/external/fieldtrip/inverse/private/solid_angle.mexw32 index dda325cac0d7aa134388ff413a50572953861617..6ffabebf93b9126092295ed7c1f25ba324aa865b 100755 GIT binary patch delta 32 lcmZp0XmFVDgQZ30S>(h&K1{byZT4c+5(o1)S4ecQ0|4tG4PXEO delta 32 kcmZp0XmFVDgC*eKr_hOie3*LMHhVE@iG%r@Dsingle'); else - error('you can read either one timeframe, or the complete timecourse'); + ft_error('you can read either one timeframe, or the complete timecourse'); end fclose(fid); else @@ -115,7 +115,7 @@ end Ntime = size(activity,2); else - error('expect column or row to be length 2394 or 6239') + ft_error('expect column or row to be length 2394 or 6239') end if isempty(timeframe) else diff --git a/external/fieldtrip/nutmeg2fieldtrip.m b/external/fieldtrip/nutmeg2fieldtrip.m index f94a348c..d5dcbe71 100644 --- a/external/fieldtrip/nutmeg2fieldtrip.m +++ b/external/fieldtrip/nutmeg2fieldtrip.m @@ -65,7 +65,7 @@ elseif isstruct(fileorstruct) structin=fileorstruct; elseif ~isstruct(fileorstruct) - error('please enter either a structure (beam or nuts) or filename containing either beam or nuts') + ft_error('please enter either a structure (beam or nuts) or filename containing either beam or nuts') end clear fileorstruct @@ -86,7 +86,7 @@ end nutsorbeam=2; else - error('not sure of the input type. maybe you need to call nut_beam_legacy_compatibility?') + ft_error('not sure of the input type. maybe you need to call nut_beam_legacy_compatibility?') end if cfg.keepmri @@ -140,7 +140,7 @@ raw.grad.tra(:,1:size(structin.meg.data,2))=eye(size(structin.meg.data,2)); raw.grad.tra(:,size(structin.meg.data,2)+1:2*size(structin.meg.data,2))=eye(size(structin.meg.data,2)); raw.grad.tra(:,2*size(structin.meg.data,2)+1:end)=structin.meg.Gcoef; - warning('FIXME: should Gcoef be added regardless of structin.meg.grad_order?') + ft_warning('FIXME: should Gcoef be added regardless of structin.meg.grad_order?') end if structin.meg.grad_order==0 @@ -232,7 +232,7 @@ end end else - error('not a valid cfg.out specified'); + ft_error('not a valid cfg.out specified'); end data=source; clear source diff --git a/external/fieldtrip/plotting/ft_plot_axes.m b/external/fieldtrip/plotting/ft_plot_axes.m index ce850c33..f97309ba 100644 --- a/external/fieldtrip/plotting/ft_plot_axes.m +++ b/external/fieldtrip/plotting/ft_plot_axes.m @@ -11,9 +11,14 @@ function ft_plot_axes(object, varargin) % % Additional optional input arguments should be specified as key-value pairs % and can include -% axisscale = scaling factor for the reference axes and sphere (default = 1) -% fontcolor = string (default = 'y') -% 'unit' = string, convert the data to the specified geometrical units (default = []) +% 'axisscale' = scaling factor for the reference axes and sphere (default = 1) +% 'unit' = string, convert the data to the specified geometrical units (default = []) +% 'coordsys' = string, assume the data to be in the specified coordinate system (default = 'unknown') +% 'fontcolor' = string, color specification (default = [1 .5 0], i.e. orange) +% 'fontsize' = number, sets the size of the text (default is automatic) +% 'fontunits' = +% 'fontname' = +% 'fontweight' = % % See also FT_PLOT_SENS, FT_PLOT_MESH, FT_PLOT_ORTHO, FT_PLOT_HEADSHAPE, FT_PLOT_DIPOLE, FT_PLOT_VOL @@ -38,24 +43,47 @@ function ft_plot_axes(object, varargin) % $Id$ axisscale = ft_getopt(varargin, 'axisscale', 1); % this is used to scale the axmax and rbol -fontcolor = ft_getopt(varargin, 'fontcolor', 'y'); % default is yellow unit = ft_getopt(varargin, 'unit'); - -if ~isempty(unit) - % convert the sensor description to the specified units - object = ft_convert_units(object, unit); +coordsys = ft_getopt(varargin, 'coordsys'); +% these have to do with the font +fontcolor = ft_getopt(varargin, 'fontcolor', [1 .5 0]); % default is orange +fontsize = ft_getopt(varargin, 'fontsize', get(0, 'defaulttextfontsize')); +fontname = ft_getopt(varargin, 'fontname', get(0, 'defaulttextfontname')); +fontweight = ft_getopt(varargin, 'fontweight', get(0, 'defaulttextfontweight')); +fontunits = ft_getopt(varargin, 'fontunits', get(0, 'defaulttextfontunits')); + +% color management +if ischar(fontcolor) && exist([fontcolor '.m'], 'file') + fontcolor = eval(fontcolor); end -if isfield(object, 'unit') +if ~isempty(object) && ~isempty(unit) + % convert the object to the specified units + object = ft_convert_units(object, unit); +elseif ~isempty(object) && isempty(unit) + % take the units from the object unit = object.unit; -else - warning('units are not known, not plotting axes') +elseif isempty(object) && ~isempty(unit) + % there is no object, but the units have been specified +elseif isempty(object) && isempty(unit) + ft_warning('units are not known, not plotting axes') return end -if isfield(object, 'coordsys') +if ~isempty(object) && ~isfield(object, 'coordsys') + % set it to unknown, that makes the subsequent code easier + object.coordsys = 'unknown'; +end + +if ~isempty(object) && ~isempty(coordsys) + % check the user specified coordinate system with the one in the object + assert(strcmp(coordsys, unit.coordsys), 'coordsys is inconsistent with the object') +elseif ~isempty(object) && isempty(coordsys) + % take the coordinate system from the object coordsys = object.coordsys; -else +elseif isempty(object) && ~isempty(coordsys) + % there is no object, but the coordsys has been specified +elseif isempty(object) && isempty(coordsys) % this is not a problem per see coordsys = 'unknown'; end @@ -105,56 +133,16 @@ function ft_plot_axes(object, varargin) ft_plot_mesh(O, 'edgecolor', 'none'); % create the labels that are to be plotted along the axes -[labelx, labely, labelz] = xyz2label(coordsys); +[labelx, labely, labelz] = coordsys2label(coordsys, 3, 1); % add the labels to the axis -text(xdat(1,1), ydat(1,1), zdat(1,1), labelx{1}, 'color', fontcolor, 'fontsize', 15, 'linewidth', 2); -text(xdat(1,2), ydat(1,2), zdat(1,2), labely{1}, 'color', fontcolor, 'fontsize', 15, 'linewidth', 2); -text(xdat(1,3), ydat(1,3), zdat(1,3), labelz{1}, 'color', fontcolor, 'fontsize', 15, 'linewidth', 2); -text(xdat(2,1), ydat(2,1), zdat(2,1), labelx{2}, 'color', fontcolor, 'fontsize', 15, 'linewidth', 2); -text(xdat(2,2), ydat(2,2), zdat(2,2), labely{2}, 'color', fontcolor, 'fontsize', 15, 'linewidth', 2); -text(xdat(2,3), ydat(2,3), zdat(2,3), labelz{2}, 'color', fontcolor, 'fontsize', 15, 'linewidth', 2); +text(xdat(1,1), ydat(1,1), zdat(1,1), labelx{1}, 'linewidth', 2, 'color', fontcolor, 'fontunits', fontunits, 'fontsize', fontsize, 'fontname', fontname, 'fontweight', fontweight); +text(xdat(1,2), ydat(1,2), zdat(1,2), labely{1}, 'linewidth', 2, 'color', fontcolor, 'fontunits', fontunits, 'fontsize', fontsize, 'fontname', fontname, 'fontweight', fontweight); +text(xdat(1,3), ydat(1,3), zdat(1,3), labelz{1}, 'linewidth', 2, 'color', fontcolor, 'fontunits', fontunits, 'fontsize', fontsize, 'fontname', fontname, 'fontweight', fontweight); +text(xdat(2,1), ydat(2,1), zdat(2,1), labelx{2}, 'linewidth', 2, 'color', fontcolor, 'fontunits', fontunits, 'fontsize', fontsize, 'fontname', fontname, 'fontweight', fontweight); +text(xdat(2,2), ydat(2,2), zdat(2,2), labely{2}, 'linewidth', 2, 'color', fontcolor, 'fontunits', fontunits, 'fontsize', fontsize, 'fontname', fontname, 'fontweight', fontweight); +text(xdat(2,3), ydat(2,3), zdat(2,3), labelz{2}, 'linewidth', 2, 'color', fontcolor, 'fontunits', fontunits, 'fontsize', fontsize, 'fontname', fontname, 'fontweight', fontweight); if ~prevhold hold off end - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% SUBFUNCTION -% -% NOTE this should be kept consistent with the longer axes labels in FT_DETERMINE_COORDSYS -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -function [labelx, labely, labelz] = xyz2label(str) - -if ~isempty(str) && ~strcmp(str, 'unknown') - % the first part is important for the orientations - % the second part optionally contains information on the origin - strx = tokenize(str, '_'); - - switch lower(strx{1}) - case {'ras' 'itab' 'neuromag' 'spm' 'mni' 'tal'} - labelx = {'-X (left)' '+X (right)' }; - labely = {'-Y (posterior)' '+Y (anterior)'}; - labelz = {'-Z (inferior)' '+Z (superior)'}; - case {'als' 'ctf' '4d', 'bti'} - labelx = {'-X (posterior)' '+X (anterior)'}; - labely = {'-Y (right)' '+Y (left)'}; - labelz = {'-Z (inferior)' '+Z (superior)'}; - case {'paxinos'} - labelx = {'-X (left)' '+X (right)'}; - labely = {'-Y (inferior)' '+Y (superior)'}; - labelz = {'-Z (anterior)' '+Z (posterior)'}; - case {'lps'} - labelx = {'-X (right)' '+X (left)'}; - labely = {'-Y (anterior)' '+Y (posterior)'}; - labelz = {'-Z (inferior)' '+Z (superior)'}; - otherwise - error('unknown coordsys'); - end - -else - labelx = {'-X (unknown)' '+X (unknown)'}; - labely = {'-Y (unknown)' '+Y (unknown)'}; - labelz = {'-Z (unknown)' '+Z (unknown)'}; -end diff --git a/external/fieldtrip/plotting/ft_plot_box.m b/external/fieldtrip/plotting/ft_plot_box.m index e3327c1d..ce9d110d 100644 --- a/external/fieldtrip/plotting/ft_plot_box.m +++ b/external/fieldtrip/plotting/ft_plot_box.m @@ -11,7 +11,7 @@ % 'facealpha' = transparency value between 0 and 1 % 'facecolor' = color specification as [r g b] values or a string, for example 'brain', 'cortex', 'skin', 'red', 'r' % 'edgecolor' = color specification as [r g b] values or a string, for example 'brain', 'cortex', 'skin', 'red', 'r' -% 'tag' = string, the name this vector gets. All tags with the same name can be deleted in a figure, without deleting other parts of the figure. +% 'tag' = string, the name assigned to the object. All tags with the same name can be deleted in a figure, without deleting other parts of the figure. % % It is possible to plot the object in a local pseudo-axis (c.f. subplot), which is specfied as follows % 'hpos' = horizontal position of the center of the local axes @@ -25,6 +25,8 @@ % Example % ft_plot_box([-1 1 2 3], 'facecolor', 'b') % axis([-4 4 -4 4]) +% +% See also FT_PLOT_LINE % Copyrights (C) 2009-2011, Robert Oostenveld % @@ -59,7 +61,15 @@ facecolor = ft_getopt(varargin, 'facecolor', 'none'); edgecolor = ft_getopt(varargin, 'edgecolor', 'k'); tag = ft_getopt(varargin, 'tag', ''); -parent = ft_getopt(varargin, 'parent', []); +parent = ft_getopt(varargin, 'parent', []); + +% color management +if ischar(facecolor) && exist([facecolor '.m'], 'file') + facecolor = eval(facecolor); +end +if ischar(edgecolor) && exist([edgecolor '.m'], 'file') + edgecolor = eval(edgecolor); +end % convert the two cornerpoints into something that the patch function understands % the box position is represented just like the argument to the AXIS function @@ -76,29 +86,27 @@ else % use the full implementation - abc = axis; - if isempty(hlim) - hlim = abc([1 2]); + hlim = get(gca, 'XLim'); end if isempty(vlim) - vlim = abc([3 4]); + vlim = get(gca, 'YLim'); end - if isempty(hpos); + if isempty(hpos) hpos = (hlim(1)+hlim(2))/2; end - if isempty(vpos); + if isempty(vpos) vpos = (vlim(1)+vlim(2))/2; end - if isempty(width), + if isempty(width) width = hlim(2)-hlim(1); end - if isempty(height), + if isempty(height) height = vlim(2)-vlim(1); end diff --git a/external/fieldtrip/plotting/ft_plot_cloud.m b/external/fieldtrip/plotting/ft_plot_cloud.m new file mode 100644 index 00000000..6cf45c5f --- /dev/null +++ b/external/fieldtrip/plotting/ft_plot_cloud.m @@ -0,0 +1,718 @@ +function ft_plot_cloud(pos, val, varargin) + +% FT_PLOT_CLOUD visualizes spatially sparse scalar data as spherical clouds and +% optionally 2D slices through the spherical clouds. This is for example useful for +% spectral power on depth (sEEG) electrodes. +% +% Use as +% ft_plot_cloud(pos, val, ...) +% where the first argument are the sensor positions and the second argument are the +% sensor values. +% +% Optional input arguments should come in key-value pairs and can include +% 'radius' = scalar, maximum radius of cloud (default = 4) +% 'rmin' = scalar >= 1, minimum radius of cloud if scalerad = 'yes' (default = 1) +% 'scalerad' = scale radius with val, can be 'yes' or 'no' (default = 'yes') +% 'colormap' = colormap for functional data, see COLORMAP +% 'colorgrad' = 'white' or a scalar (e.g. 1), degree to which color of points +% in cloud changes from its center +% 'clim' = 1x2 vector specifying the min and max for the colorscale +% 'unit' = string, convert the sensor array to the specified geometrical units (default = []) +% 'mesh' = string or Nx1 cell array, triangulated mesh(es), see FT_PREPARE_MESH +% 'slice' = requires 'mesh' as input (default = 'none') +% '2d', plots 2D slices through the cloud with an outline of the mesh +% '3d', draws an outline around the mesh at a particular slice +% 'slicetype' = 'surf' plots the slices as a surface +% 'point' (default) plots the slices as points +% +% The following inputs apply when 'slice' = 'none' or '3d', or '2dslicetype' = 'point' +% 'ptsize' = scalar, size of points in cloud (default = 1) +% 'ptdensity' = scalar, density of points in cloud (default = 20) +% 'ptgradient' = scalar, degree to which density of points in cloud changes +% from its center, default = .5 (uniform density) +% +% The following inputs apply when 'slice' = '2d' or '3d' +% 'ori' = 'x', 'y', or 'z', specifies the orthogonal plane which will be plotted (default = 'y') +% 'slicepos' = 'auto' or Nx1 vector specifying the position of the +% slice plane along the orientation axis (default = 'auto': chooses slice(s) with +% the most data) +% 'nslices' = scalar, number of slices to plot if 'slicepos' = 'auto (default = 1) +% 'minspace' = scalar, minimum spacing between slices if nslices>1 +% (default = 1) +% 'intersectcolor' = string, Nx1 cell array, or Nx3 vector specifying line color (default = 'k') +% 'intersectlinestyle' = string or Nx1 cell array, line style specification (default = '-') +% 'intersectlinewidth' = scalar or Nx1 vector, line width specification (default = 2) +% +% See also FT_ELECTRODEPLACEMENT, FT_PLOT_TOPO, FT_PLOT_TOPO3D + +% The following inputs apply when 'slicetype' = 'surf' +% 'ncirc' = scalar, number of concentric circles to plot for each +% cloud slice (default = 15) make this hidden or scale +% 'scalealpha' = 'yes' or 'no', scale the maximum alpha value of the center circle +% with distance from center of cloud + +% Copyright (C) 2017, Arjen Stolk, Sandon Griffin +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +% run some checks +if size(pos,2)~=3 + ft_error('pos has to be an Nx3 array') +end + +if isempty(val) + val = ones(size(pos,1),1); % vector of ones +end + +assert(isrow(val) || iscolumn(val), 'values should be represented as a single vector') +val = val(:); % ensure it is a column + +% estimate the unit of geometry of the positions (needed for the other defaults) +posunit = ft_estimate_units(range(pos).*2); % FIXME times 2 otherwise this fails for single/few points +% determine the desired unit of geometry +unit = ft_getopt(varargin, 'unit', posunit); +% convert the sensor positions into the desired units +pos = pos * ft_scalingfactor(posunit, unit); + +% get the generic input arguments +radius = ft_getopt(varargin, 'radius', 4 * ft_scalingfactor('mm', unit)); +rmin = ft_getopt(varargin, 'rmin', 1 * ft_scalingfactor('mm', unit)); +scalerad = ft_getopt(varargin, 'scalerad', 'yes'); +cgrad = ft_getopt(varargin, 'colorgrad', 'white'); +if ft_platform_supports('parula') + cmap = ft_getopt(varargin, 'colormap', 'parula'); +else + cmap = ft_getopt(varargin, 'colormap', 'jet'); +end +clim = ft_getopt(varargin, 'clim'); +meshplot = ft_getopt(varargin, 'mesh'); + +% point related inputs +ptsize = ft_getopt(varargin, 'ptsize', 1); +ptdens = ft_getopt(varargin, 'ptdensity', 20); +ptgrad = ft_getopt(varargin, 'ptgradient', .5); + +% slice related inputs +sli = ft_getopt(varargin, 'slice', 'none'); +slicetype = ft_getopt(varargin, 'slicetype', 'point'); +ori = ft_getopt(varargin, 'ori', 'y'); +slicepos = ft_getopt(varargin, 'slicepos', 'auto'); +nslices = ft_getopt(varargin, 'nslices', 1); +minspace = ft_getopt(varargin, 'minspace', 1); +intersectcolor = ft_getopt(varargin, 'intersectcolor', {'k'}); +intersectlinestyle = ft_getopt(varargin, 'intersectlinestyle', {'-'}); +intersectlinewidth = ft_getopt(varargin, 'intersectlinewidth', 2); +ncirc = ft_getopt(varargin, 'ncirc', 15); +scalealpha = ft_getopt(varargin, 'scalealpha', 'no'); + +% mesh related inputs +facecolor = ft_getopt(varargin, 'facecolor', [0.781 0.762 0.664]); +edgecolor = ft_getopt(varargin, 'edgecolor', 'none'); +facealpha = ft_getopt(varargin, 'facealpha', 1); +edgealpha = ft_getopt(varargin, 'edgealpha', 0); + +if rmin < 1 * ft_scalingfactor('mm', unit) + ft_error('cfg.rmin must be equal or larger than 1 mm'); +end + +if ~isempty(meshplot) + % Mesh should be a cell-array + if isstruct(meshplot) + tmp = meshplot; + meshplot = cell(size(tmp)); + for i=1:numel(tmp) + meshplot{i} = tmp(i); + end + elseif iscell(meshplot) + % do nothing + else + meshplot = {}; + end + + % replace pnt by pos + for k = 1:numel(meshplot) + meshplot{k} = fixpos(meshplot{k}); + end + + for k = 1:numel(meshplot) + if ~isfield(meshplot{k}, 'pos') || ~isfield(meshplot{k}, 'tri') + % ft_error('the mesh should be a structure with pos and tri'); + meshplot{k}.pos = []; + meshplot{k}.tri = []; + end + end + + % facecolor and edgecolor should be cell array + if ~iscell(facecolor) + tmp = facecolor; + if ischar(tmp) + facecolor = {tmp}; + elseif ismatrix(tmp) && size(tmp, 2) == 3 + facecolor = cell(size(tmp,1), 1); + for i=1:size(tmp,1) + facecolor{i} = tmp(i, 1:3); + end + else + facecolor = {}; + end + end + if ~iscell(edgecolor) + tmp = edgecolor; + if ischar(tmp) + edgecolor = {tmp}; + elseif ismatrix(tmp) && size(tmp, 2) == 3 + edgecolor = cell(size(tmp,1), 1); + for i=1:size(tmp,1) + edgecolor{i} = tmp(i, 1:3); + end + else + edgecolor = {}; + end + end + + % make sure each mesh has plotting options specified + if numel(meshplot) > 1 + nmesh = numel(meshplot); + if numel(facecolor) < numel(meshplot) + for m = numel(facecolor)+1:nmesh + facecolor{m} = facecolor{1}; + end + end + if numel(edgecolor) < numel(meshplot) + for m = numel(edgecolor)+1:nmesh + edgecolor{m} = edgecolor{1}; + end + end + if numel(facealpha) < numel(meshplot) + for m = numel(facealpha)+1:nmesh + facealpha(m) = facealpha(1); + end + end + if numel(edgealpha) < numel(meshplot) + for m = numel(edgealpha)+1:nmesh + edgealpha(m) = edgealpha(1); + end + end + end +end + +if strcmp(sli, '2d') || strcmp(sli, '3d') + if isempty(meshplot) + ft_error('plotting a slice requires a mesh as input') + else + dointersect = 1; + end +else + dointersect = 0; +end + +if dointersect % check intersection inputs + % Color and linestyle should be cell-array + if ~iscell(intersectcolor) + tmp = intersectcolor; + if ischar(tmp) + intersectcolor = {tmp}; + elseif ismatrix(tmp) && size(tmp, 2) == 3 + intersectcolor = cell(size(tmp,1), 1); + for i=1:size(tmp,1) + intersectcolor{i} = tmp(i, 1:3); + end + else + intersectcolor = {}; + end + end + if ischar(intersectlinestyle) + intersectlinestyle = {intersectlinestyle}; + elseif iscell(intersectlinestyle) + % do nothing + else + intersectlinestyle = {}; + end + + % Make sure each intersection has plotting options specified + if numel(meshplot) > 1 + nmesh = numel(meshplot); + if numel(intersectcolor) < numel(meshplot) + for m = numel(intersectcolor)+1:nmesh + intersectcolor{m} = intersectcolor{1}; + end + end + if numel(intersectlinewidth) < numel(meshplot) + for m = numel(intersectlinewidth)+1:nmesh + intersectlinewidth(m) = intersectlinewidth(1); + end + end + if numel(intersectlinestyle) < numel(meshplot) + for m = numel(intersectlinestyle)+1:nmesh + intersectlinestyle{m} = intersectlinestyle{1}; + end + end + end % end intersection plotting checks +end % end dointersect checks + +if dointersect + % Set the orientation of the slice plane + if strcmp(ori, 'x') + oriX = 1; oriY = 0; oriZ = 0; + elseif strcmp(ori, 'y') + oriX = 0; oriY = 1; oriZ = 0; + elseif strcmp(ori, 'z') + oriX = 0; oriY = 0; oriZ = 1; + else + ft_error('ori must be "x", "y" or "z"') + end +end + +if isempty(clim) + clim = [min(val) max(val)]; % use the data +end + +% functional data scaling factors +if ischar(cmap) + if strcmp(cmap, 'default') + cmapsc = get(0, 'DefaultFigureColormap'); + else + cmapsc = feval(cmap, 201); % an odd number + end +else + cmapsc = cmap; +end + +cmid = size(cmapsc,1)/2; % colorbar middle +colscf = val / max(abs(clim)); % color: between -1 and 1 (used when cgrad = 'white') +colscf(colscf>1)=1; colscf(colscf<-1)=-1; % clamp values outside the [-1 1] range +radscf = abs( val / max(abs(clim)) ); % radius: between 0 and 1 (used when cgrad = a scalar) +radscf(radscf>1)=1; radscf(radscf<0)=0; % clamp values outside the [0 1] range + +if strcmp(scalerad, 'yes') + rmax = rmin+(radius-rmin)*radscf; % maximum radius of the clouds +else + rmax = ones(length(pos), 1)*radius; % each cloud has the same radius +end + +if dointersect + % Generate Circle Points + angles = linspace(0,2*pi,50); + x = cos(angles)'; + y = sin(angles)'; + slicedim = zeros(length(angles),1); + + if strcmp(slicepos, 'auto') % Search each slice for largest area of data + % Find the potential limits of the interpolation + intxmax = max(pos(:,1))+radius; intxmin = min(pos(:,1))-radius; + intymax = max(pos(:,2))+radius; intymin = min(pos(:,2))-radius; + intzmax = max(pos(:,3))+radius; intzmin = min(pos(:,3))-radius; + + % Define potential slices with data + if oriX; potent_slices = round(intxmin):round(intxmax); end + if oriY; potent_slices = round(intymin):round(intymax); end + if oriZ; potent_slices = round(intzmin):round(intzmax); end + + area = NaN(length(pos),length(potent_slices)); % preallocate matrix of electrode interpolation area for each slice + for s = 1:length(potent_slices) % only search slices that could potentially contain data + distance = NaN(length(pos),1); % preallocate vector for each electrodes distance from the slice + for c = 1:length(pos) % cloud loop + indpos = pos(c, :); + if oriX; distance(c) = abs(indpos(1)-potent_slices(s)); end + if oriY; distance(c) = abs(indpos(2)-potent_slices(s)); end + if oriZ; distance(c) = abs(indpos(3)-potent_slices(s)); end + + if distance(c) < rmax(c) % if there is any data from this electrode in this slice + % find the circle points for the interpolation of this electrode + xmax = rmax(c)*x; + ymax = rmax(c)*y; + + % find the maximum radius of a cross section of the virtual sphere in the given slice + xmaxdif = abs(xmax-distance(c)); + imindif = find(xmaxdif == min(xmaxdif), 1); % index of x value closest to distance(e) + rcmax = abs(ymax(imindif)); + + area(c, s) = 0.5*pi*rcmax^2; + else % area must be zero + area(c, s) = 0; + end + end % end electrode loop + end % end slice loop + totalarea = sum(area); + + slicepos = zeros(nslices,1); + for n = 1:nslices + imaxslice = find(totalarea == max(totalarea), 1); % index of the slice with the maximum area + slicepos(n) = potent_slices(imaxslice); % position of the yet unlisted slice with the maximum area + totalarea(imaxslice-minspace:imaxslice+minspace) = 0; % change the totalarea of the chosen slice and those within minspace to 0 so that it is not chosen again + end + end + + % Pre-allocate logical array specifying whether intersection with a given + % mesh (k) actually exists within a given slice (s) + intersect_exists = zeros(numel(slicepos), numel(meshplot)); +end + +% draw figure +if strcmp(sli, '2d') + % Pre-allocate interpolation limits of each slice to facilitate + % finding overall limits of all slices after plotting + xsmax = NaN(numel(slicepos),1); xsmin = NaN(numel(slicepos),1); + ysmax = NaN(numel(slicepos),1); ysmin = NaN(numel(slicepos),1); + zsmax = NaN(numel(slicepos),1); zsmin = NaN(numel(slicepos),1); + + for s = 1:numel(slicepos) % slice loop + subplot(numel(slicepos),1,s); hold on; + + % Pre-allocate interpolation limits of each cloud to facilitate + % finding slice limits after plotting + xcmax = NaN(length(pos(:,1)),1); xcmin = NaN(length(pos(:,1)),1); + ycmax = NaN(length(pos(:,1)),1); ycmin = NaN(length(pos(:,1)),1); + zcmax = NaN(length(pos(:,1)),1); zcmin = NaN(length(pos(:,1)),1); + + for c = 1:length(pos(:,1)) % cloud loop + indpos = pos(c, :); + % Calculate distance from slice + if oriX; distance = abs(indpos(1)-slicepos(s)); end + if oriY; distance = abs(indpos(2)-slicepos(s)); end + if oriZ; distance = abs(indpos(3)-slicepos(s)); end + + if distance < rmax(c) + if strcmp(slicetype, 'surf') + xmax = rmax(c)*x; + ymax = rmax(c)*y; + + if strcmp(scalealpha, 'yes') + maxalpha = (rmax(c)-distance)/rmax(c); + else + maxalpha = 1; + end + + % find the maximum radius of a cross section of the virtual sphere in the given slice + xmaxdif = abs(xmax-distance); + imindif = find(xmaxdif == min(xmaxdif), 1); % index of x value closest to distance(e) + rcmax = abs(ymax(imindif)); + + % Determine points along outermost circle + xe = rcmax*x; + ye = rcmax*y; + + % Jitter values of points in the slice plane so no surfaces overlap + slicedime = slicedim+(0.01*rand*ones(length(x), 1)); + + % Plot concentric circles + for n = 0:ncirc-1 % circle loop + xo = xe*((ncirc-n)/ncirc); % outer x points + yo = ye*((ncirc-n)/ncirc); % outer z points + xi = xe*((ncirc-1-n)/ncirc); % inner x points + yi = ye*((ncirc-1-n)/ncirc); % inner z points + if n == ncirc-1 % for the last concentric circle + if oriX; hs = fill3(slicepos(s)+slicedime, indpos(2)+xo, indpos(3)+yo, val(c)); end + if oriY; hs = fill3(indpos(1)+xo, slicepos(s)+slicedime, indpos(3)+yo, val(c)); end + if oriZ; hs = fill3(indpos(1)+xo, indpos(2)+yo, slicepos(s)+slicedime, val(c)); end + else + if oriX; hs = fill3([slicepos(s)+slicedime; slicepos(s)+slicedim], [indpos(2)+xo; indpos(2)+xi], [indpos(3)+yo; indpos(3)+yi], val(c)); end + if oriY; hs = fill3([indpos(1)+xo; indpos(1)+xi], [slicepos(s)+slicedime; slicepos(s)+slicedim], [indpos(3)+yo; indpos(3)+yi], val(c)); end + if oriZ; hs = fill3([indpos(1)+xo; indpos(1)+xi], [indpos(2)+yo; indpos(2)+yi], [slicepos(s)+slicedime; slicepos(s)+slicedim], val(c)); end + end + set(hs, 'EdgeColor', 'none', 'FaceAlpha', maxalpha*n/ncirc) + end % end circle loop + + % find the limits of the plotted surfaces for this electrode + if oriX + xcmax(c) = max(slicedime+slicepos(s)); xcmin(c) = min(slicedime+slicepos(s)); + ycmax(c) = max(xe+indpos(2)); ycmin(c) = min(xe+indpos(2)); + zcmax(c) = max(ye+indpos(3)); zcmin(c) = min(ye+indpos(3)); + elseif oriY + xcmax(c) = max(xe+indpos(1)); xcmin(c) = min(xe+indpos(1)); + ycmax(c) = max(slicedime+slicepos(s)); ycmin(c) = min(slicedime+slicepos(s)); + zcmax(c) = max(ye+indpos(3)); zcmin(c) = min(ye+indpos(3)); + elseif oriZ + xcmax(c) = max(xe+indpos(1)); xcmin(c) = min(xe+indpos(1)); + ycmax(c) = max(ye+indpos(2)); ycmin(c) = min(ye+indpos(2)); + zcmax(c) = max(slicedime+slicepos(s)); zcmin(c) = min(slicedime+indpos(s)); + end + elseif strcmp(slicetype, 'point') + rng(0, 'twister'); % random number generator + npoints = round(ptdens*pi*rmax(c)^2); % number of points based on area of cloud cross section + azimuth = 2*pi*rand(npoints,1); % azimuthal angle for each point + radii = rmax(c)*(rand(npoints,1).^ptgrad); % radius value for each point + radii = sort(radii); % sort radii in ascending order so they are plotted from inside out + % convert to Carthesian; note that second input controls third output + if oriX; [y,z,x] = sph2cart(azimuth, zeros(npoints,1)+0.01*rand(npoints,1), radii); end + if oriY; [x,z,y] = sph2cart(azimuth, zeros(npoints,1)+0.01*rand(npoints,1), radii); end + if oriZ; [x,y,z] = sph2cart(azimuth, zeros(npoints,1)+0.01*rand(npoints,1), radii); end + + % color axis with radius scaling + if strcmp(cgrad, 'white') % color runs up to white + fcolidx = ceil(cmid) + sign(colscf(c))*floor(abs(colscf(c)*cmid)); + if fcolidx == 0; fcolidx = 1; end + fcol = cmapsc(fcolidx,:); % color [Nx3] + ptcol = [linspace(fcol(1), 1, npoints)' linspace(fcol(2), 1, npoints)' linspace(fcol(3), 1, npoints)']; + elseif isscalar(cgrad) % color runs down towards colorbar middle + rnorm = radii/rmax(c); % normalized radius + if radscf(c)>=.5 % extreme values + ptcol = val(c) - (flip(1-rnorm).^inv(cgrad))*val(c); % scaled fun [Nx1] + elseif radscf(c)<.5 % values closest to zero + ptcol = val(c) + (flip(1-rnorm).^inv(cgrad))*abs(val(c)); % scaled fun [Nx1] + end + else + ft_error('cfg.colorgrad should be either ''white'' or a scalar determining color falloff') + end + + % draw the points + if oriX; scatter3(x+slicepos(s), y+indpos(2), z+indpos(3), ptsize, ptcol, '.'); end + if oriY; scatter3(x+indpos(1), y+slicepos(s), z+indpos(3), ptsize, ptcol, '.'); end + if oriZ; scatter3(x+indpos(1), y+indpos(2), z+slicepos(s), ptsize, ptcol, '.'); end + + % find the limits of the plotted points for this electrode + if oriX + xcmax(c) = max(x+slicepos(s)); xcmin(c) = min(x+slicepos(s)); + ycmax(c) = max(y+indpos(2)); ycmin(c) = min(y+indpos(2)); + zcmax(c) = max(z+indpos(3)); zcmin(c) = min(z+indpos(3)); + elseif oriY + xcmax(c) = max(x+indpos(1)); xcmin(c) = min(x+indpos(1)); + ycmax(c) = max(y+slicepos(s)); ycmin(c) = min(y+slicepos(s)); + zcmax(c) = max(z+indpos(3)); zcmin(c) = min(z+indpos(3)); + elseif oriZ + xcmax(c) = max(x+indpos(1)); xcmin(c) = min(x+indpos(1)); + ycmax(c) = max(y+indpos(2)); ycmin(c) = min(y+indpos(2)); + zcmax(c) = max(z+slicepos(s)); zcmin(c) = min(z+slicepos(s)); + end + + end % cloudtype + end % if distance < rmax(c) + end % cloud loop + if dointersect + if oriX; ori = [1 0 0]; loc = [slicepos(s) 0 0]; end + if oriY; ori = [0 1 0]; loc = [0 slicepos(s) 0]; end + if oriZ; ori = [0 0 1]; loc = [0 0 slicepos(s)]; end + + % normalise the orientation vector to one + ori = ori./sqrt(sum(ori.^2)); + + % shift the location to be along the orientation vector + loc = ori*dot(loc,ori); + + % determine three points on the plane + inplane = eye(3) - (eye(3) * ori') * ori; + v1 = loc + inplane(1,:); + v2 = loc + inplane(2,:); + v3 = loc + inplane(3,:); + + for k = 1:numel(meshplot) + + % only plot if the mesh actually intersects the plane + xmmax = max(meshplot{k}.pos(:,1)); xmmin = min(meshplot{k}.pos(:,1)); + ymmax = max(meshplot{k}.pos(:,2)); ymmin = min(meshplot{k}.pos(:,2)); + zmmax = max(meshplot{k}.pos(:,3)); zmmin = min(meshplot{k}.pos(:,3)); + + if oriX + if slicepos(s) < xmmax && slicepos(s) > xmmin + intersect_exists(s,k) = 1; + else + intersect_exists(s,k) = 0; + end + elseif oriY + if slicepos(s) < ymmax && slicepos(s) > ymmin + intersect_exists(s,k) = 1; + else + intersect_exists(s,k) = 0; + end + elseif oriZ + if slicepos(s) < zmmax && slicepos(s) > zmmin + intersect_exists(s,k) = 1; + else + intersect_exists(s,k) = 0; + end + end + + if intersect_exists(s,k) + [xmesh, ymesh, zmesh] = intersect_plane(meshplot{k}.pos, meshplot{k}.tri, v1, v2, v3); + + % draw each individual line segment of the intersection + if ~isempty(xmesh) + p = patch(xmesh', ymesh', zmesh', nan(1, size(xmesh,1))); + if ~isempty(intersectcolor), set(p, 'EdgeColor', intersectcolor{k}); end + if ~isempty(intersectlinewidth), set(p, 'LineWidth', intersectlinewidth(k)); end + if ~isempty(intersectlinestyle), set(p, 'LineStyle', intersectlinestyle{k}); end + end + + % find the limits of the lines and add them to the limits of the + % interpolation to facilitate finding the limits of the slice + xcmax(end+1) = max(xmesh(:)); xcmin(end+1) = min(xmesh(:)); + ycmax(end+1) = max(ymesh(:)); ycmin(end+1) = min(ymesh(:)); + zcmax(end+1) = max(zmesh(:)); zcmin(end+1) = min(zmesh(:)); + end + end % end mesh loop + end % end if dointersect + + % Find limits of this particular slice + xsmax(s) = max(xcmax); xsmin(s) = min(xcmin); + ysmax(s) = max(ycmax); ysmin(s) = min(ycmin); + zsmax(s) = max(zcmax); zsmin(s) = min(zcmin); + + % Color Settings + colormap(cmap); + if ~isempty(clim) && clim(2)>clim(1) + caxis(gca, clim); + end + + % Axis and View Settings + set(gca, 'DataAspectRatio', [1 1 1]) + if oriX + view([90 0]); + elseif oriY + view([180 0]); + elseif oriZ + view([90 90]); + end + + % Add Title to Differentiate Slices + if oriX; title(['slicepos = [' num2str(slicepos(s)) ' 0 0]']); end + if oriY; title(['slicepos = [0 ' num2str(slicepos(s)) ' 0]']); end + if oriZ; title(['slicepos = [0 0 ' num2str(slicepos(s)) ']']); end + end + + % Set matching limits in the non-slice dimensions for each slice + for s = 1:numel(slicepos) % slice loop + subplot(numel(slicepos),1,s); + if oriX + xlim([xsmin(s)-2 xsmax(s)+2]); + ylim([min(ysmin)-2 max(ysmax)+2]); + zlim([min(zsmin)-2 max(zsmax)+2]); + elseif oriY + xlim([min(xsmin)-2 max(xsmax)+2]); + ylim([ysmin(s)-2 ysmax(s)+2]); + zlim([min(zsmin)-2 max(zsmax)+2]); + elseif oriZ + xlim([min(xsmin)-2 max(xsmax)+2]); + ylim([min(ysmin)-2 max(ysmax)+2]); + zlim([zsmin(s)-2 zsmax(s)+2]); + end + end + +else % plot 3d cloud + % generate point cloud(s) + hold on; + for n = 1:size(pos,1) % cloud loop + % point cloud with radius scaling + rng(0, 'twister'); % random number generator + npoints = round(ptdens*(4/3)*pi*rmax(n)^3); % number of points based on cloud volume + elevation = asin(2*rand(npoints,1)-1); % elevation angle for each point + azimuth = 2*pi*rand(npoints,1); % azimuth angle for each point + radii = rmax(n)*(rand(npoints,1).^ptgrad); % radius value for each point + radii = sort(radii); % sort radii in ascending order so they are plotted from inside out + [x,y,z] = sph2cart(azimuth, elevation, radii); % convert to Carthesian + + % color axis with radius scaling + if strcmp(cgrad, 'white') % color runs up to white + indx = ceil(cmid) + sign(colscf(n))*floor(abs(colscf(n)*cmid)); + indx = max(min(indx,size(cmapsc,1)),1); % index should fall within the colormap + fcol = cmapsc(indx,:); % color [Nx3] + ptcol = [linspace(fcol(1), 1, npoints)' linspace(fcol(2), 1, npoints)' linspace(fcol(3), 1, npoints)']; + elseif isscalar(cgrad) % color runs down towards colorbar middle + rnorm = radii/rmax(n); % normalized radius + if radscf(n)>=.5 % extreme values + ptcol = val(n) - (flip(1-rnorm).^inv(cgrad))*val(n); % scaled fun [Nx1] + elseif radscf(n)<.5 % values closest to zero + ptcol = val(n) + (flip(1-rnorm).^inv(cgrad))*abs(val(n)); % scaled fun [Nx1] + end + else + ft_error('color gradient should be either ''white'' or a scalar determining color falloff') + end + + % draw the points + scatter3(x+pos(n,1), y+pos(n,2), z+pos(n,3), ptsize, ptcol, '.'); + end % end cloud loop + + if ~isempty(meshplot) + for k = 1:numel(meshplot) % mesh loop + ft_plot_mesh(meshplot{k}, 'facecolor', facecolor{k}, 'EdgeColor', edgecolor{k}, ... + 'facealpha', facealpha(k), 'edgealpha', edgealpha(k)); + material dull + end % end mesh loop + + if dointersect % plot the outlines on the mesh + for s = 1:numel(slicepos) % slice loop + if oriX; ori = [1 0 0]; loc = [slicepos(s) 0 0]; end + if oriY; ori = [0 1 0]; loc = [0 slicepos(s) 0]; end + if oriZ; ori = [0 0 1]; loc = [0 0 slicepos(s)]; end + + % normalise the orientation vector to one + ori = ori./sqrt(sum(ori.^2)); + + % shift the location to be along the orientation vector + loc = ori*dot(loc,ori); + + % determine three points on the plane + inplane = eye(3) - (eye(3) * ori') * ori; + v1 = loc + inplane(1,:); + v2 = loc + inplane(2,:); + v3 = loc + inplane(3,:); + + for k = 1:numel(meshplot) + + % only plot if the mesh actually intersects the plane + xmmax = max(meshplot{k}.pos(:,1)); xmmin = min(meshplot{k}.pos(:,1)); + ymmax = max(meshplot{k}.pos(:,2)); ymmin = min(meshplot{k}.pos(:,2)); + zmmax = max(meshplot{k}.pos(:,3)); zmmin = min(meshplot{k}.pos(:,3)); + + if oriX + if slicepos(s) < xmmax && slicepos(s) > xmmin + intersect_exists(s,k) = 1; + else + intersect_exists(s,k) = 0; + end + elseif oriY + if slicepos(s) < ymmax && slicepos(s) > ymmin + intersect_exists(s,k) = 1; + else + intersect_exists(s,k) = 0; + end + elseif oriZ + if slicepos(s) < zmmax && slicepos(s) > zmmin + intersect_exists(s,k) = 1; + else + intersect_exists(s,k) = 0; + end + end + + if intersect_exists(s,k) + [xmesh, ymesh, zmesh] = intersect_plane(meshplot{k}.pos, meshplot{k}.tri, v1, v2, v3); + + % draw each individual line segment of the intersection + if ~isempty(xmesh) + p = patch(xmesh', ymesh', zmesh', nan(1, size(xmesh,1))); + if ~isempty(intersectcolor), set(p, 'EdgeColor', intersectcolor{k}); end + if ~isempty(intersectlinewidth), set(p, 'LineWidth', intersectlinewidth(k)); end + if ~isempty(intersectlinestyle), set(p, 'LineStyle', intersectlinestyle{k}); end + end + end + end % end mesh loop + end % end slice loop + end % end plotting outline + end % end mesh plotting + + % axis settings + axis off + axis vis3d + axis equal + + % Color settings + colormap(cmap); + if ~isempty(clim) && clim(2)>clim(1) + caxis(gca, clim); + end +end diff --git a/external/fieldtrip/plotting/ft_plot_crosshair.m b/external/fieldtrip/plotting/ft_plot_crosshair.m index 4ee209c2..58c9235f 100644 --- a/external/fieldtrip/plotting/ft_plot_crosshair.m +++ b/external/fieldtrip/plotting/ft_plot_crosshair.m @@ -1,18 +1,28 @@ -function ft_plot_crosshair(pos, varargin) +function h = ft_plot_crosshair(pos, varargin) -% FT_PLOT_CROSSHAIR plots a crosshair in two or three dimensions +% FT_PLOT_CROSSHAIR plots a crosshair at a specified position in two [x, y] or three +% [x, y, z] dimensions. % % Use as -% ft_plot_crosshair(pos, ...) -% where pos is the desired position of the crosshair. +% h = ft_plot_crosshair(pos, ...) +% where pos is the desired position of the crosshair. The handles of the lines are +% returned. % % Optional input arguments should be specified in key-value pairs and can include % 'color' = [r g b] value or string, see PLOT -% +% 'parent' = handle of the parent axes +% 'handle' = handle of the existing line objects to be updated +% +% You can specify the handles of existing line objects which will be then updated, +% rather than creating a new set of lines. If both parent and handle ar specified, +% the handle option prevail. +% % Example % ft_plot_crosshair([0.5 0.5], 'color', 'r') +% +% See also TEXT, LINE -% Copyright (C) 2014, Robert Oostenveld +% Copyright (C) 2003-2017, Robert Oostenveld % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -32,48 +42,94 @@ function ft_plot_crosshair(pos, varargin) % % $Id$ -ax = axis; +% get the optional input arguments +color = ft_getopt(varargin, 'color'); +parent = ft_getopt(varargin, 'parent'); +h = ft_getopt(varargin, 'handle'); -minx = ax(1); -maxx = ax(2); -miny = ax(3); -maxy = ax(4); +if ~isempty(h) + % the parent to the first handle is set as the current axes + set(gcf, 'currentaxes', get(h(1),'parent')); +elseif ~isempty(parent) + % the parent is set as the current axes + set(gcf, 'currentaxes', parent); +else + % the current axes stay as they are +end + +% color management +if ~isempty(color) + if ischar(color) && exist([color '.m'], 'file') + color = eval(color); + end + varargin = ft_setopt(varargin, 'color', color); +end + +% determine the size of the figure +border = [get(gca, 'xlim') get(gca, 'ylim') get(gca, 'zlim')]; switch numel(pos) case 2 - X = [minx maxx]; - Y = pos([2 2]); - line(X, Y, varargin{:}); - - X = pos([1 1]); - Y = [miny maxy]; - line(X, Y, varargin{:}); + x = [ border(1) pos(1) + border(2) pos(1) ]; + y = [ pos(2) border(3) + pos(2) border(4) ]; - case 3 - if numel(axis)==4 - % the figure is in 2D mode - [az, el] = view; - view([1 1 1]); - ax = axis; - view(az, el); + if isempty(h) && (~ishold) + hold on + h = line(x, y, varargin{:}); + hold off + elseif isempty(h) + h = line(x, y, varargin{:}); + else + set(h(1), 'xdata', x(:,1)'); + set(h(1), 'ydata', y(:,1)'); + set(h(2), 'xdata', x(:,2)'); + set(h(2), 'ydata', y(:,2)'); end - minz = ax(5); - maxz = ax(6); + if ~isempty(color) + set(h(1), 'color', color); + set(h(2), 'color', color); + else + % ensure they have the same color + set(h(2), 'color', get(h(1), 'color')); + end - X = [minx maxx]; - Y = pos([2 2]); - Z = pos([3 3]); - line(X, Y, Z, varargin{:}); + case 3 + x = [ border(1) pos(1) pos(1) + border(2) pos(1) pos(1)]; + y = [ pos(2) border(3) pos(2) + pos(2) border(4) pos(2)]; + z = [ pos(3) pos(3) border(5) + pos(3) pos(3) border(6)]; - X = pos([1 1]); - Y = [miny maxy]; - Z = pos([3 3]); - line(X, Y, Z, varargin{:}); + if isempty(h) && (~ishold) + hold on + h = line(x, y, z, varargin{:}); + hold off + elseif isempty(h) + h = line(x, y, z, varargin{:}); + else + set(h(1), 'xdata', x(:,1)'); + set(h(1), 'ydata', y(:,1)'); + set(h(1), 'zdata', z(:,1)'); + set(h(2), 'xdata', x(:,2)'); + set(h(2), 'ydata', y(:,2)'); + set(h(2), 'zdata', z(:,2)'); + set(h(3), 'xdata', x(:,3)'); + set(h(3), 'ydata', y(:,3)'); + set(h(3), 'zdata', z(:,3)'); + end - X = pos([1 1]); - Y = pos([2 2]); - Z = [minz maxz]; - line(X, Y, Z, varargin{:}); + if ~isempty(color) + set(h(1), 'color', color); + set(h(2), 'color', color); + set(h(3), 'color', color); + else + % ensure they have the same color + set(h(2), 'color', get(h(1), 'color')); + set(h(3), 'color', get(h(1), 'color')); + end -end +end % switch diff --git a/external/fieldtrip/plotting/ft_plot_dipole.m b/external/fieldtrip/plotting/ft_plot_dipole.m index 5dd5ae77..24ed8413 100644 --- a/external/fieldtrip/plotting/ft_plot_dipole.m +++ b/external/fieldtrip/plotting/ft_plot_dipole.m @@ -13,9 +13,10 @@ % 'color' = [r g b] values or string, for example 'brain', 'cortex', 'skin', 'black', 'red', 'r' (default = 'r') % 'unit' = 'm', 'cm' or 'mm', used for automatic scaling (default = 'cm') % 'scale' = scale the dipole with the amplitude, can be 'none', 'both', 'diameter', 'length' (default = 'none') +% 'alpha' = alpha value of the plotted dipole % % Example -% ft_plot_dipole([0 0 0], [1 2 3], 'color', 'r') +% ft_plot_dipole([0 0 0], [1 2 3], 'color', 'r', 'alpha', 1) % Copyright (C) 2009, Robert Oostenveld % @@ -45,17 +46,16 @@ diameter = ft_getopt(varargin, 'diameter', 'auto'); length = ft_getopt(varargin, 'length', 'auto'); unit = ft_getopt(varargin, 'unit', 'cm'); - +alpha = ft_getopt(varargin, 'alpha', 1); % for backward compatibility, this can be changed into an error at the end of 2016 units = ft_getopt(varargin, 'units'); if ~isempty(units) - warning('please use "unit" instead of "units"'); + ft_warning('please use "unit" instead of "units"'); unit = units; clear units end - if isequal(diameter, 'auto') % the default is a 5 mm sphere switch unit @@ -66,7 +66,7 @@ case 'mm' diameter = 5; otherwise - error('unsupported unit'); + ft_error('unsupported unit'); end end @@ -80,7 +80,7 @@ case 'mm' length = 15; otherwise - error('unsupported unit'); + ft_error('unsupported unit'); end end @@ -102,6 +102,10 @@ hold on end +% these are reused +[unitsphere.pos, unitsphere.tri] = icosahedron642; +[unitcylinder.pos, unitcylinder.tri] = cylinder(36, 2); + for i=1:size(pos,1) amplitude = norm(ori(:,i)); ori(:,i) = ori(:,i) ./ amplitude; @@ -118,10 +122,10 @@ this_diameter = diameter; end - % create a unit sphere and cylinder - [sphere.pos, sphere.tri] = icosahedron642; + % start with a unit sphere and cylinder + sphere = unitsphere; + stick = unitcylinder; sphere.pos = ft_warp_apply(scale([0.5 0.5 0.5]), sphere.pos, 'homogeneous'); % the diameter should be 1 - [stick.pos, stick.tri] = cylinder(36, 2); stick.pos = ft_warp_apply(scale([0.5 0.5 0.5]), stick.pos, 'homogeneous'); % the length should be 1 stick.pos = ft_warp_apply(translate([0 0 0.5]), stick.pos, 'homogeneous'); % it should start in the origin @@ -157,11 +161,11 @@ stick.pos = ft_warp_apply(translate([tx ty tz]), stick.pos, 'homogeneous'); % plot the sphere and the stick - p1 = ft_plot_mesh(sphere, 'vertexcolor', 'none', 'edgecolor', false, 'facecolor', color); + p1 = ft_plot_mesh(sphere, 'vertexcolor', 'none', 'edgecolor', false, 'facecolor', color, 'facealpha', alpha); h = cat(2, h(:)', p1(:)'); clear p1; - p2 = ft_plot_mesh(stick, 'vertexcolor', 'none', 'edgecolor', false, 'facecolor', color); + p2 = ft_plot_mesh(stick, 'vertexcolor', 'none', 'edgecolor', false, 'facecolor', color, 'facealpha', alpha); h = cat(2, h(:)', p2(:)'); clear p2; end % for each dipole diff --git a/external/fieldtrip/plotting/ft_plot_headshape.m b/external/fieldtrip/plotting/ft_plot_headshape.m index 7b3483b5..fca7110f 100644 --- a/external/fieldtrip/plotting/ft_plot_headshape.m +++ b/external/fieldtrip/plotting/ft_plot_headshape.m @@ -51,8 +51,9 @@ if ~isstruct(headshape) && isnumeric(headshape) && size(headshape,2)==3 % the input seems like a list of points, convert into something that resembles a headshape - warning('off', 'MATLAB:warn_r14_stucture_assignment'); + ws1 = warning('off', 'MATLAB:warn_r14_stucture_assignment'); headshape.pos = headshape; + warning(ws1); end % the default behaviour depends on whether there is a triangulated surface or not @@ -75,6 +76,11 @@ transform = ft_getopt(varargin, 'transform'); unit = ft_getopt(varargin, 'unit'); +% color management, the other colors are handled in ft_plot_mesh +if ischar(fidcolor) && exist([fidcolor '.m'], 'file') + fidcolor = eval(fidcolor); +end + if ~isempty(unit) headshape = ft_convert_units(headshape, unit); end @@ -98,7 +104,7 @@ mesh.tri = []; end -ft_plot_mesh(mesh, 'vertexcolor', vertexcolor, 'vertexsize',vertexsize, 'facecolor', facecolor, 'edgecolor', edgecolor); +ft_plot_mesh(mesh, 'vertexcolor', vertexcolor, 'vertexsize', vertexsize, 'facecolor', facecolor, 'edgecolor', edgecolor); if isfield(headshape, 'fid') fid = headshape.fid; @@ -110,14 +116,14 @@ % show the fiducial labels for i=1:size(fid.pos,1) - hs = plot3(fid.pos(i,1), fid.pos(i,2), fid.pos(i,3), 'Marker',fidmarker,'MarkerEdgeColor',fidcolor); - if isfield(fid,'label') && istrue(fidlabel) + hs = plot3(fid.pos(i,1), fid.pos(i,2), fid.pos(i,3), 'Marker', fidmarker, 'MarkerEdgeColor', fidcolor); + if isfield(fid, 'label') && istrue(fidlabel) % the text command does not like int or single position values x = double(fid.pos(i, 1)); y = double(fid.pos(i, 2)); z = double(fid.pos(i, 3)); str = sprintf('%s', fid.label{i}); - h = text(x, y, z, str, 'HorizontalAlignment', 'center', 'VerticalAlignment', 'middle','Interpreter','none'); + h = text(x, y, z, str, 'HorizontalAlignment', 'center', 'VerticalAlignment', 'middle', 'Interpreter', 'none'); hs = [hs; h]; end end diff --git a/external/fieldtrip/plotting/ft_plot_lay.m b/external/fieldtrip/plotting/ft_plot_lay.m index 83e99d41..258ce7b4 100644 --- a/external/fieldtrip/plotting/ft_plot_lay.m +++ b/external/fieldtrip/plotting/ft_plot_lay.m @@ -7,11 +7,11 @@ function ft_plot_lay(lay, varargin) % where the layout is a FieldTrip structure obtained from FT_PREPARE_LAYOUT. % % Additional options should be specified in key-value pairs and can be +% 'chanindx' = list of channels to plot (default is all) % 'point' = yes/no % 'box' = yes/no % 'label' = yes/no -% 'labelsize' = number indicating font size (e.g. 6) -% 'labeloffset' = offset of label from point (suggestion is 0.005) +% 'labeloffset' = offset of label from point (default = 0) % 'labelrotate' = scalar, vector with rotation angle (in degrees) per label (default = 0) % 'labelalignh' = string, or cell-array specifying the horizontal alignment of the text (default = 'left') % 'labelalignv' = string, or cell-array specifying the vertical alignment of the text (default = 'middle') @@ -21,12 +21,19 @@ function ft_plot_lay(lay, varargin) % 'pointsymbol' = string with symbol (e.g. 'o') - all three point options need to be used together % 'pointcolor' = string with color (e.g. 'k') % 'pointsize' = number indicating size (e.g. 8) +% 'fontcolor' = string, color specification (default = 'k') +% 'fontsize' = number, sets the size of the text (default = 10) +% 'fontunits' = +% 'fontname' = +% 'fontweight' = % % It is possible to plot the object in a local pseudo-axis (c.f. subplot), which is specfied as follows % 'hpos' = horizontal position of the lower left corner of the local axes % 'vpos' = vertical position of the lower left corner of the local axes % 'width' = width of the local axes % 'height' = height of the local axes +% +% See also FT_PREPARE_LAYOUT % Copyright (C) 2009, Robert Oostenveld % @@ -51,22 +58,31 @@ function ft_plot_lay(lay, varargin) ws = warning('on', 'MATLAB:divideByZero'); % get the optional input arguments +chanindx = ft_getopt(varargin, 'chanindx', []); hpos = ft_getopt(varargin, 'hpos', 0); vpos = ft_getopt(varargin, 'vpos', 0); -width = ft_getopt(varargin, 'width', []); -height = ft_getopt(varargin, 'height', []); +width = ft_getopt(varargin, 'width', []); +height = ft_getopt(varargin, 'height', []); point = ft_getopt(varargin, 'point', true); box = ft_getopt(varargin, 'box', true); label = ft_getopt(varargin, 'label', true); -labelsize = ft_getopt(varargin, 'labelsize', 10); -labelfont = ft_getopt(varargin, 'labelfont', 'helvetica'); labeloffset = ft_getopt(varargin, 'labeloffset', 0); +labelxoffset = ft_getopt(varargin, 'labelxoffset', labeloffset); +labelyoffset = ft_getopt(varargin, 'labelyoffset', labeloffset*1.5); mask = ft_getopt(varargin, 'mask', true); outline = ft_getopt(varargin, 'outline', true); verbose = ft_getopt(varargin, 'verbose', false); pointsymbol = ft_getopt(varargin, 'pointsymbol'); pointcolor = ft_getopt(varargin, 'pointcolor'); pointsize = ft_getopt(varargin, 'pointsize'); + +% these have to do with the font +fontcolor = ft_getopt(varargin, 'fontcolor', 'k'); % default is black +fontsize = ft_getopt(varargin, 'fontsize', get(0, 'defaulttextfontsize')); +fontname = ft_getopt(varargin, 'fontname', get(0, 'defaulttextfontname')); +fontweight = ft_getopt(varargin, 'fontweight', get(0, 'defaulttextfontweight')); +fontunits = ft_getopt(varargin, 'fontunits', get(0, 'defaulttextfontunits')); +% these have to do with the font interpreter = ft_getopt(varargin, 'interpreter', 'tex'); % some stuff related to some refined label plotting @@ -75,7 +91,6 @@ function ft_plot_lay(lay, varargin) labelalignv = ft_getopt(varargin, 'labelalignv', 'middle'); labelcolor = ft_getopt(varargin, 'labelcolor', 'k'); - % convert between true/false/yes/no etc. statements point = istrue(point); box = istrue(box); @@ -84,6 +99,11 @@ function ft_plot_lay(lay, varargin) outline = istrue(outline); verbose = istrue(verbose); +% color management +if ischar(pointcolor) && exist([pointcolor '.m'], 'file') + pointcolor = eval(pointcolor); +end + if ~(point || box || label || mask || outline) % there is nothing to be plotted return; @@ -95,10 +115,16 @@ function ft_plot_lay(lay, varargin) hold on end -% layout units can be arbitrary (e.g. pixels for .mat files) -% so we need to compute the right scaling factor and offset -% create a matrix with all coordinates -% from positions, mask, and outline +% make a selection of the channels +if ~isempty(chanindx) + lay.pos = lay.pos(chanindx,:); + lay.width = lay.width(chanindx); + lay.height = lay.height(chanindx); + lay.label = lay.label(chanindx); +end + +% the units can be arbitrary (e.g. relative or pixels), so we need to compute the right scaling factor and offset +% create a matrix with all coordinates from positions, mask, and outline allCoords = lay.pos; if isfield(lay, 'mask') && ~isempty(lay.mask) for k = 1:numel(lay.mask) @@ -139,10 +165,10 @@ function ft_plot_lay(lay, varargin) if point if ~isempty(pointsymbol) && ~isempty(pointcolor) && ~isempty(pointsize) % if they're all non-empty, don't use the default - plot(X, Y, 'marker',pointsymbol,'color',pointcolor,'markersize',pointsize,'linestyle','none'); + plot(X, Y, 'marker', pointsymbol, 'color', pointcolor, 'markersize', pointsize, 'linestyle', 'none'); else - plot(X, Y, 'marker','.','color','b','linestyle','none'); - plot(X, Y, 'marker','o','color','y','linestyle','none'); + plot(X, Y, 'marker', '.', 'color', 'b', 'linestyle', 'none'); + plot(X, Y, 'marker', 'o', 'color', 'y', 'linestyle', 'none'); end end @@ -154,7 +180,7 @@ function ft_plot_lay(lay, varargin) % check whether fancy label plotting is needed, this requires a for loop, % otherwise print text in a single shot if numel(labelrotate)==1 - text(X+labeloffset, Y+(labeloffset*1.5), Lbl ,'fontsize',labelsize,'fontname',labelfont,'interpreter',interpreter,'horizontalalignment',labelalignh,'verticalalignment',labelalignv,'color',labelcolor); + text(X+labelxoffset, Y+labelyoffset, Lbl , 'interpreter', interpreter, 'horizontalalignment', labelalignh, 'verticalalignment', labelalignv, 'color', fontcolor, 'fontunits', fontunits, 'fontsize', fontsize, 'fontname', fontname, 'fontweight', fontweight); else n = numel(Lbl); if ~iscell(labelalignh) @@ -167,7 +193,7 @@ function ft_plot_lay(lay, varargin) eror('there is something wrong with the input arguments'); end for k = 1:numel(Lbl) - text(X(k)+labeloffset, Y(k)+(labeloffset*1.5), Lbl{k}, 'fontsize', labelsize, 'fontname', labelfont, 'interpreter', interpreter, 'horizontalalignment', labelalignh{k}, 'verticalalignment', labelalignv{k}, 'rotation', labelrotate(k),'color',labelcolor); + h = text(X(k)+labelxoffset, Y(k)+labelyoffset, Lbl{k}, 'interpreter', interpreter, 'horizontalalignment', labelalignh{k}, 'verticalalignment', labelalignv{k}, 'rotation', labelrotate(k), 'color', fontcolor, 'fontunits', fontunits, 'fontsize', fontsize, 'fontname', fontname, 'fontweight', fontweight); end end end diff --git a/external/fieldtrip/plotting/ft_plot_line.m b/external/fieldtrip/plotting/ft_plot_line.m index 1c302e6a..75a93cc8 100644 --- a/external/fieldtrip/plotting/ft_plot_line.m +++ b/external/fieldtrip/plotting/ft_plot_line.m @@ -10,7 +10,7 @@ % 'color' = % 'linestyle' = % 'linewidth' = -% 'tag' = string, the name this vector gets. All tags with the same name can be deleted in a figure, without deleting other parts of the figure. +% 'tag' = string, the name assigned to the object. All tags with the same name can be deleted in a figure, without deleting other parts of the figure. % % It is possible to plot the object in a local pseudo-axis (c.f. subplot), which is specfied as follows % 'hpos' = horizontal position of the center of the local axes @@ -19,6 +19,8 @@ % 'height' = height of the local axes % 'hlim' = horizontal scaling limits within the local axes % 'vlim' = vertical scaling limits within the local axes +% +% See also FT_PLOT_BOX % Copyrights (C) 2009-2011, Robert Oostenveld % @@ -54,35 +56,38 @@ linewidth = ft_getopt(varargin, 'linewidth', 0.5); tag = ft_getopt(varargin, 'tag', ''); +% color management +if ischar(color) && exist([color '.m'], 'file') + color = eval(color); +end + if isempty(hlim) && isempty(vlim) && isempty(hpos) && isempty(vpos) && isempty(height) && isempty(width) % no scaling is needed, the input X and Y are already fine % use a shortcut to speed up the plotting else % use the full implementation - abc = axis; - if isempty(hlim) - hlim = abc([1 2]); + hlim = get(gca, 'XLim'); end if isempty(vlim) - vlim = abc([3 4]); + vlim = get(gca, 'YLim'); end - if isempty(hpos); + if isempty(hpos) hpos = (hlim(1)+hlim(2))/2; end - if isempty(vpos); + if isempty(vpos) vpos = (vlim(1)+vlim(2))/2; end - if isempty(width), + if isempty(width) width = hlim(2)-hlim(1); end - if isempty(height), + if isempty(height) height = vlim(2)-vlim(1); end @@ -109,4 +114,4 @@ h = line(X, Y, 'Color', color, 'LineStyle', linestyle, 'LineWidth', linewidth); set(h, 'tag', tag); -warning(ws); %revert to original state +warning(ws); % revert to original state diff --git a/external/fieldtrip/plotting/ft_plot_matrix.m b/external/fieldtrip/plotting/ft_plot_matrix.m index 5b56690e..1ab5b717 100644 --- a/external/fieldtrip/plotting/ft_plot_matrix.m +++ b/external/fieldtrip/plotting/ft_plot_matrix.m @@ -12,11 +12,11 @@ function ft_plot_matrix(varargin) % respectively. % % Optional arguments should come in key-value pairs and can include -% 'clim' = maximum and minimum color limit -% 'box' = draw a box around the local axes, can be 'yes' or 'no' +% 'clim' = 1x2 vector with color limits (default is automatic) % 'highlight' = a logical matrix of size C, where 0 means that the corresponding values in C are highlighted according to the highlightstyle -% 'highlightstyle' = can be 'saturation' or 'opacity' -% 'tag' = string, the name this vector gets. All tags with the same name can be deleted in a figure, without deleting other parts of the figure. +% 'highlightstyle' = can be 'saturation', 'opacity', 'outline' or 'colormix' (default = 'opacity') +% 'box' = draw a box around the local axes, can be 'yes' or 'no' +% 'tag' = string, the name assigned to the object. All tags with the same name can be deleted in a figure, without deleting other parts of the figure. % % It is possible to plot the object in a local pseudo-axis (c.f. subplot), which is specfied as follows % 'hpos' = horizontal position of the center of the local axes @@ -26,10 +26,18 @@ function ft_plot_matrix(varargin) % 'hlim' = horizontal scaling limits within the local axes % 'vlim' = vertical scaling limits within the local axes % +% When using a local pseudo-axis, you can plot a label next to the data +% 'label' = string, label to be plotted at the upper left corner +% 'fontcolor' = string, color specification (default = 'k') +% 'fontsize' = number, sets the size of the text (default = 10) +% 'fontunits' = +% 'fontname' = +% 'fontweight' = +% % Example % ft_plot_matrix(randn(30,50), 'width', 1, 'height', 1, 'hpos', 0, 'vpos', 0) % -% See also FT_PLOT_VECTOR +% See also FT_PLOT_VECTOR, IMAGESC % Copyrights (C) 2009-2011, Robert Oostenveld % @@ -68,24 +76,30 @@ function ft_plot_matrix(varargin) end % get the optional input arguments -hpos = ft_getopt(varargin, 'hpos'); -vpos = ft_getopt(varargin, 'vpos'); -width = ft_getopt(varargin, 'width'); -height = ft_getopt(varargin, 'height'); -hlim = ft_getopt(varargin, 'hlim'); -vlim = ft_getopt(varargin, 'vlim'); -clim = ft_getopt(varargin, 'clim'); -highlight = ft_getopt(varargin, 'highlight'); -highlightstyle = ft_getopt(varargin, 'highlightstyle', 'opacity'); -box = ft_getopt(varargin, 'box', false); -tag = ft_getopt(varargin, 'tag', ''); +hpos = ft_getopt(varargin, 'hpos'); +vpos = ft_getopt(varargin, 'vpos'); +width = ft_getopt(varargin, 'width'); +height = ft_getopt(varargin, 'height'); +hlim = ft_getopt(varargin, 'hlim'); +vlim = ft_getopt(varargin, 'vlim'); +clim = ft_getopt(varargin, 'clim'); +highlight = ft_getopt(varargin, 'highlight'); +highlightstyle = ft_getopt(varargin, 'highlightstyle', 'opacity'); +label = ft_getopt(varargin, 'label'); +box = ft_getopt(varargin, 'box', false); +tag = ft_getopt(varargin, 'tag', ''); +% these have to do with the font of the label +fontcolor = ft_getopt(varargin, 'fontcolor', 'k'); % default is black +fontsize = ft_getopt(varargin, 'fontsize', get(0, 'defaulttextfontsize')); +fontname = ft_getopt(varargin, 'fontname', get(0, 'defaulttextfontname')); +fontweight = ft_getopt(varargin, 'fontweight', get(0, 'defaulttextfontweight')); +fontunits = ft_getopt(varargin, 'fontunits', get(0, 'defaulttextfontunits')); if ~isempty(highlight) && ~isequal(size(highlight), size(cdat)) - error('the dimensions of the highlight should be identical to the dimensions of the data'); + ft_error('the dimensions of the highlight should be identical to the dimensions of the data'); end % axis = ft_getopt(varargin, 'axis', false); -% label = ft_getopt(varargin, 'label'); % FIXME % style = ft_getopt(varargin, 'style'); % FIXME % convert the yes/no strings into boolean values @@ -111,7 +125,7 @@ function ft_plot_matrix(varargin) hlim = max(abs(hdat)); hlim = [-hlim hlim]; otherwise - error('unsupported option for hlim') + ft_error('unsupported option for hlim') end % switch end % if ischar @@ -134,7 +148,7 @@ function ft_plot_matrix(varargin) vlim = max(abs(vdat)); vlim = [-vlim vlim]; otherwise - error('unsupported option for vlim') + ft_error('unsupported option for vlim') end % switch end % if ischar @@ -157,7 +171,7 @@ function ft_plot_matrix(varargin) clim = max(abs(cdat(:))); clim = [-clim clim]; otherwise - error('unsupported option for clim') + ft_error('unsupported option for clim') end % switch end % if ischar @@ -180,15 +194,15 @@ function ft_plot_matrix(varargin) vlim = double(vlim); clim = double(clim); -if isempty(hpos); +if isempty(hpos) hpos = (hlim(1)+hlim(2))/2; end -if isempty(vpos); +if isempty(vpos) vpos = (vlim(1)+vlim(2))/2; end -if isempty(width), +if isempty(width) width = hlim(2)-hlim(1); if length(hdat)>1 width = width * length(hdat)/(length(hdat)-1); @@ -200,7 +214,7 @@ function ft_plot_matrix(varargin) autowidth = false; end -if isempty(height), +if isempty(height) height = vlim(2)-vlim(1); if length(vdat)>1 height = height * length(vdat)/(length(vdat)-1); @@ -260,35 +274,17 @@ function ft_plot_matrix(varargin) end case 'saturation' - % This approach changes the color of pixels to white, regardless of colormap, without using opengl - % It does by converting by: - % 1) convert the to-be-plotted data to their respective rgb color values (determined by colormap) - % 2) convert these rgb color values to hsv values, hue-saturation-value - % 3) for to-be-masked-pixels, set saturation to 0 and value to 1 (hue is irrelevant when they are) - % 4) convert the hsv values back to rgb values - % 5) plot these values + cmap = get(gcf, 'colormap'); + rgbcdat = cdat2rgb(cdat, cmap, clim, highlight); - % enforce mask properties (satmask is 0 when a pixel needs to be masked, 1 if otherwise) - satmask = round(double(highlight)); % enforce binary white-masking, the hsv approach cannot be used for 'white-shading' - satmask(isnan(cdat)) = false; % make sure NaNs are plotted as white pixels, even when using non-integer mask values + h = uimagesc(hdat, vdat, rgbcdat, clim); + set(h,'tag',tag); + + case 'colormix' + cmap = get(gcf, 'colormap'); + rgbcdat = bg_rgba2rgb([1 1 1], cdat, cmap, clim, highlight, 'rampup', [0 1]); - % do 1, by converting the data-values to zero-based indices of the colormap - ncolors = size(get(gcf,'colormap'),1); % determines range of index, if a figure has been created by the caller function, gcf changes nothing, if not, a figure is created (which the below would do otherwise) - indcdat = (cdat + -clim(1)) * (ncolors / (-clim(1) + clim(2))); % transform cdat-values to have a 0-(ncolors-1) range (range depends on colormap used, and thus also on clim) - rgbcdat = ind2rgb(uint8(floor(indcdat)), colormap); - % do 2 - hsvcdat = rgb2hsv(rgbcdat); - % do 3 - hsvs = hsvcdat(:,:,2); - hsvs(~satmask) = 0; - hsvv = hsvcdat(:,:,3); - hsvv(~satmask) = 1; - hsvcdat(:,:,2) = hsvs; - hsvcdat(:,:,3) = hsvv; - % do 4 - rgbcdat = hsv2rgb(hsvcdat); - % do 5 - h = imagesc(hdat, vdat, rgbcdat,clim); + h = uimagesc(hdat, vdat, rgbcdat, clim); set(h,'tag',tag); case 'outline' @@ -311,10 +307,18 @@ function ft_plot_matrix(varargin) end otherwise - error('unsupported highlightstyle') + ft_error('unsupported highlightstyle') end % switch highlightstyle end +if ~isempty(label) + boxposition(1) = hpos - width/2; + boxposition(2) = hpos + width/2; + boxposition(3) = vpos - height/2; + boxposition(4) = vpos + height/2; + text(boxposition(1), boxposition(4), label, 'color', fontcolor, 'fontunits', fontunits, 'fontsize', fontsize, 'fontname', fontname, 'fontweight', fontweight); +end + if box boxposition = zeros(1,4); % this plots a box around the original hpos/vpos with appropriate width/height diff --git a/external/fieldtrip/plotting/ft_plot_mesh.m b/external/fieldtrip/plotting/ft_plot_mesh.m index 02f8aab3..265fc44e 100644 --- a/external/fieldtrip/plotting/ft_plot_mesh.m +++ b/external/fieldtrip/plotting/ft_plot_mesh.m @@ -1,9 +1,9 @@ function [hs] = ft_plot_mesh(mesh, varargin) -% FT_PLOT_MESH visualizes the information of a mesh contained in the first -% argument mesh. The boundary argument (mesh) typically contains two fields -% called .pos and .tri referring to the vertices and the triangulation of -% the mesh. +% FT_PLOT_MESH visualizes a surface or volumetric mesh, for example describing the +% realistic shape of the head. Surface meshes should be described by triangles and +% contain the fields "pos" and "tri". Volumetric meshes should be described with +% tetraheders or hexaheders and have the fields "pos" and "tet" or "hex". % % Use as % ft_plot_mesh(mesh, ...) @@ -11,8 +11,8 @@ % ft_plot_mesh(pos, ...) % % Optional arguments should come in key-value pairs and can include -% 'facecolor' = [r g b] values or string, for example 'brain', 'cortex', 'skin', 'black', 'red', 'r', or an Nx1 array where N is the number of faces -% 'vertexcolor' = [r g b] values or string, for example 'brain', 'cortex', 'skin', 'black', 'red', 'r', or an Nx1 array where N is the number of vertices +% 'facecolor' = [r g b] values or string, for example 'brain', 'cortex', 'skin', 'black', 'red', 'r', or an Nx3 or Nx1 array where N is the number of faces +% 'vertexcolor' = [r g b] values or string, for example 'brain', 'cortex', 'skin', 'black', 'red', 'r', or an Nx3 or Nx1 array where N is the number of vertices % 'edgecolor' = [r g b] values or string, for example 'brain', 'cortex', 'skin', 'black', 'red', 'r' % 'faceindex' = true or false % 'vertexindex' = true or false @@ -22,6 +22,10 @@ % 'vertexmarker' = character, e.g. '.', 'o' or 'x' (default = '.') % 'vertexsize' = scalar or vector with the size for each vertex (default = 10) % 'unit' = string, convert to the specified geometrical units (default = []) +% 'maskstyle', = 'opacity' or 'colormix', if the latter is specified, opacity masked color values +% are converted (in combination with a background color) to rgb. This bypasses +% openGL functionality, which behaves unpredictably on some platforms (e.g. when +% using software opengl) % % If you don't want the faces, edges or vertices to be plotted, you should specify the color as 'none'. % @@ -34,8 +38,8 @@ % % See also TRIMESH, PATCH -% Copyright (C) 2009-2015, Robert Oostenveld % Copyright (C) 2009, Cristiano Micheli +% Copyright (C) 2009-2015, Robert Oostenveld % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -77,7 +81,7 @@ % get the optional input arguments vertexcolor = ft_getopt(varargin, 'vertexcolor'); if isfield(mesh, 'tri') && size(mesh.tri,1)>10000 - facecolor = ft_getopt(varargin, 'facecolor', [0.5 0.5 0.5]); + facecolor = ft_getopt(varargin, 'facecolor', 'cortex_light'); edgecolor = ft_getopt(varargin, 'edgecolor', 'none'); else facecolor = ft_getopt(varargin, 'facecolor', 'white'); @@ -90,16 +94,13 @@ facealpha = ft_getopt(varargin, 'facealpha', 1); edgealpha = ft_getopt(varargin, 'edgealpha', 1); tag = ft_getopt(varargin, 'tag', ''); -surfaceonly = ft_getopt(varargin, 'surfaceonly', false); +surfaceonly = ft_getopt(varargin, 'surfaceonly'); % default is handled below unit = ft_getopt(varargin, 'unit'); - -if ~isempty(unit) - mesh = ft_convert_units(mesh, unit); -end - -if surfaceonly - mesh = mesh2edge(mesh); -end +clim = ft_getopt(varargin, 'clim'); +alphalim = ft_getopt(varargin, 'alphalim'); +alphamapping = ft_getopt(varargin, 'alphamap', 'rampup'); +cmap = ft_getopt(varargin, 'colormap'); +maskstyle = ft_getopt(varargin, 'maskstyle', 'opacity'); haspos = isfield(mesh, 'pos'); % vertices hastri = isfield(mesh, 'tri'); % triangles as a Mx3 matrix with vertex indices @@ -109,25 +110,43 @@ haspoly = isfield(mesh, 'poly'); % polynomial surfaces in 3-D hascolor = isfield(mesh, 'color'); % color code for vertices -if (hastet || hashex) && ~surfaceonly - warning('you probably want to use the "surfaceonly" option for plotting only the outer surface') +if hastet && isempty(surfaceonly) + ft_warning('only visualizing the outer surface of the tetrahedral mesh, see the "surfaceonly" option') + surfaceonly = true; +elseif hashex && isempty(surfaceonly) + ft_warning('only visualizing the outer surface of the hexahedral mesh, see the "surfaceonly" option') + surfaceonly = true; +else + surfaceonly = false; +end + +if ~isempty(unit) + mesh = ft_convert_units(mesh, unit); end +if surfaceonly + mesh = mesh2edge(mesh); + % update the flags that indicate which surface/volume elements are present + hastri = isfield(mesh, 'tri'); % triangles as a Mx3 matrix with vertex indices + hastet = isfield(mesh, 'tet'); % tetraheders as a Mx4 matrix with vertex indices + hashex = isfield(mesh, 'hex'); % hexaheders as a Mx8 matrix with vertex indices +end + +% convert string into boolean values +faceindex = istrue(faceindex); % yes=view the face number +vertexindex = istrue(vertexindex); % yes=view the vertex number + if isempty(vertexcolor) if haspos && hascolor && (hastri || hastet || hashex || hasline || haspoly) - vertexcolor = mesh.color; + vertexcolor = mesh.color; elseif haspos && (hastri || hastet || hashex || hasline || haspoly) - vertexcolor ='none'; + vertexcolor ='none'; else vertexcolor ='k'; end end -% convert string into boolean values -faceindex = istrue(faceindex); % yes=view the face number -vertexindex = istrue(vertexindex); % yes=view the vertex number - -% there a various ways of disabling the plotting +% there are various ways of specifying that this should not be plotted if isequal(vertexcolor, 'false') || isequal(vertexcolor, 'no') || isequal(vertexcolor, 'off') || isequal(vertexcolor, false) vertexcolor = 'none'; end @@ -138,13 +157,27 @@ edgecolor = 'none'; end -% new colors management -if strcmpi(vertexcolor,'skin') || strcmpi(vertexcolor,'brain') || strcmpi(vertexcolor,'cortex') +% color management +if ischar(vertexcolor) && exist([vertexcolor '.m'], 'file') vertexcolor = eval(vertexcolor); +elseif ischar(vertexcolor) && isequal(vertexcolor, 'curv') % default of ft_sourceplot method surface + if isfield(mesh, 'curv') + cortex_light = eval('cortex_light'); + cortex_dark = eval('cortex_dark'); + % the curvature determines the color of gyri and sulci + vertexcolor = mesh.curv(:) * cortex_dark + (1-mesh.curv(:)) * cortex_light; + else + cortex_light = eval('cortex_light'); + vertexcolor = repmat(cortex_light, size(mesh.pos,1), 1); + ft_warning('no curv field present in the mesh structure, using cortex_light as vertexcolor') + end end -if strcmpi(facecolor,'skin') || strcmpi(facecolor,'brain') || strcmpi(facecolor,'cortex') +if ischar(facecolor) && exist([facecolor '.m'], 'file') facecolor = eval(facecolor); end +if ischar(edgecolor) && exist([edgecolor '.m'], 'file') + edgecolor = eval(edgecolor); +end % everything is added to the current figure holdflag = ishold; @@ -159,7 +192,7 @@ % this happens sometimes if the 3-D vertices are projected to a 2-D plane pos = mesh.prj; else - error('no vertices found'); + ft_error('no vertices found'); end if isempty(pos) @@ -168,7 +201,7 @@ end if hastri+hastet+hashex+hasline+haspoly>1 - error('cannot deal with simultaneous triangles, tetraheders and/or hexaheders') + ft_error('cannot deal with simultaneous triangles, tetraheders and/or hexaheders') end if hastri @@ -227,29 +260,61 @@ vertexpotential = ~isempty(tri) && ~ischar(vertexcolor) && (size(pos,1)==numel(vertexcolor) || size(pos,1)==size(vertexcolor,1) && (size(vertexcolor,2)==1 || size(vertexcolor,2)==3)); facepotential = ~isempty(tri) && ~ischar(facecolor ) && (size(tri,1)==numel(facecolor ) || size(tri,1)==size(facecolor ,1) && (size(facecolor ,2)==1 || size(facecolor, 2)==3)); -% if both vertexcolor and facecolor are numeric arrays, let the vertexcolor prevail -if vertexpotential - % vertexcolor is an array with number of elements equal to the number of vertices - set(hs, 'FaceVertexCData', vertexcolor, 'FaceColor', 'interp'); -elseif facepotential - set(hs, 'FaceVertexCData', facecolor, 'FaceColor', 'flat'); -else - % the color is indicated as a single character or as a single RGB triplet - set(hs, 'FaceColor', facecolor); -end - -% if facealpha is an array with number of elements equal to the number of vertices -if size(pos,1)==numel(facealpha) - set(hs, 'FaceVertexAlphaData', facealpha); - set(hs, 'FaceAlpha', 'interp'); -elseif ~isempty(pos) && numel(facealpha)==1 && facealpha~=1 - % the default is 1, so that does not have to be set - set(hs, 'FaceAlpha', facealpha); -end - -if edgealpha~=1 - % the default is 1, so that does not have to be set - set(hs, 'EdgeAlpha', edgealpha); +switch maskstyle + case 'opacity' + % if both vertexcolor and facecolor are numeric arrays, let the vertexcolor prevail + if vertexpotential + % vertexcolor is an array with number of elements equal to the number of vertices + set(hs, 'FaceVertexCData', vertexcolor, 'FaceColor', 'interp'); + if numel(vertexcolor)==size(pos,1) + if ~isempty(clim), set(gca, 'clim', clim); end + if ~isempty(cmap), colormap(cmap); end + end + elseif facepotential + set(hs, 'FaceVertexCData', facecolor, 'FaceColor', 'flat'); + if numel(facecolor)==size(tri,1) + if ~isempty(clim), set(gca, 'clim', clim); end + if ~isempty(cmap), colormap(cmap); end + end + else + % the color is indicated as a single character or as a single RGB triplet + set(hs, 'FaceColor', facecolor); + end + + % facealpha is a scalar, or an vector matching the number of vertices + if size(pos,1)==numel(facealpha) + set(hs, 'FaceVertexAlphaData', facealpha); + set(hs, 'FaceAlpha', 'interp'); + elseif ~isempty(pos) && numel(facealpha)==1 && facealpha~=1 + % the default is 1, so that does not have to be set + set(hs, 'FaceAlpha', facealpha); + end + + if edgealpha~=1 + % the default is 1, so that does not have to be set + set(hs, 'EdgeAlpha', edgealpha); + end + + if ~(all(facealpha==1) && edgealpha==1) + if ~isempty(alphalim) + alim(gca, alphalim); + end + alphamap(alphamapping); + end + + case 'colormix' + % ensure facecolor to be 1x3 + assert(isequal(size(facecolor),[1 3]), 'facecolor should be 1x3'); + + % ensure facealpha to be nvertex x 1 + if numel(facealpha)==1 + facealpha = repmat(facealpha, size(pos,1), 1); + end + assert(isequal(numel(facealpha),size(pos,1)), 'facealpha should be %dx1', size(pos,1)); + + bgcolor = repmat(facecolor, [numel(vertexcolor) 1]); + rgb = bg_rgba2rgb(bgcolor, vertexcolor, cmap, clim, facealpha, alphamapping, alphalim); + set(hs, 'FaceVertexCData', rgb, 'facecolor', 'interp'); end if faceindex @@ -368,11 +433,12 @@ end else - error('Unknown color specification for the vertices'); + ft_error('Unknown color specification for the vertices'); end end % plotting the vertices as points + if vertexindex % plot the vertex indices (numbers) at each node for node_indx=1:size(pos,1) diff --git a/external/fieldtrip/plotting/ft_plot_montage.m b/external/fieldtrip/plotting/ft_plot_montage.m index 8fab62e9..745d907d 100644 --- a/external/fieldtrip/plotting/ft_plot_montage.m +++ b/external/fieldtrip/plotting/ft_plot_montage.m @@ -1,7 +1,9 @@ function ft_plot_montage(dat, varargin) -% FT_PLOT_MONTAGE makes a montage of a 3-D array by selecting slices at -% regular distances and combining them in one large 2-D image. +% FT_PLOT_MONTAGE makes a montage of a 3-D array by selecting slices at regular distances +% and combining them in one large 2-D image. Note that the montage of MRI slices is not to +% be confused with the EEG montage, which is a way of specifying the reference scheme +% between electrodes. % % Use as % ft_plot_montage(dat, ...) @@ -14,6 +16,10 @@ function ft_plot_montage(dat, varargin) % 'srange' = % 'slicesize' = % 'nslice' = scalar, number of slices +% 'maskstyle' = string, 'opacity' or 'colormix', defines the rendering +% 'background' = needed when maskstyle is 'colormix', 3D-matrix with +% the same size as the data matrix, serving as +% grayscale image that provides the background % % See also FT_PLOT_ORTHO, FT_PLOT_SLICE, FT_SOURCEPLOT @@ -41,19 +47,20 @@ function ft_plot_montage(dat, varargin) % % $Id$ -transform = ft_getopt(varargin, 'transform', eye(4)); -loc = ft_getopt(varargin, 'location'); -ori = ft_getopt(varargin, 'orientation'); -srange = ft_getopt(varargin, 'slicerange'); -slicesize = ft_getopt(varargin, 'slicesize'); -nslice = ft_getopt(varargin, 'nslice'); +transform = ft_getopt(varargin, 'transform', eye(4)); +loc = ft_getopt(varargin, 'location'); +ori = ft_getopt(varargin, 'orientation'); +srange = ft_getopt(varargin, 'slicerange'); +slicesize = ft_getopt(varargin, 'slicesize'); +nslice = ft_getopt(varargin, 'nslice'); backgroundcolor = ft_getopt(varargin, 'backgroundcolor', [0 0 0]); -% the intersectmesh and intersectcolor options are passed on to FT_PLOT_SLICE -dointersect = ~isempty(ft_getopt(varargin, 'intersectmesh')) || ~isempty(ft_getopt(varargin, 'plotmarker')); +% the intersectmesh and plotmarker options are passed on to FT_PLOT_SLICE +dointersect = ~isempty(ft_getopt(varargin, 'intersectmesh')); +domarker = ~isempty(ft_getopt(varargin, 'plotmarker')); % set the location if empty -if isempty(loc) && (isempty(transform) || all(all(transform-eye(4)==0)==1)) +if isempty(loc) && (isempty(transform) || isequal(transform, eye(4))) % go to the middle of the volume if the data seem to be in voxel coordinates loc = size(dat)./2; elseif isempty(loc) @@ -71,12 +78,12 @@ function ft_plot_montage(dat, varargin) nslice = size(loc, 1); elseif size(loc, 1) > 1 && ~isempty(nslice) if size(loc, 1) ~= nslice - error('you should either specify a set of locations or a single location with a number of slices'); + ft_error('you should either specify a set of locations or a single location with a number of slices'); end end % set the orientation if empty -if isempty(ori), +if isempty(ori) ori = [0 0 1]; end @@ -86,7 +93,7 @@ function ft_plot_montage(dat, varargin) end % determine the slice range -if size(loc, 1) == 1 && nslice > 1, +if size(loc, 1) == 1 && nslice > 1 if isempty(srange) || (ischar(srange) && strcmp(srange, 'auto')) srange = [-50 70]; else @@ -95,15 +102,15 @@ function ft_plot_montage(dat, varargin) end % ensure that the ori has the same size as the loc -if size(ori,1)==1 && size(loc,1)>1, +if size(ori,1)==1 && size(loc,1)>1 ori = repmat(ori, size(loc,1), 1); end div = [ceil(sqrt(nslice)) ceil(sqrt(nslice))]; optarg = varargin; corners = [inf -inf inf -inf inf -inf]; % get the corners for the axis specification + for k = 1:nslice - % define 'x' and 'y' axis in projection plane, the definition of x and y is more or less arbitrary [x, y] = projplane(ori(k,:)); % z = ori @@ -152,7 +159,7 @@ function ft_plot_montage(dat, varargin) set(h(k), 'xdata', offset(2) + ytmp); set(h(k), 'zdata', 0 * ztmp); - if dointersect, + if dointersect || domarker if ~exist('pprevious', 'var'), pprevious = []; end p = setdiff(findobj(gcf, 'type', 'patch'), pprevious); for kk = 1:numel(p) diff --git a/external/fieldtrip/plotting/ft_plot_ortho.m b/external/fieldtrip/plotting/ft_plot_ortho.m index d11451b7..1742afac 100644 --- a/external/fieldtrip/plotting/ft_plot_ortho.m +++ b/external/fieldtrip/plotting/ft_plot_ortho.m @@ -1,6 +1,6 @@ function [hx, hy, hz] = ft_plot_ortho(dat, varargin) -% FT_PLOT_ORTHO plots a 3 orthographic cuts through a 3-D volume +% FT_PLOT_ORTHO plots 3 orthographic cuts through a 3-D volume and interpolates if needed % % Use as % ft_plot_ortho(dat, ...) @@ -16,13 +16,21 @@ % 'update' = (optional) 3-element boolean vector with the axes that should be updated (default = [true true true]) % % The following options are supported and passed on to FT_PLOT_SLICE -% 'clim' = [min max], lower and upper color limits -% 'transform' = 4x4 homogeneous transformation matrix specifying the mapping from voxel space to the coordinate system in which the data are plotted -% 'location' = 1x3 vector specifying a point on the plane which will be plotted the coordinates are expressed in the coordinate system in which the data will be plotted. location defines the origin of the plane -% 'datmask' = 3D-matrix with the same size as the matrix dat, serving as opacitymap if the second input argument to the function contains a matrix, this will be used as the mask -% 'interpmethod' = string specifying the method for the interpolation, see INTERPN (default = 'nearest') -% 'colormap' = string, see COLORMAP -% 'unit' = string, can be 'm', 'cm' or 'mm (default is automatic) +% 'clim' = [min max], lower and upper color limits +% 'transform' = 4x4 homogeneous transformation matrix specifying the mapping from voxel space to the coordinate system in which the data are plotted +% 'location' = 1x3 vector specifying a point on the plane which will be plotted the coordinates are expressed in the coordinate system in which the data will be plotted. location defines the origin of the plane +% 'datmask' = 3D-matrix with the same size as the matrix dat, serving as opacitymap if the second input argument to the function contains a matrix, this will be used as the mask +% 'maskstyle' = string, 'opacity' or 'colormix', defines the rendering +% 'background' = needed when maskstyle is 'colormix', 3D-matrix with +% the same size as the data matrix, serving as +% grayscale image that provides the background +% 'interpmethod' = string specifying the method for the interpolation, see INTERPN (default = 'nearest') +% 'colormap' = string, see COLORMAP +% 'unit' = string, can be 'm', 'cm' or 'mm (default is automatic) +% 'intersectmesh' = triangulated mesh, see FT_PREPARE_MESH +% 'intersectcolor' = string, color specification +% 'intersectlinestyle' = string, line specification +% 'intersectlinewidth' = number % % See also FT_PLOT_SLICE, FT_PLOT_MONTAGE, FT_SOURCEPLOT @@ -69,7 +77,7 @@ surfhandle = ft_getopt(varargin(sellist), 'surfhandle'); update = ft_getopt(varargin(sellist), 'update', [true true true]); if ~isempty(surfhandle) && ~isempty(parents) - error('if specifying handles, you should either specify handles to the axes or to the surface objects, not both'); + ft_error('if specifying handles, you should either specify handles to the axes or to the surface objects, not both'); end end @@ -115,7 +123,7 @@ set(gcf,'currentaxes',Hx); hx = ft_plot_slice(dat, varargin{:}); set(Hx, 'view', [0 0]);%, 'xlim', [0.5 size(dat,1)-0.5], 'zlim', [0.5 size(dat,3)-0.5]); - if isempty(parents), + if isempty(parents) % only change axis behavior if no parents are specified axis off end @@ -129,7 +137,7 @@ set(gcf,'currentaxes',Hy); hy = ft_plot_slice(dat, varargin{:}); set(Hy, 'view', [90 0]);%, 'ylim', [0.5 size(dat,2)-0.5], 'zlim', [0.5 size(dat,3)-0.5]); - if isempty(parents), + if isempty(parents) % only change axis behavior if no parents are specified axis off end @@ -143,7 +151,7 @@ set(gcf,'currentaxes',Hz); hz = ft_plot_slice(dat, varargin{:}); set(Hz, 'view', [0 90]);%, 'xlim', [0.5 size(dat,1)-0.5], 'ylim', [0.5 size(dat,2)-0.5]); - if isempty(parents), + if isempty(parents) % only change axis behavior if no parents are specified axis off end @@ -171,7 +179,7 @@ end otherwise - error('unsupported style %s', style); + ft_error('unsupported style %s', style); end % switch style diff --git a/external/fieldtrip/plotting/ft_plot_patch.m b/external/fieldtrip/plotting/ft_plot_patch.m index a7f2d4aa..40547ebc 100644 --- a/external/fieldtrip/plotting/ft_plot_patch.m +++ b/external/fieldtrip/plotting/ft_plot_patch.m @@ -1,4 +1,4 @@ -function [varargout] = ft_plot_patch(hdat,vdat,varargin) +function [varargout] = ft_plot_patch(hdat, vdat, varargin) % FT_PLOT_PATCH plot a colored shape, similar to the MATLAB patch() function. It is % similar in usage as ft_plot_vector, and they can be combined, for example, @@ -11,7 +11,7 @@ % Optional arguments should come in key-value pairs and can include % 'axis' = draw the local axis, can be 'yes', 'no', 'xy', 'x' or 'y' % 'box' = draw a box around the local axes, can be 'yes' or 'no' -% 'tag' = string, the name this vector gets. All tags with the same name can be deleted in a figure, without deleting other parts of the figure. +% 'tag' = string, the name assigned to the object. All tags with the same name can be deleted in a figure, without deleting other parts of the figure. % 'facecolor' = see MATLAB standard patch properties % 'facealpha' = see MATLAB standard patch properties (note, approx. transparency can be achieved using 'facecolor') % 'edgecolor' = see MATLAB standard patch properties (default is 'none') (equivalent to 'linecolor' in PLOT) @@ -35,7 +35,7 @@ % hdat = [1:10 10:-1:1]; % vdat = rand(1,10); % vdat = [vdat vdat(end:-1:1)+1]; -% ft_plot_patch(hdat,vdat) +% ft_plot_patch(hdat, vdat) % % See also FT_PLOT_VECTOR @@ -78,10 +78,17 @@ linestyle = ft_getopt(varargin, 'linestyle', 'none'); linewidth = ft_getopt(varargin, 'linewidth', .5); - % convert the yes/no strings into boolean values box = istrue(box); +% color management +if ischar(facecolor) && exist([facecolor '.m'], 'file') + facecolor = eval(facecolor); +end +if ischar(edgecolor) && exist([edgecolor '.m'], 'file') + edgecolor = eval(edgecolor); +end + % this should be a string, because valid options include yes, no, xy, x, y if isequal(axis, true) axis = 'yes'; @@ -103,7 +110,7 @@ hlim = max(abs(hdat)); hlim = [-hlim hlim]; otherwise - error('unsupported option for hlim') + ft_error('unsupported option for hlim') end % switch end % if ischar @@ -115,7 +122,7 @@ vlim = max(abs(vdat(:))); vlim = [-vlim vlim]; otherwise - error('unsupported option for vlim') + ft_error('unsupported option for vlim') end % switch end % if ischar @@ -172,8 +179,7 @@ vdat = vdat + vpos; % plot the patch -h = patch(hdat,vdat,facecolor,'facealpha',facealpha,'edgecolor',edgecolor,'linestyle',linestyle,'linewidth',linewidth); - +h = patch(hdat, vdat, facecolor, 'facealpha', facealpha, 'edgecolor', edgecolor, 'linestyle', linestyle, 'linewidth', linewidth); if box % this plots a box around the original hpos/vpos with appropriate width/height @@ -216,7 +222,7 @@ xaxis = false; yaxis = true; otherwise - error('invalid specification of the "axis" option') + ft_error('invalid specification of the "axis" option') end if xaxis @@ -226,7 +232,7 @@ [dum minind] = min(abs(hlim)); xrange(minind) = 0; end - ft_plot_line(xrange, [0 0],'hpos',hpos,'vpos',vpos,'hlim',hlim,'vlim',vlim,'width',width,'height',height); + ft_plot_line(xrange, [0 0], 'hpos', hpos, 'vpos', vpos, 'hlim', hlim, 'vlim', vlim, 'width', width, 'height', height); end if yaxis % y-axis should touch 0,0 @@ -235,11 +241,11 @@ [dum minind] = min(abs(vlim)); yrange(minind) = 0; end - ft_plot_line([0 0], yrange,'hpos',hpos,'vpos',vpos,'hlim',hlim,'vlim',vlim,'width',width,'height',height); + ft_plot_line([0 0], yrange, 'hpos', hpos, 'vpos', vpos, 'hlim', hlim, 'vlim', vlim, 'width', width, 'height', height); end end -set(h,'tag',tag); +set(h, 'tag', tag); if ~isempty(parent) set(h, 'Parent', parent); diff --git a/external/fieldtrip/plotting/ft_plot_sens.m b/external/fieldtrip/plotting/ft_plot_sens.m index 23f09f72..cab45bac 100644 --- a/external/fieldtrip/plotting/ft_plot_sens.m +++ b/external/fieldtrip/plotting/ft_plot_sens.m @@ -1,7 +1,6 @@ function hs = ft_plot_sens(sens, varargin) -% FT_PLOT_SENS plots the position of all channels or coils that comprise the EEG or -% MEG sensor array description +% FT_PLOT_SENS visualizes the EEG, MEG or NIRS sensor array. % % Use as % ft_plot_sens(sens, ...) @@ -9,26 +8,44 @@ % by FT_PREPARE_VOL_SENS. % % Optional input arguments should come in key-value pairs and can include -% 'chantype' = string or cell-array with strings, for example 'meg' (default = 'all') -% 'unit' = string, convert the data to the specified geometrical units (default = []) % 'label' = show the label, can be 'off', 'label', 'number' (default = 'off') +% 'chantype' = string or cell-array with strings, for example 'meg' (default = 'all') +% 'unit' = string, convert the sensor array to the specified geometrical units (default = []) +% 'fontcolor' = string, color specification (default = 'k') +% 'fontsize' = number, sets the size of the text (default = 10) +% 'fontunits' = +% 'fontname' = +% 'fontweight' = +% +% The following options apply to MEG magnetometers and/or gradiometers % 'coil' = true/false, plot each individual coil (default = false) % 'orientation' = true/false, plot a line for the orientation of each coil (default = false) -% -% The following option only applies when individual coils are being plotted +% 'coilshape' = 'point', 'circle', 'square', or 'sphere' (default is automatic) % 'coilsize' = diameter or edge length of the coils (default is automatic) -% 'coilshape' = 'point', 'circle' or 'square' (default is automatic) -% 'facecolor' = [r g b] values or string, for example 'brain', 'cortex', 'skin', 'black', 'red', 'r', or an Nx1 array where N is the number of faces (default = 'none') -% 'edgecolor' = [r g b] values or string, for example 'brain', 'cortex', 'skin', 'black', 'red', 'r' (default = 'k') +% The following options apply to EEG electrodes +% 'elec' = true/false, plot each individual electrode (default = false) +% 'elecshape' = 'point', 'circle', 'square', or 'sphere' (default is automatic) +% 'elecsize' = diameter of the electrodes (default is automatic) +% The following options apply to NIRS optodes +% 'opto' = true/false, plot each individual optode (default = false) +% 'optoshape' = 'point', 'circle', 'square', or 'sphere' (default is automatic) +% 'optosize' = diameter of the optodes (default is automatic) +% +% The following options apply when electrodes/coils/optodes are NOT plotted individually +% 'style' = plotting style for the points representing the channels, see plot3 (default = []) +% 'marker' = marker type representing the channels, see plot3 (default = '.') +% The following options apply when electrodes/coils/optodes are plotted individually +% 'facecolor' = [r g b] values or string, for example 'brain', 'cortex', 'skin', 'black', 'red', 'r', or an Nx3 or Nx1 array where N is the number of faces (default is automatic) +% 'edgecolor' = [r g b] values or string, for example 'brain', 'cortex', 'skin', 'black', 'red', 'r', color of channels or coils (default is automatic) % 'facealpha' = transparency, between 0 and 1 (default = 1) % 'edgealpha' = transparency, between 0 and 1 (default = 1) % -% The following option only applies when individual coils are NOT being plotted -% 'style' = plotting style for the points representing the channels, see plot3 (default = 'k.') -% % Example % sens = ft_read_sens('Subject01.ds'); -% ft_plot_sens(sens, 'style', 'r*') +% figure; ft_plot_sens(sens, 'coilshape', 'point', 'style', 'r*') +% figure; ft_plot_sens(sens, 'coilshape', 'circle') +% figure; ft_plot_sens(sens, 'coilshape', 'circle', 'coil', true, 'chantype', 'meggrad') +% figure; ft_plot_sens(sens, 'coilshape', 'circle', 'coil', false, 'orientation', true) % % See also FT_READ_SENS, FT_DATATYPE_SENS, FT_PLOT_HEADSHAPE, FT_PREPARE_VOL_SENS @@ -54,7 +71,7 @@ ws = warning('on', 'MATLAB:divideByZero'); -% ensure that the sensor description is up-to-date (Aug 2011) +% ensure that the sensor description is up-to-date sens = ft_datatype_sens(sens); % get the optional input arguments @@ -62,34 +79,77 @@ chantype = ft_getopt(varargin, 'chantype'); unit = ft_getopt(varargin, 'unit'); orientation = ft_getopt(varargin, 'orientation', false); +% these have to do with the font +fontcolor = ft_getopt(varargin, 'fontcolor', 'k'); % default is black +fontsize = ft_getopt(varargin, 'fontsize', get(0, 'defaulttextfontsize')); +fontname = ft_getopt(varargin, 'fontname', get(0, 'defaulttextfontname')); +fontweight = ft_getopt(varargin, 'fontweight', get(0, 'defaulttextfontweight')); +fontunits = ft_getopt(varargin, 'fontunits', get(0, 'defaulttextfontunits')); + % this is for MEG magnetometer and/or gradiometer arrays coil = ft_getopt(varargin, 'coil', false); -coilsize = ft_getopt(varargin, 'coilsize'); % default depends on the input, see below coilshape = ft_getopt(varargin, 'coilshape'); % default depends on the input, see below +coilsize = ft_getopt(varargin, 'coilsize'); % default depends on the input, see below +% this is for EEG electrode arrays +elec = ft_getopt(varargin, 'elec', false); +elecshape = ft_getopt(varargin, 'elecshape'); % default depends on the input, see below +elecsize = ft_getopt(varargin, 'elecsize'); % default depends on the input, see below +% this is for NIRS optode arrays +opto = ft_getopt(varargin, 'opto', false); +optoshape = ft_getopt(varargin, 'optoshape'); % default depends on the input, see below +optosize = ft_getopt(varargin, 'optosize'); % default depends on the input, see below + +% make sure that the options are consistent with the data +if ft_senstype(sens, 'eeg') + individual = elec; + sensshape = elecshape; + sensize = elecsize; +elseif ft_senstype(sens, 'meg') + individual = coil; + sensshape = coilshape; + sensize = coilsize; +elseif ft_senstype(sens, 'nirs') + % this has not been tested + individual = opto; + sensshape = optoshape; + sensize = optosize; +else + ft_warning('unknown sensor array description'); + individual = false; + sensshape = []; + sensize = []; +end + % this is simply passed to plot3 -style = ft_getopt(varargin, 'style', 'k.'); +style = ft_getopt(varargin, 'style'); +marker = ft_getopt(varargin, 'marker', '.'); + % this is simply passed to ft_plot_mesh -edgecolor = ft_getopt(varargin, 'edgecolor', 'k'); -facecolor = ft_getopt(varargin, 'facecolor', 'none'); +if strcmp(sensshape, 'sphere') + edgecolor = ft_getopt(varargin, 'edgecolor', 'none'); +else + edgecolor = ft_getopt(varargin, 'edgecolor', 'k'); +end +facecolor = ft_getopt(varargin, 'facecolor'); % default depends on the input, see below facealpha = ft_getopt(varargin, 'facealpha', 1); edgealpha = ft_getopt(varargin, 'edgealpha', 1); if ischar(chantype) - % should be a cell array + % this should be a cell array chantype = {chantype}; end if ~isempty(ft_getopt(varargin, 'coilorientation')) % for backward compatibility, added on 17 Aug 2016 - warning('the coilorientation option is deprecated, please use orientation instead') + ft_warning('the coilorientation option is deprecated, please use "orientation" instead') orientation = ft_getopt(varargin, 'coilorientation'); end if ~isempty(ft_getopt(varargin, 'coildiameter')) % for backward compatibility, added on 6 July 2016 - % the size is the diameter for a circle, or the edge length for a square - warning('the coildiameter option is deprecated, please use coilsize instead') - coilsize = ft_getopt(varargin, 'coilsize'); + % the sensize is the diameter for a circle, or the edge length for a square + ft_warning('the coildiameter option is deprecated, please use "coilsize" instead') + sensize = ft_getopt(varargin, 'coildiameter'); end if ~isempty(unit) @@ -97,35 +157,58 @@ sens = ft_convert_units(sens, unit); end -if isempty(coilshape) +if isempty(sensshape) if ft_senstype(sens, 'neuromag') if strcmp(chantype, 'megmag') - coilshape = 'point'; % these cannot be plotted as squares + sensshape = 'point'; % these cannot be plotted as squares else - coilshape = 'square'; + sensshape = 'square'; end elseif ft_senstype(sens, 'meg') - coilshape = 'circle'; + sensshape = 'circle'; else - coilshape = 'point'; + sensshape = 'point'; end end -if isempty(coilsize) +if isempty(sensize) switch ft_senstype(sens) case 'neuromag306' - coilsize = 30; % FIXME this is only an estimate + sensize = 30; % FIXME this is only an estimate case 'neuromag122' - coilsize = 35; % FIXME this is only an estimate + sensize = 35; % FIXME this is only an estimate case 'ctf151' - coilsize = 15; % FIXME this is only an estimate + sensize = 15; % FIXME this is only an estimate case 'ctf275' - coilsize = 15; % FIXME this is only an estimate + sensize = 15; % FIXME this is only an estimate otherwise - coilsize = 10; + if strcmp(sensshape, 'sphere') + sensize = 4; % assuming spheres are used for intracranial electrodes, diameter is about 4mm + elseif strcmp(sensshape, 'point') + sensize = 30; + else + sensize = 10; + end end % convert from mm to the units of the sensor array - coilsize = coilsize/ft_scalingfactor(sens.unit, 'mm'); + sensize = sensize/ft_scalingfactor(sens.unit, 'mm'); +end + +% color management +if isempty(facecolor) % set default color depending on shape + if strcmp(sensshape, 'point') + facecolor = 'k'; + elseif strcmp(sensshape, 'circle') || strcmp(sensshape, 'square') + facecolor = 'none'; + elseif strcmp(sensshape, 'sphere') + facecolor = 'b'; + end +end +if ischar(facecolor) && exist([facecolor '.m'], 'file') + facecolor = eval(facecolor); +end +if ischar(edgecolor) && exist([edgecolor '.m'], 'file') + edgecolor = eval(edgecolor); end % select a subset of channels and coils to be plotted @@ -172,7 +255,7 @@ end if istrue(orientation) - if istrue(coil) + if istrue(individual) if isfield(sens, 'coilori') pos = sens.coilpos; ori = sens.coilori; @@ -201,29 +284,8 @@ end end -% determine the rotation-around-the-axis of each sensor -% only applicable for neuromag planar gradiometers -if ft_senstype(sens, 'neuromag') - [nchan, ncoil] = size(sens.tra); - chandir = nan(nchan,3); - for i=1:nchan - poscoil = find(sens.tra(i,:)>0); - negcoil = find(sens.tra(i,:)<0); - if numel(poscoil)==1 && numel(negcoil)==1 - % planar gradiometer - direction = sens.coilpos(poscoil,:)-sens.coilpos(negcoil,:); - direction = direction/norm(direction); - chandir(i,:) = direction; - elseif (numel([poscoil negcoil]))==1 - % magnetometer - elseif numel(poscoil)>1 || numel(negcoil)>1 - error('cannot work with balanced gradiometer definition') - end - end -end - -if istrue(coil) - % simply get the position of all coils or electrodes +if istrue(individual) + % simply get the position of all individual coils or electrodes if isfield(sens, 'coilpos') pos = sens.coilpos; elseif isfield(sens, 'elecpos') @@ -252,17 +314,70 @@ ori = []; end -end % if istrue(coil) +end % if istrue(individual) -switch coilshape +switch sensshape case 'point' - hs = plot3(pos(:,1), pos(:,2), pos(:,3), style, 'MarkerSize', 30, 'Color', edgecolor); + if ~isempty(style) + % the style can include the color and/or the shape of the marker + % check whether the marker shape is specified + possible = {'+', 'o', '*', '.', 'x', 'v', '^', '>', '<', 'square', 'diamond', 'pentagram', 'hexagram'}; + specified = false(size(possible)); + for i=1:numel(possible) + specified(i) = ~isempty(strfind(style, possible{i})); + end + if any(specified) + % the marker shape is specified in the style option + hs = plot3(pos(:,1), pos(:,2), pos(:,3), style, 'MarkerSize', sensize); + else + % the marker shape is not specified in the style option, use the marker option instead and assume that the style option represents the color + hs = plot3(pos(:,1), pos(:,2), pos(:,3), 'Marker', marker, 'MarkerSize', sensize, 'Color', style, 'Linestyle', 'none'); + end + else + % the style is not specified, use facecolor for the marker + hs = plot3(pos(:,1), pos(:,2), pos(:,3), 'Marker', marker, 'MarkerSize', sensize, 'Color', facecolor, 'Linestyle', 'none'); + end + case 'circle' - plotcoil(pos, ori, [], coilsize, coilshape, 'edgecolor', edgecolor, 'facecolor', facecolor, 'edgealpha', edgealpha, 'facealpha', facealpha); + plotcoil(pos, ori, [], sensize, sensshape, 'edgecolor', edgecolor, 'facecolor', facecolor, 'edgealpha', edgealpha, 'facealpha', facealpha); + case 'square' - plotcoil(pos, ori, chandir, coilsize, coilshape, 'edgecolor', edgecolor, 'facecolor', facecolor, 'edgealpha', edgealpha, 'facealpha', facealpha); + % determine the rotation-around-the-axis of each sensor + % only applicable for neuromag planar gradiometers + if ft_senstype(sens, 'neuromag') + [nchan, ncoil] = size(sens.tra); + chandir = nan(nchan,3); + for i=1:nchan + poscoil = find(sens.tra(i,:)>0); + negcoil = find(sens.tra(i,:)<0); + if numel(poscoil)==1 && numel(negcoil)==1 + % planar gradiometer + direction = sens.coilpos(poscoil,:)-sens.coilpos(negcoil,:); + direction = direction/norm(direction); + chandir(i,:) = direction; + elseif (numel([poscoil negcoil]))==1 + % magnetometer + elseif numel(poscoil)>1 || numel(negcoil)>1 + ft_error('cannot work with balanced gradiometer definition') + end + end + else + chandir = []; + end + + plotcoil(pos, ori, chandir, sensize, sensshape, 'edgecolor', edgecolor, 'facecolor', facecolor, 'edgealpha', edgealpha, 'facealpha', facealpha); + + case 'sphere' + [xsp, ysp, zsp] = sphere(100); + rsp = sensize/2; % convert coilsensize from diameter to radius + hold on + for i=1:size(pos,1) + hs = surf(rsp*xsp+pos(i,1), rsp*ysp+pos(i,2), rsp*zsp+pos(i,3)); + set(hs, 'EdgeColor', edgecolor, 'FaceColor', facecolor, 'EdgeAlpha', edgealpha, 'FaceAlpha', facealpha); + end + otherwise - error('incorrect coilshape'); + ft_error('incorrect shape'); end % switch if ~isempty(label) && ~any(strcmp(label, {'off', 'no'})) @@ -275,11 +390,22 @@ case {'number' 'numbers'} str = num2str(i); otherwise - error('unsupported value for option ''label'''); + ft_error('unsupported value for option ''label'''); end % switch - text(sens.chanpos(i,1), sens.chanpos(i,2), sens.chanpos(i,3), str); - end % for -end % if empty or off/no + if isfield(sens, 'chanori') + % shift the labels along the channel orientation, which is presumably orthogonal to the scalp + ori = sens.chanori(i,:); + else + % shift the labels away from the origin of the coordinate system + ori = sens.chanpos(i,:) / norm(sens.chanpos(i,:)); + end + % shift the label 5 mm + x = sens.chanpos(i,1) + 5 * ft_scalingfactor('mm', sens.unit) * ori(1); + y = sens.chanpos(i,2) + 5 * ft_scalingfactor('mm', sens.unit) * ori(2); + z = sens.chanpos(i,3) + 5 * ft_scalingfactor('mm', sens.unit) * ori(3); + text(x, y, z, str, 'color', fontcolor, 'fontunits', fontunits, 'fontsize', fontsize, 'fontname', fontname, 'fontweight', fontweight, 'horizontalalignment', 'center', 'verticalalignment', 'middle'); + end % for each channel +end % if label axis vis3d axis equal @@ -308,7 +434,7 @@ function plotcoil(coilpos, coilori, chandir, coilsize, coilshape, varargin) ncoil = size(coilpos,1); npos = size(pos,1); mesh.pos = nan(ncoil*npos,3); -mesh.poly = nan(ncoil,npos); +mesh.poly = nan(ncoil, npos); % determine the scaling of the coil as homogenous transformation matrix s = scale([coilsize coilsize coilsize]); @@ -365,9 +491,9 @@ function plotcoil(coilpos, coilori, chandir, coilsize, coilshape, varargin) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function [pos] = square pos = [ - 0.5 0.5 0 + 0.5 0.5 0 -0.5 0.5 0 -0.5 -0.5 0 - 0.5 -0.5 0 - 0.5 0.5 0 % this closes the square + 0.5 -0.5 0 + 0.5 0.5 0 % this closes the square ]; diff --git a/external/fieldtrip/plotting/ft_plot_slice.m b/external/fieldtrip/plotting/ft_plot_slice.m index fd0e1b34..fdbe1b55 100644 --- a/external/fieldtrip/plotting/ft_plot_slice.m +++ b/external/fieldtrip/plotting/ft_plot_slice.m @@ -1,9 +1,10 @@ function [h, T2] = ft_plot_slice(dat, varargin) -% FT_PLOT_SLICE cuts a 2-D slice from a 3-D volume and interpolates if needed +% FT_PLOT_SLICE plots a 2-D cut through a 3-D volume and interpolates if needed % % Use as % ft_plot_slice(dat, ...) +% or % ft_plot_slice(dat, mask, ...) % where dat and mask are equal-sized 3-D arrays. % @@ -20,21 +21,32 @@ % 'datmask' = 3D-matrix with the same size as the data matrix, serving as opacitymap % If the second input argument to the function contains a matrix, this % will be used as the mask +% 'maskstyle' = string, 'opacity' or 'colormix', defines the rendering +% 'background' = needed when maskstyle is 'colormix', 3D-matrix with +% the same size as the data matrix, serving as +% grayscale image that provides the background % 'opacitylim' = 1x2 vector specifying the limits for opacity masking % 'interpmethod' = string specifying the method for the interpolation, see INTERPN (default = 'nearest') % 'style' = string, 'flat' or '3D' % 'colormap' = string, see COLORMAP % 'clim' = 1x2 vector specifying the min and max for the colorscale % +% You can plot the slices from the volume together with an intersection of the slices +% with a triangulated surface mesh (e.g. a cortical sheet) using +% 'intersectmesh' = triangulated mesh, see FT_PREPARE_MESH +% 'intersectcolor' = string, color specification +% 'intersectlinestyle' = string, line specification +% 'intersectlinewidth' = number +% % See also FT_PLOT_ORTHO, FT_PLOT_MONTAGE, FT_SOURCEPLOT -% undocumented -% 'intersectmesh' = triangulated mesh through which the intersection of the plane will be plotted (e.g. cortical sheet) -% 'intersectcolor' = color for the intersection +% Undocumented options % 'plotmarker' = Nx3 matrix with points to be plotted as markers, e.g. dipole positions +% 'markersize' +% 'markercolor' % Copyrights (C) 2010-2014, Jan-Mathijs Schoffelen -% Copyrights (C) 2014, Robert Oostenveld and Jan-Mathijs Schoffelen +% Copyrights (C) 2014-2016, Robert Oostenveld and Jan-Mathijs Schoffelen % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -79,6 +91,8 @@ unit = ft_getopt(varargin, 'unit'); % the default will be determined further down resolution = ft_getopt(varargin, 'resolution'); % the default depends on the units and will be determined further down mask = ft_getopt(varargin, 'datmask'); +maskstyle = ft_getopt(varargin, 'maskstyle', 'opacity'); +background = ft_getopt(varargin, 'background'); opacitylim = ft_getopt(varargin, 'opacitylim'); interpmethod = ft_getopt(varargin, 'interpmethod', 'nearest'); cmap = ft_getopt(varargin, 'colormap'); @@ -142,7 +156,7 @@ if dointersect for k = 1:numel(mesh) if ~isfield(mesh{k}, 'pos') || ~isfield(mesh{k}, 'tri') - % error('the mesh should be a structure with pos and tri'); + % ft_error('the mesh should be a structure with pos and tri'); mesh{k}.pos = []; mesh{k}.tri = []; end @@ -153,7 +167,14 @@ domask = ~isempty(mask); if domask if ~isequal(size(dat), size(mask)) - error('the mask data should have the same dimensions as the functional data'); + ft_error('the mask data should have the same dimensions as the functional data'); + end +end + +dobackground = ~isempty(background); +if dobackground + if ~isequal(size(dat), size(background)) + error('the background data should have the same dimensions as the functional data'); end end @@ -279,10 +300,22 @@ Zi = Zi(sel1,sel2); end -if domask, +if domask Vmask = interpn(X, Y, Z, mask, Xi, Yi, Zi, interpmethod); end +if dobackground + Vback = interpn(X, Y, Z, background, Xi, Yi, Zi, interpmethod); + + % convert the background plane to a grayscale image + bmin = nanmin(background(:)); + bmax = nanmax(background(:)); + Vback = (Vback-bmin)./(bmax-bmin); + Vback(~isfinite(Vback)) = 0; + Vback = cat(3, Vback, Vback, Vback); + +end + interp_center_vc = [Xi(:) Yi(:) Zi(:)]; clear Xi Yi Zi interp_center_pc = ft_warp_apply(inv(T3), interp_center_vc); @@ -325,7 +358,7 @@ zlabel('z') end -if isempty(cmap), +if isempty(cmap) % treat as gray value: scale and convert to rgb if doscale dmin = min(dat(:)); @@ -333,7 +366,7 @@ V = (V-dmin)./(dmax-dmin); clear dmin dmax end - V(isnan(V)) = 0; + V(~isfinite(V)) = 0; % deal with clim for RGB data here, where the purpose is to increase the % contrast range, rather than shift the average grey value @@ -344,7 +377,6 @@ % convert into RGB values, e.g. for the plotting of anatomy V = cat(3, V, V, V); - end % get positions of the voxels in the interpolation plane in head coordinates @@ -352,30 +384,67 @@ Yh = reshape(interp_edge_hc(:,2), siz+1); Zh = reshape(interp_edge_hc(:,3), siz+1); -if isempty(h), - % create surface object - h = surface(Xh, Yh, Zh, V); - set(h, 'linestyle', 'none'); -else - % update the colordata in the surface object - set(h, 'Cdata', V); - set(h, 'Xdata', Xh); - set(h, 'Ydata', Yh); - set(h, 'Zdata', Zh); -end - -if domask, - if islogical(Vmask), Vmask = double(Vmask); end - set(h, 'FaceColor', 'texture'); - set(h, 'FaceAlpha', 'texturemap'); %flat - set(h, 'AlphaDataMapping', 'scaled'); - set(h, 'AlphaData', Vmask); - if ~isempty(opacitylim) - alim(opacitylim) +% do the actual plotting of the slice +if ~domask + % no masked slice to be plotted + if isempty(h) + % create surface object + h = surface(Xh, Yh, Zh, V); + set(h, 'linestyle', 'none'); + else + % update the colordata in the surface object + set(h, 'Cdata', V); + set(h, 'Xdata', Xh); + set(h, 'Ydata', Yh); + set(h, 'Zdata', Zh); + end +elseif domask + % what should be done depends on the maskstyle + switch maskstyle + case 'opacity' + if dobackground + warning('specifying maskstyle = ''opacity'' causes the supplied background image not to be used'); + end + if isempty(h) + % create surface object + h = surface(Xh, Yh, Zh, V); + set(h, 'linestyle', 'none'); + else + % update the colordata in the surface object + set(h, 'Cdata', V); + set(h, 'Xdata', Xh); + set(h, 'Ydata', Yh); + set(h, 'Zdata', Zh); + end + if islogical(Vmask), Vmask = double(Vmask); end + set(h, 'FaceColor', 'texture'); + set(h, 'FaceAlpha', 'texturemap'); %flat + set(h, 'AlphaDataMapping', 'scaled'); + set(h, 'AlphaData', Vmask); + if ~isempty(opacitylim) + alim(opacitylim) + end + + case 'colormix' + if isempty(cmap), error('using ''colormix'' as maskstyle requires an explicitly defined colormap'); end + V = bg_rgba2rgb(Vback,V,cmap,clim,Vmask,'rampup',opacitylim); + if isempty(h) + % create surface object + h = surface(Xh, Yh, Zh, V); + set(h, 'linestyle', 'none'); + else + % update the colordata in the surface object + set(h, 'Cdata', V); + set(h, 'Xdata', Xh); + set(h, 'Ydata', Yh); + set(h, 'Zdata', Zh); + end + otherwise + error('unsupported maskstyle'); end end - +% plot the intersection with a mesh if dointersect % determine three points on the plane inplane = eye(3) - (eye(3) * ori') * ori; @@ -387,7 +456,7 @@ [xmesh, ymesh, zmesh] = intersect_plane(mesh{k}.pos, mesh{k}.tri, v1, v2, v3); % draw each individual line segment of the intersection - if ~isempty(xmesh), + if ~isempty(xmesh) p = patch(xmesh', ymesh', zmesh', nan(1, size(xmesh,1))); if ~isempty(intersectcolor), set(p, 'EdgeColor', intersectcolor(k)); end if ~isempty(intersectlinewidth), set(p, 'LineWidth', intersectlinewidth); end diff --git a/external/fieldtrip/plotting/ft_plot_text.m b/external/fieldtrip/plotting/ft_plot_text.m index bf60994c..fc2f1870 100644 --- a/external/fieldtrip/plotting/ft_plot_text.m +++ b/external/fieldtrip/plotting/ft_plot_text.m @@ -7,11 +7,16 @@ % ft_plot_text(X, Y, str, ...) % % Optional arguments should come in key-value pairs and can include -% 'color' = -% 'fontsize' = +% 'fontcolor' = string, color specification (default = 'k') +% 'fontsize' = number, sets the size of the text (default = 10) +% 'fontunits' = % 'fontname' = +% 'fontweight' = % 'horizontalalignment' = -% 'tag' = string, the name this vector gets. All tags with the same name can be deleted in a figure, without deleting other parts of the figure. +% 'verticalalignment' = +% 'interpreter' = string, can be 'none', 'tex' or 'latex' (default = 'none') +% 'rotation' = +% 'tag' = string, the name assigned to the object. All tags with the same name can be deleted in a figure, without deleting other parts of the figure. % % It is possible to plot the object in a local pseudo-axis (c.f. subplot), which is specfied as follows % 'hpos' = horizontal position of the center of the local axes @@ -20,6 +25,14 @@ % 'height' = height of the local axes % 'hlim' = horizontal scaling limits within the local axes % 'vlim' = vertical scaling limits within the local axes +% +% Example +% figure +% ft_plot_vector(randn(1,10), rand(1,10), 'hpos', 1, 'vpos', 1, 'width', 0.2, 'height', 0.2, 'box', true) +% ft_plot_text(0, 0 , '+', 'hpos', 1, 'vpos', 1, 'width', 0.2, 'height', 0.2) +% axis([0 2 0 2]) +% +% See also FT_PLOT_VECTOR, FT_PLOT_MATRIX, FT_PLOT_LINE, FT_PLOT_BOX % Copyrights (C) 2009-2011, Robert Oostenveld % @@ -50,15 +63,23 @@ height = ft_getopt(varargin, 'height'); hlim = ft_getopt(varargin, 'hlim'); vlim = ft_getopt(varargin, 'vlim'); +tag = ft_getopt(varargin, 'tag', ''); +% these have to do with the font color = ft_getopt(varargin, 'color', 'k'); -fontsize = ft_getopt(varargin, 'fontsize'); -fontname = ft_getopt(varargin, 'fontname'); -fontunits = ft_getopt(varargin, 'fontunits'); +fontsize = ft_getopt(varargin, 'fontsize', get(0, 'defaulttextfontsize')); +fontname = ft_getopt(varargin, 'fontname', get(0, 'defaulttextfontname')); +fontweight = ft_getopt(varargin, 'fontweight', get(0, 'defaulttextfontweight')); +fontunits = ft_getopt(varargin, 'fontunits', get(0, 'defaulttextfontunits')); +% these also have to do with the font horizontalalignment = ft_getopt(varargin, 'horizontalalignment', 'center'); -rotation = ft_getopt(varargin, 'rotation', 0); verticalalignment = ft_getopt(varargin, 'verticalalignment', 'middle'); -tag = ft_getopt(varargin, 'tag', ''); -interpreter = ft_getopt(varargin, 'interpreter', 'tex'); +rotation = ft_getopt(varargin, 'rotation', 0); +interpreter = ft_getopt(varargin, 'interpreter', 'none'); + +% color management +if ischar(color) && exist([color '.m'], 'file') + color = eval(color); +end if isempty(hlim) && isempty(vlim) && isempty(hpos) && isempty(vpos) && isempty(height) && isempty(width) % no scaling is needed, the input X and Y are already fine @@ -66,48 +87,41 @@ else % use the full implementation - abc = axis; if isempty(hlim) - hlim = abc([1 2]); + ft_warning('use hlim/vlim when specifying local axes'); + hlim = get(gca, 'XLim'); end if isempty(vlim) - vlim = abc([3 4]); + ft_warning('use hlim/vlim when specifying local axes'); + vlim = get(gca, 'YLim'); end - if isempty(hpos); + if isempty(hpos) hpos = (hlim(1)+hlim(2))/2; end - if isempty(vpos); + if isempty(vpos) vpos = (vlim(1)+vlim(2))/2; end - if isempty(width), + if isempty(width) width = hlim(2)-hlim(1); end - if isempty(height), + if isempty(height) height = vlim(2)-vlim(1); end - - % first shift the horizontal axis to zero - X = X - (hlim(1)+hlim(2))/2; - % then scale to length 1 + + X = X - hlim(1); X = X ./ (hlim(2)-hlim(1)); - % then scale to the new width X = X .* width; - % then shift to the new horizontal position - X = X + hpos; + X = X + hpos - width/2; - % first shift the vertical axis to zero - Y = Y - (vlim(1)+vlim(2))/2; - % then scale to length 1 + Y = Y - vlim(1); Y = Y ./ (vlim(2)-vlim(1)); - % then scale to the new width Y = Y .* height; - % then shift to the new vertical position - Y = Y + vpos; + Y = Y + vpos - height/2; end % shortcut @@ -115,19 +129,16 @@ X = double(X); Y = double(Y); -h = text(X, Y, str); -set(h, 'horizontalalignment', horizontalalignment); -set(h, 'color', color); -set(h, 'rotation', rotation); -set(h, 'verticalalignment',verticalalignment); -if ~isempty(fontunits), set(h, 'fontunits', fontunits); end -if ~isempty(fontsize), set(h, 'fontsize', fontsize); end -if ~isempty(fontname), set(h, 'fontname', fontname); end +h = text(X, Y, str, 'color', color, 'fontunits', fontunits, 'fontsize', fontsize, 'fontname', fontname, 'fontweight', fontweight); +if ~isempty(horizontalalignment), set(h, 'horizontalalignment', horizontalalignment); end +if ~isempty(verticalalignment), set(h, 'verticalalignment', verticalalignment); end +if ~isempty(rotation), set(h, 'rotation', rotation); end + set(h, 'tag', tag); set(h, 'interpreter', interpreter); % the (optional) output is the handle -if nargout == 1; +if nargout == 1 varargout{1} = h; end diff --git a/external/fieldtrip/plotting/ft_plot_topo.m b/external/fieldtrip/plotting/ft_plot_topo.m index b2eec450..4db9974d 100644 --- a/external/fieldtrip/plotting/ft_plot_topo.m +++ b/external/fieldtrip/plotting/ft_plot_topo.m @@ -14,11 +14,11 @@ % 'isolines' = vector with values for isocontour lines (default = []) % 'interplim' = string, 'electrodes' or 'mask' (default = 'electrodes') % 'interpmethod' = string, 'nearest', 'linear', 'natural', 'cubic' or 'v4' (default = 'v4') -% 'style' = can be 'surf', 'iso', 'isofill', 'surfiso', 'imsat', 'imsatiso' +% 'style' = can be 'surf', 'iso', 'isofill', 'surfiso', 'imsat', 'imsatiso', 'colormix' % 'clim' = [min max], limits for color scaling % 'shading' = string, 'none', 'flat', 'interp' (default = 'flat') % 'parent' = handle which is set as the parent for all plots -% 'tag' = string, the name this vector gets. All tags with the same name can be deleted in a figure, without deleting other parts of the figure. +% 'tag' = string, the name assigned to the object. All tags with the same name can be deleted in a figure, without deleting other parts of the figure. % % It is possible to plot the object in a local pseudo-axis (c.f. subplot), which is specfied as follows % 'hpos' = horizontal position of the lower left corner of the local axes @@ -27,6 +27,8 @@ % 'height' = height of the local axes % 'hlim' = horizontal scaling limits within the local axes % 'vlim' = vertical scaling limits within the local axes +% +% See also FT_PLOT_TOPO3D, FT_TOPOPLOTER, FT_TOPOPLOTTFR % Copyrights (C) 2009-2013, Giovanni Piantoni, Robert Oostenveld % @@ -62,7 +64,7 @@ shading = ft_getopt(varargin, 'shading', 'flat'); interplim = ft_getopt(varargin, 'interplim', 'electrodes'); interpmethod = ft_getopt(varargin, 'interpmethod', 'v4'); -style = ft_getopt(varargin, 'style', 'surfiso'); % can be 'surf', 'iso', 'isofill', 'surfiso', 'imsat', 'imsatiso' +style = ft_getopt(varargin, 'style', 'surfiso'); % can be 'surf', 'iso', 'isofill', 'surfiso', 'imsat', 'imsatiso', 'colormix' tag = ft_getopt(varargin, 'tag', ''); isolines = ft_getopt(varargin, 'isolines'); datmask = ft_getopt(varargin, 'datmask'); @@ -73,7 +75,7 @@ % check for nans in the data, they can be still left incase people want to mask non channels. if any(isnan(dat)) - warning('the data passed to ft_plot_topo contains NaNs, these channels will be removed from the data to prevent interpolation errors, but will remain in the mask'); + ft_warning('the data passed to ft_plot_topo contains NaNs, these channels will be removed from the data to prevent interpolation errors, but will remain in the mask'); flagNaN = true; else flagNaN = false; @@ -90,7 +92,7 @@ % so we need to compute the right scaling factor % create a matrix with all coordinates % from positions, mask, and outline -allCoords = [chanX chanY]; +allCoords = [chanX(:) chanY(:)]; if ~isempty(mask) for k = 1:numel(mask) allCoords = [allCoords; mask{k}]; @@ -128,7 +130,7 @@ chanX = chanX(:) * xScaling + hpos; chanY = chanY(:) * yScaling + vpos; -if strcmp(interplim, 'electrodes'), +if strcmp(interplim, 'electrodes') hlim = [min(chanX) max(chanX)]; vlim = [min(chanY) max(chanY)]; elseif (strcmp(interplim, 'mask') || strcmp(interplim, 'mask_individual')) && ~isempty(mask), @@ -168,7 +170,7 @@ yi = linspace(vlim(1), vlim(2), gridscale); % y-axis for interpolation (row vector) [Xi, Yi] = meshgrid(xi', yi); if ~isempty(newpoints) && (hpos == 0 || vpos == 0) - warning('Some points fall outside the outline, please consider using another layout') + ft_warning('Some points fall outside the outline, please consider using another layout') % FIXME: I am not sure about it, to be tested! % tmp = [mask{1};newpoints]; % indx = convhull(tmp(:, 1), tmp(:, 2)); @@ -243,7 +245,7 @@ Zi(~maskimage) = NaN; end -% The topography should be plotted prior to the isolines to ensure that it is exported correctly, see http://bugzilla.fcdonders.nl/show_bug.cgi?id=2496 +% The topography should be plotted prior to the isolines to ensure that it is exported correctly, see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2496 if strcmp(style, 'surf') || strcmp(style, 'surfiso') deltax = xi(2)-xi(1); % length of grid entry @@ -267,44 +269,39 @@ % set mask and cdat, and check for clim if isempty(clim) - error('clim is required for style = ''imsat'' or style = ''imsatiso''') + ft_error('clim is required for style = ''imsat'' or style = ''imsatiso''') end - satmask = maskimage; - cdat = Zi; - % below code is shared with ft_plot_matrix + cmap = get(gcf, 'colormap'); + rgbcdat = cdat2rgb(Zi, cmap, clim, maskimage); - % This approach changes the color of pixels to white, regardless of colormap, without using opengl - % It does by converting by: - % 1) convert the to-be-plotted data to their respective rgb color values (determined by colormap) - % 2) convert these rgb color values to hsv values, hue-saturation-value - % 3) for to-be-masked-pixels, set saturation to 0 and value to 1 (hue is irrelevant when they are) - % 4) convert the hsv values back to rgb values - % 5) plot these values + h = imagesc(xi, yi, rgbcdat, clim); + set(h, 'tag', tag); + +elseif strcmp(style, 'colormix') + % Plot the surface in an alternate style (using imagesc and saturation masking) so that it can be nicely saved to a vectorized format + + % set mask and cdat, and check for clim + if isempty(clim) + error('clim is required for style = ''colormix''') + end - % enforce mask properties (satmask is 0 when a pixel needs to be masked, 1 if otherwise) - satmask = round(double(satmask)); % enforce binary white-masking, the hsv approach cannot be used for 'white-shading' - satmask(isnan(cdat)) = false; % make sure NaNs are plotted as white pixels, even when using non-integer mask values + if ~isempty(datmask) + % use maskimagetmp in combination with maskimage, maskimagetmp is + % scaled between 0 and 1 + maskimagetmp = maskimagetmp./max(maskimagetmp(:)); + Zmask = double(maskimage); + Zmask(Zmask>0) = maskimagetmp(Zmask>0); + else + Zmask = double(maskimage); + end - % do 1, by converting the data-values to zero-based indices of the colormap - ncolors = size(get(gcf,'colormap'),1); % determines range of index, if a figure has been created by the caller function, gcf changes nothing, if not, a figure is created (which the below would do otherwise) - indcdat = (cdat + -clim(1)) * (ncolors / (-clim(1) + clim(2))); % transform cdat-values to have a 0-(ncolors-1) range (range depends on colormap used, and thus also on clim) - rgbcdat = ind2rgb(uint8(floor(indcdat)), colormap); - % do 2 - hsvcdat = rgb2hsv(rgbcdat); - % do 3 - hsvs = hsvcdat(:,:,2); - hsvs(~satmask) = 0; - hsvv = hsvcdat(:,:,3); - hsvv(~satmask) = 1; - hsvcdat(:,:,2) = hsvs; - hsvcdat(:,:,3) = hsvv; - % do 4 - rgbcdat = hsv2rgb(hsvcdat); - % do 5 - h = imagesc(xi, yi, rgbcdat,clim); + cmap = get(gcf, 'colormap'); + rgbcdat = bg_rgba2rgb([1 1 1], Zi, cmap, clim, Zmask, 'rampup', [0 1]); + + h = imagesc(xi, yi, rgbcdat, clim); set(h,'tag',tag); - + end % Plot the outline of the head, ears and nose diff --git a/external/fieldtrip/plotting/ft_plot_topo3d.m b/external/fieldtrip/plotting/ft_plot_topo3d.m index 68d39787..da4f387e 100644 --- a/external/fieldtrip/plotting/ft_plot_topo3d.m +++ b/external/fieldtrip/plotting/ft_plot_topo3d.m @@ -14,7 +14,7 @@ function ft_plot_topo3d(pos, val, varargin) % 'facealpha' = scalar, between 0 and 1 (default = 1) % 'refine' = scalar, number of refinement steps for the triangulation, to get a smoother interpolation (default = 0) % -% See also FT_PLOT_TOPO +% See also FT_PLOT_TOPO, FT_TOPOPLOTER, FT_TOPOPLOTTFR % Copyright (C) 2009-2015, Robert Oostenveld % @@ -101,7 +101,7 @@ function ft_plot_topo3d(pos, val, varargin) end otherwise - error('unsupported topostyle'); + ft_error('unsupported topostyle'); end % switch contourstyle end % plot the interpolated topography @@ -118,7 +118,7 @@ function ft_plot_topo3d(pos, val, varargin) maxval = ceil(maxval/scale)*scale; isolines = minval:scale:maxval; else - error('unsupported isolines'); + ft_error('unsupported isolines'); end end % convert string to vector @@ -212,7 +212,7 @@ function ft_plot_topo3d(pos, val, varargin) end otherwise - error('unsupported contourstyle'); + ft_error('unsupported contourstyle'); end % switch contourstyle end % plot the contours diff --git a/external/fieldtrip/plotting/ft_plot_vector.m b/external/fieldtrip/plotting/ft_plot_vector.m index 7cdf61f1..6991b8a2 100644 --- a/external/fieldtrip/plotting/ft_plot_vector.m +++ b/external/fieldtrip/plotting/ft_plot_vector.m @@ -10,17 +10,15 @@ % % Optional arguments should come in key-value pairs and can include % 'axis' = draw the local axis, can be 'yes', 'no', 'xy', 'x' or 'y' -% 'box' = draw a box around the local axes, can be 'yes' or 'no' % 'highlight' = a logical vector of size Y, where 1 means that the corresponding values in Y are highlighted (according to the highlightstyle) % 'highlightstyle' = can be 'box', 'thickness', 'saturation', 'difference' (default='box') -% 'tag' = string, the name this vector gets. All tags with the same name can be deleted in a figure, without deleting other parts of the figure. % 'color' = see MATLAB standard line properties and see below % 'linewidth' = see MATLAB standard line properties % 'markersize' = see MATLAB standard line properties % 'markerfacecolor' = see MATLAB standard line properties % 'style' = see MATLAB standard line properties -% 'label' = see MATLAB standard line properties -% 'fontsize' = see MATLAB standard line properties +% 'tag' = string, the name assigned to the object. All tags with the same name can be deleted in a figure, without deleting other parts of the figure. +% 'box' = draw a box around the local axes, can be 'yes' or 'no' % % The line color can be specified in a variety of ways % - as a string with one character per line that you want to plot. Supported colors are teh same as in PLOT, i.e. 'bgrcmykw'. @@ -35,6 +33,14 @@ % 'hlim' = horizontal scaling limits within the local axes % 'vlim' = vertical scaling limits within the local axes % +% When using a local pseudo-axis, you can plot a label next to the data +% 'label' = string, label to be plotted at the upper left corner +% 'fontcolor' = string, color specification (default = 'k') +% 'fontsize' = number, sets the size of the text (default = 10) +% 'fontunits' = +% 'fontname' = +% 'fontweight' = +% % Example 1 % subplot(2,1,1); ft_plot_vector(1:100, randn(1,100), 'color', 'r') % subplot(2,1,2); ft_plot_vector(1:100, randn(1,100), 'color', rand(100,3)) @@ -110,7 +116,6 @@ vlim = ft_getopt(varargin, 'vlim', 'maxmin'); style = ft_getopt(varargin, 'style', '-'); label = ft_getopt(varargin, 'label'); -fontsize = ft_getopt(varargin, 'fontsize'); axis = ft_getopt(varargin, 'axis', false); box = ft_getopt(varargin, 'box', false); color = ft_getopt(varargin, 'color'); @@ -121,6 +126,12 @@ markerfacecolor = ft_getopt(varargin, 'markerfacecolor', 'none'); tag = ft_getopt(varargin, 'tag', ''); parent = ft_getopt(varargin, 'parent', []); +% these have to do with the font of the label +fontcolor = ft_getopt(varargin, 'fontcolor', 'k'); % default is black +fontsize = ft_getopt(varargin, 'fontsize', get(0, 'defaulttextfontsize')); +fontname = ft_getopt(varargin, 'fontname', get(0, 'defaulttextfontname')); +fontweight = ft_getopt(varargin, 'fontweight', get(0, 'defaulttextfontweight')); +fontunits = ft_getopt(varargin, 'fontunits', get(0, 'defaulttextfontunits')); % if any(size(vdat)==1) % % ensure that it is a column vector @@ -153,13 +164,13 @@ end if strcmp(highlightstyle, 'difference') && isempty(highlight) - warning('highlight is empty, highlighting the whole time interval'); + ft_warning('highlight is empty, highlighting the whole time interval'); highlight = ones(size(hdat)); end if ~isempty(highlight) if numel(highlight)~=npos - error('the length of the highlight vector should correspond to the length of the data'); + ft_error('the length of the highlight vector should correspond to the length of the data'); else % make sure the vector points in the same direction as the data highlight = reshape(highlight, size(hdat)); @@ -190,7 +201,7 @@ hlim = max(abs(hdat)); hlim = [-hlim hlim]; otherwise - error('unsupported option for hlim') + ft_error('unsupported option for hlim') end % switch end % if ischar @@ -202,7 +213,7 @@ vlim = max(abs(vdat(:))); vlim = [-vlim vlim]; otherwise - error('unsupported option for vlim') + ft_error('unsupported option for vlim') end % switch end % if ischar @@ -236,10 +247,10 @@ if any(hlim) ~= 0 hdat = hdat - (hlim(1)+hlim(2))/2; % then scale to length 1 - if hlim(2)-hlim(1)~=0 + if (hlim(2)-hlim(1))~=0 hdat = hdat ./ (hlim(2)-hlim(1)); else - hdat = hdat /hlim(1); + hdat = hdat / hlim(1); end % then scale to the new width hdat = hdat .* width; @@ -261,7 +272,7 @@ if ~isempty(highlight) && ~islogical(highlight) if ~all(highlight==0 | highlight==1) % only warn if really different from 0/1 - warning('converting mask to logical values') + ft_warning('converting mask to logical values') end highlight=logical(highlight); end @@ -338,7 +349,7 @@ case 'difference' if nline~=2 - error('this only works if exactly two lines are plotted'); + ft_error('this only works if exactly two lines are plotted'); end hdatbeg = [hdat(:,1) (hdat(:,1:end-1) + hdat(:,2:end))/2 ]; hdatend = [ (hdat(:,1:end-1) + hdat(:,2:end))/2 hdat(:,end)]; @@ -396,7 +407,7 @@ end end else - warning('do not know how to plot the lines in the appropriate color'); + ft_warning('do not know how to plot the lines in the appropriate color'); h = []; end if ~isempty(parent) @@ -410,43 +421,20 @@ boxposition(2) = hpos + width/2; boxposition(3) = vpos - height/2; boxposition(4) = vpos + height/2; - h = text(boxposition(1), boxposition(4), label); - if ~isempty(fontsize) - set(h, 'Fontsize', fontsize); - end - + h = text(boxposition(1), boxposition(4), label, 'color', fontcolor, 'fontunits', fontunits, 'fontsize', fontsize, 'fontname', fontname, 'fontweight', fontweight); if ~isempty(parent) set(h, 'Parent', parent); end end if box + boxposition = zeros(1,4); % this plots a box around the original hpos/vpos with appropriate width/height - x1 = hpos - width/2; - x2 = hpos + width/2; - y1 = vpos - height/2; - y2 = vpos + height/2; - - X = [x1 x2 x2 x1 x1]; - Y = [y1 y1 y2 y2 y1]; - h = line(X, Y); - set(h, 'color', 'k'); - - % this plots a box around the original hpos/vpos with appropriate width/height - % boxposition = zeros(1,4); - % boxposition(1) = hpos - width/2; - % boxposition(2) = hpos + width/2; - % boxposition(3) = vpos - height/2; - % boxposition(4) = vpos + height/2; - % ft_plot_box(boxposition, 'facecolor', 'none', 'edgecolor', 'k'); - - % this plots a box around the complete data - % boxposition = zeros(1,4); - % boxposition(1) = hlim(1); - % boxposition(2) = hlim(2); - % boxposition(3) = vlim(1); - % boxposition(4) = vlim(2); - % ft_plot_box(boxposition, 'hpos', hpos, 'vpos', vpos, 'width', width, 'height', height, 'hlim', hlim, 'vlim', vlim); + boxposition(1) = hpos - width/2; + boxposition(2) = hpos + width/2; + boxposition(3) = vpos - height/2; + boxposition(4) = vpos + height/2; + ft_plot_box(boxposition); end if ~isempty(axis) && ~strcmp(axis, 'no') @@ -461,7 +449,7 @@ xaxis = false; yaxis = true; otherwise - error('invalid specification of the "axis" option') + ft_error('invalid specification of the "axis" option') end if xaxis @@ -491,7 +479,7 @@ end % the (optional) output is the handle -if nargout == 1; +if nargout == 1 varargout{1} = h; end diff --git a/external/fieldtrip/plotting/ft_plot_vol.m b/external/fieldtrip/plotting/ft_plot_vol.m index 728bfff8..de2e65a7 100644 --- a/external/fieldtrip/plotting/ft_plot_vol.m +++ b/external/fieldtrip/plotting/ft_plot_vol.m @@ -7,8 +7,8 @@ function ft_plot_vol(headmodel, varargin) % hs = ft_plot_vol(headmodel, varargin) % % Optional arguments should come in key-value pairs and can include -% 'facecolor' = [r g b] values or string, for example 'brain', 'cortex', 'skin', 'black', 'red', 'r', or an Nx1 array where N is the number of faces -% 'vertexcolor' = [r g b] values or string, for example 'brain', 'cortex', 'skin', 'black', 'red', 'r', or an Nx1 array where N is the number of vertices +% 'facecolor' = [r g b] values or string, for example 'brain', 'cortex', 'skin', 'black', 'red', 'r', or an Nx3 or Nx1 array where N is the number of faces +% 'vertexcolor' = [r g b] values or string, for example 'brain', 'cortex', 'skin', 'black', 'red', 'r', or an Nx3 or Nx1 array where N is the number of vertices % 'edgecolor' = [r g b] values or string, for example 'brain', 'cortex', 'skin', 'black', 'red', 'r' % 'faceindex' = true or false % 'vertexindex' = true or false @@ -123,13 +123,13 @@ function ft_plot_vol(headmodel, varargin) bnd = []; case {'infinite' 'infinite_monopole' 'infinite_currentdipole' 'infinite_magneticdipole'} - warning('there is nothing to plot for an infinite volume conductor') + ft_warning('there is nothing to plot for an infinite volume conductor') % there is no boundary to be displayed bnd = []; otherwise - error('unsupported voltype') + ft_error('unsupported voltype') end % all models except for the spherical ones diff --git a/external/fieldtrip/plotting/ft_select_box.m b/external/fieldtrip/plotting/ft_select_box.m index 7a355776..0f755589 100644 --- a/external/fieldtrip/plotting/ft_select_box.m +++ b/external/fieldtrip/plotting/ft_select_box.m @@ -12,6 +12,8 @@ % Optional input arguments should come in key-value pairs and can include % 'multiple' = true/false, make multiple selections by dragging, clicking % in one will finalize the selection (default = false) +% +% See also FT_SELECT_CHANNEL, FT_SELECT_POINT, FT_SELECT_POINT3D, FT_SELECT_RANGE, FT_SELECT_VOXEL % Copyright (C) 2006, Robert Oostenveld % @@ -37,7 +39,7 @@ multiple = ft_getopt(varargin, 'multiple', false); if istrue(multiple) - error('not yet implemented'); + ft_error('not yet implemented'); else k = waitforbuttonpress; point1 = get(gca,'CurrentPoint'); % button down detected diff --git a/external/fieldtrip/plotting/ft_select_channel.m b/external/fieldtrip/plotting/ft_select_channel.m index 381b6c55..13517856 100644 --- a/external/fieldtrip/plotting/ft_select_channel.m +++ b/external/fieldtrip/plotting/ft_select_channel.m @@ -15,9 +15,13 @@ function ft_select_channel(handle, eventdata, varargin) % You can pass additional arguments to the callback function in a cell-array % like {@function_handle,arg1,arg2} % -% Example +% Example 1 % % create a figure -% lay = ft_prepare_layout([]) +% figure +% cfg = []; +% cfg.channel = {'chan1', 'chan2', 'chan3', 'chan4'}; +% cfg.layout = 'ordered'; +% lay = ft_prepare_layout(cfg); % ft_plot_lay(lay) % % % add the required guidata @@ -35,9 +39,39 @@ function ft_select_channel(handle, eventdata, varargin) % set(gcf, 'WindowButtonUpFcn', {@ft_select_channel, 'multiple', true, 'callback', @disp, 'event', 'WindowButtonDownFcn'}) % set(gcf, 'WindowButtonMotionFcn', {@ft_select_channel, 'multiple', true, 'callback', @disp, 'event', 'WindowButtonDownFcn'}) % +% Example 2 (executed from within a subplot +% % create a figure +% figure +% subplot(2,2,1) +% cfg = []; +% cfg.channel = {'chan1', 'chan2', 'chan3', 'chan4'}; +% cfg.layout = 'ordered'; +% lay = ft_prepare_layout(cfg); +% ft_plot_lay(lay) +% +% % add the channel information to guidata under identifier linked to this axis +% ident = ['axh' num2str(round(sum(clock.*1e6)))]; % unique identifier for this axis +% set(gca,'tag',ident); +% info = guidata(gcf); +% info.(ident).x = lay.pos(:, 1); +% info.(ident).y = lay.pos(:, 2); +% info.(ident).label = lay.label; +% guidata(gcf, info) +% +% % add this function as the callback to make a single selection +% set(gcf, 'WindowButtonDownFcn', {@ft_select_channel, 'callback', @disp}) +% +% % or to make multiple selections +% set(gcf, 'WindowButtonDownFcn', {@ft_select_channel, 'multiple', true, 'callback', @disp, 'event', 'WindowButtonDownFcn'}) +% set(gcf, 'WindowButtonUpFcn', {@ft_select_channel, 'multiple', true, 'callback', @disp, 'event', 'WindowButtonDownFcn'}) +% set(gcf, 'WindowButtonMotionFcn', {@ft_select_channel, 'multiple', true, 'callback', @disp, 'event', 'WindowButtonDownFcn'}) +% +% % Subsequently you can click in the figure and you'll see that the disp % function is executed as callback and that it displays the selected % channels. +% +% See also FT_SELECT_BOX, FT_SELECT_POINT, FT_SELECT_POINT3D, FT_SELECT_RANGE, FT_SELECT_VOXEL % Copyright (C) 2009, Robert Oostenveld % @@ -80,11 +114,24 @@ function ft_select_channel(handle, eventdata, varargin) % SUBFUNCTION to assist in the selection of a single channel %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function select_channel_single(pos, callback) - -info = guidata(gcf); -x = info.x; -y = info.y; -label = info.label; +% If this function is called from a plotting function that supports interactive subplots, +% then the current axis, which was used for selection, was given a tag that starts with 'axh' followed by a unique ID. +% If so, then the data (e.g. channel info) that should be used is contained in a subfield of the info (guidata) +% structure, with field name being the 'tag' in question. +% If no such tag is found, then the simple situation is assumed, where the data is contained in the 'root' field +tag = get(gca,'tag'); +% in case subplots were used +if strncmp(tag,'axh',3) + info = guidata(gcf); + x = info.(tag).x(:); + y = info.(tag).y(:); + label = info.(tag).label(:); +else % no subplots were used + info = guidata(gcf); + x = info.x(:); + y = info.y(:); + label = info.label(:); +end % compute a tolerance measure distance = sqrt(abs(sum([x y]'.*[x y]',1))); @@ -125,11 +172,24 @@ function select_channel_single(pos, callback) % SUBFUNCTION to assist in the selection of multiple channels %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function select_channel_multiple(callback,range,cmenulab) % last input is context menu label, see ft_select_range - -info = guidata(gcf); -x = info.x(:); -y = info.y(:); -label = info.label(:); +% If this function is called from a plotting function that supports interactive subplots, +% then the current axis, which was used for selection, was given a tag that starts with 'axh' followed by a unique ID. +% If so, then the data (e.g. channel info) that should be used is contained in a subfield of the info (guidata) +% structure, with field name being the 'tag' in question. +% If no such tag is found, then the simple situation is assumed, where the data is contained in the 'root' field +tag = get(gca,'tag'); +% in case subplots were used +if strncmp(tag,'axh',3) + info = guidata(gcf); + x = info.(tag).x(:); + y = info.(tag).y(:); + label = info.(tag).label(:); +else % no subplots were used + info = guidata(gcf); + x = info.x(:); + y = info.y(:); + label = info.label(:); +end % determine which channels ly in the selected range select = false(size(label)); diff --git a/external/fieldtrip/plotting/ft_select_point.m b/external/fieldtrip/plotting/ft_select_point.m index b2ac228c..7f0bf606 100644 --- a/external/fieldtrip/plotting/ft_select_point.m +++ b/external/fieldtrip/plotting/ft_select_point.m @@ -16,6 +16,8 @@ % figure % plot(pos(:,1), pos(:,2), '.') % ft_select_point(pos) +% +% See also FT_SELECT_BOX, FT_SELECT_CHANNEL, FT_SELECT_POINT3D, FT_SELECT_RANGE, FT_SELECT_VOXEL % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. diff --git a/external/fieldtrip/plotting/ft_select_point3d.m b/external/fieldtrip/plotting/ft_select_point3d.m index aa705467..a0eab2ef 100644 --- a/external/fieldtrip/plotting/ft_select_point3d.m +++ b/external/fieldtrip/plotting/ft_select_point3d.m @@ -21,6 +21,8 @@ % ft_plot_mesh(bnd) % camlight % ... do something here +% +% See also FT_SELECT_BOX, FT_SELECT_CHANNEL, FT_SELECT_POINT, FT_SELECT_RANGE, FT_SELECT_VOXEL % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -80,7 +82,7 @@ end if length(h)>1 - warning('using the first patch object in the figure'); + ft_warning('using the first patch object in the figure'); h = h(1); end diff --git a/external/fieldtrip/plotting/ft_select_range.m b/external/fieldtrip/plotting/ft_select_range.m index fe632e68..78f3d253 100644 --- a/external/fieldtrip/plotting/ft_select_range.m +++ b/external/fieldtrip/plotting/ft_select_range.m @@ -4,15 +4,15 @@ function ft_select_range(handle, eventdata, varargin) % in a figure. It allows the user to select a horizontal or a vertical % range, or one or multiple boxes. % -% The callback function (and it's arguments) specified in callback is called -% on a left-click inside a selection, or using the right-click context-menu. +% The callback function (and it's arguments) specified in callback is called +% on a left-click inside a selection, or using the right-click context-menu. % The callback function will have as its first-to-last input argument the range of % all selections. The last input argument is either empty, or, when using the context % menu, a label of the item clicked. % Context menus are shown as the labels presented in the input. When activated, % the callback function is called, with the last input argument being the label of % the selection option. -% +% % Input arguments: % 'event' = string, event used as hook. % 'callback' = function handle or cell-array containing function handle and additional input arguments @@ -41,6 +41,8 @@ function ft_select_range(handle, eventdata, varargin) % set(gcf, 'WindowButtonDownFcn', {@ft_select_range, 'event', 'WindowButtonDownFcn', 'multiple', false, 'xrange', false, 'yrange', false, 'callback', @disp}); % set(gcf, 'WindowButtonMotionFcn', {@ft_select_range, 'event', 'WindowButtonMotionFcn', 'multiple', false, 'xrange', false, 'yrange', false, 'callback', @disp}); % set(gcf, 'WindowButtonUpFcn', {@ft_select_range, 'event', 'WindowButtonUpFcn', 'multiple', false, 'xrange', false, 'yrange', false, 'callback', @disp}); +% +% See also FT_SELECT_BOX, FT_SELECT_CHANNEL, FT_SELECT_POINT, FT_SELECT_POINT3D, FT_SELECT_VOXEL % Copyright (C) 2009-2012, Robert Oostenveld % @@ -79,16 +81,16 @@ function ft_select_range(handle, eventdata, varargin) % get the figure handle, dependent on MATLAB version if ft_platform_supports('graphics_objects') - while ~isa(handle, 'matlab.ui.Figure') + while ~isa(handle, 'matlab.ui.Figure') handle = p; p = get(handle, 'parent'); - end + end else - p = handle; - while ~isequal(p, 0) - handle = p; - p = get(handle, 'parent'); - end + p = handle; + while ~isequal(p, 0) + handle = p; + p = get(handle, 'parent'); + end end if ishandle(handle) @@ -105,22 +107,21 @@ function ft_select_range(handle, eventdata, varargin) p = get(gca, 'CurrentPoint'); p = p(1,1:2); -abc = axis; -xLim = abc(1:2); -yLim = abc(3:4); +xLim = get(gca, 'XLim'); +yLim = get(gca, 'YLim'); % limit cursor coordinates -if p(1)xLim(2), p(1)=xLim(2); end; -if p(2)yLim(2), p(2)=yLim(2); end; +if p(1)xLim(2), p(1)=xLim(2); end +if p(2)yLim(2), p(2)=yLim(2); end % determine whether the user is currently making a selection selecting = numel(userData.range)>0 && any(isnan(userData.range(end,:))); pointonly = ~xrange && ~yrange; if pointonly && multiple - warning('multiple selections are not possible for a point'); + ft_warning('multiple selections are not possible for a point'); multiple = false; end @@ -198,7 +199,7 @@ case lower('WindowButtonDownFcn') case lower('WindowButtonUpFcn') switch lastmousebttn case 'normal' % left click - + if selecting % select the other corner of the box userData.range(end,2) = p(1); @@ -294,7 +295,7 @@ case lower('WindowButtonMotionFcn') otherwise - error('unexpected event "%s"', event); + ft_error('unexpected event "%s"', event); end % switch event @@ -388,7 +389,3 @@ function evalcontextcallback(hcmenuopt, eventdata, varargin) funhandle = varargin{1}; feval(funhandle, val, cmenulab); end - - - - diff --git a/external/fieldtrip/plotting/ft_select_voxel.m b/external/fieldtrip/plotting/ft_select_voxel.m index 344a5a29..2aeb826d 100644 --- a/external/fieldtrip/plotting/ft_select_voxel.m +++ b/external/fieldtrip/plotting/ft_select_voxel.m @@ -30,6 +30,8 @@ function ft_select_voxel(handle, eventdata, varargin) % Subsequently you can click in the figure and you'll see that the disp % function is executed as callback and that it displays the selected % voxel. +% +% See also FT_SELECT_BOX, FT_SELECT_CHANNEL, FT_SELECT_POINT, FT_SELECT_POINT3D, FT_SELECT_RANGE % Copyright (C) 2010, Robert Oostenveld % diff --git a/external/fieldtrip/plotting/private/bg_rgba2rgb.m b/external/fieldtrip/plotting/private/bg_rgba2rgb.m new file mode 100644 index 00000000..8624e8dc --- /dev/null +++ b/external/fieldtrip/plotting/private/bg_rgba2rgb.m @@ -0,0 +1,162 @@ +function [rgb] = bg_rgba2rgb(bg, rgba, varargin) + +% BG_RGBA2RGB overlays a transparency masked colored image on a colored background, +% and represents the result as an RGB matrix. +% +% Use as: +% rgb = bg_rgba2rgb(bg, rgba) +% +% or +% rgb = bg_rgba2rgb(bg, rgba, cmap, clim, alpha, amap, alim); +% +% When 2 input arguments are supplied: +% bg = Nx3 matrix of background rgb-coded color-values, or MxNx3 +% rgba = Nx4 matrix of rgb + alpha values, or MxNx4 +% +% When 7 input arguments are supplied: +% bg = Nx3 matrix, Nx1 vector, 1x3 vector, MxN, or MxNx3. +% rgba = Nx1 vector with 'functional values', or MxN. +% cmap = Mx3 colormap, or MATLAB-supported name of colormap +% clim = 1x2 vector denoting the color limits +% alpha = Nx1 vector with 'alpha values', or MxN +% amap = Mx1 alphamap, or MATLAB -supported name of alphamap ('rampup/down', 'vup/down') +% alim = 1x2 vector denoting the opacity limits + +if numel(varargin)==0 + siz1 = size(bg); + siz2 = size(rgba); + assert(isequal(siz1(1:end-1),siz2(1:end-1)), 'number of data points should be the same'); + assert(siz1(end)==3 && siz2(end)==4, 'inconsistent input size'); + + bg = reshape(bg, [], 3); + rgba = reshape(rgba, [], 4); + rgb = do_conversion(bg, rgba); + rgb = reshape(rgb, siz1); +else + % this requires the data to be converted into rgb values irst, and + % needs a cmap + clim, and an alpha, alphamap and alim + if numel(varargin)~=5 + error('if a vector of color data is supplied, more input arguments are required'); + end + + % colormap handling + cmap = varargin{1}; + if ischar(cmap) + cmap = colormap(cmap); + elseif size(cmap,2)~=3 + error('invalid specification of colormap, should be nx3'); + end + clim = varargin{2}; if isempty(clim), clim(1) = min(rgba(:)); clim(2) = max(rgba(:)); end + alpha = varargin{3}; + amap = varargin{4}; + alim = varargin{5}; if isempty(alim), alim(1) = min(alpha(:)); alim(2) = max(alpha(:)); end + + % deal with the color data + dat = rgba; + siz = size(dat); + dat = reshape(dat, [], 1); + alpha = reshape(alpha, [], 1); % assume to be same siza as input data! + finvals = isfinite(dat); + + rgba = zeros(size(dat,1),4); + rgba(finvals,1:3) = dat2rgb(dat(finvals), cmap, clim); + + finvals = isfinite(alpha); + rgba(finvals,4) = alpha2a(alpha(finvals), amap, alim); + rgba(~finvals,4) = 0; + + % deal with the background: allow it to be 1x3, i.e. a single color per + % pixel. + if isequal(size(bg),[1 3]) + bg = permute(repmat(bg(:), [1 siz]), [1+(1:numel(siz)) 1]); + else + siz_bg = size(bg); + if isequal(siz_bg, siz) + % make bg rgb + if all(bg(:)<=1) && all(bg(:)>=0) + % don't scale + else + bg_min = min(bg(:)); + bg_max = max(bg(:)); + bg = (bg-bg_min)./(bg_max-bg_min); + end + bg = repmat(bg, [ones(1,ndims(bg)) 3]); + else + %FIXME + end + end + bg = reshape(bg, [], 3); + + if numel(siz)==2 && siz(2)==1, siz = siz(1); end + rgb = do_conversion(bg, rgba); + rgb = reshape(rgb, [siz 3]); +end + +function rgb = do_conversion(bg, rgba) + +rgb = zeros(size(rgba,1),3); +a_ = 1-rgba(:,4); +a = rgba(:,4); + +for k = 1:3 + rgb(:,k) = bg(:,k).*a_ + rgba(:,k).*a; +end + + +function rgb = dat2rgb(dat, cmap, clim) + +dat(end+1) = clim(1); +dat(end+1) = clim(2); % add the extremes to be sure that they are included + +dat(datclim(2)) = clim(2); + + +% scale between 0 and 1 +dat = dat-min(dat); +dat = dat/max(dat); + +ind = round(dat.*(size(cmap,1)-1))+1; +rgb = cmap(ind(1:end-2),:); + +function a = alpha2a(alpha, amap, alim) + +alpha(end+1) = alim(1); +alpha(end+1) = alim(2); + +alpha(alphaalim(2)) = alim(2); + +if ischar(amap) + switch amap + case 'rampup' + a = alpha - min(alpha); + a = a./max(a); + case 'rampdown' + a = alpha - min(alpha); + a = a./max(a); + a = 1-a; + case 'vup' + a = alpha - min(alpha); + a = a./max(a); + a = 1 - 2.*abs(a - 0.5); + case 'vdown' + a = alpha - min(alpha); + a = a./max(a); + a = 2.*abs(a - 0.5); + otherwise + error('unknown alphamap specified'); + end +else + amap = amap(:); + + % assume it to be a vector that has M elements, scaled between 0 and 1 + a = alpha-min(alpha); + a = a/max(a); + ind = round(a.*(size(amap,1)-1))+1; + a = amap(ind(1:end),:); +end +a = a(1:end-2); + + + diff --git a/external/fieldtrip/plotting/private/black.m b/external/fieldtrip/plotting/private/black.m index a299792a..7f3d2875 100644 --- a/external/fieldtrip/plotting/private/black.m +++ b/external/fieldtrip/plotting/private/black.m @@ -1,4 +1,4 @@ -function rgb = rgbcolor +function rgb = black % returns a predefined color as [red green blue] values % @@ -11,7 +11,9 @@ % red = [255 0 0 ]/255; % green = [0 192 0 ]/255; % blue = [0 0 255]/255; -% yellow = [255 255 0 ]/255; +% yellow = [255 255 0 ]/255; +% cortex_light = [199 194 169]/255; +% cortex_dark = [100 97 85]/255; rgb = [0 0 0 ]/255; diff --git a/external/fieldtrip/plotting/private/blue.m b/external/fieldtrip/plotting/private/blue.m index 7445f142..0f4ad75c 100644 --- a/external/fieldtrip/plotting/private/blue.m +++ b/external/fieldtrip/plotting/private/blue.m @@ -1,4 +1,4 @@ -function rgb = rgbcolor +function rgb = blue % returns a predefined color as [red green blue] values % @@ -11,7 +11,9 @@ % red = [255 0 0 ]/255; % green = [0 192 0 ]/255; % blue = [0 0 255]/255; -% yellow = [255 255 0 ]/255; +% yellow = [255 255 0 ]/255; +% cortex_light = [199 194 169]/255; +% cortex_dark = [100 97 85]/255; rgb = [0 0 255]/255; diff --git a/external/fieldtrip/plotting/private/brain.m b/external/fieldtrip/plotting/private/brain.m index 50732efd..3a743503 100644 --- a/external/fieldtrip/plotting/private/brain.m +++ b/external/fieldtrip/plotting/private/brain.m @@ -1,4 +1,4 @@ -function rgb = rgbcolor +function rgb = brain % returns a predefined color as [red green blue] values % @@ -11,7 +11,9 @@ % red = [255 0 0 ]/255; % green = [0 192 0 ]/255; % blue = [0 0 255]/255; -% yellow = [255 255 0 ]/255; +% yellow = [255 255 0 ]/255; +% cortex_light = [199 194 169]/255; +% cortex_dark = [100 97 85]/255; rgb = [202 100 100]/255; diff --git a/external/fieldtrip/plotting/private/cdat2rgb.m b/external/fieldtrip/plotting/private/cdat2rgb.m new file mode 100644 index 00000000..fcc5814f --- /dev/null +++ b/external/fieldtrip/plotting/private/cdat2rgb.m @@ -0,0 +1,28 @@ +function rgb = cdat2rgb(cdat, cmap, clim, highlight) + +% This funcxtion changes the color of pixels to white, regardless of colormap, without using opengl +% It does by converting by: +% 1) convert the to-be-plotted data to their respective rgb color values (determined by colormap) +% 2) convert these rgb color values to hsv values, hue-saturation-value +% 3) for to-be-masked-pixels, set saturation to 0 and value to 1 (hue is irrelevant when they are) +% 4) convert the hsv values back to rgb values + +% enforce mask properties (satmask is 0 when a pixel needs to be masked, 1 if otherwise) +satmask = round(double(highlight)); % enforce binary white-masking, the hsv approach cannot be used for 'white-shading' +satmask(isnan(cdat)) = false; % make sure NaNs are plotted as white pixels, even when using non-integer mask values + +% do 1, by converting the data-values to zero-based indices of the colormap +ncolors = size(cmap, 1); % determines range of index, if a figure has been created by the caller function, gcf changes nothing, if not, a figure is created (which the below would do otherwise) +indcdat = (cdat + -clim(1)) * (ncolors / (-clim(1) + clim(2))); % transform cdat-values to have a 0-(ncolors-1) range (range depends on colormap used, and thus also on clim) +rgbcdat = ind2rgb(uint8(floor(indcdat)), cmap); +% do 2 +hsvcdat = rgb2hsv(rgbcdat); +% do 3 +hsvs = hsvcdat(:,:,2); +hsvs(~satmask) = 0; +hsvv = hsvcdat(:,:,3); +hsvv(~satmask) = 1; +hsvcdat(:,:,2) = hsvs; +hsvcdat(:,:,3) = hsvv; +% do 4 +rgb = hsv2rgb(hsvcdat); diff --git a/external/fieldtrip/plotting/private/channelposition.m b/external/fieldtrip/plotting/private/channelposition.m index 25f8db11..1eecb56a 100644 --- a/external/fieldtrip/plotting/private/channelposition.m +++ b/external/fieldtrip/plotting/private/channelposition.m @@ -110,7 +110,7 @@ dist(selrest,sum(~isinf(dist(selmode,:)))>0) = inf; numcoils = sum(isfinite(dist),2); if niter>500 - error('Failed to extract the positions of the channels. This is most likely due to the balancing matrix being rank deficient. Please replace data.grad with the original grad-structure obtained after reading the header.'); + ft_error('Failed to extract the positions of the channels. This is most likely due to the balancing matrix being rank deficient. Please replace data.grad with the original grad-structure obtained after reading the header.'); end end else @@ -332,5 +332,5 @@ % do a sanity check on the number of positions nchan = numel(sens.label); if length(lab)~=nchan || size(pnt,1)~=nchan || size(ori,1)~=nchan - warning('the positions were not determined for all channels'); + ft_warning('the positions were not determined for all channels'); end diff --git a/external/fieldtrip/plotting/private/coordsys2label.m b/external/fieldtrip/plotting/private/coordsys2label.m new file mode 100644 index 00000000..de55e2ed --- /dev/null +++ b/external/fieldtrip/plotting/private/coordsys2label.m @@ -0,0 +1,169 @@ +function [labelx, labely, labelz] = coordsys2label(coordsys, format, both) + +% COORDSYS2LABEL returns the labels for the three axes, given the symbolic +% string representation of the coordinate system. +% +% Use as +% [labelx, labely, labelz] = coordsys2label(coordsys, format, both) +% +% The scalar argument 'format' results in return values like these +% 1) 'right' +% 2) 'the right' +% 3) '+X (right)' +% +% The boolean argument 'both' results in return values like these +% 0) 'right' i.e. only the direction that it is pointing to +% 1) {'left' 'right'} i.e. both the directions that it is pointing from and to +% +% See also FT_DETERMINE_COORDSYS, FT_PLOT_AXES, FT_HEADCOORDINATES, SETVIEWPOINT + +% Copyright (C) 2017, Robert Oostenveld +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + + +% FIXME this function could also rerturn a label for the origin +% see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=3304 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +if ~isempty(coordsys) && ~strcmp(coordsys, 'unknown') + + % the coordsys consists of three letters for the direction of the positive axes + % or of a string that relates to external software, an atlas or a template + if length(coordsys)==3 && length(intersect(coordsys, 'rlasif'))==3 + axis = 'XYZ'; + label = cell(1,3); + for i=1:3 + switch coordsys(i) + case 'l' + label{i} = {['-' axis(i) ' (right)'], ['+' axis(i) ' (left)']}; + case 'r' + label{i} = {['-' axis(i) ' (left)'], ['+' axis(i) ' (right)']}; + case 'i' + label{i} = {['-' axis(i) ' (superior)'], ['+' axis(i) ' (inferior)']}; + case 's' + label{i} = {['-' axis(i) ' (inferior)'], ['+' axis(i) ' (superior)']}; + case 'a' + label{i} = {['-' axis(i) ' (posterior)'], ['+' axis(i) ' (anterior)']}; + case 'p' + label{i} = {['-' axis(i) ' (anterior)'], ['+' axis(i) ' (posterior)']}; + otherwise + ft_error('incorrect letter in the coordsys'); + end % switch + end % for each of the three axes + + labelx = label{1}; + labely = label{2}; + labelz = label{3}; + + else + switch lower(coordsys) + case {'ras' 'itab' 'neuromag' 'acpc' 'spm' 'mni' 'tal'} + labelx = {'-X (left)' '+X (right)' }; + labely = {'-Y (posterior)' '+Y (anterior)'}; + labelz = {'-Z (inferior)' '+Z (superior)'}; + case {'als' 'ctf' '4d' 'bti'} + labelx = {'-X (posterior)' '+X (anterior)'}; + labely = {'-Y (right)' '+Y (left)'}; + labelz = {'-Z (inferior)' '+Z (superior)'}; + case {'rsp' 'paxinos'} + labelx = {'-X (left)' '+X (right)'}; + labely = {'-Y (inferior)' '+Y (superior)'}; + labelz = {'-Z (anterior)' '+Z (posterior)'}; + case {'lps'} + labelx = {'-X (right)' '+X (left)'}; + labely = {'-Y (anterior)' '+Y (posterior)'}; + labelz = {'-Z (inferior)' '+Z (superior)'}; + otherwise + % the coordinate system is unknown + ft_warning('unknown coordsys ''%s''', coordsys); + labelx = {'-X (unknown)' '+X (unknown)'}; + labely = {'-Y (unknown)' '+Y (unknown)'}; + labelz = {'-Z (unknown)' '+Z (unknown)'}; + end + + end % if it matches with 'rlasif' + +else + % the coordinate system is not specified + labelx = {'-X (unknown)' '+X (unknown)'}; + labely = {'-Y (unknown)' '+Y (unknown)'}; + labelz = {'-Z (unknown)' '+Z (unknown)'}; +end + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +switch format + case 1 + % remove the -, +, X, Y, Z , (, ) and space + labelx{1} = trim(labelx{1}); + labelx{2} = trim(labelx{2}); + labely{1} = trim(labely{1}); + labely{2} = trim(labely{2}); + labelz{1} = trim(labelz{1}); + labelz{2} = trim(labelz{2}); + + case 2 + % remove the -, +, X, Y, Z , (, ) and space + labelx{1} = trim(labelx{1}); + labelx{2} = trim(labelx{2}); + labely{1} = trim(labely{1}); + labely{2} = trim(labely{2}); + labelz{1} = trim(labelz{1}); + labelz{2} = trim(labelz{2}); + % insert 'the' for left and right + if any(strcmp(labelx{1}, {'left', 'right'})), labelx{1} = ['the ' labelx{1}]; end + if any(strcmp(labelx{2}, {'left', 'right'})), labelx{2} = ['the ' labelx{2}]; end + if any(strcmp(labely{1}, {'left', 'right'})), labely{1} = ['the ' labely{1}]; end + if any(strcmp(labely{2}, {'left', 'right'})), labely{2} = ['the ' labely{2}]; end + if any(strcmp(labelz{1}, {'left', 'right'})), labelz{1} = ['the ' labelz{1}]; end + if any(strcmp(labelz{2}, {'left', 'right'})), labelz{2} = ['the ' labelz{2}]; end + + case 3 + % keep it as it is + + otherwise + ft_error('unsupported option') +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +switch both + case false + % only keep the direction that is it pointing towards + labelx = labelx{2}; + labely = labely{2}; + labelz = labelz{2}; + case true + % keep it as it is + otherwise + ft_error('unsupported option') +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function str = trim(str) +str(str=='+') = []; +str(str=='-') = []; +str(str=='(') = []; +str(str==')') = []; +str(str=='X') = []; +str(str=='Y') = []; +str(str=='Z') = []; +str(str==' ') = []; diff --git a/external/fieldtrip/plotting/private/cortex.m b/external/fieldtrip/plotting/private/cortex.m index 087e574c..9b079167 100644 --- a/external/fieldtrip/plotting/private/cortex.m +++ b/external/fieldtrip/plotting/private/cortex.m @@ -1,4 +1,4 @@ -function rgb = rgbcolor +function rgb = cortex % returns a predefined color as [red green blue] values % @@ -11,7 +11,9 @@ % red = [255 0 0 ]/255; % green = [0 192 0 ]/255; % blue = [0 0 255]/255; -% yellow = [255 255 0 ]/255; +% yellow = [255 255 0 ]/255; +% cortex_light = [199 194 169]/255; +% cortex_dark = [100 97 85]/255; rgb = [255 213 119]/255; diff --git a/external/fieldtrip/plotting/private/cortex_dark.m b/external/fieldtrip/plotting/private/cortex_dark.m new file mode 100644 index 00000000..cc2fdb1f --- /dev/null +++ b/external/fieldtrip/plotting/private/cortex_dark.m @@ -0,0 +1,19 @@ +function rgb = cortex_dark + +% returns a predefined color as [red green blue] values +% +% skin_surface = [255 213 119]/255; +% outer_skull_surface = [140 85 85]/255; +% inner_skull_surface = [202 100 100]/255; +% cortex = [255 213 119]/255; +% black = [0 0 0 ]/255; +% white = [255 255 255]/255; +% red = [255 0 0 ]/255; +% green = [0 192 0 ]/255; +% blue = [0 0 255]/255; +% yellow = [255 255 0 ]/255; +% cortex_light = [199 194 169]/255; +% cortex_dark = [100 97 85]/255; + +rgb = [100 97 85]/255; + diff --git a/external/fieldtrip/plotting/private/cortex_light.m b/external/fieldtrip/plotting/private/cortex_light.m new file mode 100644 index 00000000..ae507efb --- /dev/null +++ b/external/fieldtrip/plotting/private/cortex_light.m @@ -0,0 +1,19 @@ +function rgb = cortex_light + +% returns a predefined color as [red green blue] values +% +% skin_surface = [255 213 119]/255; +% outer_skull_surface = [140 85 85]/255; +% inner_skull_surface = [202 100 100]/255; +% cortex = [255 213 119]/255; +% black = [0 0 0 ]/255; +% white = [255 255 255]/255; +% red = [255 0 0 ]/255; +% green = [0 192 0 ]/255; +% blue = [0 0 255]/255; +% yellow = [255 255 0 ]/255; +% cortex_light = [199 194 169]/255; +% cortex_dark = [100 97 85]/255; + +rgb = [199 194 169]/255; + diff --git a/external/fieldtrip/plotting/private/defaultId.m b/external/fieldtrip/plotting/private/defaultId.m new file mode 100644 index 00000000..f4e1ee99 --- /dev/null +++ b/external/fieldtrip/plotting/private/defaultId.m @@ -0,0 +1,57 @@ +function id = defaultId + +% DEFAULTID returns a string that can serve as warning or error identifier, +% for example 'FieldTip:ft_read_header:line345'. +% +% See also WARNING, ERROR, FT_NOTICE, FT_INFO, FT_DEBUG + +% Copyright (C) 2017, Robert Oostenveld +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +stack = dbstack('-completenames'); + +% remove the functions that pertain to the notification system itself +keep = true(size(stack)); +keep(strcmp({stack.name}, 'defaultId')) = false; % this function itself +keep(strcmp({stack.name}, 'ft_notification')) = false; % this one is doing the work underneath ft_error/ft_warning/ft_notice/etc. +keep(strcmp({stack.name}, 'ft_error')) = false; +keep(strcmp({stack.name}, 'ft_warning')) = false; +keep(strcmp({stack.name}, 'ft_notice')) = false; +keep(strcmp({stack.name}, 'ft_info')) = false; +keep(strcmp({stack.name}, 'ft_debug')) = false; +stack = stack(keep); + +% remove the non-FieldTrip functions from the path, these should not be part of the default message identifier +keep = true(size(stack)); +[v, p] = ft_version; +for i=1:numel(stack) + keep(i) = strncmp(p, stack(i).file, length(p)); +end +stack = stack(keep); + +if ~isempty(stack) + % it is called from within a function + stack = flipud(stack); + name = {stack.name}; + id = ['FieldTrip' sprintf(':%s', name{:}) ':line' num2str(stack(end).line)]; +else + % it is called from the command line + id = 'FieldTrip:commandline'; +end diff --git a/external/fieldtrip/plotting/private/elproj.m b/external/fieldtrip/plotting/private/elproj.m index 94ff2578..1fb7f3be 100644 --- a/external/fieldtrip/plotting/private/elproj.m +++ b/external/fieldtrip/plotting/private/elproj.m @@ -61,7 +61,7 @@ num = length(find(z<0)); str = sprintf('%d electrodes may be folded inwards in orthographic projection\n', num); if num - warning(str); + ft_warning(str); end proj = [xp yp]; @@ -77,7 +77,7 @@ num = length(find(th==pi/2 | z<0)); str = sprintf('removing %d electrodes from gnomic projection\n', num); if num - warning(str); + ft_warning(str); end xp(find(th==pi/2 | z<0)) = NaN; yp(find(th==pi/2 | z<0)) = NaN; @@ -94,7 +94,7 @@ num = length(find(th==pi/2 | z<0)); str = sprintf('removing %d electrodes from stereographic projection\n', num); if num - warning(str); + ft_warning(str); end xp(find(th==pi/2 | z<0)) = NaN; yp(find(th==pi/2 | z<0)) = NaN; @@ -113,5 +113,5 @@ proj = [x, y]; else - error('unsupported method (%s)', method); + ft_error('unsupported method (%s)', method); end diff --git a/external/fieldtrip/plotting/private/fixname.m b/external/fieldtrip/plotting/private/fixname.m index 96a345ec..76fd5951 100644 --- a/external/fieldtrip/plotting/private/fixname.m +++ b/external/fieldtrip/plotting/private/fixname.m @@ -1,19 +1,20 @@ -function str = fixname(str) +function str = fixname(str, version) % FIXNAME changes all inappropriate characters in a sting into '_' -% such that it can be used as a filename or as a structure field name. If -% the string begins with a numeric digit, an 'x' is prepended. +% so that it can be used as a filename or as a field name in a structure. +% If the string begins with a digit, an 'x' is prepended. % % Use as % str = fixname(str) % % MATLAB 2014a introduces the matlab.lang.makeValidName and -% matlab.lang.makeUniqueStrings functions for constructing unique MATLAB identifiers, -% but this particular implementation also works with older MATLAB versions. +% matlab.lang.makeUniqueStrings functions for constructing unique +% identifiers, but this particular implementation also works with +% older MATLAB versions. % % See also DEBLANK -% Copyright (C) 2012-2016, Robert Oostenveld +% Copyright (C) 2012-2017, Robert Oostenveld % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -33,19 +34,48 @@ % % $Id$ -str = lower(str); -str(regexp(str,'\W')) = '_'; - -while(str(1) == '_'), str = str(2:end); end; % remove all underscore at the begin of the string -while(str(end) == '_'), str = str(1:end-1); end; % remove all underscore at the end of the string - -if int8(str(1))<58 && int8(str(1))>47 - % the string begins with a digit, prepend an 'x' - str = ['x' str]; +if nargin<2 + version = 'default'; end -% truncate the string if it's too long: MATLAB maximizes the string length to 63 characters (and throws a warning when truncating) -if numel(str)>63 - str = str(1:63); - ft_warning(sprintf('%s exceeds MATLAB''s maximum name length of 63 characters and has been truncated to %s', str, str(1:63))); +switch version + case 'default' + if isempty(str) + str='x'; + end + str = lower(str); + str(regexp(str,'\W')) = '_'; + while(str(1) == '_'), str = str(2:end); end % remove all underscore at the begin of the string + while(str(end) == '_'), str = str(1:end-1); end % remove all underscore at the end of the string + if int8(str(1))<58 && int8(str(1))>47 + % the string begins with a digit, prepend an 'x' + str = ['x' str]; + end + % truncate the string if it's too long: MATLAB maximizes the string length to 63 characters (and throws a warning when truncating) + if numel(str)>63 + str = str(1:63); + warning('%s exceeds MATLAB''s maximum name length of 63 characters and has been truncated to %s', str, str(1:63)); + end + + case '2014a' + str = matlab.lang.makeValidName(str); + + case 'X_base64encode_X' + % this uses some code from Mathworks file exchange + ft_hastoolbox('fileexchange', 1); + % the following is an encoding that can be reverted + str = strtrim(base64encode(str)); + str(str=='=') = '_'; % replace the '=' sign with '_' + str = ['X' str 'X']; % start and end with an 'X' + + case 'X_base64decode_X' + % this uses some code from Mathworks file exchange + ft_hastoolbox('fileexchange', 1); + % revert the encoding + str = str(2:end-1); % it starts and ends with 'X' + str(str=='_') = '='; % the '=' sign has been replaced with '_' + str = char(base64decode(str)); + + otherwise + error('unsupported version "%s"', version); end diff --git a/external/fieldtrip/plotting/private/fixoldorg.m b/external/fieldtrip/plotting/private/fixoldorg.m new file mode 100644 index 00000000..93174b7a --- /dev/null +++ b/external/fieldtrip/plotting/private/fixoldorg.m @@ -0,0 +1,36 @@ +function input = fixoldorg(input, revert) + +% FIXOLDORG use "old/new" instead of "org/new" + +if nargin<2 + revert = false; +end + +if ~(isstruct(input) && numel(input)==1) + % this does not look like a montage or a sensor description + return +end + +if ~revert + from = {'labelorg', 'chantypeorg', 'chanunitorg', 'chanposorg', 'chanoriorg'}; + to = {'labelold', 'chantypeold', 'chanunitold', 'chanposold', 'chanoriold'}; +else + to = {'labelorg', 'chantypeorg', 'chanunitorg', 'chanposorg', 'chanoriorg'}; + from = {'labelold', 'chantypeold', 'chanunitold', 'chanposold', 'chanoriold'}; +end + +% replace the fields +for i=1:numel(from) + if isfield(input, from{i}) + input.(to{i}) = input.(from{i}); + input = rmfield(input, from{i}); + end +end + +% use recursion to update the subfields +fn = fieldnames(input); +for i=1:numel(fn) + if isstruct(input.(fn{i})) + input.(fn{i}) = fixoldorg(input.(fn{i}), revert); + end +end diff --git a/external/fieldtrip/plotting/private/fixpos.m b/external/fieldtrip/plotting/private/fixpos.m index 31cee40f..88408288 100644 --- a/external/fieldtrip/plotting/private/fixpos.m +++ b/external/fieldtrip/plotting/private/fixpos.m @@ -10,7 +10,7 @@ % convert to structure, otherwise the code below won't work properly ws = warning('off', 'MATLAB:structOnObject'); mesh = struct(mesh); - warning(ws); + ft_warning(ws); end if ~isa(mesh, 'struct') @@ -42,7 +42,7 @@ case 8 mesh.hex = mesh.ConnectivityList; otherwise - error('unsupported ConnectivityList') + ft_error('unsupported ConnectivityList') end % switch mesh = removefields(mesh, {'Points', 'ConnectivityList', 'Constraints', 'UnderlyingObj'}); end diff --git a/external/fieldtrip/plotting/private/ft_apply_montage.m b/external/fieldtrip/plotting/private/ft_apply_montage.m index 2b5e73ee..5262952b 100644 --- a/external/fieldtrip/plotting/private/ft_apply_montage.m +++ b/external/fieldtrip/plotting/private/ft_apply_montage.m @@ -18,7 +18,7 @@ % montage.labelnew = Mx1 cell-array % % As an example, a bipolar montage could look like this -% bipolar.labelold = {'1', '2', '3', '4'} +% bipolar.labelold = {'1', '2', '3', '4'} % bipolar.labelnew = {'1-2', '2-3', '3-4'} % bipolar.tra = [ % +1 -1 0 0 @@ -75,8 +75,8 @@ end % use "old/new" instead of "org/new" -montage = fixmontage(montage); -input = fixmontage(input); % the input might also be a montage +montage = fixoldorg(montage); +input = fixoldorg(input); % the input might be a montage or a sensor array % get optional input arguments keepunused = ft_getopt(varargin, 'keepunused', 'no'); @@ -99,7 +99,7 @@ if ~isfield(montage, 'chantypeold') montage.chantypeold = repmat({'unknown'}, size(montage.labelold)); if isfield(input, 'chantype') && ~istrue(inverse) - warning('copying input chantype to montage'); + ft_warning('copying input chantype to montage'); [sel1, sel2] = match_str(montage.labelold, input.label); montage.chantypeold(sel1) = input.chantype(sel2); end @@ -108,7 +108,7 @@ if ~isfield(montage, 'chantypenew') montage.chantypenew = repmat({'unknown'}, size(montage.labelnew)); if isfield(input, 'chantype') && istrue(inverse) - warning('copying input chantype to montage'); + ft_warning('copying input chantype to montage'); [sel1, sel2] = match_str(montage.labelnew, input.label); montage.chantypenew(sel1) = input.chantype(sel2); end @@ -117,7 +117,7 @@ if ~isfield(montage, 'chanunitold') montage.chanunitold = repmat({'unknown'}, size(montage.labelold)); if isfield(input, 'chanunit') && ~istrue(inverse) - warning('copying input chanunit to montage'); + ft_warning('copying input chanunit to montage'); [sel1, sel2] = match_str(montage.labelold, input.label); montage.chanunitold(sel1) = input.chanunit(sel2); end @@ -126,7 +126,7 @@ if ~isfield(montage, 'chanunitnew') montage.chanunitnew = repmat({'unknown'}, size(montage.labelnew)); if isfield(input, 'chanunit') && istrue(inverse) - warning('copying input chanunit to montage'); + ft_warning('copying input chanunit to montage'); [sel1, sel2] = match_str(montage.labelnew, input.label); montage.chanunitnew(sel1) = input.chanunit(sel2); end @@ -162,19 +162,19 @@ % check the consistency of the montage if ~iscell(montage.labelold) || ~iscell(montage.labelnew) - error('montage labels need to be specified in cell-arrays'); + ft_error('montage labels need to be specified in cell-arrays'); end % check the consistency of the montage if ~all(isfield(montage, {'tra', 'labelold', 'labelnew'})) - error('the second input argument does not correspond to a montage'); + ft_error('the second input argument does not correspond to a montage'); end % check the consistency of the montage if size(montage.tra,1)~=length(montage.labelnew) - error('the number of channels in the montage is inconsistent'); + ft_error('the number of channels in the montage is inconsistent'); elseif size(montage.tra,2)~=length(montage.labelold) - error('the number of channels in the montage is inconsistent'); + ft_error('the number of channels in the montage is inconsistent'); end % use a default unit transfer from sensors to channels if not otherwise specified @@ -212,15 +212,14 @@ end % select and keep the columns that are non-empty, i.e. remove the empty columns -selcol = find(~all(montage.tra==0, 1)); -montage.tra = montage.tra(:,selcol); -montage.labelold = montage.labelold(selcol); +selcol = find(~all(montage.tra==0, 1)); +montage.tra = montage.tra(:,selcol); +montage.labelold = montage.labelold(selcol); montage.chantypeold = montage.chantypeold(selcol); montage.chanunitold = montage.chanunitold(selcol); clear selcol -% select and remove the columns corresponding to channels that are not present in the -% original data +% select and remove the columns corresponding to channels that are not present in the original data remove = setdiff(montage.labelold, intersect(montage.labelold, inputlabel)); selcol = match_str(montage.labelold, remove); % we cannot just remove the colums, all rows that depend on it should also be removed @@ -259,15 +258,15 @@ % use an anonymous function to test for the presence of NaNs in the input data hasnan = @(x) any(isnan(x(:))); if any(cellfun(hasnan, data_unused.trial)) - error('FieldTrip:NaNsinInputData', ['Your input data contains NaNs in channels that are unused '... + ft_error('FieldTrip:NaNsinInputData', ['Your input data contains NaNs in channels that are unused '... 'in the supplied montage. This would result in undesired NaNs in the '... 'output data. Please remove these channels from the input data (using '... 'ft_selectdata) before attempting to apply the montage.']); end end + if istrue(keepunused) - % add the channels that are not rereferenced to the input and output of the - % montage + % add the channels that are not rereferenced to the input and output of the montage montage.tra((m+(1:k)),(n+(1:k))) = eye(k); montage.labelold = cat(1, montage.labelold(:), addlabel(:)); montage.labelnew = cat(1, montage.labelnew(:), addlabel(:)); @@ -288,15 +287,15 @@ m = size(montage.tra,1); n = size(montage.tra,2); if length(unique(montage.labelnew))~=m - error('not all output channels of the montage are unique'); + ft_error('not all output channels of the montage are unique'); end if length(unique(montage.labelold))~=n - error('not all input channels of the montage are unique'); + ft_error('not all input channels of the montage are unique'); end % determine whether all channels that have to be rereferenced are available if length(intersect(inputlabel, montage.labelold))~=length(montage.labelold) - error('not all channels that are required in the montage are available in the data'); + ft_error('not all channels that are required in the montage are available in the data'); end % reorder the columns of the montage matrix @@ -331,9 +330,9 @@ end if isfield(input, 'chantype') && ~isequal(input.chantype, montage.chantypeold) - error('inconsistent chantype in data and montage'); + ft_error('inconsistent chantype in data and montage'); elseif isfield(input, 'chantypenew') && ~isequal(input.chantypenew, montage.chantypeold) - error('inconsistent chantype in data and montage'); + ft_error('inconsistent chantype in data and montage'); end if isfield(input, 'labelold') && isfield(input, 'labelnew') @@ -374,11 +373,13 @@ sens.tra = montage.tra * sens.tra; end - % The montage operates on the coil weights in sens.tra, but the output channels - % can be different. If possible, we want to keep the original channel positions - % and orientations. + % The montage operates on the coil weights in sens.tra, but the output channels can be different. + % If possible, we want to keep the original channel positions and orientations. [sel1, sel2] = match_str(montage.labelnew, inputlabel); - keepchans = length(sel1)==length(montage.labelnew); + keepchans = isequal(sel1(:)', 1:numel(montage.labelnew)); + + posweight = abs(montage.tra); + posweight = diag(1./sum(posweight,2)) * posweight; if isfield(sens, 'chanpos') if keepchans @@ -386,9 +387,14 @@ else if ~isfield(sens, 'chanposold') % add a chanposold only if it is not there yet - sens.chanposold = sens.chanpos; + sens.chanposold = sens.chanpos; + % also keep the old label, type and unit for reference + sens.labelold = inputlabel; + sens.chantypeold = inputchantype; + sens.chanunitold = inputchanunit; end - sens.chanpos = nan(numel(montage.labelnew),3); + % compute the channel positions as a weighted sum of the original ones + sens.chanpos = posweight * sens.chanpos; end end @@ -399,7 +405,8 @@ if ~isfield(sens, 'chanoriold') sens.chanoriold = sens.chanori; end - sens.chanori = nan(numel(montage.labelnew),3); + % compute the channel orientations as a weighted sum of the original ones + sens.chanori = posweight * sens.chanori; end end @@ -407,20 +414,6 @@ sens.chantype = montage.chantypenew; sens.chanunit = montage.chanunitnew; - % keep the - % original label, - % type and unit - % for reference - if ~isfield(sens, 'labelold') - sens.labelold = inputlabel; - end - if ~isfield(sens, 'chantypeold') - sens.chantypeold = inputchantype; - end - if ~isfield(sens, 'chanunitold') - sens.chanunitold = inputchanunit; - end - % keep track of the order of the balancing and which one is the current one if istrue(inverse) if isfield(sens, 'balance')% && isfield(sens.balance, 'previous') @@ -434,14 +427,14 @@ sens.balance.current = 'none'; end end - elseif ~istrue(inverse) && ~isempty(bname) - if isfield(sens, 'balance'), + elseif ~istrue(inverse) && ~isempty(bname) + if isfield(sens, 'balance') % check whether a balancing montage with name bname already exist, % and if so, how many mnt = fieldnames(sens.balance); sel = strmatch(bname, mnt); - if numel(sel)==0, + if numel(sel)==0 % bname can stay the same elseif numel(sel)==1 % the original should be renamed to 'bname1' and the new one should @@ -477,8 +470,8 @@ input = sens; clear sens - case 'raw'; - % apply the montage to the raw data that was preprocessed using fieldtrip + case 'raw' + % apply the montage to the raw data that was preprocessed using FieldTrip data = input; clear input @@ -533,7 +526,7 @@ end freq.fourierspctrm = output; % replace the original Fourier spectrum else - error('unsupported dimord in frequency data (%s)', freq.dimord); + ft_error('unsupported dimord in frequency data (%s)', freq.dimord); end freq.label = montage.labelnew; @@ -545,7 +538,7 @@ clear freq otherwise - error('unrecognized input'); + ft_error('unrecognized input'); end % switch inputtype % only retain the chantype and/or chanunit if they were present in the input @@ -563,30 +556,9 @@ y = false(1,n); y(x) = true; -function nowarning(varargin) -return - -function s = removefields(s, fn) -for i=1:length(fn) - if isfield(s, fn{i}) - s = rmfield(s, fn{i}); - end -end - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% HELPER FUNCTION use "old/new" instead of "org/new" +% HELPER FUNCTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -function montage = fixmontage(montage) -if isfield(montage, 'labelorg') - montage.labelold = montage.labelorg; - montage = rmfield(montage, 'labelorg'); -end -if isfield(montage, 'chantypeorg') - montage.chantypeold = montage.chantypeorg; - montage = rmfield(montage, 'chantypeorg'); -end -if isfield(montage, 'chanunitorg') - montage.chanunitold = montage.chanunitorg; - montage = rmfield(montage, 'chanunitorg'); -end +function nowarning(varargin) +return diff --git a/external/fieldtrip/plotting/private/ft_convert_units.m b/external/fieldtrip/plotting/private/ft_convert_units.m index e81f9502..47279027 100644 --- a/external/fieldtrip/plotting/private/ft_convert_units.m +++ b/external/fieldtrip/plotting/private/ft_convert_units.m @@ -19,7 +19,7 @@ % are specified, this function will only determine the native geometrical % units of the object. % -% See also FT_ESTIMATE_UNITS, FT_READ_VOL, FT_READ_SENS +% See also FT_DETERMINE_UNITS, FT_CONVERT_COORDSYS, FT_DETERMINE_COODSYS % Copyright (C) 2005-2016, Robert Oostenveld % @@ -46,16 +46,28 @@ % 2) determine the requested scaling factor to obtain the output units % 3) try to apply the scaling to the known geometrical elements in the input object +% ensure the correct number of input and output arguments +% narginchk(2,inf); % see below +% nargoutchk(0,1); + +% the "target" input argument has been made required in Aug 2017 +% prior to that it was also possible to use this function to estimate units +% the backward compatibility support can be removed in Aug 2018 +if nargin<2 + ft_warning('calling this function only to determine units is deprecated, please use FT_DETERMINE_COORDSYS instead'); + obj = ft_determine_units(obj); + return +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% parse input options feedback = ft_getopt(varargin, 'feedback', false); if isstruct(obj) && numel(obj)>1 % deal with a structure array for i=1:numel(obj) - if nargin>1 - tmp(i) = ft_convert_units(obj(i), target, varargin{:}); - else - tmp(i) = ft_convert_units(obj(i)); - end + tmp(i) = ft_convert_units(obj(i), target, varargin{:}); end obj = tmp; return @@ -69,119 +81,29 @@ end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% determine the unit-of-dimension of the input object +% determine the units of the input object %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -if isfield(obj, 'unit') && ~isempty(obj.unit) - % use the units specified in the object - unit = obj.unit; - -elseif isfield(obj, 'bnd') && isfield(obj.bnd, 'unit') - - unit = unique({obj.bnd.unit}); - if ~all(strcmp(unit, unit{1})) - error('inconsistent units in the individual boundaries'); - else - unit = unit{1}; - end - - % keep one representation of the units rather than keeping it with each boundary - % the units will be reassigned further down - obj.bnd = rmfield(obj.bnd, 'unit'); - -else - % try to determine the units by looking at the size of the object - if isfield(obj, 'chanpos') && ~isempty(obj.chanpos) - siz = norm(idrange(obj.chanpos)); - unit = ft_estimate_units(siz); - - elseif isfield(obj, 'elecpos') && ~isempty(obj.elecpos) - siz = norm(idrange(obj.elecpos)); - unit = ft_estimate_units(siz); - - elseif isfield(obj, 'coilpos') && ~isempty(obj.coilpos) - siz = norm(idrange(obj.coilpos)); - unit = ft_estimate_units(siz); - - elseif isfield(obj, 'pnt') && ~isempty(obj.pnt) - siz = norm(idrange(obj.pnt)); - unit = ft_estimate_units(siz); - - elseif isfield(obj, 'pos') && ~isempty(obj.pos) - siz = norm(idrange(obj.pos)); - unit = ft_estimate_units(siz); - - elseif isfield(obj, 'transform') && ~isempty(obj.transform) - % construct the corner points of the volume in voxel and in head coordinates - [pos_voxel, pos_head] = cornerpoints(obj.dim, obj.transform); - siz = norm(idrange(pos_head)); - unit = ft_estimate_units(siz); - - elseif isfield(obj, 'fid') && isfield(obj.fid, 'pnt') && ~isempty(obj.fid.pnt) - siz = norm(idrange(obj.fid.pnt)); - unit = ft_estimate_units(siz); - - elseif isfield(obj, 'fid') && isfield(obj.fid, 'pos') && ~isempty(obj.fid.pos) - siz = norm(idrange(obj.fid.pos)); - unit = ft_estimate_units(siz); - - elseif ft_voltype(obj, 'infinite') - % this is an infinite medium volume conductor, which does not care about units - unit = 'm'; - - elseif ft_voltype(obj,'singlesphere') - siz = obj.r; - unit = ft_estimate_units(siz); - - elseif ft_voltype(obj,'localspheres') - siz = median(obj.r); - unit = ft_estimate_units(siz); - - elseif ft_voltype(obj,'concentricspheres') - siz = max(obj.r); - unit = ft_estimate_units(siz); - - elseif isfield(obj, 'bnd') && isstruct(obj.bnd) && isfield(obj.bnd(1), 'pnt') && ~isempty(obj.bnd(1).pnt) - siz = norm(idrange(obj.bnd(1).pnt)); - unit = ft_estimate_units(siz); - - elseif isfield(obj, 'bnd') && isstruct(obj.bnd) && isfield(obj.bnd(1), 'pos') && ~isempty(obj.bnd(1).pos) - siz = norm(idrange(obj.bnd(1).pos)); - unit = ft_estimate_units(siz); - - elseif isfield(obj, 'nas') && isfield(obj, 'lpa') && isfield(obj, 'rpa') - pnt = [obj.nas; obj.lpa; obj.rpa]; - siz = norm(idrange(pnt)); - unit = ft_estimate_units(siz); - - else - error('cannot determine geometrical units'); - - end % recognized type of volume conduction model or sensor array -end % determine input units - -if nargin<2 || isempty(target) - % just remember the units in the output and return - obj.unit = unit; - return -elseif strcmp(unit, target) - % no conversion is needed - obj.unit = unit; - return -end +obj = ft_determine_units(obj); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % compute the scaling factor from the input units to the desired ones %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -scale = ft_scalingfactor(unit, target); + +if isequal(obj.unit, target) + % there is nothing to do + return +end if istrue(feedback) % give some information about the conversion - fprintf('converting units from ''%s'' to ''%s''\n', unit, target) + fprintf('converting units from ''%s'' to ''%s''\n', obj.unit, target) end + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % apply the scaling factor %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +scale = ft_scalingfactor(obj.unit, target); % volume conductor model if isfield(obj, 'r'), obj.r = scale * obj.r; end @@ -225,7 +147,7 @@ elseif strcmp(obj.chanunit{i}, 'unknown') % assume that it is T or V, don't do anything else - error('unexpected units %s', obj.chanunit{i}); + ft_error('unexpected units %s', obj.chanunit{i}); end end % for end % if @@ -243,12 +165,12 @@ if isfield(obj, 'zgrid') && ~ischar(obj.zgrid), obj.zgrid = scale * obj.zgrid; end % anatomical MRI or functional volume -if isfield(obj, 'transform'), +if isfield(obj, 'transform') H = diag([scale scale scale 1]); obj.transform = H * obj.transform; end -if isfield(obj, 'transformorig'), +if isfield(obj, 'transformorig') H = diag([scale scale scale 1]); obj.transformorig = H * obj.transformorig; end @@ -266,15 +188,3 @@ % remember the unit obj.unit = target; - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% IDRANGE interdecile range for more robust range estimation -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -function r = idrange(x) -keeprow=true(size(x,1),1); -for l=1:size(x,2) - keeprow = keeprow & isfinite(x(:,l)); -end -sx = sort(x(keeprow,:), 1); -ii = round(interp1([0, 1], [1, size(x(keeprow,:), 1)], [.1, .9])); % indices for 10 & 90 percentile -r = diff(sx(ii, :)); diff --git a/external/fieldtrip/plotting/private/ft_datatype_sens.m b/external/fieldtrip/plotting/private/ft_datatype_sens.m index 27597439..a3c1d2ec 100644 --- a/external/fieldtrip/plotting/private/ft_datatype_sens.m +++ b/external/fieldtrip/plotting/private/ft_datatype_sens.m @@ -129,11 +129,11 @@ scaling = ft_getopt(varargin, 'scaling'); % should be 'amplitude' or 'amplitude/distance', the default depends on the senstype if ~isempty(amplitude) && ~any(strcmp(amplitude, {'V' 'uV' 'T' 'mT' 'uT' 'nT' 'pT' 'fT'})) - error('unsupported unit of amplitude "%s"', amplitude); + ft_error('unsupported unit of amplitude "%s"', amplitude); end if ~isempty(distance) && ~any(strcmp(distance, {'m' 'dm' 'cm' 'mm'})) - error('unsupported unit of distance "%s"', distance); + ft_error('unsupported unit of distance "%s"', distance); end if strcmp(version, 'latest') @@ -157,31 +157,12 @@ % update it to the previous standard version sens = ft_datatype_sens(sens, 'version', '2011v2'); + % rename from org to old (reverse = false) + sens = fixoldorg(sens, false); + % ensure that all numbers are represented in double precision sens = ft_struct2double(sens); - % use "old/new" rather than "org/new" - if isfield(sens, 'labelorg') - sens.labelold = sens.labelorg; - sens = rmfield(sens, 'labelorg'); - end - if isfield(sens, 'chantypeorg') - sens.chantypeold = sens.chantypeorg; - sens = rmfield(sens, 'chantypeorg'); - end - if isfield(sens, 'chanuniteorg') - sens.chanunitold = sens.chanunitorg; - sens = rmfield(sens, 'chanunitorg'); - end - if isfield(sens, 'chanposorg') - sens.chanposold = sens.chanposorg; - sens = rmfield(sens, 'chanposorg'); - end - if isfield(sens, 'chanoriorg') - sens.chanoriold = sens.chanoriorg; - sens = rmfield(sens, 'chanoriorg'); - end - % in version 2011v2 this was optional, now it is required if ~isfield(sens, 'chantype') || all(strcmp(sens.chantype, 'unknown')) sens.chantype = ft_chantype(sens); @@ -213,7 +194,7 @@ sens.tra(i,:) = sens.tra(i,:) * ft_scalingfactor(sens.chanunit{i}, amplitude); sens.chanunit{i} = amplitude; else - error('unexpected channel unit "%s" in channel %d', sens.chanunit{i}, i); + ft_error('unexpected channel unit "%s" in channel %d', sens.chanunit{i}, i); end end else @@ -244,13 +225,13 @@ sel_mm = ~cellfun(@isempty, regexp(sens.chanunit, '/mm$')); if strcmp(sens.unit, 'm') && (any(sel_dm) || any(sel_cm) || any(sel_mm)) - error('inconsistent units in input gradiometer'); + ft_error('inconsistent units in input gradiometer'); elseif strcmp(sens.unit, 'dm') && (any(sel_m) || any(sel_cm) || any(sel_mm)) - error('inconsistent units in input gradiometer'); + ft_error('inconsistent units in input gradiometer'); elseif strcmp(sens.unit, 'cm') && (any(sel_m) || any(sel_dm) || any(sel_mm)) - error('inconsistent units in input gradiometer'); + ft_error('inconsistent units in input gradiometer'); elseif strcmp(sens.unit, 'mm') && (any(sel_m) || any(sel_dm) || any(sel_cm)) - error('inconsistent units in input gradiometer'); + ft_error('inconsistent units in input gradiometer'); end % the default should be amplitude/distance for neuromag and amplitude for all others @@ -258,7 +239,7 @@ if ft_senstype(sens, 'neuromag') scaling = 'amplitude/distance'; elseif ft_senstype(sens, 'yokogawa440') - warning('asuming that the default scaling should be amplitude rather than amplitude/distance'); + ft_warning('asuming that the default scaling should be amplitude rather than amplitude/distance'); scaling = 'amplitude'; else scaling = 'amplitude'; @@ -272,7 +253,7 @@ % this channel is expressed as amplitude per distance coil = find(abs(sens.tra(i,:))~=0); if length(coil)~=2 - error('unexpected number of coils contributing to channel %d', i); + ft_error('unexpected number of coils contributing to channel %d', i); end baseline = norm(sens.coilpos(coil(1),:) - sens.coilpos(coil(2),:)); sens.tra(i,:) = sens.tra(i,:)*baseline; % scale with the baseline distance @@ -281,7 +262,7 @@ % no conversion needed else % see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=3144 - ft_warning(sprintf('unexpected channel unit "%s" in channel %d', sens.chanunit{i}, i)); + ft_warning('unexpected channel unit "%s" in channel %d', sens.chanunit{i}, i); end % if end % for @@ -294,7 +275,7 @@ % this is a magnetometer channel, no conversion needed continue elseif length(coil)~=2 - error('unexpected number of coils (%d) contributing to channel %s (%d)', length(coil), sens.label{i}, i); + ft_error('unexpected number of coils (%d) contributing to channel %s (%d)', length(coil), sens.label{i}, i); end baseline = norm(sens.coilpos(coil(1),:) - sens.coilpos(coil(2),:)); sens.tra(i,:) = sens.tra(i,:)/baseline; % scale with the baseline distance @@ -303,7 +284,7 @@ % no conversion needed else % see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=3144 - ft_warning(sprintf('unexpected channel unit "%s" in channel %d', sens.chanunit{i}, i)); + ft_warning('unexpected channel unit "%s" in channel %d', sens.chanunit{i}, i); end % if end % for @@ -315,16 +296,19 @@ sel_cm = ~cellfun(@isempty, regexp(sens.chanunit, '/cm$')); sel_mm = ~cellfun(@isempty, regexp(sens.chanunit, '/mm$')); if any(sel_m | sel_dm | sel_cm | sel_mm) - error('scaling of amplitude/distance has not been considered yet for EEG'); + ft_error('scaling of amplitude/distance has not been considered yet for EEG'); end end % if iseeg or ismeg %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% case '2011v2' - + + % rename from old to org (reverse = true) + sens = fixoldorg(sens, true); + if ~isempty(amplitude) || ~isempty(distance) || ~isempty(scaling) - warning('amplitude, distance and scaling are not supported for version "%s"', version); + ft_warning('amplitude, distance and scaling are not supported for version "%s"', version); end % This speeds up subsequent calls to ft_senstype and channelposition. @@ -357,7 +341,7 @@ sens.chanpos(selsens,:) = chanpos(selpos,:); sens.chanori(selsens,:) = chanori(selpos,:); if length(selsens)~=length(sens.label) - warning('cannot determine the position and orientation for all channels'); + ft_warning('cannot determine the position and orientation for all channels'); end else % sensor description is something else, EEG/ECoG etc @@ -369,7 +353,7 @@ % insert the determined position/orientation on the appropriate rows sens.chanpos(selsens,:) = chanpos(selpos,:); if length(selsens)~=length(sens.label) - warning('cannot determine the position and orientation for all channels'); + ft_warning('cannot determine the position and orientation for all channels'); end end end @@ -384,7 +368,7 @@ if ~isfield(sens, 'unit') % this should be done prior to calling ft_chanunit, since ft_chanunit uses this for planar neuromag channels - sens = ft_convert_units(sens); + sens = ft_determine_units(sens); end if ~isfield(sens, 'chanunit') || all(strcmp(sens.chanunit, 'unknown')) @@ -397,7 +381,7 @@ if any(strcmp(sens.type, {'meg', 'eeg', 'magnetometer', 'electrode', 'unknown'})) % this is not sufficiently informative, so better remove it - % see also http://bugzilla.fcdonders.nl/show_bug.cgi?id=1806 + % see also http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=1806 sens = rmfield(sens, 'type'); end @@ -408,7 +392,7 @@ isfield(sens, 'tra') && isfield(sens, 'coilori') && size(sens.tra,2)~=size(sens.coilori,1) || ... isfield(sens, 'chanpos') && size(sens.chanpos,1)~=length(sens.label) || ... isfield(sens, 'chanori') && size(sens.chanori,1)~=length(sens.label) - error('inconsistent number of channels in sensor description'); + ft_error('inconsistent number of channels in sensor description'); end if ismeg @@ -465,7 +449,7 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% otherwise - error('converting to version %s is not supported', version); + ft_error('converting to version %s is not supported', version); end % switch diff --git a/external/fieldtrip/plotting/private/ft_datatype_volume.m b/external/fieldtrip/plotting/private/ft_datatype_volume.m index 2e7d5fab..eb99e9ff 100644 --- a/external/fieldtrip/plotting/private/ft_datatype_volume.m +++ b/external/fieldtrip/plotting/private/ft_datatype_volume.m @@ -133,7 +133,7 @@ try volume.(fn{i}) = reshape(volume.(fn{i}), volume.dim); catch - warning('could not reshape %s to the expected dimensions', fn{i}); + ft_warning('could not reshape "%s" to the expected dimensions', fn{i}); end end @@ -179,5 +179,5 @@ otherwise %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - error('unsupported version "%s" for volume datatype', version); + ft_error('unsupported version "%s" for volume datatype', version); end diff --git a/external/fieldtrip/plotting/private/ft_determine_units.m b/external/fieldtrip/plotting/private/ft_determine_units.m new file mode 100644 index 00000000..8c5864a3 --- /dev/null +++ b/external/fieldtrip/plotting/private/ft_determine_units.m @@ -0,0 +1,171 @@ +function [obj] = ft_determine_units(obj) + +% FT_DETERMINE_UNITS tries to determine the units of a geometrical object by +% looking at its size and by relating this to the approximate size of the +% human head according to the following table: +% from 0.050 to 0.500 -> meter +% from 0.500 to 5.000 -> decimeter +% from 5.000 to 50.000 -> centimeter +% from 50.000 to 500.000 -> millimeter +% +% Use as +% dataout = ft_determine_units(datain) +% where the input obj structure can be +% - an anatomical MRI +% - an electrode or gradiometer definition +% - a volume conduction model of the head +% or most other FieldTrip structures that represent geometrical information. +% +% See also FT_CONVERT_UNITS, FT_DETERMINE_COODSYS, FT_CONVERT_COORDSYS + +% Copyright (C) 2005-2017, Robert Oostenveld +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +% ensure the correct number of input and output arguments +% narginchk(1,1); +% nargoutchk(0,1); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +if isstruct(obj) && numel(obj)>1 + % deal with a structure array + for i=1:numel(obj) + tmp(i) = ft_determine_units(obj(i)); + end + obj = tmp; + return +elseif iscell(obj) && numel(obj)>1 + % deal with a cell array + % this might represent combined EEG, ECoG and/or MEG + for i=1:numel(obj) + obj{i} = ft_determine_units(obj{i}); + end + return +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +if isfield(obj, 'unit') && ~isempty(obj.unit) + % use the units specified in the object + unit = obj.unit; + +elseif isfield(obj, 'bnd') && isfield(obj.bnd, 'unit') + + unit = unique({obj.bnd.unit}); + if ~all(strcmp(unit, unit{1})) + ft_error('inconsistent units in the individual boundaries'); + else + unit = unit{1}; + end + + % keep one representation of the units rather than keeping it with each boundary + % the units will be reassigned further down + obj.bnd = rmfield(obj.bnd, 'unit'); + +else + % try to determine the units by looking at the size of the object + if isfield(obj, 'chanpos') && ~isempty(obj.chanpos) + siz = norm(idrange(obj.chanpos)); + unit = ft_estimate_units(siz); + + elseif isfield(obj, 'elecpos') && ~isempty(obj.elecpos) + siz = norm(idrange(obj.elecpos)); + unit = ft_estimate_units(siz); + + elseif isfield(obj, 'coilpos') && ~isempty(obj.coilpos) + siz = norm(idrange(obj.coilpos)); + unit = ft_estimate_units(siz); + + elseif isfield(obj, 'pnt') && ~isempty(cat(1, obj.pnt)) + % the obj can be a struct.array, hence the concatenation + siz = norm(idrange(cat(1, obj.pnt))); + unit = ft_estimate_units(siz); + + elseif isfield(obj, 'pos') && ~isempty(cat(1, obj.pos)) + % the obj can be a struct.array, hence the concatenation + siz = norm(idrange(cat(1, obj.pos))); + unit = ft_estimate_units(siz); + + elseif isfield(obj, 'transform') && ~isempty(obj.transform) + % construct the corner points of the volume in voxel and in head coordinates + [pos_voxel, pos_head] = cornerpoints(obj.dim, obj.transform); + siz = norm(idrange(pos_head)); + unit = ft_estimate_units(siz); + + elseif isfield(obj, 'fid') && isfield(obj.fid, 'pnt') && ~isempty(obj.fid.pnt) + siz = norm(idrange(obj.fid.pnt)); + unit = ft_estimate_units(siz); + + elseif isfield(obj, 'fid') && isfield(obj.fid, 'pos') && ~isempty(obj.fid.pos) + siz = norm(idrange(obj.fid.pos)); + unit = ft_estimate_units(siz); + + elseif ft_voltype(obj, 'infinite') + % this is an infinite medium volume conductor, which does not care about units + unit = 'm'; + + elseif ft_voltype(obj,'singlesphere') + siz = obj.r; + unit = ft_estimate_units(siz); + + elseif ft_voltype(obj,'localspheres') + siz = median(obj.r); + unit = ft_estimate_units(siz); + + elseif ft_voltype(obj,'concentricspheres') + siz = max(obj.r); + unit = ft_estimate_units(siz); + + elseif isfield(obj, 'bnd') && isstruct(obj.bnd) && isfield(obj.bnd(1), 'pnt') && ~isempty(obj.bnd(1).pnt) + siz = norm(idrange(obj.bnd(1).pnt)); + unit = ft_estimate_units(siz); + + elseif isfield(obj, 'bnd') && isstruct(obj.bnd) && isfield(obj.bnd(1), 'pos') && ~isempty(obj.bnd(1).pos) + siz = norm(idrange(obj.bnd(1).pos)); + unit = ft_estimate_units(siz); + + elseif isfield(obj, 'nas') && isfield(obj, 'lpa') && isfield(obj, 'rpa') + pnt = [obj.nas; obj.lpa; obj.rpa]; + siz = norm(idrange(pnt)); + unit = ft_estimate_units(siz); + + else + ft_error('cannot determine geometrical units'); + + end % recognized type of volume conduction model or sensor array +end % determine input units + +% add the units to the output object +for i=1:numel(obj) + % obj can be a struct-array, hence the loop + obj(i).unit = unit; +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% IDRANGE interdecile range for more robust range estimation +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function r = idrange(x) +keeprow=true(size(x,1),1); +for l=1:size(x,2) + keeprow = keeprow & isfinite(x(:,l)); +end +sx = sort(x(keeprow,:), 1); +ii = round(interp1([0, 1], [1, size(x(keeprow,:), 1)], [.1, .9])); % indices for 10 & 90 percentile +r = diff(sx(ii, :)); diff --git a/external/fieldtrip/plotting/private/ft_estimate_units.m b/external/fieldtrip/plotting/private/ft_estimate_units.m index ce0b457f..d44dc8ae 100644 --- a/external/fieldtrip/plotting/private/ft_estimate_units.m +++ b/external/fieldtrip/plotting/private/ft_estimate_units.m @@ -46,14 +46,14 @@ if indx>length(unit) indx = length(unit); - warning('assuming that the units are "%s"', unit{indx}); + ft_warning('assuming that the units are "%s"', unit{indx}); elseif indx<1 indx = 1; - warning('assuming that the units are "%s"', unit{indx}); + ft_warning('assuming that the units are "%s"', unit{indx}); elseif abs((est-floor(est)) - 0.5)<0.1 % the size estimate falls within the expected range, but is not very decisive % for example round(1.49) results in meter, but round(1.51) results in decimeter - warning('the estimated units are not very decisive, assuming that the units are "%s"', unit{indx}); + ft_warning('the estimated units are not very decisive, assuming that the units are "%s"', unit{indx}); end unit = unit{indx}; diff --git a/external/fieldtrip/plotting/private/ft_getopt.m b/external/fieldtrip/plotting/private/ft_getopt.m index 21ed892a..0d433115 100644 --- a/external/fieldtrip/plotting/private/ft_getopt.m +++ b/external/fieldtrip/plotting/private/ft_getopt.m @@ -8,19 +8,19 @@ % where the input values are % s = structure or cell-array % key = string -% default = any valid MATLAB data type +% default = any valid MATLAB data type (optional, default = []) % emptymeaningful = boolean value (optional, default = 0) % -% If the key is present as field in the structure, or as key-value -% pair in the cell-array, the corresponding value will be returned. +% If the key is present as field in the structure, or as key-value pair in the +% cell-array, the corresponding value will be returned. % -% If the key is not present, ft_getopt will return an empty array. +% If the key is not present, ft_getopt will return the default, or an empty array +% when no default was specified. % -% If the key is present but has an empty value, then the emptymeaningful -% flag specifies whether the empty value or the default value should -% be returned. If emptymeaningful==true, then an empty array will be -% returned. If emptymeaningful==false, then the specified default will -% be returned. +% If the key is present but has an empty value, then the emptymeaningful flag +% specifies whether the empty value or the default value should be returned. +% If emptymeaningful==true, then the empty array will be returned. +% If emptymeaningful==false, then the specified default will be returned. % % See also FT_SETOPT, FT_CHECKOPT @@ -60,27 +60,27 @@ else val = opt.(key); end - + elseif isa(opt, 'cell') % get the key-value from the cell-array if mod(length(opt),2) error('optional input arguments should come in key-value pairs, i.e. there should be an even number'); end - + % the 1st, 3rd, etc. contain the keys, the 2nd, 4th, etc. contain the values keys = opt(1:2:end); vals = opt(2:2:end); - + % the following may be faster than cellfun(@ischar, keys) valid = false(size(keys)); for i=1:numel(keys) valid(i) = ischar(keys{i}); end - + if ~all(valid) error('optional input arguments should come in key-value pairs, the optional input argument %d is invalid (should be a string)', i); end - + hit = find(strcmpi(key, keys)); if isempty(hit) % the requested key was not found @@ -91,7 +91,7 @@ else error('multiple input arguments with the same name'); end - + elseif isempty(opt) % no options are specified, return default val = default; diff --git a/external/fieldtrip/plotting/private/ft_notification.m b/external/fieldtrip/plotting/private/ft_notification.m new file mode 100644 index 00000000..dc9b7369 --- /dev/null +++ b/external/fieldtrip/plotting/private/ft_notification.m @@ -0,0 +1,482 @@ +function [varargout] = ft_notification(varargin) + +% FT_NOTIFICATION works mostly like the WARNING and ERROR commands in MATLAB and +% is called by FT_ERROR, FT_WARNING, FT_NOTICE, FT_INFO, FT_DEBUG. Note that you +% should not call this function directly. +% +% Some examples: +% ft_info on +% ft_info on msgId +% ft_info off +% ft_info off msgId +% ft_info once +% ft_info once msgId +% ft_info on backtrace +% ft_info off backtrace +% ft_info on verbose +% ft_info off verbose +% +% ft_info query % shows the status of all notifications +% ft_info last % shows the last notification +% ft_info clear % clears the status of all notifications +% ft_info timeout 10 % sets the timeout (for 'once') to 10 seconds +% +% See also DEFAULTID + +% Copyright (C) 2012-2017, Robert Oostenveld, J?rn M. Horschig +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +global ft_default + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% determine who is calling + +stack = dbstack('-completenames'); +% st(1) is this function +% st(2) is the calling function +switch stack(2).name + case 'ft_debug' + level = 'debug'; + case 'ft_info' + level = 'info'; + case 'ft_notice' + level = 'notice'; + case 'ft_warning' + level = 'warning'; + case 'ft_error' + level = 'error'; + otherwise + error('this function cannot be called from %s', stack(2).name); +end + +% remove this function itself and the ft_xxx calling function +stack = stack(3:end); + +% remove the non-FieldTrip functions from the path, these should not be part of the default message identifier +keep = true(size(stack)); +p = fileparts(which('ft_defaults')); +for i=1:numel(stack) + keep(i) = strncmp(p, stack(i).file, length(p)); +end +stack = stack(keep); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% handle the defaults + +if isfield(ft_default, 'notification') && isfield(ft_default.notification, level) + % this would be error, warning, notice, info, debug + s = ft_default.notification.(level); +else + s = []; +end + +% start with an empty state structure +if isempty(s) + s = struct('identifier', {}, 'state', {}, 'timestamp', {}); +end + +% set the default notification state +if ~ismember('all', {s.identifier}) + s = setstate(s, 'all', 'on'); +end + +% set the default backtrace state +defaultbacktrace = false; +if ~ismember('backtrace', {s.identifier}) + switch level + case {'debug' 'info' 'notice'} + s = setstate(s, 'backtrace', 'off'); + case 'warning' + defaultbacktrace = true; + t = warning('query', 'backtrace'); % get the default state + s = setstate(s, 'backtrace', t.state); + case 'error' + s = setstate(s, 'backtrace', 'on'); + end % switch +end + +% set the default verbose state +defaultverbose = false; +if ~ismember('verbose', {s.identifier}) + switch level + case 'warning' + defaultverbose = true; + t = warning('query', 'verbose');% get the default state + s = setstate(s, 'verbose', t.state); + otherwise + s = setstate(s, 'verbose', 'off'); + end +end + +% set the default timeout +if ~ismember('timeout', {s.identifier}) + s = setstate(s, 'timeout', 60); +end + +% set the last notification to empty +if ~ismember('last', {s.identifier}) + state.message = ''; + state.identifier = ''; + state.stack = struct('file', {}, 'name', {}, 'line', {}); + s = setstate(s, 'last', state); +end + +if strcmp(level, 'warning') + ws = warning; + % warnings should be on in general + warning on + % the backtrace is handled by this function + warning off backtrace + % the verbose message is handled by this function + warning off verbose +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% set the notification state according to the input + +if numel(varargin)>0 && (isstruct(varargin{1}) || isempty(varargin{1})) + ft_default.notification.(level) = varargin{1}; + return +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% act according to the first input argument + +if isempty(varargin) + varargin{1} = 'query'; +end + +switch varargin{1} + case 'on' + if numel(varargin)>1 + % switch a specific item on + msgId = varargin{2}; + s = setstate(s, msgId, 'on'); + if strcmp(msgId, 'backtrace') + defaultbacktrace = false; + end + if strcmp(msgId, 'verbose') + defaultverbose = false; + end + % return the message state of all + varargout{1} = getreturnstate(s, msgId); + else + % switch all on + s = setstate(s, 'all', 'on'); + % return the message state of all + varargout{1} = getreturnstate(s); + end + + case 'off' + if numel(varargin)>1 + % switch a specific item off + msgId = varargin{2}; + s = setstate(s, msgId, 'off'); + if strcmp(msgId, 'backtrace') + defaultbacktrace = false; + end + if strcmp(msgId, 'verbose') + defaultverbose = false; + end + % return the specific message state + varargout{1} = getreturnstate(s, msgId); + else + % switch all off + s = setstate(s, 'all', 'off'); + % return the message state of all + varargout{1} = getreturnstate(s); + end + + case 'once' + if numel(varargin)>1 + % switch a specific item to once + msgId = varargin{2}; + s = setstate(s, msgId, 'once'); + % return the specific message state + varargout{1} = getreturnstate(s, msgId); + else + % switch all to once + s = setstate(s, 'all', 'once'); + % return the message state of all + varargout{1} = getreturnstate(s); + end + + case 'timeout' + % set the timeout, this is used for 'once' + if ischar(varargin{2}) + s = setstate(s, 'timeout', str2double(varargin{2})); + else + s = setstate(s, 'timeout', varargin{2}); + end + + case {'last' '-last'} + % return the last notification + varargout{1} = getstate(s, 'last'); + + case {'clear' '-clear'} + % reset the notification system + s = []; + + case {'query' '-query'} + if numel(varargin)>1 + % select a specific item + msgId = varargin{2}; + if ~ismember(msgId, {s.identifier}) + error('Unknown setting or incorrect message identifier ''%s''.', msgId); + end + msgState = getstate(s, msgId); + if nargout + varargout{1} = getreturnstate(s, msgId); + elseif strcmp(msgId, 'verbose') + if istrue(msgState) + fprintf('%s output is verbose.\n', level); + else + fprintf('%s output is terse.\n', level); + end + elseif strcmp(msgId, 'backtrace') + if istrue(msgState) + fprintf('%s backtraces are enabled.\n', level); + else + fprintf('%s backtraces are disabled.\n', level); + end + else + fprintf('The state of %s ''%s'' is ''%s''\n', level, msgId, msgState); + end + else + % return all items + r = getreturnstate(s); + + if nargout + % return the state of all items + varargout{1} = r; + else + % show the state of all items that are different from the default + default = getstate(s, 'all'); + fprintf('The default %s state is ''%s''.', level, default); + r = r(~strcmp({r.state}, default)); + % don't show these + r(strcmp('verbose', {r.identifier})) = []; + r(strcmp('backtrace', {r.identifier})) = []; + if ~isempty(r) + fprintf(' Items not set to the default are\n\n'); + end + for i=1:numel(r) + fprintf(' %4s %s\n', r(i).state, r(i).identifier); + end + fprintf('\n'); + end + end + + otherwise + + if nargout + varargout{1} = getreturnstate(s); + end + + % first input might be msgId + if numel(varargin)>1 && ~isempty(regexp(varargin{1}, '^\w*:', 'once')) + msgId = varargin{1}; + varargin = varargin(2:end); % shift them all by one + else + msgId = defaultId; + end + + % get the state for this notification, it will default to the 'all' state + msgState = getstate(s, msgId); + + % errors are always to be printed + if strcmp(level, 'error') + msgState = 'on'; + end + + if strcmp(msgState, 'once') + timeout = getstate(s, 'timeout'); + since = elapsed(gettimestamp(s, msgId)); + if (since>timeout) + % the timeout has passed, update the timestamp and print the message + s = settimestamp(s, msgId, tic); + msgState = 'on'; + else + % the timeout has not yet passed, do not print the message + msgState = 'off'; + end + end + + % use an automatically generated default identifier + if isempty(msgId) + msgId = defaultId; + end + + % store the last notification + state.message = strtrim(sprintf(varargin{:})); % remove the trailing newline + state.identifier = msgId; + state.stack = stack; + s = setstate(s, 'last', state); + + if strcmp(msgState, 'on') + + if strcmp(level, 'error') + % update the global variable, we won't return here after the error + ft_default.notification.(level) = s; + % the remainder is fully handled by the ERROR function + if ~isempty(msgId) + error(msgId, varargin{:}); + else + error(varargin{:}); + end + + elseif strcmp(level, 'warning') + if ~isempty(msgId) + warning(msgId, varargin{:}); + else + warning(varargin{:}); + end + + else + % ensure there is a line end + if isempty(regexp(varargin{1}, '\\n$', 'once')) % note the double \\ + varargin{1} = [varargin{1} '\n']; + end + fprintf(varargin{:}); + + end % if level=error, warning or otherwise + + % decide whether the stack trace should be shown + if istrue(getstate(s, 'backtrace')) + for i=1:numel(stack) + % show the deepest and lowest-level function first + [p, f, x] = fileparts(stack(i).file); + if isequal(f, stack(i).name) + funname = stack(i).name; + else + funname = sprintf('%s>%s', f, stack(i).name); + end + filename = stack(i).file; + if isempty(fileparts(filename)) + % it requires the full path + filename = fullfile(pwd, filename); + end + if ft_platform_supports('html') + fprintf(' In %s at line %d\n', filename, stack(i).line, funname, stack(i).line); + else + fprintf(' In ''%s'' at line %d\n', filename, stack(i).line); + end + end + fprintf('\n'); + end + + % decide whether a verboe message should be shown + if istrue(getstate(s, 'verbose')) + if ~isempty(msgId) + fprintf('Type "ft_%s off %s" to suppress this message.\n', level, msgId) + else + fprintf('Type "ft_%s off" to suppress this message.\n', level) + end + end + + end % if msgState is on + +end % switch varargin{1} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% update the global variable +if defaultbacktrace && ~isempty(s) + % do not keep the default, it will be determined again on the next call + s = s(~strcmp({s.identifier}, 'backtrace')); +end +if defaultverbose && ~isempty(s) + % do not keep the default, it will be determined again on the next call + s = s(~strcmp({s.identifier}, 'verbose')); +end +ft_default.notification.(level) = s; + +if strcmp(level, 'warning') + % return to the original warning state + warning(ws); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTIONS +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +function r = getreturnstate(s, msgId) +if nargin<2 + r = s; + % don't return these + r(strcmp('timeout', {r.identifier})) = []; + r(strcmp('last', {r.identifier})) = []; + % don't return the timestamps + r = rmfield(r, 'timestamp'); +else + msgState = getstate(s, msgId); + r = struct('identifier', msgId, 'state', msgState); +end + +function state = getstate(s, msgId) +identifier = {s.identifier}; +sel = find(strcmp(identifier, msgId)); +if numel(sel)==1 + state = s(sel).state; + if isempty(state) + state = getstate(s, 'all'); + end +else + state = getstate(s, 'all'); +end + +function timestamp = gettimestamp(s, msgId) +identifier = {s.identifier}; +sel = find(strcmp(identifier, msgId)); +if numel(sel)==1 + timestamp = s(sel).timestamp; +else + timestamp = nan; +end + +function s = setstate(s, msgId, state) +if isempty(msgId), return; end % this happens from the command line +identifier = {s.identifier}; +sel = find(strcmp(identifier, msgId)); +if numel(sel)==1 + s(sel).state = state; +else + s(end+1).identifier = msgId; + s(end ).state = state; + s(end ).timestamp = nan; +end + +function s = settimestamp(s, msgId, timestamp) +if isempty(msgId), return; end % this happens from the command line +identifier = {s.identifier}; +sel = find(strcmp(identifier, msgId)); +if numel(sel)==1 + s(sel).timestamp = timestamp; +else + s(end+1).identifier = msgId; + s(end ).state = []; + s(end ).timestamp = timestamp; +end + +function t = elapsed(start) +if isempty(start) || isnan(start) + t = inf; +else + t = toc(start); +end diff --git a/external/fieldtrip/plotting/private/ft_platform_supports.m b/external/fieldtrip/plotting/private/ft_platform_supports.m index 0770d385..c0676b62 100644 --- a/external/fieldtrip/plotting/private/ft_platform_supports.m +++ b/external/fieldtrip/plotting/private/ft_platform_supports.m @@ -3,41 +3,43 @@ % FT_PLATFORM_SUPPORTS returns a boolean indicating whether the current platform % supports a specific capability % -% Usage: -% tf = ft_platform_supports(what) -% tf = ft_platform_supports('matlabversion', min_version, max_version) +% Use as +% status = ft_platform_supports(what) +% or +% status = ft_platform_supports('matlabversion', min_version, max_version) % -% The following values are allowed for the 'what' parameter: -% value means that the following is supported: +% The following values are allowed for the 'what' parameter, which means means that +% the specific feature explained on the right is supported: % % 'which-all' which(...,'all') -% 'exists-in-private-directory' exists(...) will look in the /private -% subdirectory to see if a file exists +% 'exists-in-private-directory' exists(...) will look in the /private subdirectory to see if a file exists % 'onCleanup' onCleanup(...) % 'alim' alim(...) % 'int32_logical_operations' bitand(a,b) with a, b of type int32 % 'graphics_objects' graphics sysem is object-oriented -% 'libmx_c_interface' libmx is supported through mex in the -% C-language (recent Matlab versions only -% support C++) -% 'stats' all statistical functions in -% FieldTrip's external/stats directory +% 'libmx_c_interface' libmx is supported through mex in the C-language (recent MATLAB versions only support C++) +% 'images' all image processing functions in FieldTrip's external/images directory +% 'signal' all signal processing functions in FieldTrip's external/signal directory +% 'stats' all statistical functions in FieldTrip's external/stats directory % 'program_invocation_name' program_invocation_name() (GNU Octave) -% 'singleCompThread' start Matlab with -singleCompThread -% 'nosplash' -nosplash -% 'nodisplay' -nodisplay -% 'nojvm' -nojvm +% 'singleCompThread' start MATLAB with -singleCompThread +% 'nosplash' start MATLAB with -nosplash +% 'nodisplay' start MATLAB with -nodisplay +% 'nojvm' start MATLAB with -nojvm % 'no-gui' start GNU Octave with --no-gui % 'RandStream.setGlobalStream' RandStream.setGlobalStream(...) % 'RandStream.setDefaultStream' RandStream.setDefaultStream(...) % 'rng' rng(...) % 'rand-state' rand('state') % 'urlread-timeout' urlread(..., 'Timeout', t) -% 'griddata-vector-input' griddata(...,...,...,a,b) with a and b -% vectors -% 'griddata-v4' griddata(...,...,...,...,...,'v4'), -% that is v4 interpolation support +% 'griddata-vector-input' griddata(...,...,...,a,b) with a and b vectors +% 'griddata-v4' griddata(...,...,...,...,...,'v4') with v4 interpolation support % 'uimenu' uimenu(...) +% 'weboptions' weboptions(...) +% 'parula' parula(...) +% 'html' html rendering in desktop +% +% See also FT_VERSION, VERSION, VER, VERLESSTHAN if ~ischar(what) error('first argument must be a string'); @@ -60,30 +62,42 @@ tf = is_matlab(); case 'int32_logical_operations' - % earlier version of Matlab don't support bitand (and similar) + % earlier version of MATLAB don't support bitand (and similar) % operations on int32 - tf = is_octave() || ~matlabversion(-inf, '2012a'); + tf = is_octave() || ~matlabversion(-Inf, '2012a'); case 'graphics_objects' - % introduced in Matlab 2014b, graphics is handled through objects; + % introduced in MATLAB 2014b, graphics is handled through objects; % previous versions use numeric handles tf = is_matlab() && matlabversion('2014b', Inf); case 'libmx_c_interface' % removed after 2013b - tf = matlabversion(-Inf, '2013b'); + tf = is_matlab() && matlabversion(-Inf, '2013b'); + + case 'images' + root_dir = fileparts(which('ft_defaults')); + external_stats_dir = fullfile(root_dir, 'external', 'images'); + + tf = has_all_functions_in_dir(external_stats_dir, {}); + + case 'signal' + root_dir = fileparts(which('ft_defaults')); + external_stats_dir = fullfile(root_dir, 'external', 'signal'); + + tf = has_all_functions_in_dir(external_stats_dir, {}); case 'stats' - root_dir=fileparts(which('ft_defaults')); - external_stats_dir=fullfile(root_dir,'external','stats'); + root_dir = fileparts(which('ft_defaults')); + external_stats_dir = fullfile(root_dir, 'external', 'stats'); - % these files are only used by other functions in the external/stats - % directory - exclude_mfiles={'common_size.m',... - 'iscomplex.m',... - 'lgamma.m'}; + % these files are only used by other functions in the external/stats directory + exclude_mfiles = { + 'common_size.m' + 'iscomplex.m' + }; - tf = has_all_functions_in_dir(external_stats_dir,exclude_mfiles); + tf = has_all_functions_in_dir(external_stats_dir, exclude_mfiles); case 'program_invocation_name' % Octave supports program_invocation_name, which returns the path @@ -91,10 +105,10 @@ tf = is_octave(); case 'singleCompThread' - tf = is_matlab() && matlabversion(7.8, inf); + tf = is_matlab() && matlabversion(7.8, Inf); - case {'nosplash','nodisplay','nojvm'} - % Only on Matlab + case {'nosplash', 'nodisplay', 'nojvm'} + % Only on MATLAB tf = is_matlab(); case 'no-gui' @@ -105,31 +119,46 @@ tf = is_matlab() && matlabversion('2008b', '2011b'); case 'RandStream.setGlobalStream' - tf = is_matlab() && matlabversion('2012a', inf); + tf = is_matlab() && matlabversion('2012a', Inf); case 'randomized_PRNG_on_startup' - tf = is_octave() || ~matlabversion(-Inf,'7.3'); + tf = is_octave() || ~matlabversion(-Inf, '7.3'); case 'rng' - % recent Matlab versions - tf = is_matlab() && matlabversion('7.12',Inf); + % recent MATLAB versions + tf = is_matlab() && matlabversion('7.12', Inf); case 'rand-state' % GNU Octave tf = is_octave(); case 'urlread-timeout' - tf = is_matlab() && matlabversion('2012b',Inf); + tf = is_matlab() && matlabversion('2012b', Inf); case 'griddata-vector-input' tf = is_matlab(); case 'griddata-v4' - tf = is_matlab() && matlabversion('2009a',Inf); + tf = is_matlab() && matlabversion('2009a', Inf); case 'uimenu' tf = is_matlab(); + case {'weboptions', 'webread', 'websave'} + tf = is_matlab() && matlabversion('2014b', Inf); + + case 'webwrite' + tf = is_matlab() && matlabversion('2015a', Inf); + + case 'boundary' + tf = is_matlab() && matlabversion('2014b', Inf); + + case 'parula' + tf = is_matlab() && matlabversion('2014b', Inf); + + case 'html' + tf = ~is_octave() && usejava('desktop') && desktop('-inuse'); + otherwise error('unsupported value for first argument: %s', what); @@ -148,7 +177,7 @@ % SUBFUNCTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function tf = is_octave() -persistent cached_tf; +persistent cached_tf if isempty(cached_tf) cached_tf = logical(exist('OCTAVE_VERSION', 'builtin')); @@ -161,21 +190,19 @@ % SUBFUNCTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function tf = has_all_functions_in_dir(in_dir, exclude_mfiles) -% returns true if all functions in in_dir are already provided by the -% platform -m_files=dir(fullfile(in_dir,'*.m')); -n=numel(m_files); +% returns true if all functions in in_dir are already provided by the platform +m_files = dir(fullfile(in_dir,'*.m')); +n = numel(m_files); -for k=1:n - m_filename=m_files(k).name; - if isempty(which(m_filename)) && ... - isempty(strmatch(m_filename,exclude_mfiles)) - tf=false; +for k = 1:n + m_filename = m_files(k).name; + if isempty(which(m_filename)) && isempty(strmatch(m_filename,exclude_mfiles)) + tf = false; return; end end -tf=true; +tf = true; end % function @@ -187,19 +214,19 @@ % MATLABVERSION checks if the current MATLAB version is within the interval % specified by min and max. % -% Use, e.g., as: -% if matlabversion(7.0, 7.9) -% % do something -% end +% Use as +% if matlabversion(7.0, 7.9) +% % do something +% end % % Both strings and numbers, as well as infinities, are supported, eg.: -% matlabversion(7.1, 7.9) % is version between 7.1 and 7.9? -% matlabversion(6, '7.10') % is version between 6 and 7.10? (note: '7.10', not 7.10) -% matlabversion(-Inf, 7.6) % is version <= 7.6? -% matlabversion('2009b') % exactly 2009b -% matlabversion('2008b', '2010a') % between two versions -% matlabversion('2008b', Inf) % from a version onwards -% etc. +% matlabversion(7.1, 7.9) % is version between 7.1 and 7.9? +% matlabversion(6, '7.10') % is version between 6 and 7.10? (note: '7.10', not 7.10) +% matlabversion(-Inf, 7.6) % is version <= 7.6? +% matlabversion('2009b') % exactly 2009b +% matlabversion('2008b', '2010a') % between two versions +% matlabversion('2008b', Inf) % from a version onwards +% etc. % % See also VERSION, VER, VERLESSTHAN @@ -209,22 +236,22 @@ % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. % -% FieldTrip is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. % -% FieldTrip is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. % -% You should have received a copy of the GNU General Public License -% along with FieldTrip. If not, see . +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . % % $Id$ -% this does not change over subsequent calls, making it persistent speeds it up +% the version does not change, making it persistent speeds up the subsequent calls persistent curVer if nargin<2 @@ -245,7 +272,9 @@ [maxY, maxAb] = parseMatlabRelease(max); inInterval = orderedComparison(minY, minAb, maxY, maxAb, year, ab); -else % perform comparison with respect to version number + +else + % perform comparison with respect to version number [major, minor] = parseMatlabVersion(curVer); [minMajor, minMinor] = parseMatlabVersion(min); [maxMajor, maxMinor] = parseMatlabVersion(max); @@ -255,6 +284,9 @@ end % function +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function [year, ab] = parseMatlabRelease(str) if (str == Inf) year = Inf; ab = Inf; @@ -266,6 +298,9 @@ end end % function +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function [major, minor] = parseMatlabVersion(ver) if (ver == Inf) major = Inf; minor = Inf; @@ -279,10 +314,13 @@ major = str2num(major); minor = str2num(strtok(rest, '.')); end -end % function +end % function -% checks if testA is in interval (lowerA,upperA); if at edges, checks if testB is in interval (lowerB,upperB). +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function inInterval = orderedComparison(lowerA, lowerB, upperA, upperB, testA, testB) +% checks if testA is in interval (lowerA,upperA); if at edges, checks if testB is in interval (lowerB,upperB). if (testA < lowerA || testA > upperA) inInterval = false; else @@ -295,5 +333,4 @@ inInterval = inInterval && (testB <= upperB); end end -end % function - +end % function diff --git a/external/fieldtrip/plotting/private/ft_progress.m b/external/fieldtrip/plotting/private/ft_progress.m index 559686aa..d7dce75e 100644 --- a/external/fieldtrip/plotting/private/ft_progress.m +++ b/external/fieldtrip/plotting/private/ft_progress.m @@ -27,6 +27,8 @@ function ft_progress(varargin) % pause(0.1); % end % ft_progress('close') +% +% See also WAITBAR % Copyright (C) 2004-2008, Robert Oostenveld % diff --git a/external/fieldtrip/plotting/private/ft_scalingfactor.m b/external/fieldtrip/plotting/private/ft_scalingfactor.m index 804871df..ad7a8512 100644 --- a/external/fieldtrip/plotting/private/ft_scalingfactor.m +++ b/external/fieldtrip/plotting/private/ft_scalingfactor.m @@ -87,7 +87,7 @@ end if ~isequal(class(old), class(new)) - error('the input arguments should be of the same class'); + ft_error('the input arguments should be of the same class'); end if iscell(old) @@ -178,7 +178,7 @@ eval(sprintf('oldunit = %s;', old)); eval(sprintf('newunit = %s;', new)); if ~isequal(oldunit, newunit) - error('cannot convert %s to %s', old, new); + ft_error('cannot convert %s to %s', old, new); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/external/fieldtrip/plotting/private/ft_senslabel.m b/external/fieldtrip/plotting/private/ft_senslabel.m index 4ab57989..85e062af 100644 --- a/external/fieldtrip/plotting/private/ft_senslabel.m +++ b/external/fieldtrip/plotting/private/ft_senslabel.m @@ -87,7 +87,7 @@ output = ft_getopt(varargin, 'output', 'normal'); % 'normal' or 'planarcombined' if ~exist(type, 'var') - error('the requested sensor type "%s" is not supported', type); + ft_error('the requested sensor type "%s" is not supported', type); elseif isempty(eval(type)) % assign the list of channels only once, keep it as persistent variable @@ -3673,7 +3673,7 @@ label = ft_senslabel(type); otherwise - error('the requested sensor type "%s" is not supported', type); + ft_error('the requested sensor type "%s" is not supported', type); end % switch @@ -3700,6 +3700,6 @@ label = [planar(:,1:2) combined]; % magnetometers are in the 3rd column for neuromag306 otherwise - error('unsupported output "%s"', output); + ft_error('unsupported output "%s"', output); end diff --git a/external/fieldtrip/plotting/private/ft_senstype.m b/external/fieldtrip/plotting/private/ft_senstype.m index 1d91722d..b6753338 100644 --- a/external/fieldtrip/plotting/private/ft_senstype.m +++ b/external/fieldtrip/plotting/private/ft_senstype.m @@ -43,18 +43,27 @@ % 'biosemi64' % 'biosemi128' % 'biosemi256' +% 'ant128' % 'neuralynx' % 'plexon' % 'artinis' -% 'ext1020' this includes eeg1020, eeg1010 and eeg1005 -% 'eeg' this was called 'electrode' in older versions -% 'meg' this was called 'magnetometer' in older versions % 'nirs' +% 'meg' +% 'eeg' +% 'ieeg' +% 'seeg' +% 'ecog' +% 'eeg1020' +% 'eeg1010' +% 'eeg1005' +% 'ext1020' in case it is a small subset of eeg1020, eeg1010 or eeg1005 % % The optional input argument for the desired type can be any of the above, or any of % the following generic classes of acquisition systems % 'eeg' +% 'ieeg' % 'ext1020' +% 'ant' % 'biosemi' % 'egi' % 'meg' @@ -81,7 +90,7 @@ % % See also FT_SENSLABEL, FT_CHANTYPE, FT_READ_SENS, FT_COMPUTE_LEADFIELD, FT_DATATYPE_SENS -% Copyright (C) 2007-2016, Robert Oostenveld +% Copyright (C) 2007-2017, Robert Oostenveld % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -146,7 +155,8 @@ iselec = (isa(input, 'struct') && isfield(input, 'label') && isfield(input, 'elecpos')) || iselec; % new style isnirs = isa(input, 'struct') && isfield(input, 'label') && isfield(input, 'transceiver'); islabel = isa(input, 'cell') && ~isempty(input) && isa(input{1}, 'char'); -haslabel = isa(input, 'struct') && isfield(input, 'label'); +haslabel = isa(input, 'struct') && isfield(input, 'label'); +haschantype = isa(input, 'struct') && isfield(input, 'chantype'); if ~(isdata || isheader || isgrad || iselec || isnirs || islabel || haslabel) && isfield(input, 'hdr') input = input.hdr; @@ -211,8 +221,8 @@ elseif haslabel % it does not resemble anything that we had expected at this location, but it does have channel labels % the channel labels can be used to determine the type of sensor array - sens.label = input.label; - islabel = true; + sens = keepfields(input, {'label' 'chantype'}); + islabel = true; else sens = []; @@ -265,21 +275,18 @@ % start with unknown, then try to determine the proper type by looking at the labels type = 'unknown'; - if isgrad && isfield(sens, 'type') - type = sens.type; - - elseif isgrad + if isgrad % this looks like MEG + % revert the component balancing that was previously applied if isfield(sens, 'balance') && strcmp(sens.balance.current, 'comp') sens = undobalancing(sens); end - % determine the type of magnetometer/gradiometer system based on the channel names alone + % determine the particular type of acquisition system based on the channel names alone % this uses a recursive call to the "islabel" section further down type = ft_senstype(sens.label); - %sens_temp.type = type; - if strcmp(type, 'unknown') %|| ~ft_senstype(sens_temp,'meg') + if strcmp(type, 'unknown') % although we don't know the type, we do know that it is MEG type = 'meg'; end @@ -287,24 +294,33 @@ elseif iselec % this looks like EEG - % determine the type of eeg/acquisition system based on the channel names alone + % determine the particular type of acquisition system based on the channel names alone % this uses a recursive call to the "islabel" section further down type = ft_senstype(sens.label); - %sens_temp.type = type; - if strcmp(type, 'unknown') %|| ~ft_senstype(sens_temp,'eeg') - % although we don't know the type, we do know that it is EEG - type = 'eeg'; + if strcmp(type, 'unknown') + % although we don't know the type, we do know that it is EEG, IEEG, SEEG, or ECOG + if haschantype && all(strcmp(sens.chantype, 'eeg')) + type = 'eeg'; + elseif haschantype && all(strcmp(sens.chantype, 'seeg')) + type = 'seeg'; + elseif haschantype && all(strcmp(sens.chantype, 'ecog')) + type = 'ecog'; + elseif haschantype && all(ismember(sens.chantype, {'ieeg' 'seeg' 'ecog'})) + type = 'ieeg'; + else + % fall back to the most generic description + type = 'eeg'; + end end elseif isnirs % this looks like NIRS - % determine the type of eeg/acquisition system based on the channel names alone + % determine the particular type of acquisition system based on the channel names alone % this uses a recursive call to the "islabel" section further down type = ft_senstype(sens.label); - %sens_temp.type = type; - if strcmp(type, 'unknown') %|| ~ft_senstype(sens_temp,'eeg') - % although we don't know the type, we do know that it is EEG + if strcmp(type, 'unknown') + % although we don't know the type, we do know that it is NIRS type = 'nirs'; end @@ -382,7 +398,7 @@ elseif (mean(ismember(ft_senslabel('egi32'), sens.label)) > 0.8) type = 'egi32'; - % the following check on the fraction of channels in the user's data rather than on the fraction of channels in the predefined set + % the following check looks at the fraction of channels in the user's data rather than the fraction in the predefined set elseif (mean(ismember(sens.label, ft_senslabel('eeg1020'))) > 0.8) type = 'eeg1020'; elseif (mean(ismember(sens.label, ft_senslabel('eeg1010'))) > 0.8) @@ -390,12 +406,14 @@ elseif (mean(ismember(sens.label, ft_senslabel('eeg1005'))) > 0.8) type = 'eeg1005'; - elseif (sum(ismember(sens.label, ft_senslabel('eeg1005'))) > 10) % Otherwise it's not even worth recognizing + % the following check looks at the fraction of channels in the user's data rather than the fraction in the predefined set + % there is a minumum number of channels, otherwise it is not worth recognizing + elseif (sum(ismember(sens.label, ft_senslabel('eeg1005'))) > 10) type = 'ext1020'; % this will also cover small subsets of eeg1020, eeg1010 and eeg1005 - elseif any(ismember(ft_senslabel('btiref'), sens.label)) - type = 'bti'; % it might be 148 or 248 channels - elseif any(ismember(ft_senslabel('ctfref'), sens.label)) - type = 'ctf'; % it might be 151 or 275 channels + elseif (sum(ismember(ft_senslabel('btiref'), sens.label)) > 10) + type = 'bti'; % 23 in the reference set, it might be 148 or 248 channels + elseif (sum(ismember(ft_senslabel('ctfref'), sens.label)) > 10) + type = 'ctf'; % 29 in the reference set, it might be 151 or 275 channels end end % look at label, ori and/or pos @@ -432,26 +450,30 @@ if ~isempty(desired) % return a boolean flag switch desired + case {'eeg'} + type = any(strcmp(type, {'eeg' 'ieeg' 'seeg' 'ecog' 'ant128' 'biosemi64' 'biosemi128' 'biosemi256' 'egi32' 'egi64' 'egi128' 'egi256' 'ext1020' 'eeg1005' 'eeg1010' 'eeg1020'})); case 'ext1020' - type = any(strcmp(type, {'eeg1005' 'eeg1010' 'eeg1020' 'ext1020'})); - case {'eeg' 'electrode'} - type = any(strcmp(type, {'eeg' 'electrode' 'ant128' 'biosemi64' 'biosemi128' 'biosemi256' 'egi32' 'egi64' 'egi128' 'egi256' 'eeg1005' 'eeg1010' 'eeg1020' 'ext1020'})); + type = any(strcmp(type, {'ext1020' 'eeg1005' 'eeg1010' 'eeg1020'})); + case {'ieeg'} + type = any(strcmp(type, {'ieeg' 'seeg' 'ecog'})); + case 'ant' + type = any(strcmp(type, {'ant' 'ant128'})); case 'biosemi' - type = any(strcmp(type, {'biosemi64' 'biosemi128' 'biosemi256'})); + type = any(strcmp(type, {'biosemi' 'biosemi64' 'biosemi128' 'biosemi256'})); case 'egi' - type = any(strcmp(type, {'egi32' 'egi64' 'egi128' 'egi256'})); + type = any(strcmp(type, {'egi' 'egi32' 'egi64' 'egi128' 'egi256'})); case 'meg' - type = any(strcmp(type, {'meg' 'magnetometer' 'ctf' 'bti' 'ctf64' 'ctf151' 'ctf275' 'ctf151_planar' 'ctf275_planar' 'neuromag122' 'neuromag306' 'neuromag306_combined' 'bti148' 'bti148_planar' 'bti248' 'bti248_planar' 'bti248grad' 'bti248grad_planar' 'yokogawa9' 'yokogawa160' 'yokogawa160_planar' 'yokogawa64' 'yokogawa64_planar' 'yokogawa440' 'itab' 'itab28' 'itab153' 'itab153_planar'})); + type = any(strcmp(type, {'meg' 'ctf' 'ctf64' 'ctf151' 'ctf275' 'ctf151_planar' 'ctf275_planar' 'neuromag' 'neuromag122' 'neuromag306' 'neuromag306_combined' 'bti' 'bti148' 'bti148_planar' 'bti248' 'bti248_planar' 'bti248grad' 'bti248grad_planar' 'yokogawa' 'yokogawa9' 'yokogawa160' 'yokogawa160_planar' 'yokogawa64' 'yokogawa64_planar' 'yokogawa440' 'itab' 'itab28' 'itab153' 'itab153_planar' 'babysquid' 'babysquid74' 'artenis123' 'magview'})); case 'ctf' type = any(strcmp(type, {'ctf' 'ctf64' 'ctf151' 'ctf275' 'ctf151_planar' 'ctf275_planar'})); case 'bti' type = any(strcmp(type, {'bti' 'bti148' 'bti148_planar' 'bti248' 'bti248_planar' 'bti248grad' 'bti248grad_planar'})); case 'neuromag' - type = any(strcmp(type, {'neuromag122' 'neuromag306'})); + type = any(strcmp(type, {'neuromag' 'neuromag122' 'neuromag306'})); case 'babysquid' - type = any(strcmp(type, {'babysquid74' 'artenis123' 'magview'})); + type = any(strcmp(type, {'babysquid' 'babysquid74' 'artenis123' 'magview'})); case 'yokogawa' - type = any(strcmp(type, {'yokogawa160' 'yokogawa160_planar' 'yokogawa64' 'yokogawa64_planar' 'yokogawa440'})); + type = any(strcmp(type, {'yokogawa' 'yokogawa160' 'yokogawa160_planar' 'yokogawa64' 'yokogawa64_planar' 'yokogawa440'})); case 'itab' type = any(strcmp(type, {'itab' 'itab28' 'itab153' 'itab153_planar'})); case 'meg_axial' diff --git a/external/fieldtrip/plotting/private/ft_warning.m b/external/fieldtrip/plotting/private/ft_warning.m index 18b0ce00..58f3985e 100644 --- a/external/fieldtrip/plotting/private/ft_warning.m +++ b/external/fieldtrip/plotting/private/ft_warning.m @@ -1,39 +1,40 @@ -function [ws, warned] = ft_warning(varargin) +function varargout = ft_warning(varargin) -% FT_WARNING will throw a warning for every unique point in the -% stacktrace only, e.g. in a for-loop a warning is thrown only once. +% FT_WARNING prints a warning message on screen, depending on the verbosity +% settings of the calling high-level FieldTrip function. This function works +% similar to the standard WARNING function, but also features the "once" mode. % -% Use as one of the following -% ft_warning(string) -% ft_warning(id, string) -% Alternatively, you can use ft_warning using a timeout -% ft_warning(string, timeout) -% ft_warning(id, string, timeout) -% where timeout should be inf if you don't want to see the warning ever -% again. +% Use as +% ft_warning(...) +% with arguments similar to fprintf, or +% ft_warning(msgId, ...) +% with arguments similar to warning. % -% Use as ft_warning('-clear') to clear old warnings from the current -% stack +% You can switch of all warning messages using +% ft_warning off +% or for specific ones using +% ft_warning off msgId % -% It can be used instead of the MATLAB built-in function WARNING, thus as -% s = ft_warning(...) -% or as -% ft_warning(s) -% where s is a structure with fields 'identifier' and 'state', storing the -% state information. In other words, ft_warning accepts as an input the -% same structure it returns as an output. This returns or restores the -% states of warnings to their previous values. +% To switch them back on, you would use +% ft_warning on +% or for specific ones using +% ft_warning on msgId +% +% Warning messages are only printed once per timeout period using +% ft_warning timeout 60 +% ft_warning once +% or for specific ones using +% ft_warning once msgId % -% It can also be used as -% [s w] = ft_warning(...) -% where w is a boolean that indicates whether a warning as been thrown or not. +% You can see the most recent messages and identifier using +% ft_warning last % -% Please note that you can NOT use it like this -% ft_warning('the value is %d', 10) -% instead you should do -% ft_warning(sprintf('the value is %d', 10)) +% You can query the current on/off/once state for all messages using +% ft_warning query +% +% See also FT_ERROR, FT_WARNING, FT_NOTICE, FT_warning, FT_DEBUG, ERROR, WARNING -% Copyright (C) 2012-2016, Robert Oostenveld, J?rn M. Horschig +% Copyright (C) 2012-2017, Robert Oostenveld, J?rn M. Horschig % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -53,205 +54,12 @@ % % $Id$ -global ft_default -warned = false; -ws = []; - -stack = dbstack; -if any(strcmp({stack(2:end).file}, 'ft_warning.m')) - % don't call FT_WARNING recursively, see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=3068 - return; -end - -if nargin < 1 - error('You need to specify at least a warning message'); -end - -if isstruct(varargin{1}) - warning(varargin{1}); - return; -end - -if ~isfield(ft_default, 'warning') - ft_default.warning = []; -end -if ~isfield(ft_default.warning, 'stopwatch') - ft_default.warning.stopwatch = []; -end -if ~isfield(ft_default.warning, 'identifier') - ft_default.warning.identifier = []; -end -if ~isfield(ft_default.warning, 'ignore') - ft_default.warning.ignore = {}; -end - -% put the arguments we will pass to warning() in this cell array -warningArgs = {}; - -if nargin==3 - % calling syntax (id, msg, timeout) - - warningArgs = varargin(1:2); - msg = warningArgs{2}; - timeout = varargin{3}; - fname = [warningArgs{1} '_' warningArgs{2}]; - -elseif nargin==2 && isnumeric(varargin{2}) - % calling syntax (msg, timeout) - - warningArgs = varargin(1); - msg = warningArgs{1}; - timeout = varargin{2}; - fname = warningArgs{1}; - -elseif nargin==2 && isequal(varargin{1}, 'off') - - ft_default.warning.ignore = union(ft_default.warning.ignore, varargin{2}); - return - -elseif nargin==2 && isequal(varargin{1}, 'on') - - ft_default.warning.ignore = setdiff(ft_default.warning.ignore, varargin{2}); - return - -elseif nargin==2 && ~isnumeric(varargin{2}) - % calling syntax (id, msg) - - warningArgs = varargin(1:2); - msg = warningArgs{2}; - timeout = inf; - fname = [warningArgs{1} '_' warningArgs{2}]; - -elseif nargin==1 - % calling syntax (msg) - - warningArgs = varargin(1); - msg = warningArgs{1}; - timeout = inf; % default timeout in seconds - fname = [warningArgs{1}]; - -end - -if ismember(msg, ft_default.warning.ignore) - % do not show this warning - return; -end - -if isempty(timeout) - error('Timeout ill-specified'); -end - -if timeout ~= inf - fname = fixname(fname); % make a nice string that is allowed as fieldname in a structures - line = []; -else - % here, we create the fieldname functionA.functionB.functionC... - [tmpfname, ft_default.warning.identifier, line] = fieldnameFromStack(ft_default.warning.identifier); - if ~isempty(tmpfname), - fname = tmpfname; - clear tmpfname; - end -end - -if nargin==1 && ischar(varargin{1}) && strcmp('-clear', varargin{1}) - if strcmp(fname, '-clear') % reset all fields if called outside a function - ft_default.warning.identifier = []; - ft_default.warning.stopwatch = []; - else - if issubfield(ft_default.warning.identifier, fname) - ft_default.warning.identifier = rmsubfield(ft_default.warning.identifier, fname); - end - end - return; -end - -% and add the line number to make this unique for the last function -fname = horzcat(fname, line); - -if ~issubfield('ft_default.warning.stopwatch', fname) - ft_default.warning.stopwatch = setsubfield(ft_default.warning.stopwatch, fname, tic); -end - -now = toc(getsubfield(ft_default.warning.stopwatch, fname)); % measure time since first function call - -if ~issubfield(ft_default.warning.identifier, fname) || ... - (issubfield(ft_default.warning.identifier, fname) && now>getsubfield(ft_default.warning.identifier, [fname '.timeout'])) - - % create or reset field - ft_default.warning.identifier = setsubfield(ft_default.warning.identifier, fname, []); - - % warning never given before or timed out - ws = warning(warningArgs{:}); - ft_default.warning.identifier = setsubfield(ft_default.warning.identifier, [fname '.timeout'], now+timeout); - ft_default.warning.identifier = setsubfield(ft_default.warning.identifier, [fname '.ws'], msg); - warned = true; +if nargout + varargout{:} = ft_notification(varargin{:}); +elseif isequal(varargin, {'last'}) + % return an answer anyway + varargout{1} = ft_notification(varargin{:}); else - - % the warning has been issued before, but has not timed out yet - ws = getsubfield(ft_default.warning.identifier, [fname '.ws']); - -end - -end % function ft_warning - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% helper functions -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -function [fname, ft_previous_warnings, line] = fieldnameFromStack(ft_previous_warnings) -% stack(1) is this function, stack(2) is ft_warning -stack = dbstack('-completenames'); -if size(stack) < 3 - fname = []; - line = []; - return; -end -i0 = 3; -% ignore ft_preamble -while strfind(stack(i0).name, 'ft_preamble') - i0=i0+1; + ft_notification(varargin{:}); end -fname = horzcat(fixname(stack(end).name)); -if ~issubfield(ft_previous_warnings, fixname(stack(end).name)) - ft_previous_warnings.(fixname(stack(end).name)) = []; % iteratively build up structure fields -end - - -for i=numel(stack)-1:-1:(i0) - % skip postamble scripts - if strncmp(stack(i).name, 'ft_postamble', 12) - break; - end - - fname = horzcat(fname, '.', horzcat(fixname(stack(i).name))); % , stack(i).file - if ~issubfield(ft_previous_warnings, fname) % iteratively build up structure fields - setsubfield(ft_previous_warnings, fname, []); - end -end - -% line of last function call -line = ['.line', int2str(stack(i0).line)]; -end - -% function outcome = issubfield(strct, fname) -% substrindx = strfind(fname, '.'); -% if numel(substrindx) > 0 -% % separate the last fieldname from all former -% outcome = eval(['isfield(strct.' fname(1:substrindx(end)-1) ', ''' fname(substrindx(end)+1:end) ''')']); -% else -% % there is only one fieldname -% outcome = isfield(strct, fname); -% end -% end - -% function strct = rmsubfield(strct, fname) -% substrindx = strfind(fname, '.'); -% if numel(substrindx) > 0 -% % separate the last fieldname from all former -% strct = eval(['rmfield(strct.' fname(1:substrindx(end)-1) ', ''' fname(substrindx(end)+1:end) ''')']); -% else -% % there is only one fieldname -% strct = rmfield(strct, fname); -% end -% end diff --git a/external/fieldtrip/plotting/private/ft_warp_apply.m b/external/fieldtrip/plotting/private/ft_warp_apply.m index 980e1b88..fa7fa903 100644 --- a/external/fieldtrip/plotting/private/ft_warp_apply.m +++ b/external/fieldtrip/plotting/private/ft_warp_apply.m @@ -102,19 +102,19 @@ s = size(M); if s(1)~=3 - error('invalid size of nonlinear transformation matrix'); + ft_error('invalid size of nonlinear transformation matrix'); elseif strcmp(method, 'nonlin0') && s(2)~=1 - error('invalid size of nonlinear transformation matrix'); + ft_error('invalid size of nonlinear transformation matrix'); elseif strcmp(method, 'nonlin1') && s(2)~=4 - error('invalid size of nonlinear transformation matrix'); + ft_error('invalid size of nonlinear transformation matrix'); elseif strcmp(method, 'nonlin2') && s(2)~=10 - error('invalid size of nonlinear transformation matrix'); + ft_error('invalid size of nonlinear transformation matrix'); elseif strcmp(method, 'nonlin3') && s(2)~=20 - error('invalid size of nonlinear transformation matrix'); + ft_error('invalid size of nonlinear transformation matrix'); elseif strcmp(method, 'nonlin4') && s(2)~=35 - error('invalid size of nonlinear transformation matrix'); + ft_error('invalid size of nonlinear transformation matrix'); elseif strcmp(method, 'nonlin5') && s(2)~=56 - error('invalid size of nonlinear transformation matrix'); + ft_error('invalid size of nonlinear transformation matrix'); end if s(2)==1 @@ -143,7 +143,7 @@ yy = M(2,1) + M(2,2)*x + M(2,3)*y + M(2,4)*z + M(2,5)*x.*x + M(2,6)*x.*y + M(2,7)*x.*z + M(2,8)*y.*y + M(2,9)*y.*z + M(2,10)*z.*z + M(2,11)*x.*x.*x + M(2,12)*x.*x.*y + M(2,13)*x.*x.*z + M(2,14)*x.*y.*y + M(2,15)*x.*y.*z + M(2,16)*x.*z.*z + M(2,17)*y.*y.*y + M(2,18)*y.*y.*z + M(2,19)*y.*z.*z + M(2,20)*z.*z.*z + M(2,21)*x.*x.*x.*x + M(2,22)*x.*x.*x.*y + M(2,23)*x.*x.*x.*z + M(2,24)*x.*x.*y.*y + M(2,25)*x.*x.*y.*z + M(2,26)*x.*x.*z.*z + M(2,27)*x.*y.*y.*y + M(2,28)*x.*y.*y.*z + M(2,29)*x.*y.*z.*z + M(2,30)*x.*z.*z.*z + M(2,31)*y.*y.*y.*y + M(2,32)*y.*y.*y.*z + M(2,33)*y.*y.*z.*z + M(2,34)*y.*z.*z.*z + M(2,35)*z.*z.*z.*z + M(2,36)*x.*x.*x.*x.*x + M(2,37)*x.*x.*x.*x.*y + M(2,38)*x.*x.*x.*x.*z + M(2,39)*x.*x.*x.*y.*y + M(2,40)*x.*x.*x.*y.*z + M(2,41)*x.*x.*x.*z.*z + M(2,42)*x.*x.*y.*y.*y + M(2,43)*x.*x.*y.*y.*z + M(2,44)*x.*x.*y.*z.*z + M(2,45)*x.*x.*z.*z.*z + M(2,46)*x.*y.*y.*y.*y + M(2,47)*x.*y.*y.*y.*z + M(2,48)*x.*y.*y.*z.*z + M(2,49)*x.*y.*z.*z.*z + M(2,50)*x.*z.*z.*z.*z + M(2,51)*y.*y.*y.*y.*y + M(2,52)*y.*y.*y.*y.*z + M(2,53)*y.*y.*y.*z.*z + M(2,54)*y.*y.*z.*z.*z + M(2,55)*y.*z.*z.*z.*z + M(2,56)*z.*z.*z.*z.*z; zz = M(3,1) + M(3,2)*x + M(3,3)*y + M(3,4)*z + M(3,5)*x.*x + M(3,6)*x.*y + M(3,7)*x.*z + M(3,8)*y.*y + M(3,9)*y.*z + M(3,10)*z.*z + M(3,11)*x.*x.*x + M(3,12)*x.*x.*y + M(3,13)*x.*x.*z + M(3,14)*x.*y.*y + M(3,15)*x.*y.*z + M(3,16)*x.*z.*z + M(3,17)*y.*y.*y + M(3,18)*y.*y.*z + M(3,19)*y.*z.*z + M(3,20)*z.*z.*z + M(3,21)*x.*x.*x.*x + M(3,22)*x.*x.*x.*y + M(3,23)*x.*x.*x.*z + M(3,24)*x.*x.*y.*y + M(3,25)*x.*x.*y.*z + M(3,26)*x.*x.*z.*z + M(3,27)*x.*y.*y.*y + M(3,28)*x.*y.*y.*z + M(3,29)*x.*y.*z.*z + M(3,30)*x.*z.*z.*z + M(3,31)*y.*y.*y.*y + M(3,32)*y.*y.*y.*z + M(3,33)*y.*y.*z.*z + M(3,34)*y.*z.*z.*z + M(3,35)*z.*z.*z.*z + M(3,36)*x.*x.*x.*x.*x + M(3,37)*x.*x.*x.*x.*y + M(3,38)*x.*x.*x.*x.*z + M(3,39)*x.*x.*x.*y.*y + M(3,40)*x.*x.*x.*y.*z + M(3,41)*x.*x.*x.*z.*z + M(3,42)*x.*x.*y.*y.*y + M(3,43)*x.*x.*y.*y.*z + M(3,44)*x.*x.*y.*z.*z + M(3,45)*x.*x.*z.*z.*z + M(3,46)*x.*y.*y.*y.*y + M(3,47)*x.*y.*y.*y.*z + M(3,48)*x.*y.*y.*z.*z + M(3,49)*x.*y.*z.*z.*z + M(3,50)*x.*z.*z.*z.*z + M(3,51)*y.*y.*y.*y.*y + M(3,52)*y.*y.*y.*y.*z + M(3,53)*y.*y.*y.*z.*z + M(3,54)*y.*y.*z.*z.*z + M(3,55)*y.*z.*z.*z.*z + M(3,56)*z.*z.*z.*z.*z; else - error('invalid size of nonlinear transformation matrix'); + ft_error('invalid size of nonlinear transformation matrix'); end warped = [xx yy zz]; @@ -188,7 +188,7 @@ %error('individual2sn is not yet implemented'); warped = individual2sn(M, input); else - error('unrecognized transformation method'); + ft_error('unrecognized transformation method'); end if ~input3d diff --git a/external/fieldtrip/plotting/private/green.m b/external/fieldtrip/plotting/private/green.m index faded83a..861754b5 100644 --- a/external/fieldtrip/plotting/private/green.m +++ b/external/fieldtrip/plotting/private/green.m @@ -1,4 +1,4 @@ -function rgb = rgbcolor +function rgb = green % returns a predefined color as [red green blue] values % @@ -11,7 +11,9 @@ % red = [255 0 0 ]/255; % green = [0 192 0 ]/255; % blue = [0 0 255]/255; -% yellow = [255 255 0 ]/255; +% yellow = [255 255 0 ]/255; +% cortex_light = [199 194 169]/255; +% cortex_dark = [100 97 85]/255; rgb = [0 192 0 ]/255; diff --git a/external/fieldtrip/plotting/private/icosahedron.m b/external/fieldtrip/plotting/private/icosahedron.m index 2798b1f7..b6d65c34 100644 --- a/external/fieldtrip/plotting/private/icosahedron.m +++ b/external/fieldtrip/plotting/private/icosahedron.m @@ -25,7 +25,6 @@ % You should have received a copy of the GNU General Public License % along with FieldTrip. If not, see . % -% $Id$ tri = [ 1 2 3 diff --git a/external/fieldtrip/plotting/private/icosahedron162.m b/external/fieldtrip/plotting/private/icosahedron162.m index a39f3ee9..ae3bfe69 100644 --- a/external/fieldtrip/plotting/private/icosahedron162.m +++ b/external/fieldtrip/plotting/private/icosahedron162.m @@ -20,7 +20,6 @@ % You should have received a copy of the GNU General Public License % along with FieldTrip. If not, see . % -% $Id$ [pos, tri] = icosahedron; [pos, tri] = refine(pos, tri); diff --git a/external/fieldtrip/plotting/private/icosahedron2562.m b/external/fieldtrip/plotting/private/icosahedron2562.m index 26fdf53d..11752a0c 100644 --- a/external/fieldtrip/plotting/private/icosahedron2562.m +++ b/external/fieldtrip/plotting/private/icosahedron2562.m @@ -1,4 +1,4 @@ -function [pnt, tri] = icosahedron() +function [pnt, tri] = icosahedron2562() % ICOSAHEDRON2562 creates a 4-fold refined icosahedron diff --git a/external/fieldtrip/plotting/private/icosahedron42.m b/external/fieldtrip/plotting/private/icosahedron42.m index 86a1425a..833c11eb 100644 --- a/external/fieldtrip/plotting/private/icosahedron42.m +++ b/external/fieldtrip/plotting/private/icosahedron42.m @@ -20,7 +20,6 @@ % You should have received a copy of the GNU General Public License % along with FieldTrip. If not, see . % -% $Id$ [pos, tri] = icosahedron; [pos, tri] = refine(pos, tri); diff --git a/external/fieldtrip/plotting/private/icosahedron642.m b/external/fieldtrip/plotting/private/icosahedron642.m index cc4b5a15..4d932e5c 100644 --- a/external/fieldtrip/plotting/private/icosahedron642.m +++ b/external/fieldtrip/plotting/private/icosahedron642.m @@ -20,7 +20,6 @@ % You should have received a copy of the GNU General Public License % along with FieldTrip. If not, see . % -% $Id$ [pos, tri] = icosahedron; [pos, tri] = refine(pos, tri); diff --git a/external/fieldtrip/plotting/private/istrue.m b/external/fieldtrip/plotting/private/istrue.m index 79631e32..742a0997 100644 --- a/external/fieldtrip/plotting/private/istrue.m +++ b/external/fieldtrip/plotting/private/istrue.m @@ -1,7 +1,7 @@ function y = istrue(x) -% ISTRUE ensures that a true/false input argument like "yes", "true" -% or "on" is converted into a boolean +% ISTRUE converts an input argument like "yes/no", "true/false" or "on/off" into a +% boolean. If the input is boolean, then it will remain like that. % Copyright (C) 2009-2012, Robert Oostenveld % diff --git a/external/fieldtrip/plotting/private/keyval.m b/external/fieldtrip/plotting/private/keyval.m index b176ce8d..0043c72b 100644 --- a/external/fieldtrip/plotting/private/keyval.m +++ b/external/fieldtrip/plotting/private/keyval.m @@ -44,7 +44,7 @@ end if mod(length(varargin),2) - error('optional input arguments should come in key-value pairs, i.e. there should be an even number'); + ft_error('optional input arguments should come in key-value pairs, i.e. there should be an even number'); end % the 1st, 3rd, etc. contain the keys, the 2nd, 4th, etc. contain the values @@ -58,7 +58,7 @@ end if ~all(valid) - error('optional input arguments should come in key-value pairs, the optional input argument %d is invalid (should be a string)', i); + ft_error('optional input arguments should come in key-value pairs, the optional input argument %d is invalid (should be a string)', i); end hit = find(strcmpi(key, keys)); @@ -69,7 +69,7 @@ % the requested key was found val = vals{hit}; else - error('multiple input arguments with the same name'); + ft_error('multiple input arguments with the same name'); end if nargout>1 diff --git a/external/fieldtrip/plotting/private/keyvalcheck.m b/external/fieldtrip/plotting/private/keyvalcheck.m index 9f2cdaac..667287df 100644 --- a/external/fieldtrip/plotting/private/keyvalcheck.m +++ b/external/fieldtrip/plotting/private/keyvalcheck.m @@ -46,7 +46,7 @@ function keyvalcheck(arglist, varargin) vals = arglist(2:2:end); if numel(keys)~=numel(vals) - error('optional input arguments should come in key-value pairs, i.e. there should be an even number'); + ft_error('optional input arguments should come in key-value pairs, i.e. there should be an even number'); end keys = cellfun(@lower, keys, 'UniformOutput', false); @@ -56,7 +56,7 @@ function keyvalcheck(arglist, varargin) required = cellfun(@lower, required, 'UniformOutput', false); set = intersect(keys, required); if numel(set)~=numel(required) - error('the required input argument ''%s'' was not specified', set{:}); + ft_error('the required input argument ''%s'' was not specified', set{:}); end end @@ -65,7 +65,7 @@ function keyvalcheck(arglist, varargin) forbidden = cellfun(@lower, forbidden, 'UniformOutput', false); set = intersect(keys, forbidden); if numel(set)~=0 - error('the input argument ''%s'' is forbidden', set{:}); + ft_error('the input argument ''%s'' is forbidden', set{:}); end end @@ -74,7 +74,7 @@ function keyvalcheck(arglist, varargin) optional = cellfun(@lower, optional, 'UniformOutput', false); set = setdiff(keys, optional); if numel(set)>0 - error('the input argument ''%s'' is forbidden', set{:}); + ft_error('the input argument ''%s'' is forbidden', set{:}); end end diff --git a/external/fieldtrip/plotting/private/lmoutrn.m b/external/fieldtrip/plotting/private/lmoutrn.m new file mode 100644 index 00000000..11ee76df --- /dev/null +++ b/external/fieldtrip/plotting/private/lmoutrn.m @@ -0,0 +1,61 @@ +function [la, mu, dist, proj] = lmoutrn(v1, v2, v3, r) + +% LMOUTRN computes the la/mu parameters of a point projected to triangles +% +% Use as +% [la, mu, dist, proj] = lmoutrn(v1, v2, v3, r) +% where v1, v2 and v3 are Nx3 matrices with vertex positions of the triangles, +% and r is the point that is projected onto the planes spanned by the vertices +% This is a vectorized version of Robert's lmoutrn function and is +% generally faster than a for-loop around the mex-file. It also returns the +% projection of the point r onto the planes of the triangles, and the signed +% distance to the triangles. The sign of the distance is negative if the point +% lies closer to the average across all vertices and the triangle under consideration. + +% Copyright (C) 2012, Jan-Mathijs Schoffelen +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +if size(r,1)==1 && size(v1,1)>1 + r = repmat(r, [size(v1,1), 1]); +end + +% compute la/mu parameters +vec0 = r - v1; +vec1 = v2 - v1; +%vec2 = v3 - v2; +vec3 = v3 - v1; +origin = repmat(mean([v1;v2;v3]), [size(v1,1), 1]); + +tmp(:,1,:) = vec1'; +tmp(:,2,:) = vec3'; +tmp = pinvNx2(tmp); +la = sum(vec0'.*shiftdim(tmp(1,:,:))).'; % tmp*vec0'; +mu = sum(vec0'.*shiftdim(tmp(2,:,:))).'; + +% determine the projection onto the plane of the triangle +proj = v1 + [la la la].*vec1 + [mu mu mu].*vec3; + +% determine the signed distance from the original point to its projection +% where the sign is negative if the original point is closer to the origin +origin_r = sum((r - origin).^2,2); +origin_proj = sum((proj - origin).^2,2); + +dist = sqrt(sum((r-proj).^2,2)).*sign(origin_r-origin_proj); + diff --git a/external/fieldtrip/plotting/private/ltrisect.m b/external/fieldtrip/plotting/private/ltrisect.m index cf3c66bd..49378274 100644 --- a/external/fieldtrip/plotting/private/ltrisect.m +++ b/external/fieldtrip/plotting/private/ltrisect.m @@ -1,4 +1,4 @@ -function [varargout] = funname(varargin) +function [varargout] = ltrisect(varargin) % LTRISECT intersects a line with a plane spanned by three vertices % @@ -38,7 +38,7 @@ try % try to compile the mex file on the fly - warning('trying to compile MEX file from %s', mexsrc); + ft_warning('trying to compile MEX file from %s', mexsrc); cd(mexdir); if ispc @@ -55,7 +55,7 @@ catch % compilation failed disp(lasterr); - error('could not locate MEX file for %s', mexname); + ft_error('could not locate MEX file for %s', mexname); cd(pwdir); success = false; end diff --git a/external/fieldtrip/plotting/private/match_str.m b/external/fieldtrip/plotting/private/match_str.m index 440a3818..39eced66 100644 --- a/external/fieldtrip/plotting/private/match_str.m +++ b/external/fieldtrip/plotting/private/match_str.m @@ -1,10 +1,11 @@ function [sel1, sel2] = match_str(a, b, fullout) -% MATCH_STR looks for matching labels in two listst of strings +% MATCH_STR looks for matching labels in two lists of strings % and returns the indices into both the 1st and 2nd list of the matches. % They will be ordered according to the first input argument. % -% [sel1, sel2] = match_str(strlist1, strlist2) +% Use as +% [sel1, sel2] = match_str(strlist1, strlist2) % % The strings can be stored as a char matrix or as an vertical array of % cells, the matching is done for each row. @@ -69,7 +70,7 @@ % According to the original implementation empty numeric elements are % allowed, but are not returned as match. This is different to empty string % elements, which are returned as match. -% See also http://bugzilla.fcdonders.nl/show_bug.cgi?id=1808 +% See also http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=1808 empty_a = cellfun(@isnumeric, a) & cellfun(@isempty, a); empty_b = cellfun(@isnumeric, b) & cellfun(@isempty, b); % the following allows the unique function to operate normally diff --git a/external/fieldtrip/plotting/private/mesh2edge.m b/external/fieldtrip/plotting/private/mesh2edge.m index 71b4c0e4..4fc082ae 100644 --- a/external/fieldtrip/plotting/private/mesh2edge.m +++ b/external/fieldtrip/plotting/private/mesh2edge.m @@ -99,7 +99,7 @@ end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% SUBFUNCTION, see http://bugzilla.fcdonders.nl/show_bug.cgi?id=1833#c12 +% SUBFUNCTION, see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=1833#c12 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function indx = findsingleoccurringrows(X) [X, indx] = sortrows(X); diff --git a/external/fieldtrip/plotting/private/ndgrid.m b/external/fieldtrip/plotting/private/ndgrid.m index c88a655c..cfc6870f 100644 --- a/external/fieldtrip/plotting/private/ndgrid.m +++ b/external/fieldtrip/plotting/private/ndgrid.m @@ -50,7 +50,7 @@ % $Id$ if nargin==0 - error('MATLAB:ndgrid:NotEnoughInputs', 'Not enough input arguments.'); + ft_error('MATLAB:ndgrid:NotEnoughInputs', 'Not enough input arguments.'); end if nargin==1, varargin = repmat(varargin,[1 max(nargout,2)]); end @@ -117,7 +117,7 @@ varargout{4} = xx(ones1, ones2, ones3, :,ones5); varargout{5} = yy(ones1, ones2, ones3, :,ones5); otherwise - error('this version of ndgrid supports inputs up to 5 dimensions'); + ft_error('this version of ndgrid supports inputs up to 5 dimensions'); %call the ndgrid from elmat %FIXME this has to be done end diff --git a/external/fieldtrip/plotting/private/pinvNx2.m b/external/fieldtrip/plotting/private/pinvNx2.m new file mode 100644 index 00000000..2690a767 --- /dev/null +++ b/external/fieldtrip/plotting/private/pinvNx2.m @@ -0,0 +1,36 @@ +function y = pinvNx2(x) + +% PINVNX2 computes a pseudo-inverse of the slices of an Nx2xM real-valued matrix. +% Output has dimensionality 2xNxM. This implementation is generally faster +% than calling pinv in a for-loop, once M > 2 + +siz = [size(x) 1]; +xtx = zeros([2,2,siz(3:end)]); +xtx(1,1,:,:) = sum(x(:,1,:,:).^2,1); +xtx(2,2,:,:) = sum(x(:,2,:,:).^2,1); +tmp = sum(x(:,1,:,:).*x(:,2,:,:),1); +xtx(1,2,:,:) = tmp; +xtx(2,1,:,:) = tmp; +ixtx = inv2x2(xtx); +y = mtimes2xN(ixtx, permute(x, [2 1 3:ndims(x)])); + +function [d] = inv2x2(x) + +% INV2X2 computes inverse of matrix x, where x = 2x2xN, using explicit analytic definition + +adjx = [x(2,2,:,:) -x(1,2,:,:); -x(2,1,:,:) x(1,1,:,:)]; +denom = x(1,1,:,:).*x(2,2,:,:) - x(1,2,:,:).*x(2,1,:,:); +d = adjx./denom([1 1],[1 1],:,:); + +function [z] = mtimes2xN(x, y) + +% MTIMES2XN computes x*y where x = 2x2xM and y = 2xNxM +% and output dimensionatity is 2xNxM + +siz = size(y); +z = zeros(siz); + +for k = 1:siz(2) + z(1,k,:,:) = x(1,1,:,:).*y(1,k,:,:) + x(1,2,:,:).*y(2,k,:,:); + z(2,k,:,:) = x(2,1,:,:).*y(1,k,:,:) + x(2,2,:,:).*y(2,k,:,:); +end diff --git a/external/fieldtrip/plotting/private/projecttri.m b/external/fieldtrip/plotting/private/projecttri.m index 729f0ab5..f18a34e7 100644 --- a/external/fieldtrip/plotting/private/projecttri.m +++ b/external/fieldtrip/plotting/private/projecttri.m @@ -48,7 +48,7 @@ prj = elproj(pnt); tri = delaunay(prj(:,1), prj(:,2)); otherwise - error('unsupported method'); + ft_error('unsupported method'); end diff --git a/external/fieldtrip/plotting/private/ptriside.m b/external/fieldtrip/plotting/private/ptriside.m index 88a57863..df119914 100644 --- a/external/fieldtrip/plotting/private/ptriside.m +++ b/external/fieldtrip/plotting/private/ptriside.m @@ -1,7 +1,7 @@ function [side] = ptriside(v1, v2, v3, r, tolerance) -% PTRISIDE determines the side of a plane on which a set of points lie. it -% returns 0 for the points that lie on the plane +% PTRISIDE determines the side of a plane on which a set of points lie. It +% returns 0 for the points that lie exactly on the plane. % % [side] = ptriside(v1, v2, v3, r) % diff --git a/external/fieldtrip/plotting/private/quaternion.m b/external/fieldtrip/plotting/private/quaternion.m index ad8d5e06..bd34c4f6 100644 --- a/external/fieldtrip/plotting/private/quaternion.m +++ b/external/fieldtrip/plotting/private/quaternion.m @@ -48,7 +48,7 @@ % $Id$ if numel(q)~=7 - error('incorrect input vector'); + ft_error('incorrect input vector'); end % all of these quaternions are zero-offset in the original equation, but one-offset in the MATLAB vector diff --git a/external/fieldtrip/plotting/private/red.m b/external/fieldtrip/plotting/private/red.m index 092dbfbc..4c908259 100644 --- a/external/fieldtrip/plotting/private/red.m +++ b/external/fieldtrip/plotting/private/red.m @@ -1,4 +1,4 @@ -function rgb = rgbcolor +function rgb = red % returns a predefined color as [red green blue] values % @@ -11,7 +11,9 @@ % red = [255 0 0 ]/255; % green = [0 192 0 ]/255; % blue = [0 0 255]/255; -% yellow = [255 255 0 ]/255; +% yellow = [255 255 0 ]/255; +% cortex_light = [199 194 169]/255; +% cortex_dark = [100 97 85]/255; rgb = [255 0 0 ]/255; diff --git a/external/fieldtrip/plotting/private/refine.m b/external/fieldtrip/plotting/private/refine.m index c2c2fb1d..9dc242d4 100644 --- a/external/fieldtrip/plotting/private/refine.m +++ b/external/fieldtrip/plotting/private/refine.m @@ -45,7 +45,6 @@ % You should have received a copy of the GNU General Public License % along with FieldTrip. If not, see . % -% $Id$ if nargin<3 method = 'banks'; @@ -190,6 +189,6 @@ [trir, pntr] = reducepatch(tri, pnt, numtri); otherwise - error('unsupported method "%s"', method); + ft_error('unsupported method "%s"', method); end diff --git a/external/fieldtrip/plotting/private/rotate.m b/external/fieldtrip/plotting/private/rotate.m index d6b05256..2512a5a8 100644 --- a/external/fieldtrip/plotting/private/rotate.m +++ b/external/fieldtrip/plotting/private/rotate.m @@ -49,7 +49,7 @@ % $Id$ if numel(f)~=3 - error('incorrect input vector'); + ft_error('incorrect input vector'); end % convert degrees to radians diff --git a/external/fieldtrip/plotting/private/scale.m b/external/fieldtrip/plotting/private/scale.m index 7ba67e67..c77b0340 100644 --- a/external/fieldtrip/plotting/private/scale.m +++ b/external/fieldtrip/plotting/private/scale.m @@ -44,7 +44,7 @@ % $Id$ if numel(f)~=3 - error('incorrect input vector'); + ft_error('incorrect input vector'); end H = [ diff --git a/external/fieldtrip/plotting/private/select3d.m b/external/fieldtrip/plotting/private/select3d.m index 61405261..4ee6b63b 100644 --- a/external/fieldtrip/plotting/private/select3d.m +++ b/external/fieldtrip/plotting/private/select3d.m @@ -63,16 +63,16 @@ % other variables ERRMSG = 'Input argument must be a valid graphics handle'; -isline = logical(0); -isperspective = logical(0); +isline = false; +isperspective = false; % Parse input arguments if nargin<1 obj = gco; end -if isempty(obj) | ~ishandle(obj) | length(obj)~=1 - error(ERRMSG); +if isempty(obj) || ~ishandle(obj) || length(obj)~=1 + ft_error(ERRMSG); end % if obj is a figure @@ -121,7 +121,7 @@ [a b] = view(ax); xform = viewmtx(a,b); if is_perspective - warning('%s does not support perspective axes projection.',mfilename); + ft_warning('%s does not support perspective axes projection.',mfilename); d = norm(camtarget(ax)-campos(ax)) P = [1 0 0 0; 0 1 0 0; @@ -154,7 +154,7 @@ zdata = get(axchild,'zdata'); vert = [xdata', ydata',zdata']; faces = []; - isline = logical(1); + isline = true; % Ignore all other objects else @@ -172,8 +172,8 @@ % NaN and Inf check nan_inf_test1 = isnan(faces) | isinf(faces); nan_inf_test2 = isnan(vert) | isinf(vert); -if any(nan_inf_test1(:)) | any(nan_inf_test2(:)) - warning('%s does not support NaNs or Infs in face/vertex data.',mfilename); +if any(nan_inf_test1(:)) || any(nan_inf_test2(:)) + ft_warning('%s does not support NaNs or Infs in face/vertex data.',mfilename); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -259,7 +259,7 @@ vert_with_negative_y = zeros(size(faces)); face_y_vert = xvert(2,faces); ind_vert_with_negative_y = find(face_y_vert<0); -vert_with_negative_y(ind_vert_with_negative_y) = logical(1); +vert_with_negative_y(ind_vert_with_negative_y) = true; % Find all the line segments that span the x axis is_line_segment_spanning_x = abs(diff([vert_with_negative_y, vert_with_negative_y(:,1)],1,2)); @@ -308,7 +308,7 @@ % three vertices since that is all we need to define a plane). % assuming planar polygons. candidate_faces = candidate_faces(ind_intersection_test,1:3); -candidate_faces = reshape(candidate_faces',1,prod(size(candidate_faces))); +candidate_faces = reshape(candidate_faces',1,numel(candidate_faces)); vert = vert'; candidate_facev = vert(:,candidate_faces); candidate_facev = reshape(candidate_facev,3,3,length(ind_intersection_test)); @@ -319,8 +319,8 @@ v3 = squeeze(candidate_facev(:,3,:)); % Get normal to face plane -vec1 = [v2-v1]; -vec2 = [v3-v2]; +vec1 = v2-v1; +vec2 = v3-v2; crs = cross(vec1,vec2); mag = sqrt(sum(crs.*crs)); nplane(1,:) = crs(1,:)./mag; diff --git a/external/fieldtrip/plotting/private/select3dtool.m b/external/fieldtrip/plotting/private/select3dtool.m index 8b4ba340..3ec064c6 100644 --- a/external/fieldtrip/plotting/private/select3dtool.m +++ b/external/fieldtrip/plotting/private/select3dtool.m @@ -48,7 +48,7 @@ function select3dtool(arg) fig = getappdata(gcbf,'select3dhost'); -if ~isempty(fig) & ishandle(fig) +if ~isempty(fig) && ishandle(fig) state = getappdata(fig,'select3dtool'); uirestore(state.uistate); delete(state.marker1); @@ -58,7 +58,7 @@ function select3dtool(arg) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function click -[p v vi] = select3d; +[p, v, vi] = select3d; state = getappdata(gcbf,'select3dtool'); if ~ishandle(state.text) diff --git a/external/fieldtrip/plotting/private/skin.m b/external/fieldtrip/plotting/private/skin.m index 4ca15784..c7ceffc8 100644 --- a/external/fieldtrip/plotting/private/skin.m +++ b/external/fieldtrip/plotting/private/skin.m @@ -1,4 +1,4 @@ -function rgb = rgbcolor +function rgb = skin % returns a predefined color as [red green blue] values % diff --git a/external/fieldtrip/plotting/private/skull.m b/external/fieldtrip/plotting/private/skull.m index 8f80fe6f..e5e78e55 100644 --- a/external/fieldtrip/plotting/private/skull.m +++ b/external/fieldtrip/plotting/private/skull.m @@ -1,4 +1,4 @@ -function rgb = rgbcolor +function rgb = skull % returns a predefined color as [red green blue] values % diff --git a/external/fieldtrip/plotting/private/translate.m b/external/fieldtrip/plotting/private/translate.m index 4f9c0112..6eb184eb 100644 --- a/external/fieldtrip/plotting/private/translate.m +++ b/external/fieldtrip/plotting/private/translate.m @@ -44,7 +44,7 @@ % $Id$ if numel(f)~=3 - error('incorrect input vector'); + ft_error('incorrect input vector'); end H = [ diff --git a/external/fieldtrip/plotting/private/undobalancing.m b/external/fieldtrip/plotting/private/undobalancing.m index 6b5c555a..e91c7e3e 100644 --- a/external/fieldtrip/plotting/private/undobalancing.m +++ b/external/fieldtrip/plotting/private/undobalancing.m @@ -21,7 +21,7 @@ tmp = tra1*tra2; tmp = null(tmp); % nullspace after ft_componentanalysis and ft_rejectcomponent tmp = tmp*tmp'; % this is the part which was removed at some point - [ix,iy] = match_str(sens.balance.comp.labelorg, sens.balance.invcomp.labelnew); + [ix,iy] = match_str(sens.balance.comp.labelold, sens.balance.invcomp.labelnew); tra3(iy,iy) = (eye(numel(ix))+tmp(ix,ix))*tra1(iy,iy); sens.balance.invcomp.tra = tra3; % FIXME check whether this is robust @@ -49,7 +49,7 @@ end else - warning('cannot undo %s balancing in the gradiometer definition\n', sens.balance.current); + ft_warning('cannot undo %s balancing in the gradiometer definition\n', sens.balance.current); break end end diff --git a/external/fieldtrip/plotting/private/white.m b/external/fieldtrip/plotting/private/white.m index f6298d2f..6fff31e9 100644 --- a/external/fieldtrip/plotting/private/white.m +++ b/external/fieldtrip/plotting/private/white.m @@ -1,4 +1,4 @@ -function rgb = rgbcolor +function rgb = white % returns a predefined color as [red green blue] values % @@ -11,7 +11,9 @@ % red = [255 0 0 ]/255; % green = [0 192 0 ]/255; % blue = [0 0 255]/255; -% yellow = [255 255 0 ]/255; +% yellow = [255 255 0 ]/255; +% cortex_light = [199 194 169]/255; +% cortex_dark = [100 97 85]/255; rgb = [255 255 255]/255; diff --git a/external/fieldtrip/plotting/private/yellow.m b/external/fieldtrip/plotting/private/yellow.m index 5f367571..61e59e2f 100644 --- a/external/fieldtrip/plotting/private/yellow.m +++ b/external/fieldtrip/plotting/private/yellow.m @@ -1,4 +1,4 @@ -function rgb = rgbcolor +function rgb = yellow % returns a predefined color as [red green blue] values % @@ -11,7 +11,9 @@ % red = [255 0 0 ]/255; % green = [0 192 0 ]/255; % blue = [0 0 255]/255; -% yellow = [255 255 0 ]/255; +% yellow = [255 255 0 ]/255; +% cortex_light = [199 194 169]/255; +% cortex_dark = [100 97 85]/255; rgb = [255 255 0 ]/255; diff --git a/external/fieldtrip/preproc/ft_preproc_bandpassfilter.m b/external/fieldtrip/preproc/ft_preproc_bandpassfilter.m index b9e4b6f3..a8ea8090 100644 --- a/external/fieldtrip/preproc/ft_preproc_bandpassfilter.m +++ b/external/fieldtrip/preproc/ft_preproc_bandpassfilter.m @@ -1,4 +1,4 @@ -function [filt] = ft_preproc_bandpassfilter(dat,Fs,Fbp,N,type,dir,instabilityfix,df,wintype,dev,plotfiltresp,usefftfilt) +function [filt, B, A] = ft_preproc_bandpassfilter(dat,Fs,Fbp,N,type,dir,instabilityfix,df,wintype,dev,plotfiltresp,usefftfilt) % FT_PREPROC_BANDPASSFILTER applies a band-pass filter to the data and thereby % removes the spectral components in the data except for the ones in the @@ -25,6 +25,7 @@ % 'twopass-reverse' zero-phase reverse and forward filter % 'twopass-average' average of the twopass and the twopass-reverse % 'onepass-zerophase' zero-phase forward filter with delay compensation (default for firws, linear-phase symmetric FIR only) +% 'onepass-reverse-zerophase' zero-phase reverse filter with delay compensation % 'onepass-minphase' minimum-phase converted forward filter (non-linear!, firws only) % instabilityfix optional method to deal with filter instabilities % 'no' only detect and give error (default) @@ -131,11 +132,15 @@ end % Filtering does not work on integer data -typ = class(dat); -if ~strcmp(typ, 'double') && ~strcmp(typ, 'single') +if ~isa(dat, 'double') && ~isa(dat, 'single') dat = cast(dat, 'double'); end +% preprocessing fails on channels that contain NaN +if any(isnan(dat(:))) + ft_warning('FieldTrip:dataContainsNaN', 'data contains NaN values'); +end + % Nyquist frequency Fn = Fs/2; @@ -151,12 +156,12 @@ % Input arguments if length(Fbp) ~= 2 - error('Two cutoff frequencies required.') + ft_error('Two cutoff frequencies required.') end % Filter order AND transition width set? if ~isempty(N) && ~isempty(df) - warning('firws:dfOverridesN', 'Filter order AND transition width set - transition width setting will override filter order.') + ft_warning('firws:dfOverridesN', 'Filter order AND transition width set - transition width setting will override filter order.') elseif isempty(N) && isempty(df) % Default transition width heuristic df = fir_df(Fbp, Fs); end @@ -166,14 +171,14 @@ isOrderLow = false; if ~isempty(df) if df > maxDf - error('Transition band too wide. Maximum transition width is %.2f Hz.', maxDf) + ft_error('Transition band too wide. Maximum transition width is %.2f Hz.', maxDf) end [N, dev] = firwsord(wintype, Fs, df, dev); else % Check filter order otherwise [df, dev] = invfirwsord(wintype, Fs, N, dev); if df > maxDf nOpt = firwsord(wintype, Fs, maxDf, dev); - warning('firws:filterOrderLow', 'Filter order too low. For better results a minimum filter order of %d is recommended. Effective cutoff frequency might deviate from requested cutoff frequency.', nOpt) + ft_warning('firws:filterOrderLow', 'Filter order too low. For better results a minimum filter order of %d is recommended. Effective cutoff frequency might deviate from requested cutoff frequency.', nOpt) isOrderLow = true; end end @@ -232,11 +237,12 @@ if N > floor( (size(dat,2) - 1) / 3) N=floor(size(dat,2)/3) - 1; end - [B, A] = fir1(N, [min(Fbp)/Fn max(Fbp)/Fn]); + B = fir1(N, [min(Fbp)/Fn max(Fbp)/Fn]); + A = 1; case 'firls' % from NUTMEG's implementation % Deprecated: see bug 2453 - warning('The filter type you requested is not recommended for neural signals, only proceed if you know what you are doing.') + ft_warning('The filter type you requested is not recommended for neural signals, only proceed if you know what you are doing.') if isempty(N) N = 3*fix(Fs / Fbp(1)); end @@ -275,7 +281,7 @@ return otherwise - error('unsupported filter type "%s"', type); + ft_error('unsupported filter type "%s"', type); end % demean the data before filtering @@ -289,20 +295,19 @@ case 'no' rethrow(lasterror); case 'reduce' - warning('backtrace', 'off') - warning('instability detected - reducing the %dth order filter to an %dth order filter', N, N-1); - warning('backtrace', 'on') + ft_warning('off','backtrace'); + ft_warning('instability detected - reducing the %dth order filter to an %dth order filter', N, N-1); + ft_warning('on','backtrace'); filt = ft_preproc_bandpassfilter(dat,Fs,Fbp,N-1,type,dir,instabilityfix); case 'split' N1 = ceil(N/2); N2 = floor(N/2); - warning('backtrace', 'off') - warning('instability detected - splitting the %dth order filter in a sequential %dth and a %dth order filter', N, N1, N2); - warning('backtrace', 'on') + ft_warning('off','backtrace'); + ft_warning('instability detected - splitting the %dth order filter in a sequential %dth and a %dth order filter', N, N1, N2); + ft_warning('on','backtrace'); filt = ft_preproc_bandpassfilter(dat ,Fs,Fbp,N1,type,dir,instabilityfix); filt = ft_preproc_bandpassfilter(filt,Fs,Fbp,N2,type,dir,instabilityfix); otherwise - error('incorrect specification of instabilityfix'); + ft_error('incorrect specification of instabilityfix'); end % switch end - diff --git a/external/fieldtrip/preproc/ft_preproc_bandstopfilter.m b/external/fieldtrip/preproc/ft_preproc_bandstopfilter.m index 4f1178fa..f777415e 100644 --- a/external/fieldtrip/preproc/ft_preproc_bandstopfilter.m +++ b/external/fieldtrip/preproc/ft_preproc_bandstopfilter.m @@ -1,4 +1,4 @@ -function [filt] = ft_preproc_bandstopfilter(dat,Fs,Fbp,N,type,dir,instabilityfix,df,wintype,dev,plotfiltresp,usefftfilt) +function [filt, B, A] = ft_preproc_bandstopfilter(dat,Fs,Fbp,N,type,dir,instabilityfix,df,wintype,dev,plotfiltresp,usefftfilt) % FT_PREPROC_BANDSTOPFILTER applies a band-stop filter to the data and thereby % removes the spectral components in the specified frequency band @@ -24,6 +24,7 @@ % 'twopass-reverse' zero-phase reverse and forward filter % 'twopass-average' average of the twopass and the twopass-reverse % 'onepass-zerophase' zero-phase forward filter with delay compensation (default for firws, linear-phase symmetric FIR only) +% 'onepass-reverse-zerophase' zero-phase reverse filter with delay compensation % 'onepass-minphase' minimum-phase converted forward filter (non-linear!, firws only) % instabilityfix optional method to deal with filter instabilities % 'no' only detect and give error (default) @@ -130,11 +131,15 @@ end % Filtering does not work on integer data -typ = class(dat); -if ~strcmp(typ, 'double') && ~strcmp(typ, 'single') +if ~isa(dat, 'double') && ~isa(dat, 'single') dat = cast(dat, 'double'); end +% preprocessing fails on channels that contain NaN +if any(isnan(dat(:))) + ft_warning('FieldTrip:dataContainsNaN', 'data contains NaN values'); +end + % Nyquist frequency Fn = Fs/2; @@ -150,12 +155,12 @@ % Input arguments if length(Fbp) ~= 2 - error('Two cutoff frequencies required.') + ft_error('Two cutoff frequencies required.') end % Filter order AND transition width set? if ~isempty(N) && ~isempty(df) - warning('firws:dfOverridesN', 'Filter order AND transition width set - transition width setting will override filter order.') + ft_warning('firws:dfOverridesN', 'Filter order AND transition width set - transition width setting will override filter order.') elseif isempty(N) && isempty(df) % Default transition width heuristic df = fir_df(Fbp, Fs); end @@ -165,14 +170,14 @@ isOrderLow = false; if ~isempty(df) if df > maxDf - error('Transition band too wide. Maximum transition width is %.2f Hz.', maxDf) + ft_error('Transition band too wide. Maximum transition width is %.2f Hz.', maxDf) end [N, dev] = firwsord(wintype, Fs, df, dev); else % Check filter order otherwise [df, dev] = invfirwsord(wintype, Fs, N, dev); if df > maxDf nOpt = firwsord(wintype, Fs, maxDf, dev); - warning('firws:filterOrderLow', 'Filter order too low. For better results a minimum filter order of %d is recommended. Effective cutoff frequency might deviate from requested cutoff frequency.', nOpt) + ft_warning('firws:filterOrderLow', 'Filter order too low. For better results a minimum filter order of %d is recommended. Effective cutoff frequency might deviate from requested cutoff frequency.', nOpt) isOrderLow = true; end end @@ -233,10 +238,11 @@ N=floor(size(dat,2)/3) - 2; if rem(N,2)==1, N=N+1; end end - [B, A] = fir1(N, [min(Fbp)/Fn max(Fbp)/Fn], 'stop'); + B = fir1(N, [min(Fbp)/Fn max(Fbp)/Fn], 'stop'); + A = 1; case 'firls' % from NUTMEG's implementation % Deprecated: see bug 2453 - warning('The filter type you requested is not recommended for neural signals, only proceed if you know what you are doing.') + ft_warning('The filter type you requested is not recommended for neural signals, only proceed if you know what you are doing.') if isempty(N) N = 3*fix(Fs / Fbp(1)); end @@ -272,7 +278,7 @@ filt = 2*real(ifft(f,[],2)); % iFFT return otherwise - error('unsupported filter type "%s"', type); + ft_error('unsupported filter type "%s"', type); end % demean the data before filtering @@ -286,23 +292,22 @@ case 'no' rethrow(lasterror); case 'reduce' - warning('backtrace', 'off') - warning('instability detected - reducing the %dth order filter to an %dth order filter', N, N-1); - warning('backtrace', 'on') + ft_warning('off','backtrace'); + ft_warning('instability detected - reducing the %dth order filter to an %dth order filter', N, N-1); + ft_warning('on','backtrace'); filt = ft_preproc_bandstopfilter(dat,Fs,Fbp,N-1,type,dir,instabilityfix); case 'split' N1 = ceil(N/2); N2 = floor(N/2); - warning('backtrace', 'off') - warning('instability detected - splitting the %dth order filter in a sequential %dth and a %dth order filter', N, N1, N2); - warning('backtrace', 'on') + ft_warning('off','backtrace'); + ft_warning('instability detected - splitting the %dth order filter in a sequential %dth and a %dth order filter', N, N1, N2); + ft_warning('on','backtrace'); filt1 = ft_preproc_bandstopfilter(dat ,Fs,Fbp,N1,type,dir,instabilityfix); filt = ft_preproc_bandstopfilter(filt1,Fs,Fbp,N2,type,dir,instabilityfix); otherwise - error('incorrect specification of instabilityfix'); + ft_error('incorrect specification of instabilityfix'); end % switch end % add the mean back to the filtered data filt = bsxfun(@plus, filt, meandat); - diff --git a/external/fieldtrip/preproc/ft_preproc_denoise.m b/external/fieldtrip/preproc/ft_preproc_denoise.m index 416cce16..bd78a985 100644 --- a/external/fieldtrip/preproc/ft_preproc_denoise.m +++ b/external/fieldtrip/preproc/ft_preproc_denoise.m @@ -36,10 +36,15 @@ % % $Id$ -if nargin<3, +if nargin<3 hilbertflag = 0; end +% preprocessing fails on channels that contain NaN +if any(isnan(dat(:))) || any(isnan(refdat(:))) + ft_warning('FieldTrip:dataContainsNaN', 'data contains NaN values'); +end + n1 = size(dat,2); n2 = size(refdat,2); m1 = mean(dat,2); @@ -50,7 +55,7 @@ tmpdat = dat-m1(:,ones(n1,1)); %do hilbert transformation -if hilbertflag>0, +if hilbertflag>0 hrefdat = hilbert(refdat')'; refdat = [real(hrefdat);imag(hrefdat)]; end diff --git a/external/fieldtrip/preproc/ft_preproc_derivative.m b/external/fieldtrip/preproc/ft_preproc_derivative.m index 16d6153f..7395141e 100644 --- a/external/fieldtrip/preproc/ft_preproc_derivative.m +++ b/external/fieldtrip/preproc/ft_preproc_derivative.m @@ -36,7 +36,12 @@ order = 1; end +% preprocessing fails on channels that contain NaN +if any(isnan(dat(:))) + ft_warning('FieldTrip:dataContainsNaN', 'data contains NaN values'); +end + % compute the derivative for i=1:order - dat = gradient(dat); + dat = gradient(dat); end diff --git a/external/fieldtrip/preproc/ft_preproc_dftfilter.m b/external/fieldtrip/preproc/ft_preproc_dftfilter.m index 9f6166e5..9c7e6f3b 100644 --- a/external/fieldtrip/preproc/ft_preproc_dftfilter.m +++ b/external/fieldtrip/preproc/ft_preproc_dftfilter.m @@ -1,27 +1,62 @@ -function [filt] = ft_preproc_dftfilter(dat, Fs, Fl) +function [filt] = ft_preproc_dftfilter(dat, Fs, Fl, varargin) -% FT_PREPROC_DFTFILTER applies a notch filter to the data to remove the 50Hz -% or 60Hz line noise components. This is done by fitting a sine and cosine -% at the specified frequency to the data and subsequently subtracting the -% estimated components. The longer the data is, the sharper the spectral -% notch will be that is removed from the data. +% FT_PREPROC_DFTFILTER reduces power line noise (50 or 60Hz) via two +% alternative methods: +% A) DFT filter (Flreplace = 'zero') or +% B) Spectrum Interpolation (Flreplace = 'neighbour'). % -% Use as -% [filt] = ft_preproc_dftfilter(dat, Fsample, Fline) -% where -% dat data matrix (Nchans X Ntime) -% Fsample sampling frequency in Hz -% Fline line noise frequency -% -% The line frequency should be specified as a single number. -% If omitted, a European default of 50Hz will be assumed. -% -% Preferaby the data should have a length that is a multiple of the +% A) The DFT filter applies a notch filter to the data to remove the 50Hz +% or 60Hz line noise components ('zeroing'). This is done by fitting a sine +% and cosine at the specified frequency to the data and subsequently +% subtracting the estimated components. The longer the data is, the sharper +% the spectral notch will be that is removed from the data. +% Preferably the data should have a length that is a multiple of the % oscillation period of the line noise (i.e. 20ms for 50Hz noise). If the % data is of different lenght, then only the first N complete periods are % used to estimate the line noise. The estimate is subtracted from the % complete data. % +% B) Alternatively line noise is reduced via spectrum interpolation +% (introduced by Mewett et al., 2004, Med. Biol. Eng. Comput. 42, +% doi:10.1007/BF02350994). +% The signal is: +% I) transformed into the frequency domain via a discrete Fourier +% transform (DFT), +% II) the line noise component (e.g. 50Hz, Flwidth = 1 (±1Hz): 49-51Hz) is +% interpolated in the amplitude spectrum by replacing the amplitude +% of this frequency bin by the mean of the adjacent frequency bins +% ('neighbours', e.g. 49Hz and 51Hz). +% Neighwidth defines frequencies considered for the mean (e.g. +% Neighwidth = 2 (±2Hz) implies 47-49 Hz and 51-53 Hz). +% The original phase information of the noise frequency bin is +% retained. +% III) the signal is transformed back into the time domain via inverse DFT +% (iDFT). +% If Fline is a vector (e.g. [50 100 150]), harmonics are also considered. +% Preferably the data should be continuous or consist of long data segments +% (several seconds) to avoid edge effects. If the sampling rate and the +% data length are such, that a full cycle of the line noise and the harmonics +% fit in the data and if the line noise is stationary (e.g. no variations +% in amplitude or frequency), then spectrum interpolation can also be +% applied to short trials. But it should be used with caution and checked +% for edge effects. +% +% Use as +% [filt] = ft_preproc_dftfilter(dat, Fsample, Fline, varargin) +% where +% dat data matrix (Nchans X Ntime) +% Fsample sampling frequency in Hz +% Fline line noise frequency (and harmonics) +% +% Additional input arguments come as key-value pairs: +% +% Flreplace 'zero' or 'neighbour', method used to reduce line noise, 'zero' implies DFT filter, 'neighbour' implies spectrum interpolation +% Flwidth bandwidth of line noise frequencies, applies to spectrum interpolation, in Hz +% Neighwidth width of frequencies neighbouring line noise frequencies, applies to spectrum interpolation (Flreplace = 'neighbour'), in Hz +% +% The line frequency should be specified as a single number for the DFT filter. +% If omitted, a European default of 50Hz will be assumed +% % See also PREPROC % Undocumented option: @@ -31,6 +66,7 @@ % % Copyright (C) 2003, Pascal Fries % Copyright (C) 2003-2015, Robert Oostenveld +% Copyright (C) 2016, Sabine Leske % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -50,6 +86,11 @@ % % $Id$ +% defaults +Flreplace = ft_getopt(varargin,'dftreplace','zero'); +Flwidth = ft_getopt(varargin, 'dftbandwidth', [1 2 3]); +Neighwidth = ft_getopt(varargin, 'dftneighbourwidth', [2 2 2]); + % determine the size of the data [nchans, nsamples] = size(dat); @@ -61,37 +102,84 @@ % ensure to be a column vector Fl = Fl(:); -% determine the largest integer number of line-noise cycles that fits in the data -n = round(floor(nsamples .* Fl./Fs) * Fs./Fl); -if all(n==n(1)) - % make a selection of samples such that the line-noise fits the data - sel = 1:n(1); -else - % the different frequencies require different numbers of samples, apply the filters sequentially - for i=1:numel(Fl) - filt = dat; - filt = ft_preproc_dftfilter(filt, Fs, Fl(i)); - end - return +% preprocessing fails on channels that contain NaN +if any(isnan(dat(:))) + ft_warning('FieldTrip:dataContainsNaN', 'data contains NaN values'); end -% temporarily remove mean to avoid leakage -meandat = mean(dat(:,sel),2); -for i=1:nsamples - % demean the data - dat(:,i) = dat(:,i) - meandat; -end +% Method A): DFT filter +if strcmp(Flreplace,'zero') + % determine the largest integer number of line-noise cycles that fits in the data + n = round(floor(nsamples .* Fl./Fs) * Fs./Fl); + if all(n==n(1)) + % make a selection of samples such that the line-noise fits the data + sel = 1:n(1); + else + % the different frequencies require different numbers of samples, apply the filters sequentially + filt = dat; + for i=1:numel(Fl) + optarg = varargin; + filt = ft_preproc_dftfilter(filt, Fs, Fl(i), optarg{:}); + end + return + end + + % temporarily remove mean to avoid leakage + meandat = mean(dat(:,sel),2); + for i=1:nsamples + % demean the data + dat(:,i) = dat(:,i) - meandat; + end + + % fit a sine and cosine to each channel in the data and subtract them + time = (0:nsamples-1)/Fs; + tmp = exp(1i*2*pi*Fl*time); % complex sin and cos + ampl = 2*dat(:,sel)/tmp(:,sel); % estimated amplitude of complex sin and cos on integer number of cycles + est = ampl*tmp; % estimated signal at this frequency + filt = dat - est; % subtract estimated signal + filt = real(filt); + + for i=1:nsamples + % add the mean back to the filtered data + filt(:,i) = filt(:,i) + meandat; + end -% fit a sine and cosine to each channel in the data and subtract them -time = (0:nsamples-1)/Fs; -tmp = exp(1i*2*pi*Fl*time); % complex sin and cos -ampl = 2*dat(:,sel)/tmp(:,sel); % estimated amplitude of complex sin and cos on integer number of cycles -est = ampl*tmp; % estimated signal at this frequency -filt = dat - est; % subtract estimated signal -filt = real(filt); +% Method B): Spectrum Interpolation +elseif strcmp(Flreplace,'neighbour') + Flwidth = Flwidth(:); + Neighwidth = Neighwidth(:); + + if (length(Fl) ~= length(Flwidth)) || (length(Fl) ~= length(Neighwidth)) + ft_error('The number of frequencies to interpolate (cfg.dftfreq) should be the same as the number of bandwidths (cfg.dftbandwidth) and bandwidths of neighbours (cfg.neighbourwidth)'); + end -for i=1:nsamples - % add the mean back to the filtered data - filt(:,i) = filt(:,i) + meandat; + % frequencies to interpolate + for i = 1:length(Fl) + f2int(i,:) = [Fl(i)-Flwidth(i) Fl(i)+Flwidth(i)]; + end + % frequencies used for interpolation + for i = 1:length(Neighwidth) + f4int(i,:) = [f2int(i,1)-Neighwidth(i) f2int(i,:) f2int(i,2)+Neighwidth(i)]; + end + + data_fft = fft(dat,nsamples,2); % calculate fft to obtain spectrum that will be interpolated + frq = Fs*linspace(0,1,nsamples+1); + + % interpolate 50Hz (and harmonics) amplitude in spectrum + for i = 1:length(Fl) + smpl2int = nearest(frq,f2int(i,1)):nearest(frq,f2int(i,2)); % samples of frequencies that will be interpolated + smpl4int = [(nearest(frq,f4int(i,1)):nearest(frq,f4int(i,2))-1),(nearest(frq,f4int(i,3))+1:nearest(frq,f4int(i,4)))]; % samples of neighbouring frequencies used to calculate the mean + + % new amplitude is calculated as the mean of the neighbouring frequencies + mns4int= bsxfun(@times, ones(size(data_fft(:,smpl2int))), mean(abs(data_fft(:,smpl4int)),2)); + + % Eulers formula: replace noise components with new mean amplitude combined with phase, that is retained from the original data + data_fft(:,smpl2int) = bsxfun(@times, exp(bsxfun(@times,angle(data_fft(:,smpl2int)),1i)), mns4int); + end + + % complex fourier coefficients are transformed back into time domin, fourier coefficients are treated as conjugate 'symmetric' + % to ensure a real valued signal after iFFT + filt = ifft(data_fft,[],2,'symmetric'); + end diff --git a/external/fieldtrip/preproc/ft_preproc_highpassfilter.m b/external/fieldtrip/preproc/ft_preproc_highpassfilter.m index c2b3c6d8..bed2ee3c 100644 --- a/external/fieldtrip/preproc/ft_preproc_highpassfilter.m +++ b/external/fieldtrip/preproc/ft_preproc_highpassfilter.m @@ -1,4 +1,4 @@ -function [filt] = ft_preproc_highpassfilter(dat,Fs,Fhp,N,type,dir,instabilityfix,df,wintype,dev,plotfiltresp,usefftfilt) +function [filt, B, A] = ft_preproc_highpassfilter(dat,Fs,Fhp,N,type,dir,instabilityfix,df,wintype,dev,plotfiltresp,usefftfilt) % FT_PREPROC_HIGHPASSFILTER applies a high-pass filter to the data and thereby removes % the low frequency components in the data @@ -24,6 +24,7 @@ % 'twopass-reverse' zero-phase reverse and forward filter % 'twopass-average' average of the twopass and the twopass-reverse % 'onepass-zerophase' zero-phase forward filter with delay compensation (default for firws, linear-phase symmetric FIR only) +% 'onepass-reverse-zerophase' zero-phase reverse filter with delay compensation % 'onepass-minphase' minimum-phase converted forward filter (non-linear!, firws only) % instabilityfix optional method to deal with filter instabilities % 'no' only detect and give error (default) @@ -130,11 +131,15 @@ end % Filtering does not work on integer data -typ = class(dat); -if ~strcmp(typ, 'double') && ~strcmp(typ, 'single') +if ~isa(dat, 'double') && ~isa(dat, 'single') dat = cast(dat, 'double'); end +% preprocessing fails on channels that contain NaN +if any(isnan(dat(:))) + ft_warning('FieldTrip:dataContainsNaN', 'data contains NaN values'); +end + % Nyquist frequency Fn = Fs/2; @@ -150,12 +155,12 @@ % Input arguments if length(Fhp) ~= 1 - error('One cutoff frequency required.') + ft_error('One cutoff frequency required.') end % Filter order AND transition width set? if ~isempty(N) && ~isempty(df) - warning('firws:dfOverridesN', 'Filter order AND transition width set - transition width setting will override filter order.') + ft_warning('firws:dfOverridesN', 'Filter order AND transition width set - transition width setting will override filter order.') elseif isempty(N) && isempty(df) % Default transition width heuristic df = fir_df(Fhp, Fs); end @@ -165,14 +170,14 @@ isOrderLow = false; if ~isempty(df) if df > maxDf - error('Transition band too wide. Maximum transition width is %.2f Hz.', maxDf) + ft_error('Transition band too wide. Maximum transition width is %.2f Hz.', maxDf) end [N, dev] = firwsord(wintype, Fs, df, dev); else % Check filter order otherwise [df, dev] = invfirwsord(wintype, Fs, N, dev); if df > maxDf nOpt = firwsord(wintype, Fs, maxDf, dev); - warning('firws:filterOrderLow', 'Filter order too low. For better results a minimum filter order of %d is recommended. Effective cutoff frequency might deviate from requested cutoff frequency.', nOpt) + ft_warning('firws:filterOrderLow', 'Filter order too low. For better results a minimum filter order of %d is recommended. Effective cutoff frequency might deviate from requested cutoff frequency.', nOpt) isOrderLow = true; end end @@ -232,11 +237,12 @@ N=floor(size(dat,2)/3) - 2; if rem(N,2)==1, N=N+1; end end - [B, A] = fir1(N, max(Fhp)/Fn, 'high'); + B = fir1(N, max(Fhp)/Fn, 'high'); + A = 1; case 'firls' % from NUTMEG's implementation % Deprecated: see bug 2453 - warning('The filter type you requested is not recommended for neural signals, only proceed if you know what you are doing.') + ft_warning('The filter type you requested is not recommended for neural signals, only proceed if you know what you are doing.') if isempty(N) N = 3*fix(Fs / Fhp); if rem(N,2)==1, N=N+1; end @@ -266,7 +272,7 @@ return otherwise - error('unsupported filter type "%s"', type); + ft_error('unsupported filter type "%s"', type); end % demean the data before filtering @@ -280,20 +286,19 @@ case 'no' rethrow(lasterror); case 'reduce' - warning('backtrace', 'off') - ft_warning(sprintf('filter instability detected - reducing the %dth order filter to an %dth order filter', N, N-1)); - warning('backtrace', 'on') + ft_warning('off','backtrace'); + ft_warning('filter instability detected - reducing the %dth order filter to an %dth order filter', N, N-1); + ft_warning('on','backtrace'); filt = ft_preproc_highpassfilter(dat,Fs,Fhp,N-1,type,dir,instabilityfix); case 'split' N1 = ceil(N/2); N2 = floor(N/2); - warning('backtrace', 'off') - ft_warning(sprintf('filter instability detected - splitting the %dth order filter in a sequential %dth and a %dth order filter', N, N1, N2)); - warning('backtrace', 'on') + ft_warning('off','backtrace'); + ft_warning('filter instability detected - splitting the %dth order filter in a sequential %dth and a %dth order filter', N, N1, N2); + ft_warning('on','backtrace'); filt = ft_preproc_highpassfilter(dat ,Fs,Fhp,N1,type,dir,instabilityfix); filt = ft_preproc_highpassfilter(filt,Fs,Fhp,N2,type,dir,instabilityfix); otherwise - error('incorrect specification of instabilityfix'); + ft_error('incorrect specification of instabilityfix'); end % switch end - diff --git a/external/fieldtrip/preproc/ft_preproc_hilbert.m b/external/fieldtrip/preproc/ft_preproc_hilbert.m index 8c301924..5e1f260c 100644 --- a/external/fieldtrip/preproc/ft_preproc_hilbert.m +++ b/external/fieldtrip/preproc/ft_preproc_hilbert.m @@ -48,6 +48,11 @@ option = 'abs'; end +% preprocessing fails on channels that contain NaN +if any(isnan(dat(:))) + ft_warning('FieldTrip:dataContainsNaN', 'data contains NaN values'); +end + % use the non-conjugate transpose to be sure dat = transpose(hilbert(transpose(dat))); @@ -70,5 +75,5 @@ case 'unwrap_angle' dat = unwrap(angle(dat./abs(dat)),[],2); otherwise - error('incorrect specification of the optional input argument'); + ft_error('incorrect specification of the optional input argument'); end diff --git a/external/fieldtrip/preproc/ft_preproc_lowpassfilter.m b/external/fieldtrip/preproc/ft_preproc_lowpassfilter.m index 6b8c72c7..995e8c12 100644 --- a/external/fieldtrip/preproc/ft_preproc_lowpassfilter.m +++ b/external/fieldtrip/preproc/ft_preproc_lowpassfilter.m @@ -1,4 +1,4 @@ -function [filt] = ft_preproc_lowpassfilter(dat,Fs,Flp,N,type,dir,instabilityfix,df,wintype,dev,plotfiltresp,usefftfilt) +function [filt, B, A] = ft_preproc_lowpassfilter(dat,Fs,Flp,N,type,dir,instabilityfix,df,wintype,dev,plotfiltresp,usefftfilt) % FT_PREPROC_LOWPASSFILTER applies a low-pass filter to the data and thereby % removes all high frequency components in the data @@ -130,11 +130,15 @@ end % Filtering does not work on integer data -typ = class(dat); -if ~strcmp(typ, 'double') && ~strcmp(typ, 'single') +if ~isa(dat, 'double') && ~isa(dat, 'single') dat = cast(dat, 'double'); end +% preprocessing fails on channels that contain NaN +if any(isnan(dat(:))) + ft_warning('FieldTrip:dataContainsNaN', 'data contains NaN values'); +end + % Nyquist frequency Fn = Fs/2; @@ -155,12 +159,12 @@ % Input arguments if length(Flp) ~= 1 - error('One cutoff frequency required.') + ft_error('One cutoff frequency required.') end % Filter order AND transition width set? if ~isempty(N) && ~isempty(df) - warning('firws:dfOverridesN', 'Filter order AND transition width set - transition width setting will override filter order.') + ft_warning('firws:dfOverridesN', 'Filter order AND transition width set - transition width setting will override filter order.') elseif isempty(N) && isempty(df) % Default transition width heuristic df = fir_df(Flp, Fs); end @@ -170,14 +174,14 @@ isOrderLow = false; if ~isempty(df) if df > maxDf - error('Transition band too wide. Maximum transition width is %.2f Hz.', maxDf) + ft_error('Transition band too wide. Maximum transition width is %.2f Hz.', maxDf) end [N, dev] = firwsord(wintype, Fs, df, dev); else % Check filter order otherwise [df, dev] = invfirwsord(wintype, Fs, N, dev); if df > maxDf nOpt = firwsord(wintype, Fs, maxDf, dev); - warning('firws:filterOrderLow', 'Filter order too low. For better results a minimum filter order of %d is recommended. Effective cutoff frequency might deviate from requested cutoff frequency.', nOpt) + ft_warning('firws:filterOrderLow', 'Filter order too low. For better results a minimum filter order of %d is recommended. Effective cutoff frequency might deviate from requested cutoff frequency.', nOpt) isOrderLow = true; end end @@ -235,10 +239,11 @@ if N > floor( (size(dat,2) - 1) / 3) N=floor(size(dat,2)/3) - 1; end - [B, A] = fir1(N, max(Flp)/Fn); + B = fir1(N, max(Flp)/Fn); + A = 1; case 'firls' % from NUTMEG's implementation % Deprecated: see bug 2453 - warning('The filter type you requested is not recommended for neural signals, only proceed if you know what you are doing.') + ft_warning('The filter type you requested is not recommended for neural signals, only proceed if you know what you are doing.') if isempty(N) N = 3*fix(Fs / Flp); end @@ -268,7 +273,7 @@ filt = 2*real(ifft(f,[],2)); % iFFT return otherwise - error('unsupported filter type "%s"', type); + ft_error('unsupported filter type "%s"', type); end % demean the data before filtering @@ -282,23 +287,22 @@ case 'no' rethrow(lasterror); case 'reduce' - warning('backtrace', 'off') - warning('instability detected - reducing the %dth order filter to an %dth order filter', N, N-1); - warning('backtrace', 'on') + ft_warning('off','backtrace'); + ft_warning('instability detected - reducing the %dth order filter to an %dth order filter', N, N-1); + ft_warning('on','backtrace'); filt = ft_preproc_lowpassfilter(dat,Fs,Flp,N-1,type,dir,instabilityfix); case 'split' N1 = ceil(N/2); N2 = floor(N/2); - warning('backtrace', 'off') - warning('instability detected - splitting the %dth order filter in a sequential %dth and a %dth order filter', N, N1, N2); - warning('backtrace', 'on') + ft_warning('off','backtrace'); + ft_warning('instability detected - splitting the %dth order filter in a sequential %dth and a %dth order filter', N, N1, N2); + ft_warning('on','backtrace'); filt = ft_preproc_lowpassfilter(dat ,Fs,Flp,N1,type,dir,instabilityfix); filt = ft_preproc_lowpassfilter(filt,Fs,Flp,N2,type,dir,instabilityfix); otherwise - error('incorrect specification of instabilityfix'); + ft_error('incorrect specification of instabilityfix'); end % switch end % add the mean back to the filtered data filt = bsxfun(@plus, filt, meandat); - diff --git a/external/fieldtrip/preproc/ft_preproc_medianfilter.m b/external/fieldtrip/preproc/ft_preproc_medianfilter.m index 13b9b34e..56e3b2fa 100644 --- a/external/fieldtrip/preproc/ft_preproc_medianfilter.m +++ b/external/fieldtrip/preproc/ft_preproc_medianfilter.m @@ -34,7 +34,12 @@ % set the default filter order if nargin<2 || isempty(order) - error('the order of the median filter is not specified'); + ft_error('the order of the median filter is not specified'); +end + +% preprocessing fails on channels that contain NaN +if any(isnan(dat(:))) + ft_warning('FieldTrip:dataContainsNaN', 'data contains NaN values'); end % deal with padding @@ -48,9 +53,26 @@ dat(k,:) = fastmedfilt1d(dat(k,:), order); end else - % use Mathworks slow version - dat = medfilt1(dat, order, [], 2); + is_matlab=ft_platform_supports('matlabversion',1,inf); + if is_matlab + % use Mathworks slow version + dat = medfilt1(dat, order, [], 2); + else + % use helper function that uses Octave's medfilt1 + dat = medfilt1_rowwise(dat, order); + end end % cut the eges dat = ft_preproc_padding(dat, 'remove', pad); + +%%%%%%%%%%%%%%%%%%%%%% +% Helper function +%%%%%%%%%%%%%%%%%%%%%% +function y = medfilt1_rowwise(x,order) +% this function is compatible with Octave; +% Octave's medfilt1 accepts only two input arguments + y = zeros(size(x)); + for k = 1:size(x,1) + y(k,:) = medfilt1(x(k,:),order); + end diff --git a/external/fieldtrip/preproc/ft_preproc_online_filter_apply.m b/external/fieldtrip/preproc/ft_preproc_online_filter_apply.m index e3767db7..18b8d5aa 100644 --- a/external/fieldtrip/preproc/ft_preproc_online_filter_apply.m +++ b/external/fieldtrip/preproc/ft_preproc_online_filter_apply.m @@ -3,7 +3,9 @@ % function [FM, xf] = ft_preproc_online_filter_apply(FM, x) % % Passes signal x (channels times samples) through the filter, -% returns updated filter model (delay states!) and filtered signal. +% returns updated filter model (delay states) and filtered signal. +% +% See also FT_PREPROC_ONLINE_FILTER_INIT % Copyright (C) 2010, Stefan Klanke % @@ -28,18 +30,18 @@ [dimX, numX] = size(x); if dimX > numX - % explicit algorithm - faster for many channels, 1 sample (=fMRI) - xf = zeros(size(x)); - - for k=1:numX; - z_old = FM.z; - z0 = x(:,k) - z_old*FM.A2; - xf(:,k) = z_old * FM.B2 + z0*FM.B1; - FM.z(:,2:end) = z_old(:,1:end-1); - FM.z(:,1) = z0; - end + % explicit algorithm - faster for many channels, 1 sample (=fMRI) + xf = zeros(size(x)); + + for k=1:numX; + z_old = FM.z; + z0 = x(:,k) - z_old*FM.A2; + xf(:,k) = z_old * FM.B2 + z0*FM.B1; + FM.z(:,2:end) = z_old(:,1:end-1); + FM.z(:,1) = z0; + end else - % use built-in MATLAB stuff - faster for many samples - [xf, z] = filter(FM.B,FM.A, x, FM.z',2); - FM.z = z'; + % use built-in MATLAB stuff - faster for many samples, few channels + [xf, z] = filter(FM.B, FM.A, x, FM.z',2); + FM.z = z'; end diff --git a/external/fieldtrip/preproc/ft_preproc_online_filter_init.m b/external/fieldtrip/preproc/ft_preproc_online_filter_init.m index 0ed0f211..3f77e65e 100644 --- a/external/fieldtrip/preproc/ft_preproc_online_filter_init.m +++ b/external/fieldtrip/preproc/ft_preproc_online_filter_init.m @@ -5,8 +5,10 @@ % Initialize an IIR filter model with coefficients B and A, as used in filter and butter etc. % One sample x of the signal must be given as a column vector. % -% This function will calculate the filter delay states such that the initial response +% This function will calculate the filter delay states such that the initial response % is as if 'x' would have been applied since forever. +% +% See also FT_PREPROC_ONLINE_FILTER_APPLY % Copyright (C) 2010, Stefan Klanke % @@ -33,8 +35,8 @@ B = B(:); % use column vector if A(1)~=1 - B = B/A(1); - A = A/A(1); + B = B/A(1); + A = A/A(1); end La = length(A); @@ -44,15 +46,15 @@ FM.d = size(x,1); if LaLb - % pad B with zeros - B = [B; zeros(La-Lb,1)]; - FM.N = La-1; + % pad B with zeros + B = [B; zeros(La-Lb,1)]; + FM.N = La-1; else - FM.N = La-1; + FM.N = La-1; end FM.A = A; @@ -70,6 +72,7 @@ % We want to find the delay states corresponding to constant input (=1). M = [[0; -A(2:end); 0],[eye(FM.N);zeros(2,FM.N)],[B;1]]; n = null(M-eye(2+FM.N)); % = eigenvector of M corresponding to eigenvalue=1, that is n=M*n +n = n(:,1); % ensure that it is only the first eigenvector z = n(2:end-1); % delay state part of it z = z*(1-B(1))/z(1); % scale appropiately -FM.z = x*z; +FM.z = x*z'; diff --git a/external/fieldtrip/preproc/ft_preproc_padding.m b/external/fieldtrip/preproc/ft_preproc_padding.m index 25dd0c98..59622c68 100644 --- a/external/fieldtrip/preproc/ft_preproc_padding.m +++ b/external/fieldtrip/preproc/ft_preproc_padding.m @@ -10,16 +10,16 @@ % where % dat data matrix (Nchan x Ntime) % padtype 'zero', 'mean', 'localmean', 'edge', 'mirror', 'nan' or 'remove' -% padlength scalar, number of samples that will be padded +% padlength scalar, number of samples that will be padded % prepadlength scalar, number of samples that will be padded before the data % postpadlength scalar, number of samples that will be padded after the data % % If padlength is used instead of prepadlength and postpadlength, padding % will be symmetrical (i.e. padlength = prepadlength = postpadlength) -% +% % See also FT_PREPROCESSING -% Copyright (C) 2012, Jörn M. Horschig, Robert Oostenveld, Jan-Mathijs Schoffelen +% Copyright (C) 2012, J?rn M. Horschig, Robert Oostenveld, Jan-Mathijs Schoffelen % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -50,10 +50,10 @@ nchans = size(dat, 1); nsamples = size(dat, 2); -switch(padtype) +switch(padtype) case 'remove' dat = dat(:, prepadlength+1:end-postpadlength); - return; + case 'mirror' padbeg = 1:prepadlength; padend = 1:postpadlength; @@ -89,28 +89,29 @@ end dat = [dat(:, padbeg) dat dat(:, padend)]; - return; + case 'edge' dat = [dat(:,1)*ones(1,prepadlength) dat dat(:,end)*ones(1,postpadlength)]; - return; + case 'mean' mu = mean(dat, 2); dat = [mu*ones(1,prepadlength) dat mu*ones(1,postpadlength)]; + case 'localmean' prepad = min(prepadlength, floor(size(dat, 2)/2)); edgeleft = mean(dat(:, 1:prepad), 2); postpad = min(postpadlength, floor(size(dat, 2)/2)); edgeright = mean(dat(:, 1+end-postpad:end), 2); dat = [edgeleft*ones(1,prepadlength) dat edgeright*ones(1,postpadlength)]; - return; + case 'zero' dat = [zeros(nchans,prepadlength) dat zeros(nchans,postpadlength)]; - return; + case 'nan' dat = [nan(nchans,prepadlength) dat nan(nchans,postpadlength)]; - return; + otherwise - error('unknown padding option'); + ft_error('unknown padding option'); end end diff --git a/external/fieldtrip/preproc/ft_preproc_polyremoval.m b/external/fieldtrip/preproc/ft_preproc_polyremoval.m index 6e1fb25c..b16bb60e 100644 --- a/external/fieldtrip/preproc/ft_preproc_polyremoval.m +++ b/external/fieldtrip/preproc/ft_preproc_polyremoval.m @@ -58,9 +58,37 @@ flag = 0; end -% this does not work on integer data +% This does not work on integer data typ = class(dat); -dat = cast(dat, 'double'); +if ~isa(dat, 'double') && ~isa(dat, 'single') + dat = cast(dat, 'double'); +end + +usesamples = false(1,size(dat,2)); +usesamples(begsample:endsample) = true; + +% preprocessing fails on channels that contain NaN +if any(isnan(dat(:))) + ft_warning('FieldTrip:dataContainsNaN', 'data contains NaN values'); + + datnans = isnan(dat); + + % if a nan occurs, it's for all time points + check1 = all(ismember(sum(datnans,1),[0 size(dat,1)])); + + % if a channel has nans, it's for all samples + check2 = all(ismember(sum(datnans,2),[0 size(dat,2)])); + + if ~(check1 || check2) + usesamples = repmat(usesamples, [size(dat,1) 1]); + usesamples = usesamples & ~isnan(dat); + elseif check1 + usesamples(sum(datnans,1)==size(dat,1)) = false; % switch the nan samples off, they are not to be used for the regression + end +else + check1 = true; + check2 = true; +end % construct a "time" axis nsamples = size(dat,2); @@ -75,10 +103,20 @@ x(i+1,:) = basis.^(i); end -% estimate the contribution of the basis functions -% beta = dat(:,begsample:endsample)/x(:,begsample:endsample); <-this leads to numerical issues, even in simple examples -invxcov = inv(x(:,begsample:endsample)*x(:,begsample:endsample)'); -beta = dat(:,begsample:endsample)*x(:,begsample:endsample)'*invxcov; +if ~(check1 || check2) + % loop across rows + beta = zeros(size(dat,1),size(x,1)); + for k = 1:size(dat,1) + invxcov = inv(x(:,usesamples(k,:))*x(:,usesamples(k,:))'); + beta(k,:) = dat(k,usesamples(k,:))*x(:,usesamples(k,:))'*invxcov; + end +else + + % estimate the contribution of the basis functions + % beta = dat(:,begsample:endsample)/x(:,begsample:endsample); <-this leads to numerical issues, even in simple examples + invxcov = inv(x(:,usesamples)*x(:,usesamples)'); + beta = dat(:,usesamples)*x(:,usesamples)'*invxcov; +end % remove the estimated basis functions dat = dat - beta*x; diff --git a/external/fieldtrip/preproc/ft_preproc_rereference.m b/external/fieldtrip/preproc/ft_preproc_rereference.m index 0833128e..552de62b 100644 --- a/external/fieldtrip/preproc/ft_preproc_rereference.m +++ b/external/fieldtrip/preproc/ft_preproc_rereference.m @@ -1,21 +1,22 @@ -function [dat, ref] = ft_preproc_rereference(dat, refchan, method) +function [dat, ref] = ft_preproc_rereference(dat, refchan, method, handlenan) % FT_PREPROC_REREFERENCE computes the average reference over all EEG channels % or rereferences the data to the selected channels % % Use as -% [dat] = ft_preproc_rereference(dat, refchan) +% [dat] = ft_preproc_rereference(dat, refchan, method, handlenan) % where % dat data matrix (Nchans X Ntime) -% refchan vector with indices of the new reference channels +% refchan vector with indices of the new reference channels, or 'all' % method string, can be 'avg' or 'median' +% handlenan boolean, can be true or false % % If the new reference channel is not specified, the data will be % rereferenced to the average of all channels. % % See also PREPROC -% Copyright (C) 1998-2008, Robert Oostenveld +% Copyright (C) 1998-2017, Robert Oostenveld % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -42,18 +43,44 @@ if nargin<2 || isempty(refchan) || (ischar(refchan) && strcmp(refchan, 'all')) refchan = 1:Nchans; end + if nargin<3 || isempty(method) method = 'avg'; end -% compute the average value over the reference channels -if strcmp(method, 'avg') - ref = mean(dat(refchan,:), 1); -elseif strcmp(method, 'median') - ref = median(dat(refchan,:), 1); +if nargin<4 || isempty(handlenan) + handlenan = false; +end + +hasnan = any(any(isnan(dat(refchan,:)))); + +if hasnan && handlenan + % preprocessing works differently if channels contain NaN + switch method + case 'avg' + ref = nanmean(dat(refchan,:), 1); + case 'median' + ref = nanmedian(dat(refchan,:), 1); + otherwise + ft_error('unsupported method') + end % switch +else + % preprocessing fails on channels that contain NaN + if any(isnan(dat(:))) + ft_warning('FieldTrip:dataContainsNaN', 'data contains NaN values'); + end + % compute the average value over the reference channels + switch method + case 'avg' + ref = mean(dat(refchan,:), 1); + case 'median' + ref = median(dat(refchan,:), 1); + otherwise + ft_error('unsupported method') + end % switch end -% apply the new reference to the data +% subtract the new reference from the data for chan=1:Nchans dat(chan,:) = dat(chan,:) - ref; end diff --git a/external/fieldtrip/preproc/ft_preproc_resample.m b/external/fieldtrip/preproc/ft_preproc_resample.m index 5028ba12..e55e3ea5 100644 --- a/external/fieldtrip/preproc/ft_preproc_resample.m +++ b/external/fieldtrip/preproc/ft_preproc_resample.m @@ -45,6 +45,8 @@ end if Fold==Fnew + ft_warning('requested sampling rate after resampling is the same as the sampling rate of the data, no resampling is performed'); + datout = dat; return end @@ -54,6 +56,11 @@ dat = cast(dat, 'double'); end +% preprocessing fails on channels that contain NaN +if any(isnan(dat(:))) + ft_warning('FieldTrip:dataContainsNaN', 'data contains NaN values'); +end + switch method case 'resample' [fold, fnew] = rat(Fold./Fnew);%account for non-integer fs @@ -76,32 +83,32 @@ % the actual implementation resamples along columns datout = downsample(dat', fac)'; - case 'fft' - % Code written for SPM by Jean Daunizeau - fac = Fnew/Fold; - nresampled = floor(nsamples*fac); - fac = nresampled/nsamples; - datfft = fftshift(fft(dat,[],2),2); - middle = floor(size(datfft,2)./2)+1; - if fac>1 % upsample - npad = floor((nresampled-nsamples)./2); - - if nsamples/2 == floor(nsamples/2) - datfft(:,1) = []; % throw away non symmetric DFT coef - end - - datfft = [zeros(size(datfft,1),npad), datfft,zeros(size(datfft,1),npad)]; - else % downsample - ncut = floor(nresampled./2); - datfft = datfft(:,middle-ncut:middle+ncut); - end - datout = fac*ifft(ifftshift(datfft,2),[],2); - otherwise - error('unsupported resampling method'); + case 'fft' + % Code written for SPM by Jean Daunizeau + fac = Fnew/Fold; + nresampled = floor(nsamples*fac); + fac = nresampled/nsamples; + datfft = fftshift(fft(dat,[],2),2); + middle = floor(size(datfft,2)./2)+1; + if fac>1 % upsample + npad = floor((nresampled-nsamples)./2); + + if nsamples/2 == floor(nsamples/2) + datfft(:,1) = []; % throw away non symmetric DFT coef + end + + datfft = [zeros(size(datfft,1),npad), datfft,zeros(size(datfft,1),npad)]; + else % downsample + ncut = floor(nresampled./2); + datfft = datfft(:,middle-ncut:middle+ncut); + end + datout = fac*ifft(ifftshift(datfft,2),[],2); + otherwise + ft_error('unsupported resampling method'); end if ~strcmp(method, 'downsample') - % convert back into the original input format - datout = cast(datout, typ); + % convert back into the original input format + datout = cast(datout, typ); end diff --git a/external/fieldtrip/preproc/ft_preproc_slidingrange.m b/external/fieldtrip/preproc/ft_preproc_slidingrange.m index 2177542f..9fdf2459 100644 --- a/external/fieldtrip/preproc/ft_preproc_slidingrange.m +++ b/external/fieldtrip/preproc/ft_preproc_slidingrange.m @@ -33,8 +33,13 @@ normalize = ft_getopt(varargin, 'normalize', false); +% preprocessing fails on channels that contain NaN +if any(isnan(dat(:))) + ft_warning('FieldTrip:dataContainsNaN', 'data contains NaN values'); +end + if mod(width+1, 2) - error('width should be an odd number'); + ft_error('width should be an odd number'); end % compute half width diff --git a/external/fieldtrip/preproc/ft_preproc_smooth.m b/external/fieldtrip/preproc/ft_preproc_smooth.m index 58e7d19c..71928704 100644 --- a/external/fieldtrip/preproc/ft_preproc_smooth.m +++ b/external/fieldtrip/preproc/ft_preproc_smooth.m @@ -33,6 +33,11 @@ % % $Id$ +% preprocessing fails on channels that contain NaN +if any(isnan(dat(:))) + ft_warning('FieldTrip:dataContainsNaN', 'data contains NaN values'); +end + % create smoothing kernel if isscalar(n) krn = ones(1,n)/n; @@ -44,7 +49,6 @@ % deal with padding dat = ft_preproc_padding(dat, 'localmean', ceil(n/2)); - % do the smoothing if n<100 % heuristic: for large kernel the convolution is faster when done along diff --git a/external/fieldtrip/preproc/ft_preproc_standardize.m b/external/fieldtrip/preproc/ft_preproc_standardize.m index d3ce30f5..c1905a44 100644 --- a/external/fieldtrip/preproc/ft_preproc_standardize.m +++ b/external/fieldtrip/preproc/ft_preproc_standardize.m @@ -1,4 +1,4 @@ -function [x, state] = ft_preproc_standardize(x, begsample, endsample, state) +function [dat, state] = ft_preproc_standardize(dat, begsample, endsample, state) % FT_PREPROC_STANDARDIZE performs a z-transformation or standardization % of the data. The standardized data will have a zero-mean and a unit @@ -7,7 +7,7 @@ % Use as % [dat] = ft_preproc_standardize(dat, begsample, endsample) % where -% dat data matrix (Nchans X Ntime) +% dat data matrix (Nchans dat Ntime) % begsample index of the begin sample for the mean and stdev estimate % endsample index of the end sample for the mean and stdev estimate % @@ -41,17 +41,22 @@ end if nargin<3 || isempty(endsample) - endsample = size(x,2); + endsample = size(dat,2); end if nargin<4 state = []; end +% preprocessing fails on channels that contain NaN +if any(isnan(dat(:))) + ft_warning('FieldTrip:dataContainsNaN', 'data contains NaN values'); +end + % get the data selection -y = x(:,begsample:endsample); +y = dat(:,begsample:endsample); -% determine the size of the selected data: nChans X nSamples +% determine the size of the selected data: nChans dat nSamples [m, n] = size(y); % compute the sum and sum of squares @@ -70,7 +75,7 @@ sy = sqrt((ss - (s.^2)./n) ./ (n-1)); % standardize the complete input data -x = (x - repmat(my, 1, size(x, 2))) ./ repmat(sy, 1, size(x, 2)); +dat = (dat - repmat(my, 1, size(dat, 2))) ./ repmat(sy, 1, size(dat, 2)); % remember the state state.s = s; % sum diff --git a/external/fieldtrip/preproc/private/defaultId.m b/external/fieldtrip/preproc/private/defaultId.m new file mode 100644 index 00000000..f4e1ee99 --- /dev/null +++ b/external/fieldtrip/preproc/private/defaultId.m @@ -0,0 +1,57 @@ +function id = defaultId + +% DEFAULTID returns a string that can serve as warning or error identifier, +% for example 'FieldTip:ft_read_header:line345'. +% +% See also WARNING, ERROR, FT_NOTICE, FT_INFO, FT_DEBUG + +% Copyright (C) 2017, Robert Oostenveld +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +stack = dbstack('-completenames'); + +% remove the functions that pertain to the notification system itself +keep = true(size(stack)); +keep(strcmp({stack.name}, 'defaultId')) = false; % this function itself +keep(strcmp({stack.name}, 'ft_notification')) = false; % this one is doing the work underneath ft_error/ft_warning/ft_notice/etc. +keep(strcmp({stack.name}, 'ft_error')) = false; +keep(strcmp({stack.name}, 'ft_warning')) = false; +keep(strcmp({stack.name}, 'ft_notice')) = false; +keep(strcmp({stack.name}, 'ft_info')) = false; +keep(strcmp({stack.name}, 'ft_debug')) = false; +stack = stack(keep); + +% remove the non-FieldTrip functions from the path, these should not be part of the default message identifier +keep = true(size(stack)); +[v, p] = ft_version; +for i=1:numel(stack) + keep(i) = strncmp(p, stack(i).file, length(p)); +end +stack = stack(keep); + +if ~isempty(stack) + % it is called from within a function + stack = flipud(stack); + name = {stack.name}; + id = ['FieldTrip' sprintf(':%s', name{:}) ':line' num2str(stack(end).line)]; +else + % it is called from the command line + id = 'FieldTrip:commandline'; +end diff --git a/external/fieldtrip/preproc/private/filter_with_correction.m b/external/fieldtrip/preproc/private/filter_with_correction.m index 0ade7fd1..72638aa0 100644 --- a/external/fieldtrip/preproc/private/filter_with_correction.m +++ b/external/fieldtrip/preproc/private/filter_with_correction.m @@ -9,11 +9,14 @@ % B,A filter coefficients % dat data matrix (Nchans X Ntime) % dir optional filter direction, can be -% 'onepass' forward filter only -% 'onepass-reverse' reverse filter only, i.e. backward in time -% 'twopass' zero-phase forward and reverse filter (default) -% 'twopass-reverse' zero-phase reverse and forward filter -% 'twopass-average' average of the twopass and the twopass-reverse +% 'onepass' forward filter only +% 'onepass-reverse' reverse filter only, i.e. backward in time +% 'twopass' zero-phase forward and reverse filter (default) +% 'twopass-reverse' zero-phase reverse and forward filter +% 'twopass-average' average of the twopass and the twopass-reverse +% 'onepass-zerophase' zero-phase forward filter with delay compensation (default for firws, linear-phase symmetric FIR only) +% 'onepass-reverse-zerophase' zero-phase reverse filter with delay compensation +% 'onepass-minphase' minimum-phase converted forward filter (non-linear!, firws only) % % Note that a one- or two-pass filter has consequences for the % strength of the filter, i.e. a two-pass filter with the same filter @@ -40,7 +43,7 @@ % $Id$ % convert the data to double precision -% see http://bugzilla.fcdonders.nl/show_bug.cgi?id=2653 +% see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2653 inputclass = class(dat); B = double(B); A = double(A); @@ -48,7 +51,7 @@ poles = roots(A); if any(abs(poles) >= 1) - error('Calculated filter coefficients have poles on or outside the unit circle and will not be stable. Try a higher cutoff frequency or a different type/order of filter.'); + ft_error('Calculated filter coefficients have poles on or outside the unit circle and will not be stable. Try a higher cutoff frequency or a different type/order of filter.'); end dcGain = sum(B)/sum(A); @@ -78,10 +81,15 @@ filt = (filt1 + filt2)/2; case 'onepass-zerophase' filt = fir_filterdcpadded(B, A, dat', 0, usefftfilt)'; + case 'onepass-reverse-zerophase' + offset = dat(:,end); + dat = fliplr(dat) - repmat(offset,1,N); + filt = fir_filterdcpadded(B, A, dat', 0, usefftfilt)'; + filt = fliplr(filt) + repmat(dcGain*offset, 1, N); case 'onepass-minphase' filt = fir_filterdcpadded(B, A, dat', 1, usefftfilt)'; otherwise - error('unsupported filter direction "%s"', dir); + ft_error('unsupported filter direction "%s"', dir); end % cast it back into the type of the input data, which can e.g. be single or int32 diff --git a/external/fieldtrip/preproc/private/fir_df.m b/external/fieldtrip/preproc/private/fir_df.m index 6155df6e..da2a059f 100644 --- a/external/fieldtrip/preproc/private/fir_df.m +++ b/external/fieldtrip/preproc/private/fir_df.m @@ -38,7 +38,7 @@ % $Id$ if nargin < 2 || isempty(cutoffArray) || isempty(Fs) - error('Not enough input arguments.') + ft_error('Not enough input arguments.') end % Constants diff --git a/external/fieldtrip/preproc/private/fir_filterdcpadded.m b/external/fieldtrip/preproc/private/fir_filterdcpadded.m index e2beff69..dccb0991 100644 --- a/external/fieldtrip/preproc/private/fir_filterdcpadded.m +++ b/external/fieldtrip/preproc/private/fir_filterdcpadded.m @@ -51,17 +51,17 @@ % Check arguments if nargin < 2 - error('Not enough input arguments.'); + ft_error('Not enough input arguments.'); end % Is FIR? if ~isscalar(a) || a ~= 1 - error('Not a FIR filter. onepass-zerophase and onepass-minphase filtering is available for FIR filters only.') + ft_error('Not a FIR filter. onepass-zerophase and onepass-minphase filtering is available for FIR filters only.') end % Group delay if mod(length(b), 2) ~= 1 - error('Filter order is not even.'); + ft_error('Filter order is not even.'); end groupDelay = (length(b) - 1) / 2; @@ -69,7 +69,7 @@ isSym = all(b(1:groupDelay) == b(end:-1:groupDelay + 2)); isAntisym = all([b(1:groupDelay) == -b(end:-1:groupDelay + 2) b(groupDelay + 1) == 0]); if causal == 0 && ~(isSym || isAntisym) - error('Filter is not anti-/symmetric. For onepass-zerophase filtering the filter must be anti-/symmetric.') + ft_error('Filter is not anti-/symmetric. For onepass-zerophase filtering the filter must be anti-/symmetric.') end % Padding diff --git a/external/fieldtrip/preproc/private/firws.m b/external/fieldtrip/preproc/private/firws.m index 5ea75af2..52b28613 100644 --- a/external/fieldtrip/preproc/private/firws.m +++ b/external/fieldtrip/preproc/private/firws.m @@ -59,14 +59,14 @@ a = 1; if nargin < 2 - error('Not enough input arguments'); + ft_error('Not enough input arguments'); end if length(m) > 1 || ~isnumeric(m) || ~isreal(m) || mod(m, 2) ~= 0 || m < 2 - error('Filter order must be a real, even, positive integer.'); + ft_error('Filter order must be a real, even, positive integer.'); end f = f / 2; if any(f <= 0) || any(f >= 0.5) - error('Frequencies must fall in range between 0 and 1.'); + ft_error('Frequencies must fall in range between 0 and 1.'); end if nargin < 3 || isempty(t) t = ''; diff --git a/external/fieldtrip/preproc/private/firwsord.m b/external/fieldtrip/preproc/private/firwsord.m index 1d7ad21e..7d191786 100644 --- a/external/fieldtrip/preproc/private/firwsord.m +++ b/external/fieldtrip/preproc/private/firwsord.m @@ -60,20 +60,20 @@ % Check arguments if nargin < 3 || isempty(fs) || isempty(df) || isempty(wintype) - error('Not enough input arguments.') + ft_error('Not enough input arguments.') end % Window type wintype = find(strcmp(wintype, winTypeArray)); if isempty(wintype) - error('Unknown window type.') + ft_error('Unknown window type.') end df = df / fs; % Normalize transition band width if wintype == 6 % Kaiser window if nargin < 4 || isempty(dev) - error('Not enough input arguments.') + ft_error('Not enough input arguments.') end devdb = -20 * log10(dev); m = 1 + (devdb - 8) / (2.285 * 2 * pi * df); diff --git a/external/fieldtrip/preproc/private/fixname.m b/external/fieldtrip/preproc/private/fixname.m index 96a345ec..76fd5951 100644 --- a/external/fieldtrip/preproc/private/fixname.m +++ b/external/fieldtrip/preproc/private/fixname.m @@ -1,19 +1,20 @@ -function str = fixname(str) +function str = fixname(str, version) % FIXNAME changes all inappropriate characters in a sting into '_' -% such that it can be used as a filename or as a structure field name. If -% the string begins with a numeric digit, an 'x' is prepended. +% so that it can be used as a filename or as a field name in a structure. +% If the string begins with a digit, an 'x' is prepended. % % Use as % str = fixname(str) % % MATLAB 2014a introduces the matlab.lang.makeValidName and -% matlab.lang.makeUniqueStrings functions for constructing unique MATLAB identifiers, -% but this particular implementation also works with older MATLAB versions. +% matlab.lang.makeUniqueStrings functions for constructing unique +% identifiers, but this particular implementation also works with +% older MATLAB versions. % % See also DEBLANK -% Copyright (C) 2012-2016, Robert Oostenveld +% Copyright (C) 2012-2017, Robert Oostenveld % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -33,19 +34,48 @@ % % $Id$ -str = lower(str); -str(regexp(str,'\W')) = '_'; - -while(str(1) == '_'), str = str(2:end); end; % remove all underscore at the begin of the string -while(str(end) == '_'), str = str(1:end-1); end; % remove all underscore at the end of the string - -if int8(str(1))<58 && int8(str(1))>47 - % the string begins with a digit, prepend an 'x' - str = ['x' str]; +if nargin<2 + version = 'default'; end -% truncate the string if it's too long: MATLAB maximizes the string length to 63 characters (and throws a warning when truncating) -if numel(str)>63 - str = str(1:63); - ft_warning(sprintf('%s exceeds MATLAB''s maximum name length of 63 characters and has been truncated to %s', str, str(1:63))); +switch version + case 'default' + if isempty(str) + str='x'; + end + str = lower(str); + str(regexp(str,'\W')) = '_'; + while(str(1) == '_'), str = str(2:end); end % remove all underscore at the begin of the string + while(str(end) == '_'), str = str(1:end-1); end % remove all underscore at the end of the string + if int8(str(1))<58 && int8(str(1))>47 + % the string begins with a digit, prepend an 'x' + str = ['x' str]; + end + % truncate the string if it's too long: MATLAB maximizes the string length to 63 characters (and throws a warning when truncating) + if numel(str)>63 + str = str(1:63); + warning('%s exceeds MATLAB''s maximum name length of 63 characters and has been truncated to %s', str, str(1:63)); + end + + case '2014a' + str = matlab.lang.makeValidName(str); + + case 'X_base64encode_X' + % this uses some code from Mathworks file exchange + ft_hastoolbox('fileexchange', 1); + % the following is an encoding that can be reverted + str = strtrim(base64encode(str)); + str(str=='=') = '_'; % replace the '=' sign with '_' + str = ['X' str 'X']; % start and end with an 'X' + + case 'X_base64decode_X' + % this uses some code from Mathworks file exchange + ft_hastoolbox('fileexchange', 1); + % revert the encoding + str = str(2:end-1); % it starts and ends with 'X' + str(str=='_') = '='; % the '=' sign has been replaced with '_' + str = char(base64decode(str)); + + otherwise + error('unsupported version "%s"', version); end diff --git a/external/fieldtrip/preproc/private/ft_notification.m b/external/fieldtrip/preproc/private/ft_notification.m new file mode 100644 index 00000000..dc9b7369 --- /dev/null +++ b/external/fieldtrip/preproc/private/ft_notification.m @@ -0,0 +1,482 @@ +function [varargout] = ft_notification(varargin) + +% FT_NOTIFICATION works mostly like the WARNING and ERROR commands in MATLAB and +% is called by FT_ERROR, FT_WARNING, FT_NOTICE, FT_INFO, FT_DEBUG. Note that you +% should not call this function directly. +% +% Some examples: +% ft_info on +% ft_info on msgId +% ft_info off +% ft_info off msgId +% ft_info once +% ft_info once msgId +% ft_info on backtrace +% ft_info off backtrace +% ft_info on verbose +% ft_info off verbose +% +% ft_info query % shows the status of all notifications +% ft_info last % shows the last notification +% ft_info clear % clears the status of all notifications +% ft_info timeout 10 % sets the timeout (for 'once') to 10 seconds +% +% See also DEFAULTID + +% Copyright (C) 2012-2017, Robert Oostenveld, J?rn M. Horschig +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +global ft_default + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% determine who is calling + +stack = dbstack('-completenames'); +% st(1) is this function +% st(2) is the calling function +switch stack(2).name + case 'ft_debug' + level = 'debug'; + case 'ft_info' + level = 'info'; + case 'ft_notice' + level = 'notice'; + case 'ft_warning' + level = 'warning'; + case 'ft_error' + level = 'error'; + otherwise + error('this function cannot be called from %s', stack(2).name); +end + +% remove this function itself and the ft_xxx calling function +stack = stack(3:end); + +% remove the non-FieldTrip functions from the path, these should not be part of the default message identifier +keep = true(size(stack)); +p = fileparts(which('ft_defaults')); +for i=1:numel(stack) + keep(i) = strncmp(p, stack(i).file, length(p)); +end +stack = stack(keep); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% handle the defaults + +if isfield(ft_default, 'notification') && isfield(ft_default.notification, level) + % this would be error, warning, notice, info, debug + s = ft_default.notification.(level); +else + s = []; +end + +% start with an empty state structure +if isempty(s) + s = struct('identifier', {}, 'state', {}, 'timestamp', {}); +end + +% set the default notification state +if ~ismember('all', {s.identifier}) + s = setstate(s, 'all', 'on'); +end + +% set the default backtrace state +defaultbacktrace = false; +if ~ismember('backtrace', {s.identifier}) + switch level + case {'debug' 'info' 'notice'} + s = setstate(s, 'backtrace', 'off'); + case 'warning' + defaultbacktrace = true; + t = warning('query', 'backtrace'); % get the default state + s = setstate(s, 'backtrace', t.state); + case 'error' + s = setstate(s, 'backtrace', 'on'); + end % switch +end + +% set the default verbose state +defaultverbose = false; +if ~ismember('verbose', {s.identifier}) + switch level + case 'warning' + defaultverbose = true; + t = warning('query', 'verbose');% get the default state + s = setstate(s, 'verbose', t.state); + otherwise + s = setstate(s, 'verbose', 'off'); + end +end + +% set the default timeout +if ~ismember('timeout', {s.identifier}) + s = setstate(s, 'timeout', 60); +end + +% set the last notification to empty +if ~ismember('last', {s.identifier}) + state.message = ''; + state.identifier = ''; + state.stack = struct('file', {}, 'name', {}, 'line', {}); + s = setstate(s, 'last', state); +end + +if strcmp(level, 'warning') + ws = warning; + % warnings should be on in general + warning on + % the backtrace is handled by this function + warning off backtrace + % the verbose message is handled by this function + warning off verbose +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% set the notification state according to the input + +if numel(varargin)>0 && (isstruct(varargin{1}) || isempty(varargin{1})) + ft_default.notification.(level) = varargin{1}; + return +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% act according to the first input argument + +if isempty(varargin) + varargin{1} = 'query'; +end + +switch varargin{1} + case 'on' + if numel(varargin)>1 + % switch a specific item on + msgId = varargin{2}; + s = setstate(s, msgId, 'on'); + if strcmp(msgId, 'backtrace') + defaultbacktrace = false; + end + if strcmp(msgId, 'verbose') + defaultverbose = false; + end + % return the message state of all + varargout{1} = getreturnstate(s, msgId); + else + % switch all on + s = setstate(s, 'all', 'on'); + % return the message state of all + varargout{1} = getreturnstate(s); + end + + case 'off' + if numel(varargin)>1 + % switch a specific item off + msgId = varargin{2}; + s = setstate(s, msgId, 'off'); + if strcmp(msgId, 'backtrace') + defaultbacktrace = false; + end + if strcmp(msgId, 'verbose') + defaultverbose = false; + end + % return the specific message state + varargout{1} = getreturnstate(s, msgId); + else + % switch all off + s = setstate(s, 'all', 'off'); + % return the message state of all + varargout{1} = getreturnstate(s); + end + + case 'once' + if numel(varargin)>1 + % switch a specific item to once + msgId = varargin{2}; + s = setstate(s, msgId, 'once'); + % return the specific message state + varargout{1} = getreturnstate(s, msgId); + else + % switch all to once + s = setstate(s, 'all', 'once'); + % return the message state of all + varargout{1} = getreturnstate(s); + end + + case 'timeout' + % set the timeout, this is used for 'once' + if ischar(varargin{2}) + s = setstate(s, 'timeout', str2double(varargin{2})); + else + s = setstate(s, 'timeout', varargin{2}); + end + + case {'last' '-last'} + % return the last notification + varargout{1} = getstate(s, 'last'); + + case {'clear' '-clear'} + % reset the notification system + s = []; + + case {'query' '-query'} + if numel(varargin)>1 + % select a specific item + msgId = varargin{2}; + if ~ismember(msgId, {s.identifier}) + error('Unknown setting or incorrect message identifier ''%s''.', msgId); + end + msgState = getstate(s, msgId); + if nargout + varargout{1} = getreturnstate(s, msgId); + elseif strcmp(msgId, 'verbose') + if istrue(msgState) + fprintf('%s output is verbose.\n', level); + else + fprintf('%s output is terse.\n', level); + end + elseif strcmp(msgId, 'backtrace') + if istrue(msgState) + fprintf('%s backtraces are enabled.\n', level); + else + fprintf('%s backtraces are disabled.\n', level); + end + else + fprintf('The state of %s ''%s'' is ''%s''\n', level, msgId, msgState); + end + else + % return all items + r = getreturnstate(s); + + if nargout + % return the state of all items + varargout{1} = r; + else + % show the state of all items that are different from the default + default = getstate(s, 'all'); + fprintf('The default %s state is ''%s''.', level, default); + r = r(~strcmp({r.state}, default)); + % don't show these + r(strcmp('verbose', {r.identifier})) = []; + r(strcmp('backtrace', {r.identifier})) = []; + if ~isempty(r) + fprintf(' Items not set to the default are\n\n'); + end + for i=1:numel(r) + fprintf(' %4s %s\n', r(i).state, r(i).identifier); + end + fprintf('\n'); + end + end + + otherwise + + if nargout + varargout{1} = getreturnstate(s); + end + + % first input might be msgId + if numel(varargin)>1 && ~isempty(regexp(varargin{1}, '^\w*:', 'once')) + msgId = varargin{1}; + varargin = varargin(2:end); % shift them all by one + else + msgId = defaultId; + end + + % get the state for this notification, it will default to the 'all' state + msgState = getstate(s, msgId); + + % errors are always to be printed + if strcmp(level, 'error') + msgState = 'on'; + end + + if strcmp(msgState, 'once') + timeout = getstate(s, 'timeout'); + since = elapsed(gettimestamp(s, msgId)); + if (since>timeout) + % the timeout has passed, update the timestamp and print the message + s = settimestamp(s, msgId, tic); + msgState = 'on'; + else + % the timeout has not yet passed, do not print the message + msgState = 'off'; + end + end + + % use an automatically generated default identifier + if isempty(msgId) + msgId = defaultId; + end + + % store the last notification + state.message = strtrim(sprintf(varargin{:})); % remove the trailing newline + state.identifier = msgId; + state.stack = stack; + s = setstate(s, 'last', state); + + if strcmp(msgState, 'on') + + if strcmp(level, 'error') + % update the global variable, we won't return here after the error + ft_default.notification.(level) = s; + % the remainder is fully handled by the ERROR function + if ~isempty(msgId) + error(msgId, varargin{:}); + else + error(varargin{:}); + end + + elseif strcmp(level, 'warning') + if ~isempty(msgId) + warning(msgId, varargin{:}); + else + warning(varargin{:}); + end + + else + % ensure there is a line end + if isempty(regexp(varargin{1}, '\\n$', 'once')) % note the double \\ + varargin{1} = [varargin{1} '\n']; + end + fprintf(varargin{:}); + + end % if level=error, warning or otherwise + + % decide whether the stack trace should be shown + if istrue(getstate(s, 'backtrace')) + for i=1:numel(stack) + % show the deepest and lowest-level function first + [p, f, x] = fileparts(stack(i).file); + if isequal(f, stack(i).name) + funname = stack(i).name; + else + funname = sprintf('%s>%s', f, stack(i).name); + end + filename = stack(i).file; + if isempty(fileparts(filename)) + % it requires the full path + filename = fullfile(pwd, filename); + end + if ft_platform_supports('html') + fprintf(' In %s at line %d\n', filename, stack(i).line, funname, stack(i).line); + else + fprintf(' In ''%s'' at line %d\n', filename, stack(i).line); + end + end + fprintf('\n'); + end + + % decide whether a verboe message should be shown + if istrue(getstate(s, 'verbose')) + if ~isempty(msgId) + fprintf('Type "ft_%s off %s" to suppress this message.\n', level, msgId) + else + fprintf('Type "ft_%s off" to suppress this message.\n', level) + end + end + + end % if msgState is on + +end % switch varargin{1} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% update the global variable +if defaultbacktrace && ~isempty(s) + % do not keep the default, it will be determined again on the next call + s = s(~strcmp({s.identifier}, 'backtrace')); +end +if defaultverbose && ~isempty(s) + % do not keep the default, it will be determined again on the next call + s = s(~strcmp({s.identifier}, 'verbose')); +end +ft_default.notification.(level) = s; + +if strcmp(level, 'warning') + % return to the original warning state + warning(ws); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTIONS +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +function r = getreturnstate(s, msgId) +if nargin<2 + r = s; + % don't return these + r(strcmp('timeout', {r.identifier})) = []; + r(strcmp('last', {r.identifier})) = []; + % don't return the timestamps + r = rmfield(r, 'timestamp'); +else + msgState = getstate(s, msgId); + r = struct('identifier', msgId, 'state', msgState); +end + +function state = getstate(s, msgId) +identifier = {s.identifier}; +sel = find(strcmp(identifier, msgId)); +if numel(sel)==1 + state = s(sel).state; + if isempty(state) + state = getstate(s, 'all'); + end +else + state = getstate(s, 'all'); +end + +function timestamp = gettimestamp(s, msgId) +identifier = {s.identifier}; +sel = find(strcmp(identifier, msgId)); +if numel(sel)==1 + timestamp = s(sel).timestamp; +else + timestamp = nan; +end + +function s = setstate(s, msgId, state) +if isempty(msgId), return; end % this happens from the command line +identifier = {s.identifier}; +sel = find(strcmp(identifier, msgId)); +if numel(sel)==1 + s(sel).state = state; +else + s(end+1).identifier = msgId; + s(end ).state = state; + s(end ).timestamp = nan; +end + +function s = settimestamp(s, msgId, timestamp) +if isempty(msgId), return; end % this happens from the command line +identifier = {s.identifier}; +sel = find(strcmp(identifier, msgId)); +if numel(sel)==1 + s(sel).timestamp = timestamp; +else + s(end+1).identifier = msgId; + s(end ).state = []; + s(end ).timestamp = timestamp; +end + +function t = elapsed(start) +if isempty(start) || isnan(start) + t = inf; +else + t = toc(start); +end diff --git a/external/fieldtrip/preproc/private/ft_platform_supports.m b/external/fieldtrip/preproc/private/ft_platform_supports.m new file mode 100644 index 00000000..c0676b62 --- /dev/null +++ b/external/fieldtrip/preproc/private/ft_platform_supports.m @@ -0,0 +1,336 @@ +function tf = ft_platform_supports(what,varargin) + +% FT_PLATFORM_SUPPORTS returns a boolean indicating whether the current platform +% supports a specific capability +% +% Use as +% status = ft_platform_supports(what) +% or +% status = ft_platform_supports('matlabversion', min_version, max_version) +% +% The following values are allowed for the 'what' parameter, which means means that +% the specific feature explained on the right is supported: +% +% 'which-all' which(...,'all') +% 'exists-in-private-directory' exists(...) will look in the /private subdirectory to see if a file exists +% 'onCleanup' onCleanup(...) +% 'alim' alim(...) +% 'int32_logical_operations' bitand(a,b) with a, b of type int32 +% 'graphics_objects' graphics sysem is object-oriented +% 'libmx_c_interface' libmx is supported through mex in the C-language (recent MATLAB versions only support C++) +% 'images' all image processing functions in FieldTrip's external/images directory +% 'signal' all signal processing functions in FieldTrip's external/signal directory +% 'stats' all statistical functions in FieldTrip's external/stats directory +% 'program_invocation_name' program_invocation_name() (GNU Octave) +% 'singleCompThread' start MATLAB with -singleCompThread +% 'nosplash' start MATLAB with -nosplash +% 'nodisplay' start MATLAB with -nodisplay +% 'nojvm' start MATLAB with -nojvm +% 'no-gui' start GNU Octave with --no-gui +% 'RandStream.setGlobalStream' RandStream.setGlobalStream(...) +% 'RandStream.setDefaultStream' RandStream.setDefaultStream(...) +% 'rng' rng(...) +% 'rand-state' rand('state') +% 'urlread-timeout' urlread(..., 'Timeout', t) +% 'griddata-vector-input' griddata(...,...,...,a,b) with a and b vectors +% 'griddata-v4' griddata(...,...,...,...,...,'v4') with v4 interpolation support +% 'uimenu' uimenu(...) +% 'weboptions' weboptions(...) +% 'parula' parula(...) +% 'html' html rendering in desktop +% +% See also FT_VERSION, VERSION, VER, VERLESSTHAN + +if ~ischar(what) + error('first argument must be a string'); +end + +switch what + case 'matlabversion' + tf = is_matlab() && matlabversion(varargin{:}); + + case 'exists-in-private-directory' + tf = is_matlab(); + + case 'which-all' + tf = is_matlab(); + + case 'onCleanup' + tf = is_octave() || matlabversion(7.8, Inf); + + case 'alim' + tf = is_matlab(); + + case 'int32_logical_operations' + % earlier version of MATLAB don't support bitand (and similar) + % operations on int32 + tf = is_octave() || ~matlabversion(-Inf, '2012a'); + + case 'graphics_objects' + % introduced in MATLAB 2014b, graphics is handled through objects; + % previous versions use numeric handles + tf = is_matlab() && matlabversion('2014b', Inf); + + case 'libmx_c_interface' + % removed after 2013b + tf = is_matlab() && matlabversion(-Inf, '2013b'); + + case 'images' + root_dir = fileparts(which('ft_defaults')); + external_stats_dir = fullfile(root_dir, 'external', 'images'); + + tf = has_all_functions_in_dir(external_stats_dir, {}); + + case 'signal' + root_dir = fileparts(which('ft_defaults')); + external_stats_dir = fullfile(root_dir, 'external', 'signal'); + + tf = has_all_functions_in_dir(external_stats_dir, {}); + + case 'stats' + root_dir = fileparts(which('ft_defaults')); + external_stats_dir = fullfile(root_dir, 'external', 'stats'); + + % these files are only used by other functions in the external/stats directory + exclude_mfiles = { + 'common_size.m' + 'iscomplex.m' + }; + + tf = has_all_functions_in_dir(external_stats_dir, exclude_mfiles); + + case 'program_invocation_name' + % Octave supports program_invocation_name, which returns the path + % of the binary that was run to start Octave + tf = is_octave(); + + case 'singleCompThread' + tf = is_matlab() && matlabversion(7.8, Inf); + + case {'nosplash', 'nodisplay', 'nojvm'} + % Only on MATLAB + tf = is_matlab(); + + case 'no-gui' + % Only on Octave + tf = is_octave(); + + case 'RandStream.setDefaultStream' + tf = is_matlab() && matlabversion('2008b', '2011b'); + + case 'RandStream.setGlobalStream' + tf = is_matlab() && matlabversion('2012a', Inf); + + case 'randomized_PRNG_on_startup' + tf = is_octave() || ~matlabversion(-Inf, '7.3'); + + case 'rng' + % recent MATLAB versions + tf = is_matlab() && matlabversion('7.12', Inf); + + case 'rand-state' + % GNU Octave + tf = is_octave(); + + case 'urlread-timeout' + tf = is_matlab() && matlabversion('2012b', Inf); + + case 'griddata-vector-input' + tf = is_matlab(); + + case 'griddata-v4' + tf = is_matlab() && matlabversion('2009a', Inf); + + case 'uimenu' + tf = is_matlab(); + + case {'weboptions', 'webread', 'websave'} + tf = is_matlab() && matlabversion('2014b', Inf); + + case 'webwrite' + tf = is_matlab() && matlabversion('2015a', Inf); + + case 'boundary' + tf = is_matlab() && matlabversion('2014b', Inf); + + case 'parula' + tf = is_matlab() && matlabversion('2014b', Inf); + + case 'html' + tf = ~is_octave() && usejava('desktop') && desktop('-inuse'); + + otherwise + error('unsupported value for first argument: %s', what); + +end % switch + +end % function + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function tf = is_matlab() +tf = ~is_octave(); +end % function + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function tf = is_octave() +persistent cached_tf + +if isempty(cached_tf) + cached_tf = logical(exist('OCTAVE_VERSION', 'builtin')); +end + +tf = cached_tf; +end % function + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function tf = has_all_functions_in_dir(in_dir, exclude_mfiles) +% returns true if all functions in in_dir are already provided by the platform +m_files = dir(fullfile(in_dir,'*.m')); +n = numel(m_files); + +for k = 1:n + m_filename = m_files(k).name; + if isempty(which(m_filename)) && isempty(strmatch(m_filename,exclude_mfiles)) + tf = false; + return; + end +end + +tf = true; + +end % function + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function [inInterval] = matlabversion(min, max) + +% MATLABVERSION checks if the current MATLAB version is within the interval +% specified by min and max. +% +% Use as +% if matlabversion(7.0, 7.9) +% % do something +% end +% +% Both strings and numbers, as well as infinities, are supported, eg.: +% matlabversion(7.1, 7.9) % is version between 7.1 and 7.9? +% matlabversion(6, '7.10') % is version between 6 and 7.10? (note: '7.10', not 7.10) +% matlabversion(-Inf, 7.6) % is version <= 7.6? +% matlabversion('2009b') % exactly 2009b +% matlabversion('2008b', '2010a') % between two versions +% matlabversion('2008b', Inf) % from a version onwards +% etc. +% +% See also VERSION, VER, VERLESSTHAN + +% Copyright (C) 2006, Robert Oostenveld +% Copyright (C) 2010, Eelke Spaak +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +% the version does not change, making it persistent speeds up the subsequent calls +persistent curVer + +if nargin<2 + max = min; +end + +if isempty(curVer) + curVer = version(); +end + +if ((ischar(min) && isempty(str2num(min))) || (ischar(max) && isempty(str2num(max)))) + % perform comparison with respect to release string + + ind = strfind(curVer, '(R'); + [year, ab] = parseMatlabRelease(curVer((ind + 2):(numel(curVer) - 1))); + + [minY, minAb] = parseMatlabRelease(min); + [maxY, maxAb] = parseMatlabRelease(max); + + inInterval = orderedComparison(minY, minAb, maxY, maxAb, year, ab); + +else + % perform comparison with respect to version number + [major, minor] = parseMatlabVersion(curVer); + [minMajor, minMinor] = parseMatlabVersion(min); + [maxMajor, maxMinor] = parseMatlabVersion(max); + + inInterval = orderedComparison(minMajor, minMinor, maxMajor, maxMinor, major, minor); +end + +end % function + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function [year, ab] = parseMatlabRelease(str) +if (str == Inf) + year = Inf; ab = Inf; +elseif (str == -Inf) + year = -Inf; ab = -Inf; +else + year = str2num(str(1:4)); + ab = str(5); +end +end % function + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function [major, minor] = parseMatlabVersion(ver) +if (ver == Inf) + major = Inf; minor = Inf; +elseif (ver == -Inf) + major = -Inf; minor = -Inf; +elseif (isnumeric(ver)) + major = floor(ver); + minor = int8((ver - floor(ver)) * 10); +else % ver is string (e.g. '7.10'), parse accordingly + [major, rest] = strtok(ver, '.'); + major = str2num(major); + minor = str2num(strtok(rest, '.')); +end +end % function + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function inInterval = orderedComparison(lowerA, lowerB, upperA, upperB, testA, testB) +% checks if testA is in interval (lowerA,upperA); if at edges, checks if testB is in interval (lowerB,upperB). +if (testA < lowerA || testA > upperA) + inInterval = false; +else + inInterval = true; + if (testA == lowerA) + inInterval = inInterval && (testB >= lowerB); + end + + if (testA == upperA) + inInterval = inInterval && (testB <= upperB); + end +end +end % function diff --git a/external/fieldtrip/preproc/private/ft_warning.m b/external/fieldtrip/preproc/private/ft_warning.m index 18b0ce00..58f3985e 100644 --- a/external/fieldtrip/preproc/private/ft_warning.m +++ b/external/fieldtrip/preproc/private/ft_warning.m @@ -1,39 +1,40 @@ -function [ws, warned] = ft_warning(varargin) +function varargout = ft_warning(varargin) -% FT_WARNING will throw a warning for every unique point in the -% stacktrace only, e.g. in a for-loop a warning is thrown only once. +% FT_WARNING prints a warning message on screen, depending on the verbosity +% settings of the calling high-level FieldTrip function. This function works +% similar to the standard WARNING function, but also features the "once" mode. % -% Use as one of the following -% ft_warning(string) -% ft_warning(id, string) -% Alternatively, you can use ft_warning using a timeout -% ft_warning(string, timeout) -% ft_warning(id, string, timeout) -% where timeout should be inf if you don't want to see the warning ever -% again. +% Use as +% ft_warning(...) +% with arguments similar to fprintf, or +% ft_warning(msgId, ...) +% with arguments similar to warning. % -% Use as ft_warning('-clear') to clear old warnings from the current -% stack +% You can switch of all warning messages using +% ft_warning off +% or for specific ones using +% ft_warning off msgId % -% It can be used instead of the MATLAB built-in function WARNING, thus as -% s = ft_warning(...) -% or as -% ft_warning(s) -% where s is a structure with fields 'identifier' and 'state', storing the -% state information. In other words, ft_warning accepts as an input the -% same structure it returns as an output. This returns or restores the -% states of warnings to their previous values. +% To switch them back on, you would use +% ft_warning on +% or for specific ones using +% ft_warning on msgId +% +% Warning messages are only printed once per timeout period using +% ft_warning timeout 60 +% ft_warning once +% or for specific ones using +% ft_warning once msgId % -% It can also be used as -% [s w] = ft_warning(...) -% where w is a boolean that indicates whether a warning as been thrown or not. +% You can see the most recent messages and identifier using +% ft_warning last % -% Please note that you can NOT use it like this -% ft_warning('the value is %d', 10) -% instead you should do -% ft_warning(sprintf('the value is %d', 10)) +% You can query the current on/off/once state for all messages using +% ft_warning query +% +% See also FT_ERROR, FT_WARNING, FT_NOTICE, FT_warning, FT_DEBUG, ERROR, WARNING -% Copyright (C) 2012-2016, Robert Oostenveld, J?rn M. Horschig +% Copyright (C) 2012-2017, Robert Oostenveld, J?rn M. Horschig % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -53,205 +54,12 @@ % % $Id$ -global ft_default -warned = false; -ws = []; - -stack = dbstack; -if any(strcmp({stack(2:end).file}, 'ft_warning.m')) - % don't call FT_WARNING recursively, see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=3068 - return; -end - -if nargin < 1 - error('You need to specify at least a warning message'); -end - -if isstruct(varargin{1}) - warning(varargin{1}); - return; -end - -if ~isfield(ft_default, 'warning') - ft_default.warning = []; -end -if ~isfield(ft_default.warning, 'stopwatch') - ft_default.warning.stopwatch = []; -end -if ~isfield(ft_default.warning, 'identifier') - ft_default.warning.identifier = []; -end -if ~isfield(ft_default.warning, 'ignore') - ft_default.warning.ignore = {}; -end - -% put the arguments we will pass to warning() in this cell array -warningArgs = {}; - -if nargin==3 - % calling syntax (id, msg, timeout) - - warningArgs = varargin(1:2); - msg = warningArgs{2}; - timeout = varargin{3}; - fname = [warningArgs{1} '_' warningArgs{2}]; - -elseif nargin==2 && isnumeric(varargin{2}) - % calling syntax (msg, timeout) - - warningArgs = varargin(1); - msg = warningArgs{1}; - timeout = varargin{2}; - fname = warningArgs{1}; - -elseif nargin==2 && isequal(varargin{1}, 'off') - - ft_default.warning.ignore = union(ft_default.warning.ignore, varargin{2}); - return - -elseif nargin==2 && isequal(varargin{1}, 'on') - - ft_default.warning.ignore = setdiff(ft_default.warning.ignore, varargin{2}); - return - -elseif nargin==2 && ~isnumeric(varargin{2}) - % calling syntax (id, msg) - - warningArgs = varargin(1:2); - msg = warningArgs{2}; - timeout = inf; - fname = [warningArgs{1} '_' warningArgs{2}]; - -elseif nargin==1 - % calling syntax (msg) - - warningArgs = varargin(1); - msg = warningArgs{1}; - timeout = inf; % default timeout in seconds - fname = [warningArgs{1}]; - -end - -if ismember(msg, ft_default.warning.ignore) - % do not show this warning - return; -end - -if isempty(timeout) - error('Timeout ill-specified'); -end - -if timeout ~= inf - fname = fixname(fname); % make a nice string that is allowed as fieldname in a structures - line = []; -else - % here, we create the fieldname functionA.functionB.functionC... - [tmpfname, ft_default.warning.identifier, line] = fieldnameFromStack(ft_default.warning.identifier); - if ~isempty(tmpfname), - fname = tmpfname; - clear tmpfname; - end -end - -if nargin==1 && ischar(varargin{1}) && strcmp('-clear', varargin{1}) - if strcmp(fname, '-clear') % reset all fields if called outside a function - ft_default.warning.identifier = []; - ft_default.warning.stopwatch = []; - else - if issubfield(ft_default.warning.identifier, fname) - ft_default.warning.identifier = rmsubfield(ft_default.warning.identifier, fname); - end - end - return; -end - -% and add the line number to make this unique for the last function -fname = horzcat(fname, line); - -if ~issubfield('ft_default.warning.stopwatch', fname) - ft_default.warning.stopwatch = setsubfield(ft_default.warning.stopwatch, fname, tic); -end - -now = toc(getsubfield(ft_default.warning.stopwatch, fname)); % measure time since first function call - -if ~issubfield(ft_default.warning.identifier, fname) || ... - (issubfield(ft_default.warning.identifier, fname) && now>getsubfield(ft_default.warning.identifier, [fname '.timeout'])) - - % create or reset field - ft_default.warning.identifier = setsubfield(ft_default.warning.identifier, fname, []); - - % warning never given before or timed out - ws = warning(warningArgs{:}); - ft_default.warning.identifier = setsubfield(ft_default.warning.identifier, [fname '.timeout'], now+timeout); - ft_default.warning.identifier = setsubfield(ft_default.warning.identifier, [fname '.ws'], msg); - warned = true; +if nargout + varargout{:} = ft_notification(varargin{:}); +elseif isequal(varargin, {'last'}) + % return an answer anyway + varargout{1} = ft_notification(varargin{:}); else - - % the warning has been issued before, but has not timed out yet - ws = getsubfield(ft_default.warning.identifier, [fname '.ws']); - -end - -end % function ft_warning - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% helper functions -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -function [fname, ft_previous_warnings, line] = fieldnameFromStack(ft_previous_warnings) -% stack(1) is this function, stack(2) is ft_warning -stack = dbstack('-completenames'); -if size(stack) < 3 - fname = []; - line = []; - return; -end -i0 = 3; -% ignore ft_preamble -while strfind(stack(i0).name, 'ft_preamble') - i0=i0+1; + ft_notification(varargin{:}); end -fname = horzcat(fixname(stack(end).name)); -if ~issubfield(ft_previous_warnings, fixname(stack(end).name)) - ft_previous_warnings.(fixname(stack(end).name)) = []; % iteratively build up structure fields -end - - -for i=numel(stack)-1:-1:(i0) - % skip postamble scripts - if strncmp(stack(i).name, 'ft_postamble', 12) - break; - end - - fname = horzcat(fname, '.', horzcat(fixname(stack(i).name))); % , stack(i).file - if ~issubfield(ft_previous_warnings, fname) % iteratively build up structure fields - setsubfield(ft_previous_warnings, fname, []); - end -end - -% line of last function call -line = ['.line', int2str(stack(i0).line)]; -end - -% function outcome = issubfield(strct, fname) -% substrindx = strfind(fname, '.'); -% if numel(substrindx) > 0 -% % separate the last fieldname from all former -% outcome = eval(['isfield(strct.' fname(1:substrindx(end)-1) ', ''' fname(substrindx(end)+1:end) ''')']); -% else -% % there is only one fieldname -% outcome = isfield(strct, fname); -% end -% end - -% function strct = rmsubfield(strct, fname) -% substrindx = strfind(fname, '.'); -% if numel(substrindx) > 0 -% % separate the last fieldname from all former -% strct = eval(['rmfield(strct.' fname(1:substrindx(end)-1) ', ''' fname(substrindx(end)+1:end) ''')']); -% else -% % there is only one fieldname -% strct = rmfield(strct, fname); -% end -% end diff --git a/external/fieldtrip/preproc/private/invfirwsord.m b/external/fieldtrip/preproc/private/invfirwsord.m index eca51c76..8f9f37bc 100644 --- a/external/fieldtrip/preproc/private/invfirwsord.m +++ b/external/fieldtrip/preproc/private/invfirwsord.m @@ -60,18 +60,18 @@ % Check arguments if nargin < 3 || isempty(fs) || isempty(m) || isempty(wintype) - error('Not enough input arguments.') + ft_error('Not enough input arguments.') end % Window type wintype = find(strcmp(wintype, winTypeArray)); if isempty(wintype) - error('Unknown window type.') + ft_error('Unknown window type.') end if wintype == 6 % Kaiser window if nargin < 4 || isempty(dev) - error('Not enough input arguments.') + ft_error('Not enough input arguments.') end devdb = -20 * log10(dev); df = (devdb - 8) / (2.285 * 2 * pi * (m - 1)); diff --git a/external/fieldtrip/preproc/private/istrue.m b/external/fieldtrip/preproc/private/istrue.m index 79631e32..742a0997 100644 --- a/external/fieldtrip/preproc/private/istrue.m +++ b/external/fieldtrip/preproc/private/istrue.m @@ -1,7 +1,7 @@ function y = istrue(x) -% ISTRUE ensures that a true/false input argument like "yes", "true" -% or "on" is converted into a boolean +% ISTRUE converts an input argument like "yes/no", "true/false" or "on/off" into a +% boolean. If the input is boolean, then it will remain like that. % Copyright (C) 2009-2012, Robert Oostenveld % diff --git a/external/fieldtrip/preproc/private/keyval.m b/external/fieldtrip/preproc/private/keyval.m index b176ce8d..0043c72b 100644 --- a/external/fieldtrip/preproc/private/keyval.m +++ b/external/fieldtrip/preproc/private/keyval.m @@ -44,7 +44,7 @@ end if mod(length(varargin),2) - error('optional input arguments should come in key-value pairs, i.e. there should be an even number'); + ft_error('optional input arguments should come in key-value pairs, i.e. there should be an even number'); end % the 1st, 3rd, etc. contain the keys, the 2nd, 4th, etc. contain the values @@ -58,7 +58,7 @@ end if ~all(valid) - error('optional input arguments should come in key-value pairs, the optional input argument %d is invalid (should be a string)', i); + ft_error('optional input arguments should come in key-value pairs, the optional input argument %d is invalid (should be a string)', i); end hit = find(strcmpi(key, keys)); @@ -69,7 +69,7 @@ % the requested key was found val = vals{hit}; else - error('multiple input arguments with the same name'); + ft_error('multiple input arguments with the same name'); end if nargout>1 diff --git a/external/fieldtrip/preproc/private/plotfresp.m b/external/fieldtrip/preproc/private/plotfresp.m index a6c380f5..f0aed859 100644 --- a/external/fieldtrip/preproc/private/plotfresp.m +++ b/external/fieldtrip/preproc/private/plotfresp.m @@ -53,7 +53,7 @@ function plotfresp(b, a, nfft, fs, dir) a = 1; end if nargin < 1 - error('Not enough input arguments.'); + ft_error('Not enough input arguments.'); end % FIR? @@ -74,9 +74,9 @@ function plotfresp(b, a, nfft, fs, dir) if strncmp('twopass', dir, 7) isTwopass = true; isZerophase = true; -elseif strcmp('onepass-zerophase', dir) +elseif strcmp('onepass-zerophase', dir) || strcmp('onepass-reverse-zerophase', dir) if ~isLinPhaseFir - error('Onepass-zerophase filtering is only allowed for linear-phase FIR filters.') + ft_error('Onepass-zerophase filtering is only allowed for linear-phase FIR filters.') end isTwopass = false; isZerophase = true; @@ -90,7 +90,7 @@ function plotfresp(b, a, nfft, fs, dir) impresp = b(:)'; else if ~exist('impz', 'file') - warning('Plotting IIR filter responses requires signal processing toolbox.') + ft_warning('Plotting IIR filter responses requires signal processing toolbox.') return end impresp = impz(b, a)'; diff --git a/external/fieldtrip/preproc/private/print_once.m b/external/fieldtrip/preproc/private/print_once.m index b16a8fde..e9996e8e 100644 --- a/external/fieldtrip/preproc/private/print_once.m +++ b/external/fieldtrip/preproc/private/print_once.m @@ -1,5 +1,5 @@ function [ws warned] = print_once(varargin) -% + % PRINT_ONCE will print a message for every unique point in the % stacktrace only, e.g. in a for-loop a warning is thrown only once. % @@ -19,6 +19,8 @@ % print_once('the value is %d', 10) % instead you should do % print_once(sprintf('the value is %d', 10)) +% +% See also FT_WARNING % Copyright (C) 2012, Robert Oostenveld % Copyright (C) 2013, Robert Oostenveld, Jörn M. Horschig @@ -44,7 +46,7 @@ global ft_default if nargin < 1 - error('You need to specify at least a message'); + ft_error('You need to specify at least a message'); end warned = false; @@ -92,7 +94,7 @@ end if isempty(timeout) - error('Timeout ill-specified'); + ft_error('Timeout ill-specified'); end if timeout ~= inf diff --git a/external/fieldtrip/preproc/private/windows.m b/external/fieldtrip/preproc/private/windows.m index 388c1469..cf1389f6 100644 --- a/external/fieldtrip/preproc/private/windows.m +++ b/external/fieldtrip/preproc/private/windows.m @@ -40,16 +40,16 @@ function w = windows(t, m, a) if nargin < 2 || isempty(t) || isempty(m) - error('Not enough input arguments.'); + ft_error('Not enough input arguments.'); end % Check window length if m ~= round(m) m = round(m); - warning('firws:nonIntegerWindowLength', 'Non-integer window length. Rounding to integer.') + ft_warning('firws:nonIntegerWindowLength', 'Non-integer window length. Rounding to integer.') end if m < 1 - error('Invalid window length.') + ft_error('Invalid window length.') end % Length 1 @@ -102,7 +102,7 @@ w = [0.5 * (1 + cos(pi * xTaper)); ones(length(x) - mTaper, 1)]; end otherwise - error('Unkown window type') + ft_error('Unkown window type') end % Make symmetric diff --git a/external/fieldtrip/private/align_ijk2xyz.m b/external/fieldtrip/private/align_ijk2xyz.m index 07a464c2..51204668 100644 --- a/external/fieldtrip/private/align_ijk2xyz.m +++ b/external/fieldtrip/private/align_ijk2xyz.m @@ -43,7 +43,7 @@ permutemat(permutevec(3),3) = 1; transform = permutemat; if length(unique(permutevec))<3 - error('could not determine the correspondence between volume and headcoordinate axes'); + ft_error('could not determine the correspondence between volume and headcoordinate axes'); else for i=1:length(param) interp = setsubfield(interp, param{i}, permute(getsubfield(interp, param{i}), permutevec)); diff --git a/external/fieldtrip/private/append_common.m b/external/fieldtrip/private/append_common.m new file mode 100644 index 00000000..5405e26f --- /dev/null +++ b/external/fieldtrip/private/append_common.m @@ -0,0 +1,348 @@ +function data = append_common(cfg, varargin) + +% APPEND_COMMON is used for concatenating raw, timelock or freq data +% +% The general bookkeeping and the correct specification of the cfg +% should be taken care of by the calling function. +% +% See FT_APPENDDATA, T_APPENDTIMELOCK, FT_APPENDFREQ + +% Copyright (C) 2017, Robert Oostenveld +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +% when present, these must be consistent in all inputs +hastime = isfield(varargin{1}, 'time'); +hasfreq = isfield(varargin{1}, 'freq'); +hastrialinfo = isfield(varargin{1}, 'trialinfo'); +hassampleinfo = isfield(varargin{1}, 'sampleinfo'); +hascumsumcnt = isfield(varargin{1}, 'cumsumcnt'); +hascumtapcnt = isfield(varargin{1}, 'cumtapcnt'); +hastopolabel = isfield(varargin{1}, 'topolabel'); +hastopo = isfield(varargin{1}, 'topo'); +hasunmixing = isfield(varargin{1}, 'unmixing'); +for i=2:numel(varargin) + hastime = hastime && isfield(varargin{i}, 'time'); + hasfreq = hasfreq && isfield(varargin{i}, 'freq'); + hastrialinfo = hastrialinfo && isfield(varargin{i}, 'trialinfo'); + hassampleinfo = hassampleinfo && isfield(varargin{i}, 'sampleinfo'); + hascumsumcnt = hascumsumcnt && isfield(varargin{i}, 'cumsumcnt'); + hascumtapcnt = hascumtapcnt && isfield(varargin{i}, 'cumtapcnt'); + hastopolabel = hastopolabel && isfield(varargin{i}, 'topolabel'); + hastopo = hastopo && isfield(varargin{i}, 'topo'); + hasunmixing = hasunmixing && isfield(varargin{i}, 'unmixing'); +end + +% these can be present in a subset of the inputs, e.g. for appending EEG and MEG data +hasgrad = false; +haselec = false; +hasopto = false; +for i=1:length(varargin) + hasgrad = hasgrad || isfield(varargin{i}, 'grad'); + haselec = haselec || isfield(varargin{i}, 'elec'); + hasopto = hasopto || isfield(varargin{i}, 'opto'); +end + +if hastopolabel || hastopo || hasunmixing + identical = true; + for i=2:numel(varargin) + if hastopolabel, identical = identical && isequal(varargin{1}.topolabel, varargin{i}.topolabel); end + if hastopo, identical = identical && isequal(varargin{1}.topo, varargin{i}.topo); end + if hasunmixing, identical = identical && isequal(varargin{1}.unmixing, varargin{i}.unmixing); end + end + if strcmp(cfg.appenddim, 'chan') + % It is possible to combine the component timeseries of different decompositions + % in the same dataset. In principle this could be improved by also concatenating + % the topo and unmixing along the correct dimension. However, at the moment the + % topo/unmixing are discarded. + ft_warning('discarding ICA/PCA topographies and/or unmixing matrix'); + else + % only proceed if the ICA/PCA topographies and/or unmixing matrix is identical in all datasets + assert(identical, 'cannot append data from different ICA/PCA decompositions'); + end +end + +switch cfg.appenddim + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + case 'chan' + assert(checkchan(varargin{:}, 'unique'), 'not all channels are unique'); + % remember the original channel labels in each input + oldlabel = cell(size(varargin)); + for i=1:numel(varargin) + oldlabel{i} = varargin{i}.label; + end + + % determine the union of all input data + tmpcfg = keepfields(cfg, {'tolerance', 'channel', 'showcallinfo'}); + tmpcfg.select = 'union'; + [varargin{:}] = ft_selectdata(tmpcfg, varargin{:}); + for i=1:numel(varargin) + [cfg, varargin{i}] = rollback_provenance(cfg, varargin{i}); + end + + % start with the union of all input data + data = keepfields(varargin{1}, {'label', 'time', 'freq', 'dimord'}); + + % keep these fields (when identical) + fn = {'trialinfo' 'sampleinfo', 'cumsumcnt', 'cumtapcnt'}; + for i=1:numel(fn) + keepfield = isfield(varargin{1}, fn{i}); + for j=1:numel(varargin) + if ~isfield(varargin{j}, fn{i}) || ~isequaln(varargin{j}.(fn{i}), varargin{1}.(fn{i})) + keepfield = false; + break + end + end + if keepfield + data.(fn{i}) = varargin{1}.(fn{i}); + end + end % for each of the fields to keep + + for i=1:numel(cfg.parameter) + dimsiz = getdimsiz(varargin{1}, cfg.parameter{i}); + switch getdimord(varargin{1}, cfg.parameter{i}) + case {'chan_chan'} + data.(cfg.parameter{i}) = nan(dimsiz); + for j=1:numel(varargin) + chansel = match_str(varargin{j}.label, oldlabel{j}); + data.(cfg.parameter{i})(chansel,chansel) = varargin{j}.(cfg.parameter{i})(chansel,chansel); + end + + case {'rpt_chan_chan'} + data.(cfg.parameter{i}) = nan(dimsiz); + for j=1:numel(varargin) + chansel = match_str(varargin{j}.label, oldlabel{j}); + data.(cfg.parameter{i})(:,chansel,chansel) = varargin{j}.(cfg.parameter{i})(:,chansel,chansel); + end + + case {'chan' 'chan_time' 'chan_freq'} + data.(cfg.parameter{i}) = nan(dimsiz); + for j=1:numel(varargin) + chansel = match_str(varargin{j}.label, oldlabel{j}); + data.(cfg.parameter{i})(chansel,:) = varargin{j}.(cfg.parameter{i})(chansel,:); + end + + case {'rpt_chan_time' 'subj_chan_time' 'rpt_chan_freq' 'subj_chan_freq'} + data.(cfg.parameter{i}) = nan(dimsiz); + for j=1:numel(varargin) + chansel = match_str(varargin{j}.label, oldlabel{j}); + data.(cfg.parameter{i})(:,chansel,:) = varargin{j}.(cfg.parameter{i})(:,chansel,:); + end + + otherwise + % do not concatenate this field + end % switch + end % for cfg.parameter + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + case {'time' 'freq'} + + % remember the original axes in each input + if hasfreq + oldfreq = cell(size(varargin)); + for i=1:numel(varargin) + oldfreq{i} = varargin{i}.freq; + end + end + if hastime + oldtime = cell(size(varargin)); + for i=1:numel(varargin) + oldtime{i} = varargin{i}.time; + end + end + + % determine the union of all input data + tmpcfg = keepfields(cfg, {'tolerance', 'channel'}); + tmpcfg.select = 'union'; + [varargin{:}] = ft_selectdata(tmpcfg, varargin{:}); + for i=1:numel(varargin) + [cfg, varargin{i}] = rollback_provenance(cfg, varargin{i}); + end + + % start with the union of all input data + data = keepfields(varargin{1}, {'label', 'time', 'freq', 'dimord', 'topo', 'unmixing', 'topolabel'}); + + % keep the trialinfo (when identical) + % note that we are NOT keeing the sampleinfo, cumsumcnt, cumtapcnt + fn = {'trialinfo'}; + for i=1:numel(fn) + keepfield = isfield(varargin{1}, fn{i}); + for j=1:numel(varargin) + if ~isfield(varargin{j}, fn{i}) || ~isequal(varargin{j}.(fn{i}), varargin{1}.(fn{i})) + keepfield = false; + break + end + end + if keepfield + data.(fn{i}) = varargin{1}.(fn{i}); + end + end % for each of the fields to keep + + for i=1:numel(cfg.parameter) + dimsiz = getdimsiz(varargin{1}, cfg.parameter{i}); + switch getdimord(varargin{1}, cfg.parameter{i}) + case 'chan_time' + data.(cfg.parameter{i}) = nan(dimsiz); + for j=1:numel(varargin) + timesel = match_val(varargin{j}.time, oldtime{j}); + data.(cfg.parameter{i})(:,timesel) = varargin{j}.(cfg.parameter{i})(:,timesel); + end + + case 'chan_freq' + data.(cfg.parameter{i}) = nan(dimsiz); + for j=1:numel(varargin) + freqsel = match_val(varargin{j}.freq, oldfreq{j}); + data.(cfg.parameter{i})(:,freqsel) = varargin{j}.(cfg.parameter{i})(:,freqsel); + end + + case 'chan_freq_time' + data.(cfg.parameter{i}) = nan(dimsiz); + for j=1:numel(varargin) + freqsel = match_val(varargin{j}.freq, oldfreq{j}); + timesel = match_val(varargin{j}.time, oldtime{j}); + data.(cfg.parameter{i})(:,freqsel,timesel) = varargin{j}.(cfg.parameter{i})(:,freqsel,timesel); + end + + case {'rpt_chan_time' 'subj_chan_time'} + data.(cfg.parameter{i}) = nan(dimsiz); + for j=1:numel(varargin) + timesel = match_val(varargin{j}.time, oldtime{j}); + data.(cfg.parameter{i})(:,:,timesel) = varargin{j}.(cfg.parameter{i})(:,:,timesel); + end + + case {'rpt_chan_freq' 'rpttap_chan_freq' 'subj_chan_freq'} + data.(cfg.parameter{i}) = nan(dimsiz); + for j=1:numel(varargin) + freqsel = match_val(varargin{j}.freq, oldfreq{j}); + data.(cfg.parameter{i})(:,:,freqsel) = varargin{j}.(cfg.parameter{i})(:,:,freqsel); + end + + case {'rpt_chan_freq_time' 'rpttap_chan_freq_time' 'subj_chan_freq_time'} + data.(cfg.parameter{i}) = nan(dimsiz); + for j=1:numel(varargin) + freqsel = match_val(varargin{j}.freq, oldfreq{j}); + timesel = match_val(varargin{j}.time, oldtime{j}); + data.(cfg.parameter{i})(:,:,freqsel,timesel) = varargin{j}.(cfg.parameter{i})(:,:,freqsel,timesel); + end + + otherwise + % do not concatenate this field + + end % switch + end % for cfg.parameter + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + case 'rpt' + + % determine the intersection of all input data + tmpcfg = keepfields(cfg, {'tolerance', 'channel'}); + tmpcfg.select = 'intersect'; + [varargin{:}] = ft_selectdata(tmpcfg, varargin{:}); + for i=1:numel(varargin) + [cfg, varargin{i}] = rollback_provenance(cfg, varargin{i}); + end + + % start with the intersection of all input data + data = keepfields(varargin{1}, {'label', 'time', 'freq', 'dimord', 'topo', 'unmixing', 'topolabel'}); + if numel(cfg.parameter)>0 + % this check should not be done if there is no data to append, this happens when called from ft_appenddata + assert(numel(data.label)>0); + end + if hastime, assert(numel(data.time)>0); end + if hasfreq, assert(numel(data.freq)>0); end + + % also append these when present + if hastrialinfo, cfg.parameter{end+1} = 'trialinfo'; end + if hassampleinfo, cfg.parameter{end+1} = 'sampleinfo'; end + if hascumsumcnt, cfg.parameter{end+1} = 'cumsumcnt'; end + if hascumtapcnt, cfg.parameter{end+1} = 'cumtapcnt'; end + + for i=1:numel(cfg.parameter) + dimsiz = getdimsiz(varargin{1}, cfg.parameter{i}); + switch getdimord(varargin{1}, cfg.parameter{i}) + case {'chan' 'chan_time' 'chan_freq' 'chan_chan' 'chan_freq_time' 'chan_chan_freq' 'chan_chan_time' 'chan_chan_freq_time'} + dat = cell(size(varargin)); + for j=1:numel(varargin) + % add a singleton dimension to the beginning + dat{j} = reshape(varargin{j}.(cfg.parameter{i}), [1, dimsiz]); + end + data.(cfg.parameter{i}) = cat(1, dat{:}); + + case {'rpt' 'rpt_chan' 'rpt_chan_time' 'rpt_chan_freq' 'rpt_chan_chan' 'rpt_chan_freq_time' 'rpttap_chan_freq' 'rpttap_chan_freq_time' 'rpt_other'} + dat = cell(size(varargin)); + for j=1:numel(varargin) + dat{j} = varargin{j}.(cfg.parameter{i}); + end + data.(cfg.parameter{i}) = cat(1, dat{:}); + + otherwise + % do not concatenate this field + + end % switch + end % for cfg.parameter + + otherwise + ft_error('unsupported cfg.appenddim'); +end + +if isfield(data, 'dimord') + dimtok = tokenize(data.dimord, '_'); + if strcmp(cfg.appenddim, 'rpt') && ~any(strcmp(dimtok{1}, {'rpt', 'rpttap', 'subj'})) + data.dimord = ['rpt_' data.dimord]; + end +end + +if hasgrad || haselec || hasopto + % gather the sensor definitions from all inputs + grad = cell(size(varargin)); + elec = cell(size(varargin)); + opto = cell(size(varargin)); + for j=1:length(varargin) + if isfield(varargin{j}, 'elec') + elec{j} = varargin{j}.elec; + end + if isfield(varargin{j}, 'grad') + grad{j} = varargin{j}.grad; + end + if isfield(varargin{j}, 'opto') + opto{j} = varargin{j}.opto; + end + end + % see test_pull393.m for a description of the expected behavior + if strcmp(cfg.appendsens, 'yes') + fprintf('concatenating sensor information across input arguments\n'); + % append the sensor descriptions, skip the empty ones + if hasgrad, data.grad = ft_appendsens([], grad{~cellfun(@isempty, grad)}); end + if haselec, data.elec = ft_appendsens([], elec{~cellfun(@isempty, elec)}); end + if hasopto, data.opto = ft_appendsens([], opto{~cellfun(@isempty, opto)}); end + else + % discard sensor information when it is inconsistent across the input arguments + removegrad = any(cellfun(@isempty, grad)); + removeelec = any(cellfun(@isempty, elec)); + removeopto = any(cellfun(@isempty, opto)); + for j=2:length(varargin) + removegrad = removegrad || ~isequaln(grad{j}, grad{1}); + removeelec = removeelec || ~isequaln(elec{j}, elec{1}); + removeopto = removeopto || ~isequaln(opto{j}, opto{1}); + end + if hasgrad && ~removegrad, data.grad = grad{1}; end + if haselec && ~removeelec, data.elec = elec{1}; end + if hasopto && ~removeopto, data.opto = opto{1}; end + end +end diff --git a/external/fieldtrip/private/atlas_lookup.m b/external/fieldtrip/private/atlas_lookup.m index 2a72287d..b09ae6b4 100644 --- a/external/fieldtrip/private/atlas_lookup.m +++ b/external/fieldtrip/private/atlas_lookup.m @@ -6,6 +6,8 @@ % label = atlas_lookup(atlas, pos, ...); % % Optinal input arguments should come in key-value pairs and can include +% 'method' = 'sphere' (default) searches surrounding voxels in a sphere +% 'cube' searches surrounding voxels in a cube % 'queryrange' = number, should be 1, 3, 5, 7, 9 or 11 (default = 3) % 'inputcoord' = 'mni' or 'tal' (default = []) % @@ -34,15 +36,16 @@ % $Id$ % get the optional input arguments +method = ft_getopt(varargin, 'method', 'sphere'); queryrange = ft_getopt(varargin, 'queryrange', 3); inputcoord = ft_getopt(varargin, 'inputcoord'); if isempty(inputcoord) - error('you must specify inputcoord'); + ft_error('you must specify inputcoord'); end -if isempty(intersect(queryrange, [1 3 5 7 9 11])) - error('incorrect query range, should be one of [1 3 5 7 9 11]'); +if isempty(intersect(queryrange, 1:2:queryrange)) + ft_error('incorrect query range, should be an odd number'); end if size(pos,1)==3 && size(pos,2)~=3 @@ -82,10 +85,10 @@ % nothing to do elseif strcmp(inputcoord, 'tal') && strcmp(atlas.coordsys, 'mni') pos = tal2mni(pos')'; % this function likes 3xN -elseif strcmp(inputcoord, 'spm') && strcmp(atlas.coordsys, 'mni') +elseif (strcmp(inputcoord, 'spm') && strcmp(atlas.coordsys, 'mni')) || (strcmp(inputcoord, 'mni') && strcmp(atlas.coordsys, 'spm')) %fprintf('coordinate system of input data ''spm'' is assume to represent the same coordinate system as the atlas, which is ''mni''\n'); elseif ~strcmp(inputcoord, atlas.coordsys) - error('there is a mismatch between the coordinate system in the atlas and the coordinate system in the data, which cannot be resolved'); + ft_error('there is a mismatch between the coordinate system in the atlas and the coordinate system in the data, which cannot be resolved'); end num = size(pos,1); @@ -101,38 +104,90 @@ ijk_center = vox(i,:); if isindexed - for di=(-(queryrange-1)/2):1:((queryrange-1)/2) - for dj=(-(queryrange-1)/2):1:((queryrange-1)/2) - for dk=(-(queryrange-1)/2):1:((queryrange-1)/2) - - % search in a cube around the center voxel - ijk = round(ijk_center + [di dj dk]); - - if ijk(1)>=1 && ijk(1)<=atlas.dim(1) && ... - ijk(2)>=1 && ijk(2)<=atlas.dim(2) && ... - ijk(3)>=1 && ijk(3)<=atlas.dim(3) - for k=1:numel(fn) - sel{k} = [sel{k}; atlas.(fn{k})(ijk(1), ijk(2), ijk(3))]; - end - %brick0_val = atlas.brick0(ijk(1), ijk(2), ijk(3)); - %brick1_val = atlas.brick1(ijk(1), ijk(2), ijk(3)); - %sel = [sel; find(atlas.descr.brick==0 & atlas.descr.value==brick0_val)]; - %sel = [sel; find(atlas.descr.brick==1 & atlas.descr.value==brick1_val)]; - else - warning('location is outside atlas volume'); - end % k - %FIXME the three loops can probably be easily vectorized - end % dk - end % dj - end % di + if strcmp(method, 'sphere'); + % search in a sphere around the center voxel + + % first, identify the voxels (x,y,z) in a sphere around the center voxel + [x, y, z] = sphere(1000); + ori = [0 0 0]; + ptswithinq = []; + for r = 0:(queryrange/2 - 0.5) + xs = round(r*x(:)); + ys = round(r*y(:)); + zs = round(r*z(:)); + pts = unique([xs ys zs], 'rows'); + + spherepts = []; + for a = 1:size(pts,1) + d2ori = sqrt(sum((pts(a, :)-ori).^2)); + if d2ori <= r + spherepts = [spherepts; pts(a, :)]; + end + end + + ptswithinr = []; % voxels located at a radius of r voxels from the center voxel + for n = 1:size(spherepts,1) + ptswithinr = [ptswithinr; spherepts(n, 1)+ijk_center(1), spherepts(n, 2)+ijk_center(2), spherepts(n,3)+ijk_center(3)]; + end + + ptswithinq = [ptswithinq; ptswithinr]; % voxels within a radius of queryrange from the center voxel + end + ptswithinq = unique(round(ptswithinq), 'rows'); + + for n = 1:size(ptswithinq,1) + ijk = ptswithinq(n, :); + if ijk(1)>=1 && ijk(1)<=atlas.dim(1) && ... + ijk(2)>=1 && ijk(2)<=atlas.dim(2) && ... + ijk(3)>=1 && ijk(3)<=atlas.dim(3) + for k=1:numel(fn) + sel{k} = [sel{k}; atlas.(fn{k})(ijk(1), ijk(2), ijk(3))]; + end + else + ft_warning('location is outside atlas volume'); + end + end + + elseif strcmp(method, 'cube'); + % search in a cube around the center voxel + for di=(-(queryrange-1)/2):1:((queryrange-1)/2) + for dj=(-(queryrange-1)/2):1:((queryrange-1)/2) + for dk=(-(queryrange-1)/2):1:((queryrange-1)/2) + + % search in a cube around the center voxel + ijk = round(ijk_center + [di dj dk]); + + if ijk(1)>=1 && ijk(1)<=atlas.dim(1) && ... + ijk(2)>=1 && ijk(2)<=atlas.dim(2) && ... + ijk(3)>=1 && ijk(3)<=atlas.dim(3) + for k=1:numel(fn) + sel{k} = [sel{k}; atlas.(fn{k})(ijk(1), ijk(2), ijk(3))]; + end + %brick0_val = atlas.brick0(ijk(1), ijk(2), ijk(3)); + %brick1_val = atlas.brick1(ijk(1), ijk(2), ijk(3)); + %sel = [sel; find(atlas.descr.brick==0 & atlas.descr.value==brick0_val)]; + %sel = [sel; find(atlas.descr.brick==1 & atlas.descr.value==brick1_val)]; + else + ft_warning('location is outside atlas volume'); + end % k + %FIXME the three loops can probably be easily vectorized + end % dk + end % dj + end % di + end for k = 1:numel(fn) if ~isempty(sel{k}) - label = [label; atlas.([fn{k} 'label'])(setdiff(unique(sel{k}),0))]; + % Get rid of zeros in sel{k} + for t = numel(sel{k}):-1:1 + if sel{k}(t) == 0; + sel{k}(t) = []; + end + end + label = [label; atlas.([fn{k} 'label'])(sel{k})]; % by using setdiff and/or unique, the count for each label is lost, and ft_volumelookup cannot provide an accurate number for labels.count end end else - error('support for atlases that have a probabilistic segmentationstyle is not supported yet'); + ft_error('support for atlases that have a probabilistic segmentationstyle is not supported yet'); end end diff --git a/external/fieldtrip/private/avw_img_write.m b/external/fieldtrip/private/avw_img_write.m index e8e268e1..7d3b6f71 100644 --- a/external/fieldtrip/private/avw_img_write.m +++ b/external/fieldtrip/private/avw_img_write.m @@ -65,18 +65,18 @@ function avw_img_write(avw, fileprefix, IMGorient, machine, verbose) %------------------------------------------------------------------------ % Check inputs -if ~exist('avw','var'), +if ~exist('avw','var') doc avw_img_write; - error('...no input avw.'); -elseif isempty(avw), - error('...empty input avw.'); -elseif ~isfield(avw,'img'), - error('...empty input avw.img'); + ft_error('...no input avw.'); +elseif isempty(avw) + ft_error('...empty input avw.'); +elseif ~isfield(avw,'img') + ft_error('...empty input avw.img'); end -if ~exist('fileprefix','var'), - if isfield(avw,'fileprefix'), - if ~isempty(avw.fileprefix), +if ~exist('fileprefix','var') + if isfield(avw,'fileprefix') + if ~isempty(avw.fileprefix) fileprefix = avw.fileprefix; else fileprefix = []; @@ -85,20 +85,20 @@ function avw_img_write(avw, fileprefix, IMGorient, machine, verbose) fileprefix = []; end end -if isempty(fileprefix), +if isempty(fileprefix) [fileprefix, pathname, filterindex] = uiputfile('*.hdr','Specify an output Analyze .hdr file'); if pathname, cd(pathname); end - if ~fileprefix, + if ~fileprefix doc avw_img_write; - error('no output .hdr file specified'); + ft_error('no output .hdr file specified'); end end -if findstr('.hdr',fileprefix), +if findstr('.hdr',fileprefix) % fprintf('AVW_IMG_WRITE: Removing .hdr extension from ''%s''\n',fileprefix); fileprefix = strrep(fileprefix,'.hdr',''); end -if findstr('.img',fileprefix), +if findstr('.img',fileprefix) % fprintf('AVW_IMG_WRITE: Removing .img extension from ''%s''\n',fileprefix); fileprefix = strrep(fileprefix,'.img',''); end @@ -115,20 +115,19 @@ function avw_img_write(avw, fileprefix, IMGorient, machine, verbose) %------------------------------------------------------------------------ % MAIN -if verbose, +if verbose version = '[$Revision$]'; fprintf('\nAVW_IMG_WRITE [v%s]\n',version(12:16)); tic; end fid = fopen(sprintf('%s.img',fileprefix),'w',machine); -if fid < 0, - msg = sprintf('Cannot open file %s.img\n',fileprefix); - error(msg); +if fid < 0 + ft_error('Cannot open file %s.img\n',fileprefix); else avw = write_image(fid,avw,fileprefix,IMGorient,machine,verbose); end -if verbose, +if verbose t=toc; fprintf('...done (%5.2f sec).\n\n',t); end @@ -189,40 +188,39 @@ function avw_hdr_write(avw, fileprefix, machine, verbose) %---------------------------------------------------------------------------- % Check inputs -if ~exist('avw','var'), - warning('...no input avw - calling avw_hdr_make\n'); +if ~exist('avw','var') + ft_warning('...no input avw - calling avw_hdr_make\n'); avw = avw_hdr_make; -elseif isempty(avw), - warning('...empty input avw - calling avw_hdr_make\n'); +elseif isempty(avw) + ft_warning('...empty input avw - calling avw_hdr_make\n'); avw = avw_hdr_make; -elseif ~isfield(avw,'hdr'), - warning('...empty input avw.hdr - calling avw_hdr_make\n'); +elseif ~isfield(avw,'hdr') + ft_warning('...empty input avw.hdr - calling avw_hdr_make\n'); avw = avw_hdr_make; end -if ~isequal(avw.hdr.hk.sizeof_hdr,348), - msg = sprintf('...avw.hdr.hk.sizeof_hdr must be 348!\n'); - error(msg); +if ~isequal(avw.hdr.hk.sizeof_hdr,348) + ft_error('...avw.hdr.hk.sizeof_hdr must be 348!\n'); end quit = 0; -if ~exist('fileprefix','var'), - if isfield(avw,'fileprefix'), - if ~isempty(avw.fileprefix), +if ~exist('fileprefix','var') + if isfield(avw,'fileprefix') + if ~isempty(avw.fileprefix) fileprefix = avw.fileprefix; - else, + else quit = 1; end else quit = 1; end - if quit, + if quit helpwin avw_hdr_write; - error('...no input fileprefix - see help avw_hdr_write\n\n'); + ft_error('...no input fileprefix - see help avw_hdr_write\n\n'); return; end end -if findstr('.hdr',fileprefix), +if findstr('.hdr',fileprefix) % fprintf('AVW_HDR_WRITE: Removing .hdr extension from ''%s''\n',fileprefix); fileprefix = strrep(fileprefix,'.hdr',''); end @@ -247,13 +245,12 @@ function avw_hdr_write(avw, fileprefix, machine, verbose) % avw.hdr.dime.dim(currDim+2:minDim+1) = int16(1); % avw.hdr.dime.pixdim(1) = int16(minDim); % avw.hdr.dime.pixdim(currDim+2:minDim+1) = int16(1); -% end; +% end fid = fopen(sprintf('%s.hdr',fileprefix),'w',machine); -if fid < 0, - msg = sprintf('Cannot write to file %s.hdr\n',fileprefix); - error(msg); +if fid < 0 + ft_error('Cannot write to file %s.hdr\n',fileprefix); else if verbose, fprintf('...writing %s Analyze header.\n',machine); end write_header(fid,avw,verbose); @@ -283,25 +280,25 @@ function avw_hdr_write(avw, fileprefix, machine, verbose) % #define DT_RGB 128 /*A Red-Green-Blue datatype*/ % #define DT_ALL 255 /*Undocumented*/ -switch double(avw.hdr.dime.datatype), -case 1, +switch double(avw.hdr.dime.datatype) +case 1 avw.hdr.dime.bitpix = int16( 1); precision = 'bit1'; -case 2, +case 2 avw.hdr.dime.bitpix = int16( 8); precision = 'uchar'; -case 4, +case 4 avw.hdr.dime.bitpix = int16(16); precision = 'int16'; -case 8, +case 8 avw.hdr.dime.bitpix = int16(32); precision = 'int32'; -case 16, +case 16 avw.hdr.dime.bitpix = int16(32); precision = 'single'; -case 32, - error('...complex datatype not yet supported.\n'); -case 64, +case 32 + ft_error('...complex datatype not yet supported.\n'); +case 64 avw.hdr.dime.bitpix = int16(64); precision = 'double'; -case 128, - error('...RGB datatype not yet supported.\n'); +case 128 + ft_error('...RGB datatype not yet supported.\n'); otherwise - warning('...unknown datatype, using type 16 (32 bit floats).\n'); + ft_warning('...unknown datatype, using type 16 (32 bit floats).\n'); avw.hdr.dime.datatype = int16(16); avw.hdr.dime.bitpix = int16(32); precision = 'single'; end @@ -321,7 +318,7 @@ function avw_hdr_write(avw, fileprefix, machine, verbose) ' in axial unflipped orientation in memory. This is\n',... ' created by the avw_img_read function, which converts\n',... ' any input file image to axial unflipped in memory.\n']; - warning(msg) + ft_warning(msg) end if isempty(IMGorient), @@ -552,7 +549,7 @@ function write_header(fid,avw,verbose) fclose(fid); if ~isequal(fbytes,348), msg = sprintf('...file size is not 348 bytes!\n'); - warning(msg); + ft_warning(msg); end return diff --git a/external/fieldtrip/private/bandpassfilter.m b/external/fieldtrip/private/bandpassfilter.m index fd69eec0..0fdd547d 100644 --- a/external/fieldtrip/private/bandpassfilter.m +++ b/external/fieldtrip/private/bandpassfilter.m @@ -72,7 +72,8 @@ if isempty(N) N = 25; end - [B, A] = fir1(N, [min(Fbp)/Fn max(Fbp)/Fn]); + B = fir1(N, [min(Fbp)/Fn max(Fbp)/Fn]); + A = 1; end % apply filter to the data diff --git a/external/fieldtrip/private/bandstopfilter.m b/external/fieldtrip/private/bandstopfilter.m index b5fb3a11..8920e065 100644 --- a/external/fieldtrip/private/bandstopfilter.m +++ b/external/fieldtrip/private/bandstopfilter.m @@ -72,7 +72,8 @@ if isempty(N) N = 25; end - [B, A] = fir1(N, [min(Fbp)/Fn max(Fbp)/Fn], 'stop'); + B = fir1(N, [min(Fbp)/Fn max(Fbp)/Fn], 'stop'); + A = 1; end % apply filter to the data diff --git a/external/fieldtrip/private/binomialprob.m b/external/fieldtrip/private/binomialprob.m index 90b0c76c..a27613ba 100644 --- a/external/fieldtrip/private/binomialprob.m +++ b/external/fieldtrip/private/binomialprob.m @@ -80,7 +80,7 @@ % threshold the single subject probability maps at the alpha level x = sum(pobs<=alpha, 2); elseif ~isthresh && ~isalpha - error('can only determine alpha automatically from thresholded statistical maps'); + ft_error('can only determine alpha automatically from thresholded statistical maps'); end % this uses MATLAB stats toolbox diff --git a/external/fieldtrip/private/bivariate_common.m b/external/fieldtrip/private/bivariate_common.m new file mode 100644 index 00000000..a2da0095 --- /dev/null +++ b/external/fieldtrip/private/bivariate_common.m @@ -0,0 +1,169 @@ +function [varargout] = bivariate_common(cfg, varargin) + +% BIVARIATE_COMMON makes a selection for a specific reference channel from a +% bivariate (i.e. connectivity) dataset and returns that selection as a univariate +% dataset. This is used in singleplot/multiplot/topoplot for both ER and TFR data. +% +% Use as +% [varargout] = bivariate_common(cfg, varargin) +% +% See also TOPOPLOT_COMMON + +% reference channel is required +if ~isfield(cfg, 'refchannel') || isempty(cfg.refchannel) + ft_error('no reference channel is specified'); +end + +% check for refchannel being part of selection +if ~strcmp(cfg.refchannel, 'gui') + if isfield(varargin{1}, 'labelcmb') + cfg.refchannel = ft_channelselection(cfg.refchannel, unique(varargin{1}.labelcmb(:))); + else + cfg.refchannel = ft_channelselection(cfg.refchannel, varargin{1}.label); + end + if (isfield(varargin{1}, 'label') && ~any(ismember(varargin{1}.label, cfg.refchannel))) || ... + (isfield(varargin{1}, 'labelcmb') && ~any(ismember(varargin{1}.labelcmb(:), cfg.refchannel))) + ft_error('cfg.refchannel is a not present in the (selected) channels)') + end +end + +% Interactively select the reference channel +if strcmp(cfg.refchannel, 'gui') + tmpcfg = keepfields(cfg, {'channel', 'layout'}); + lay = ft_prepare_layout(tmpcfg, varargin{1}); + % Open a single figure with the channel layout, the user can click on a reference channel + h = clf; + ft_plot_lay(lay, 'box', false); + title('Select the reference channel by dragging a selection window, more than 1 channel can be selected...'); + % add the channel information to the figure + info = guidata(gcf); + info.x = lay.pos(:, 1); + info.y = lay.pos(:, 2); + info.label = lay.label; + info.dataname = ''; + guidata(h, info); + set(h, 'WindowButtonUpFcn', {@ft_select_channel, 'multiple', true, 'callback', {@make_selection, cfg, varargin{:}}, 'event', 'WindowButtonUpFcn'}); + set(h, 'WindowButtonDownFcn', {@ft_select_channel, 'multiple', true, 'callback', {@make_selection, cfg, varargin{:}}, 'event', 'WindowButtonDownFcn'}); + set(h, 'WindowButtonMotionFcn', {@ft_select_channel, 'multiple', true, 'callback', {@make_selection, cfg, varargin{:}}, 'event', 'WindowButtonMotionFcn'}); +else + make_figure(cfg, varargin{:}); +end + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION which creates the figure with the selected reference channels +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function make_figure(cfg, varargin) + +if isfield(cfg, 'inputfile') + % the reading has already been done and varargin contains the data + cfg = rmfield(cfg, 'inputfile'); +end + +dimord = getdimord(varargin{1}, cfg.parameter); +dimtok = tokenize(dimord, '_'); + +for i=1:numel(varargin) + if isequal(dimtok{1}, 'chancmb') + % Convert 2-dimensional channel matrix to a single dimension + if isempty(cfg.directionality) + sel1 = match_str(varargin{i}.labelcmb(:, 2), cfg.refchannel); + sel2 = match_str(varargin{i}.labelcmb(:, 1), cfg.refchannel); + elseif strcmp(cfg.directionality, 'outflow') + sel1 = []; + sel2 = match_str(varargin{i}.labelcmb(:, 1), cfg.refchannel); + elseif strcmp(cfg.directionality, 'inflow') + sel1 = match_str(varargin{i}.labelcmb(:, 2), cfg.refchannel); + sel2 = []; + end + fprintf('selected %d channels for %s\n', length(sel1)+length(sel2), cfg.parameter); + if length(sel1)+length(sel2)==0 + ft_error('there are no channels selected for plotting: you may need to look at the specification of cfg.directionality'); + end + varargin{i}.(cfg.parameter) = varargin{i}.(cfg.parameter)([sel1;sel2], :, :); + varargin{i}.label = [varargin{i}.labelcmb(sel1, 1); varargin{i}.labelcmb(sel2, 2)]; + varargin{i} = rmfield(varargin{i}, 'labelcmb'); + + % Update the dimord + dimtok{1} = 'chan'; + varargin{i} = removefields(varargin{i}, {'dimord', [cfg.parameter 'dimord']}); + varargin{i}.dimord = sprintf('%s_', dimtok{1:end}); + varargin{i}.dimord(end) = []; % remove the trailing "_" + + elseif isequal(dimtok{1}, 'chan') && isequal(dimtok{2}, 'chan') + sel = match_str(varargin{i}.label, cfg.refchannel); + siz = [size(varargin{i}.(cfg.parameter)) 1]; + + if strcmp(cfg.directionality, 'inflow') || isempty(cfg.directionality) + % The interpretation of 'inflow' and 'outflow' depend on the definition in the + % bivariate representation of the data. In FieldTrip the row index 'causes' the + % column index channel + sel1 = 1:siz(1); + sel2 = sel; + meandir = 2; + + elseif strcmp(cfg.directionality, 'outflow') + sel1 = sel; + sel2 = 1:siz(1); + meandir = 1; + + elseif strcmp(cfg.directionality, 'ff-fd') + ft_error('cfg.directionality = ''ff-fd'' is not supported anymore, you have to manually subtract the two prior to plotting'); + + elseif strcmp(cfg.directionality, 'fd-ff') + ft_error('cfg.directionality = ''fd-ff'' is not supported anymore, you have to manually subtract the two prior to plotting'); + end % if directionality + + % Make a univariate selection of the data + varargin{i}.(cfg.parameter) = mean(varargin{i}.(cfg.parameter)(sel1, sel2,:,:), meandir); + siz(meandir) = []; + varargin{i}.(cfg.parameter) = reshape(varargin{i}.(cfg.parameter), siz); + + % Update the dimord + varargin{i} = removefields(varargin{i}, {'dimord', [cfg.parameter 'dimord']}); + varargin{i}.dimord = sprintf('%s_', dimtok{2:end}); + varargin{i}.dimord(end) = []; % remove the trailing "_" + + else + error('unexpected dimord'); + + end % if sparse or full +end % for varargin + +% Ensure that the new figure appears at the same position +figure('Position', get(gcf, 'Position')); + +% Remove these fields from the configuration +fn = {'originalfunction', 'inputfile', 'refchannel'}; + +% This applies to the topoplots +cfg.highlight = 'on'; +cfg.highlightsymbol = '.'; +cfg.highlightcolor = 'r'; +cfg.highlightsize = 20; +cfg.highlightchannel = cfg.refchannel; + +switch cfg.originalfunction + case 'ft_multiplotER' + ft_multiplotER(removefields(cfg, fn), varargin{:}); + case 'ft_multiplotTFR' + ft_multiplotTFR(removefields(cfg, fn), varargin{:}); + case 'ft_singleplotER' + ft_singleplotER(removefields(cfg, fn), varargin{:}); + case 'ft_singleplotTFR' + ft_singleplotTFR(removefields(cfg, fn), varargin{:}); + case 'ft_topoplotER' + ft_topoplotER(removefields(cfg, fn), varargin{:}); + case 'ft_topoplotTFR' + ft_topoplotTFR(removefields(cfg, fn), varargin{:}); + otherwise + error('unsupported cfg.originalfunction') +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION which is called by ft_select_channel in case cfg.refchannel='gui' +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function make_selection(label, cfg, varargin) +fprintf('selected cfg.refchannel = ''%s''\n', join_str(', ', cfg.refchannel)); +cfg.refchannel = label; +make_figure(cfg, varargin{:}) diff --git a/external/fieldtrip/private/bounding_mesh.m b/external/fieldtrip/private/bounding_mesh.m index e0e2bb95..22b9c25c 100644 --- a/external/fieldtrip/private/bounding_mesh.m +++ b/external/fieldtrip/private/bounding_mesh.m @@ -30,12 +30,11 @@ % You should have received a copy of the GNU General Public License % along with FieldTrip. If not, see . % -% $Id$ % this can be used for printing detailled user feedback fb = false; -% this is a work-around for http://bugzilla.fcdonders.nl/show_bug.cgi?id=2369 +% this is a work-around for http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2369 pos = double(pos); pnt = double(pnt); tri = double(tri); diff --git a/external/fieldtrip/private/bsscca.m b/external/fieldtrip/private/bsscca.m index 26325435..62744bef 100644 --- a/external/fieldtrip/private/bsscca.m +++ b/external/fieldtrip/private/bsscca.m @@ -1,37 +1,96 @@ -function [w,rho] = bsscca(X, delay) - -% BSSCCA computes the unmixing matrix based on the canonical correlation between a signal and its lagged-one copy. It implements the algorithm described in [1] +function [unmixing, mixing, rho, compdata, time] = bsscca(X, varargin) + +% BSSCCA computes the unmixing matrix based on the canonical correlation between +% two sets of (possibly multivariate) signals, the sets may contain time shifted copies. +% In its default, it implements the algorithm described in [1], computing the +% canonical correlation between a set of signals and their lag-one-shifted +% copy. Alternatively, if the input contains a reference signal (possibly multivariate), +% the canonical correlation between the data in X and the reference signal is computed. +% It requires JM's cellfunction toolbox on the MATLAB path: +% (github.com/schoffelen/cellfunction.git) % -% DeClercq et al 2006, IEEE Biomed Eng 2583. +% [1] DeClercq et al 2006, IEEE Biomed Eng 2583. + +% Copyright (C) 2017, Jan-Mathijs Schoffelen -if nargin<2, - delay = 1; +if isa(X, 'cell') + n = size(X{1},1); +else + n = size(X,1); end +refdelay = ft_getopt(varargin, 'delay', 1); +refdelay = ft_getopt(varargin, 'refdelay', refdelay); % allow for old naming 'delay' +chandelay = ft_getopt(varargin, 'chandelay', 0); +time = ft_getopt(varargin, 'time'); +Y = ft_getopt(varargin, 'refdata', {}); +dowhiten = istrue(ft_getopt(varargin, 'prewhiten', 0)); +tol = ft_getopt(varargin, 'tol', 1e-6); + +hasrefdata = ~isempty(Y); + % hmmmm we need to observe the epochs' boundaries to not create rubbish % support cell array input if isa(X, 'cell') - delay = setdiff(delay(:)', 0); - n = size(X{1},1); - mX = cellmean(X,2); - X = cellvecadd(X, -mX); + % demean + X = cellvecadd(X, -cellmean(X, 2)); - C = cellcovshift(X,[0 delay],2,0); - m = size(C,1)-n; + maxshift = [abs(min(min(refdelay),min(chandelay))) abs(max(max(refdelay),max(chandelay)))]; - XY = C(1:n, (n+1):end); % cross terms XY - XX = C(1:n, 1:n); % auto terms X; - YY = C((n+1):end, (n+1):end); % auto terms Y - YX = C((n+1):end, 1:n); - %A(1:n,1:n) = 0; - %A((n+1):end,(n+1):end) = 0; + if ~hasrefdata + Y = cellshift(X, refdelay, 2, maxshift); + else + Y = cellvecadd(Y, -cellmean(Y, 2)); + Y = cellshift(Y, refdelay, 2, maxshift); + end + X = cellshift(X, chandelay, 2, maxshift); - %B(1:n,(n+1):end) = 0; - %B((n+1):end,1:n) = 0; + if ~isempty(time) + time = cellshift(time, 0, 2, maxshift); + end + + if dowhiten + % do an svd based whitening based on the relative tolerance parameter tol + % (relative to the largest singular value) + [ux,sx,vx] = svd(cov(X,1,2,1)); + [uy,sy,vy] = svd(cov(Y,1,2,1)); + + sx = diag(sx); + sy = diag(sy); + + keepx = sx./sx(1)>tol; + keepy = sy./sy(1)>tol; + + fprintf('whitening the data, keeping %d signal components in X\n', sum(keepx)); + fprintf('whitening the data, keeping %d signal components in Y\n', sum(keepy)); + + whiten_x = diag(1./sqrt(sx(keepx)))*ux(:,keepx)'; + whiten_y = diag(1./sqrt(sy(keepy)))*uy(:,keepy)'; + + unwhiten_x = ux(:,keepx)*diag(sqrt(sx(keepx))); + unwhiten_y = uy(:,keepy)*diag(sqrt(sy(keepy))); + + X = whiten_x*X; + Y = whiten_y*Y; + end + + + % compute covariance + C = cov(cellcat(1,X,Y), 1, 2, 1); + ix = 1:size(X{1},1); + iy = ix(end)+(1:size(Y{1},1)); + + + XY = C(ix,iy); % cross terms XY + XX = C(ix,ix); % auto terms X; + YY = C(iy,iy); % auto terms Y + YX = C(iy,ix); else + ft_error('this does not work at the moment'); + ft_warning('Running bsscca with concatenated trial in the input, represented as a single matrix, is not optimal. Consider using cellmode'); % input is a single data matrix assumed to be a continuous stretch [n,m] = size(X); @@ -55,262 +114,54 @@ XX = X(:,delay+(1:(m-delay)))*X(:,delay+(1:(m-delay)))'; YY = Xlag*Xlag'; - %XY = (X(:,2:end)-mX*m)*(X(:,1:end-1)-mX2*m)'; - A(1:n,(n+1):end) = XY; A((n+1):end,1:n) = XY'; B(1:n,1:n) = XX; B((n+1):end,(n+1):end) = YY; - %B(1:n,1:n) = (X(:,2:end)-mX*m)*(X(:,2:end)-mX*m)'; - %B((n+1):end,(n+1):end) = (X(:,1:end-1)-mX2*m)*(X(:,1:end-1)-mX2*m)'; -end - -%if cond(B)>1e8 -% s = svd(B); -% [w,rho] = eig((B+eye(size(B,1))*s(1)*0.00000001)\A); -%else -% [w,rho] = eig(B\A); -%end -if cond(XX)>1e8 - s = svd(XX); - XX = XX+eye(size(XX,1))*s(1)*0.00000001; -end -if cond(YY)>1e8 - s = svd(YY); - YY = YY+eye(size(YY,1))*s(1)*0.00000001; -end -[wx,rho] = eig((XX\XY)*(YY\YX)); -rho = sqrt(real(diag(rho))); -[dummy,ix] = sort(rho, 'descend'); -rho = rho(ix); -wx = wx(:,ix); -w = wx'; - -%[dummy,ix] = sort(diag(abs(rho).^2),'descend'); -%w = w(1:n,ix(2:2:end))'; -%w = w(1:n,1:n); -%rho = abs(rho(ix(2:2:2*n),ix(2:2:2*n))).^2; - -% normalise to unit norm -%for k= 1:size(w,1) -% w(k,:) = w(k,:)./norm(w(k,:)); -%end - -function [m] = cellmean(x, dim) - -% [M] = CELLMEAN(X, DIM) computes the mean, across all cells in x along -% the dimension dim. -% -% X should be an linear cell-array of matrices for which the size in at -% least one of the dimensions should be the same for all cells - -nx = size(x); -if ~iscell(x) || length(nx)>2 || all(nx>1), - error('incorrect input for cellmean'); -end - -if nargin==1, - scx1 = cellfun('size', x, 1); - scx2 = cellfun('size', x, 2); - if all(scx2==scx2(1)), dim = 2; %let second dimension prevail - elseif all(scx1==scx1(1)), dim = 1; - else error('no dimension to compute mean for'); - end -end - -nx = max(nx); -nsmp = cellfun('size', x, dim); -ssmp = cellfun(@sum, x, repmat({dim},1,nx), 'UniformOutput', 0); -m = sum(cell2mat(ssmp), dim)./sum(nsmp); - - -function [y] = cellvecadd(x, v) - -% [Y]= CELLVECADD(X, V) - add vector to all rows or columns of each matrix -% in cell-array X - -% check once and for all to save time -persistent bsxfun_exists; -if isempty(bsxfun_exists); - bsxfun_exists=(exist('bsxfun')==5); - if ~bsxfun_exists; - error('bsxfun not found.'); - end -end - -nx = size(x); -if ~iscell(x) || length(nx)>2 || all(nx>1), - error('incorrect input for cellmean'); -end - -if ~iscell(v), - v = repmat({v}, nx); end -sx1 = cellfun('size', x, 1); -sx2 = cellfun('size', x, 2); -sv1 = cellfun('size', v, 1); -sv2 = cellfun('size', v, 2); -if all(sx1==sv1) && all(sv2==1), - dim = mat2cell([ones(length(sx2),1) sx2(:)]', repmat(2,nx(1),1), repmat(1,nx(2),1)); -elseif all(sx2==sv2) && all(sv1==1), - dim = mat2cell([sx1(:) ones(length(sx1),1)]', repmat(2,nx(1),1), repmat(1,nx(2),1)); -elseif all(sv1==1) && all(sv2==1), - dim = mat2cell([sx1(:) sx2(:)]'', nx(1), nx(2)); -else error('inconsistent input'); -end +XXXY = XX\XY; +YYYX = YY\YX; -y = cellfun(@bsxfun, repmat({@plus}, nx), x, v, 'UniformOutput', 0); -%y = cellfun(@vplus, x, v, dim, 'UniformOutput', 0); +[wx,rho] = eig(XXXY*YYYX); +[wy,rho2] = eig(YYYX*XXXY); -function [c] = cellcov(x, y, dim, flag) +rho = sqrt(real(diag(rho))); +rho2 = sqrt(real(diag(rho2))); +[rho,srt1] = sort(rho, 'descend'); +[rho2,srt2] = sort(rho2, 'descend'); -% [C] = CELLCOV(X, DIM) computes the covariance, across all cells in x along -% the dimension dim. When there are three inputs, covariance is computed between -% all cells in x and y -% -% X (and Y) should be linear cell-array(s) of matrices for which the size in at -% least one of the dimensions should be the same for all cells +n = min(numel(srt1),numel(srt2)); +wx = wx(:,srt1(1:n)); +wy = wy(:,srt2(1:n)); +rho = rho(1:n); +% get the tranpose +wx = wx'; +wy = wy'; -if nargin<4 && iscell(y) - flag = 1; -elseif nargin<4 && isnumeric(y) - flag = dim; -end +% unmix the data +x = wx*X; +y = wy*Y; -if nargin<3 && iscell(y) - scx1 = cellfun('size', x, 1); - scx2 = cellfun('size', x, 2); - if all(scx2==scx2(1)), dim = 2; %let second dimension prevail - elseif all(scx1==scx1(1)), dim = 1; - else error('no dimension to compute covariance for'); - end -elseif nargin<=3 && isnumeric(y) - dim = y; -end -if isnumeric(y), y = []; end +ax = (XX*wx')/cov(x,1,2,1); % by construction wx*ax = I +ay = (YY*wy')/cov(y,1,2,1); -nx = size(x); -if ~iscell(x) || length(nx)>2 || all(nx>1), - error('incorrect input for cellmean'); -end -if flag, - mx = cellmean(x, 2); - x = cellvecadd(x, -mx); - if ~isempty(y), - my = cellmean(y, 2); - y = cellvecadd(y, -my); - end +if dowhiten + wx = wx*whiten_x; + wy = wy*whiten_y; + ax = unwhiten_x*ax; + ay = unwhiten_y*ay; end -nx = max(nx); -nsmp = cellfun('size', x, dim); -if isempty(y), - csmp = cellfun(@covc, x, repmat({dim},1,nx), 'UniformOutput', 0); +if hasrefdata + unmixing = blkdiag(wx,wy); + mixing = blkdiag(ax,ay); + compdata = cellcat(1, x, y); else - csmp = cellfun(@covc, x, y, repmat({dim},1,nx), 'UniformOutput', 0); -end -nc = size(csmp{1}); -c = sum(reshape(cell2mat(csmp), [nc(1) nc(2) nx]), 3)./sum(nsmp); - -function [c] = covc(x, y, dim) - -if nargin==2, - dim = y; - y = x; -end - -if dim==1, - c = x'*y; -elseif dim==2, - c = x*y'; -end - -function [c] = cellcovshift(x, shift, dim, flag) - -% [C] = CELLCOVSHIFT(X, SHIFT, DIM) computes the covariance, across all cells -% in x along the dimension dim. -% -% X should be linear cell-array(s) of matrices for which the size in at -% least one of the dimensions is be the same for all cells - -if nargin<4, - flag = 1; -end - -if nargin<3, - dim = find(size(x{1})>1, 1, 'first'); -end - -nx = size(x); -if ~iscell(x) || length(nx)>2 || all(nx>1) || ndims(x{1})>2, - error('incorrect input for cellcovshift'); -end - -% shift the time axis -y = cellshift(x, shift, dim); - -% compute covariance -c = cellcov(y, dim, flag); - -function [x] = cellshift(x, shift, dim, maxshift) - -% CELLSHIFT(X, SHIFT, DIM) - -if numel(shift)>1 - x = x(:)'; - y = cell(numel(shift),numel(x)); - for k = 1:numel(shift) - y(k,:) = cellshift(x, shift(k), dim, max(abs(shift))); - end - for k = 1:size(y,2) - y{1,k} = cell2mat(y(:,k)); - for m = 2:size(y,1) - y{m,k} = nan; - end - end - x = y(1,:); - return; -end - -if nargin<4 - maxshift = max(abs(shift)); -end - -if any(abs(shift))>abs(maxshift) - error('the value for maxshift should be >= shift'); -end - -if nargin<3 - dim = find(size(x{1})>1, 1, 'first'); -end - -maxshift = abs(maxshift); -if numel(maxshift)==1, maxshift = maxshift([1 1]); end - -nx = size(x); -if ~iscell(x) || length(nx)>2 || all(nx>1), - error('incorrect input for cellshift'); -end - -n = numel(x); -nsmp = cellfun('size', x, dim); -beg1 = ones(1,n) + shift + maxshift(1); -end1 = nsmp + shift - maxshift(2); - -switch dim -case 1 - for k = 1:n - x{k} = x{k}(beg1(k):end1(k),:); - end -case 2 - for k = 1:n - x{k} = x{k}(:,beg1(k):end1(k)); - end -otherwise - error('dimensionality of >2 is not supported'); -end - + unmixing = wx; + mixing = ax; + compdata = x; +end diff --git a/external/fieldtrip/private/cancorr.m b/external/fieldtrip/private/cancorr.m index d8916c62..06bc17b3 100644 --- a/external/fieldtrip/private/cancorr.m +++ b/external/fieldtrip/private/cancorr.m @@ -31,7 +31,7 @@ % $Id$ if nargin<3, - error('to compute canonical coherence, you need to specify the indices to the cross-spectral density making up the dependent and independent variable'); + ft_error('to compute canonical coherence, you need to specify the indices to the cross-spectral density making up the dependent and independent variable'); elseif nargin==3, powflag = 0; realflag = 0; diff --git a/external/fieldtrip/private/cellStruct2StructCell.m b/external/fieldtrip/private/cellStruct2StructCell.m index b8cdf60b..f7513677 100644 --- a/external/fieldtrip/private/cellStruct2StructCell.m +++ b/external/fieldtrip/private/cellStruct2StructCell.m @@ -3,6 +3,6 @@ structCell = struct; for i=1:numel(cellStruct) - if i==1, structCell = cellStruct{i}; end; + if i==1, structCell = cellStruct{i}; end structCell(i) = cellStruct{i}; end diff --git a/external/fieldtrip/private/channelconnectivity.m b/external/fieldtrip/private/channelconnectivity.m index f1105920..dd81b6ba 100644 --- a/external/fieldtrip/private/channelconnectivity.m +++ b/external/fieldtrip/private/channelconnectivity.m @@ -20,7 +20,7 @@ elseif nargin == 2 chans = data.label; else - error('either the cfg needs to have both cfg.channel and cfg.neighbours, or a second (data) input argument needs to be specified'); + ft_error('either the cfg needs to have both cfg.channel and cfg.neighbours, or a second (data) input argument needs to be specified'); end nchan = length(chans); @@ -44,7 +44,7 @@ % the following code should be equivalent: if numel(neighbours) < nchan/4 - error('channelconnectivity only works when at least 1/4th of all channels has neighbours defined (or with neighbours = [])'); + ft_error('channelconnectivity only works when at least 1/4th of all channels has neighbours defined (or with neighbours = [])'); % FIXME the above error is true (or maybe with <1/5th) but I don't % understand why, ES 25-nov-2013 % the above error will cause the code to fall through to the catch diff --git a/external/fieldtrip/private/channelposition.m b/external/fieldtrip/private/channelposition.m index 25f8db11..1eecb56a 100644 --- a/external/fieldtrip/private/channelposition.m +++ b/external/fieldtrip/private/channelposition.m @@ -110,7 +110,7 @@ dist(selrest,sum(~isinf(dist(selmode,:)))>0) = inf; numcoils = sum(isfinite(dist),2); if niter>500 - error('Failed to extract the positions of the channels. This is most likely due to the balancing matrix being rank deficient. Please replace data.grad with the original grad-structure obtained after reading the header.'); + ft_error('Failed to extract the positions of the channels. This is most likely due to the balancing matrix being rank deficient. Please replace data.grad with the original grad-structure obtained after reading the header.'); end end else @@ -332,5 +332,5 @@ % do a sanity check on the number of positions nchan = numel(sens.label); if length(lab)~=nchan || size(pnt,1)~=nchan || size(ori,1)~=nchan - warning('the positions were not determined for all channels'); + ft_warning('the positions were not determined for all channels'); end diff --git a/external/fieldtrip/private/chanscale_common.m b/external/fieldtrip/private/chanscale_common.m new file mode 100644 index 00000000..1d98a271 --- /dev/null +++ b/external/fieldtrip/private/chanscale_common.m @@ -0,0 +1,152 @@ +function data = chanscale_common(cfg, data) + +% CHANSCALE_COMMON applies a scaling to specific channel types +% +% Use as +% data = chanscale_common(cfg, data) +% where the configuration contains +% cfg.parameter +% +% For specific channel groups you can use +% cfg.eegscale = number, scaling to apply to the EEG channels prior to display +% cfg.eogscale = number, scaling to apply to the EOG channels prior to display +% cfg.ecgscale = number, scaling to apply to the ECG channels prior to display +% cfg.emgscale = number, scaling to apply to the EMG channels prior to display +% cfg.megscale = number, scaling to apply to the MEG channels prior to display +% cfg.gradscale = number, scaling to apply to the MEG gradiometer channels prior to display (in addition to the cfg.megscale factor) +% cfg.magscale = number, scaling to apply to the MEG magnetometer channels prior to display (in addition to the cfg.megscale factor) +% +% For individual control off the scaling for all channels you can use +% cfg.chanscale = Nx1 vector with scaling factors, one per channel specified in cfg.channel +% +% For control over specific channels you can use +% cfg.mychanscale = number, scaling to apply to the channels specified in cfg.mychan +% cfg.mychan = Nx1 cell-array with selection of channels + +cfg.eegscale = ft_getopt(cfg, 'eegscale'); +cfg.eogscale = ft_getopt(cfg, 'eogscale'); +cfg.ecgscale = ft_getopt(cfg, 'ecgscale'); +cfg.emgscale = ft_getopt(cfg, 'emgscale'); +cfg.megscale = ft_getopt(cfg, 'megscale'); +cfg.gradscale = ft_getopt(cfg, 'gradscale'); +cfg.magscale = ft_getopt(cfg, 'magscale'); +cfg.chanscale = ft_getopt(cfg, 'chanscale'); +cfg.mychanscale = ft_getopt(cfg, 'mychanscale'); +cfg.mychan = ft_getopt(cfg, 'mychan'); + +dimord = getdimord(data, cfg.parameter); + +switch dimord + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + case {'chan_time' 'chan_freq' 'chan_comp' 'chan_freq_time' 'chan_time_freq'} + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + % get the data from the structure + dat = data.(cfg.parameter); + + % apply scaling to selected channels, using wildcard to support subselection of channels + if ~isempty(cfg.eegscale) + chansel = match_str(data.label, ft_channelselection('EEG', data.label)); + dat(chansel,:,:) = dat(chansel,:,:) .* cfg.eegscale; + end + if ~isempty(cfg.eogscale) + chansel = match_str(data.label, ft_channelselection('EOG', data.label)); + dat(chansel,:,:) = dat(chansel,:,:) .* cfg.eogscale; + end + if ~isempty(cfg.ecgscale) + chansel = match_str(data.label, ft_channelselection('ECG', data.label)); + dat(chansel,:,:) = dat(chansel,:,:) .* cfg.ecgscale; + end + if ~isempty(cfg.emgscale) + chansel = match_str(data.label, ft_channelselection('EMG', data.label)); + dat(chansel,:,:) = dat(chansel,:,:) .* cfg.emgscale; + end + if ~isempty(cfg.megscale) + type = opt.hdr.grad.type; + chansel = match_str(data.label, ft_channelselection('MEG', data.label, type)); + dat(chansel,:,:) = dat(chansel,:,:) .* cfg.megscale; + end + if ~isempty(cfg.magscale) + chansel = match_str(data.label, ft_channelselection('MEGMAG', data.label)); + dat(chansel,:,:) = dat(chansel,:,:) .* cfg.magscale; + end + if ~isempty(cfg.gradscale) + chansel = match_str(data.label, ft_channelselection('MEGGRAD', data.label)); + dat(chansel,:,:) = dat(chansel,:,:) .* cfg.gradscale; + end + if ~isempty(cfg.chanscale) + chansel = match_str(data.label, ft_channelselection(cfg.channel, data.label)); + dat(chansel,:,:) = dat(chansel,:,:) .* repmat(cfg.chanscale(:),1,size(dat,2),size(dat,3)); + end + if ~isempty(cfg.mychanscale) + chansel = match_str(data.label, ft_channelselection(cfg.mychan, data.label)); + dat(chansel,:,:) = dat(chansel,:,:) .* repmat(cfg.mychanscale(:),1,size(dat,2),size(dat,3)); + end + + % put the data back into the structure + data.(cfg.parameter) = dat; + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + case '{rpt}_chan_time' + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + for i=1:numel(data.(cfg.parameter)) + % get the data from the structure + dat = data.(cfg.parameter){i}; + + % apply scaling to selected channels, using wildcard to support subselection of channels + if ~isempty(cfg.eegscale) + chansel = match_str(data.label, ft_channelselection('EEG', data.label)); + dat(chansel,:) = dat(chansel,:) .* cfg.eegscale; + end + if ~isempty(cfg.eogscale) + chansel = match_str(data.label, ft_channelselection('EOG', data.label)); + dat(chansel,:) = dat(chansel,:) .* cfg.eogscale; + end + if ~isempty(cfg.ecgscale) + chansel = match_str(data.label, ft_channelselection('ECG', data.label)); + dat(chansel,:) = dat(chansel,:) .* cfg.ecgscale; + end + if ~isempty(cfg.emgscale) + chansel = match_str(data.label, ft_channelselection('EMG', data.label)); + dat(chansel,:) = dat(chansel,:) .* cfg.emgscale; + end + if ~isempty(cfg.megscale) + type = opt.hdr.grad.type; + chansel = match_str(data.label, ft_channelselection('MEG', data.label, type)); + dat(chansel,:) = dat(chansel,:) .* cfg.megscale; + end + if ~isempty(cfg.magscale) + chansel = match_str(data.label, ft_channelselection('MEGMAG', data.label)); + dat(chansel,:) = dat(chansel,:) .* cfg.magscale; + end + if ~isempty(cfg.gradscale) + chansel = match_str(data.label, ft_channelselection('MEGGRAD', data.label)); + dat(chansel,:) = dat(chansel,:) .* cfg.gradscale; + end + if ~isempty(cfg.chanscale) + chansel = match_str(data.label, ft_channelselection(cfg.channel, data.label)); + dat(chansel,:) = dat(chansel,:) .* repmat(cfg.chanscale(:),1,size(dat,2)); + end + if ~isempty(cfg.mychanscale) + chansel = match_str(data.label, ft_channelselection(cfg.mychan, data.label)); + dat(chansel,:) = dat(chansel,:) .* repmat(cfg.mychanscale(:),1,size(dat,2)); + end + + % put the data back into the structure + data.(cfg.parameter){i} = dat; + end % for each trial + + otherwise + if ~isempty(cfg.eegscale) || ... + ~isempty(cfg.eogscale) || ... + ~isempty(cfg.ecgscale) || ... + ~isempty(cfg.emgscale) || ... + ~isempty(cfg.megscale) || ... + ~isempty(cfg.magscale) || ... + ~isempty(cfg.gradscale) || ... + ~isempty(cfg.chanscale) || ... + ~isempty(cfg.mychanscale) + ft_error('unsupported dimord "%s"', dimord); + end +end % switch dimord diff --git a/external/fieldtrip/private/checktime.m b/external/fieldtrip/private/checktime.m index 713b3d02..349ddd6f 100644 --- a/external/fieldtrip/private/checktime.m +++ b/external/fieldtrip/private/checktime.m @@ -17,8 +17,7 @@ boolval = numel(unique(taxis))==numel(taxis) && ~all(isnan(taxis)); % the second condition is included when the time is set to dummy nan elseif strcmp(required, 'identical') - % the number of time bins needs at least to be the same across - % inputs + % the number of time bins needs at least to be the same across inputs boolval = all(Ntime==Ntime(1)); if boolval % then check whether the axes are equal diff --git a/external/fieldtrip/private/clusterstat.m b/external/fieldtrip/private/clusterstat.m index 5c11f329..f0f379ed 100644 --- a/external/fieldtrip/private/clusterstat.m +++ b/external/fieldtrip/private/clusterstat.m @@ -40,9 +40,13 @@ cfg.orderedstats = ft_getopt(cfg, 'orderedstats', 'no'); cfg.multivariate = ft_getopt(cfg, 'multivariate', 'no'); cfg.minnbchan = ft_getopt(cfg, 'minnbchan', 0); +cfg.spmversion = ft_getopt(cfg, 'spmversion', 'spm8'); + +% ensure that the preferred SPM version is on the path +ft_hastoolbox(cfg.spmversion, 1); if cfg.tail~=cfg.clustertail - error('cfg.tail and cfg.clustertail should be identical') + ft_error('cfg.tail and cfg.clustertail should be identical') end % get conncevitiy matrix for the spatially neighbouring elements @@ -100,7 +104,7 @@ negtailcritval = cfg.clustercritval(1); postailcritval = cfg.clustercritval(2); else - error('cannot make sense out of the specified parametric critical values'); + ft_error('cannot make sense out of the specified parametric critical values'); end elseif strcmp(cfg.clusterthreshold, 'nonparametric_individual') @@ -140,7 +144,7 @@ end else - error('no valid threshold for clustering was given') + ft_error('no valid threshold for clustering was given') end % determine clusterthreshold % these should be scalars or column vectors @@ -162,13 +166,16 @@ cfg.inside = true(cfg.dim); end % cfg.inside is set in ft_sourcestatistics, but is also needed for timelock and freq -if isfield(cfg, 'origdim'), +if isfield(cfg, 'origdim') cfg.dim = cfg.origdim; end % this snippet is to support correct clustering of N-dimensional data, not fully tested yet +% ensure that SPM is available, needed for spm_bwlabeln +ft_hastoolbox('spm8up', 3) || ft_hastoolbox('spm2up', 1); + % first do the clustering on the observed data spacereshapeable = numel(channeighbstructmat)==1&&~isfinite(channeighbstructmat); -if needpos, +if needpos if spacereshapeable % this pertains to data for which the spatial dimension can be reshaped @@ -179,7 +186,6 @@ numdims = length(cfg.dim); if numdims == 2 || numdims == 3 % if 2D or 3D data - ft_hastoolbox('spm8',1); % use spm_bwlabel for 2D/3D data to avoid usage of image processing toolbox [posclusobs, posnum] = spm_bwlabel(tmp, 2*numdims); else @@ -189,7 +195,7 @@ posclusobs = posclusobs(cfg.inside); else - if 0 + if false posclusobs = findcluster(reshape(postailobs, [cfg.dim,1]),cfg.chancmbneighbstructmat,cfg.chancmbneighbselmat,cfg.minnbchan); else posclusobs = findcluster(reshape(postailobs, [cfg.dim,1]),channeighbstructmat,cfg.minnbchan); @@ -200,7 +206,7 @@ fprintf('found %d positive clusters in observed data\n', Nobspos); end % if needpos -if needneg, +if needneg if spacereshapeable % this pertains to data for which the spatial dimension can be reshaped @@ -211,7 +217,6 @@ numdims = length(cfg.dim); if numdims == 2 || numdims == 3 % if 2D or 3D data - ft_hastoolbox('spm8',1); % use spm_bwlabel for 2D/3D data to avoid usage of image processing toolbox [negclusobs, negnum] = spm_bwlabel(tmp, 2*numdims); else @@ -221,7 +226,7 @@ negclusobs = negclusobs(cfg.inside); else - if 0 + if false negclusobs = findcluster(reshape(negtailobs, [cfg.dim,1]),cfg.chancmbneighbstructmat,cfg.chancmbneighbselmat,cfg.minnbchan); else negclusobs = findcluster(reshape(negtailobs, [cfg.dim,1]),channeighbstructmat,cfg.minnbchan); @@ -239,7 +244,7 @@ % catch situation where no clustering of the random data is needed if (Nobspos+Nobsneg)==0 - warning('no clusters were found in the observed data'); + ft_warning('no clusters were found in the observed data'); stat.prob = ones(Nsample, 1); return end @@ -283,16 +288,16 @@ stat = zeros(1,Nrndpos); % this will hold the statistic for each cluster % fprintf('found %d positive clusters in this randomization\n', Nrndpos); for j = 1:Nrndpos - if strcmp(cfg.clusterstatistic, 'max'), + if strcmp(cfg.clusterstatistic, 'max') stat(j) = max(statrnd(posclusrnd==j,i)); - elseif strcmp(cfg.clusterstatistic, 'maxsize'), + elseif strcmp(cfg.clusterstatistic, 'maxsize') stat(j) = length(find(posclusrnd==j)); - elseif strcmp(cfg.clusterstatistic, 'maxsum'), + elseif strcmp(cfg.clusterstatistic, 'maxsum') stat(j) = sum(statrnd(posclusrnd==j,i)); - elseif strcmp(cfg.clusterstatistic, 'wcm'), + elseif strcmp(cfg.clusterstatistic, 'wcm') stat(j) = sum((statrnd(posclusrnd==j,i)-postailcritval).^cfg.wcm_weight); else - error('unknown clusterstatistic'); + ft_error('unknown clusterstatistic'); end end % for 1:Nrdnpos if strcmp(cfg.multivariate, 'yes') || strcmp(cfg.orderedstats, 'yes') @@ -307,7 +312,7 @@ if ~isempty(stat), posdistribution(i) = max(stat); end end end % needpos - if needneg, + if needneg if spacereshapeable tmp = zeros(cfg.dim); @@ -332,16 +337,16 @@ stat = zeros(1,Nrndneg); % this will hold the statistic for each cluster % fprintf('found %d negative clusters in this randomization\n', Nrndneg); for j = 1:Nrndneg - if strcmp(cfg.clusterstatistic, 'max'), + if strcmp(cfg.clusterstatistic, 'max') stat(j) = min(statrnd(negclusrnd==j,i)); - elseif strcmp(cfg.clusterstatistic, 'maxsize'), + elseif strcmp(cfg.clusterstatistic, 'maxsize') stat(j) = -length(find(negclusrnd==j)); % encode the size of a negative cluster as a negative value - elseif strcmp(cfg.clusterstatistic, 'maxsum'), + elseif strcmp(cfg.clusterstatistic, 'maxsum') stat(j) = sum(statrnd(negclusrnd==j,i)); - elseif strcmp(cfg.clusterstatistic, 'wcm'), + elseif strcmp(cfg.clusterstatistic, 'wcm') stat(j) = -sum((abs(statrnd(negclusrnd==j,i)-negtailcritval)).^cfg.wcm_weight); % encoded as a negative value else - error('unknown clusterstatistic'); + ft_error('unknown clusterstatistic'); end end % for 1:Nrndneg if strcmp(cfg.multivariate, 'yes') || strcmp(cfg.orderedstats, 'yes') @@ -360,20 +365,20 @@ ft_progress('close'); % compare the values for the observed clusters with the randomization distribution -if needpos, +if needpos posclusters = []; stat = zeros(1,Nobspos); for j = 1:Nobspos - if strcmp(cfg.clusterstatistic, 'max'), + if strcmp(cfg.clusterstatistic, 'max') stat(j) = max(statobs(posclusobs==j)); - elseif strcmp(cfg.clusterstatistic, 'maxsize'), + elseif strcmp(cfg.clusterstatistic, 'maxsize') stat(j) = length(find(posclusobs==j)); - elseif strcmp(cfg.clusterstatistic, 'maxsum'), + elseif strcmp(cfg.clusterstatistic, 'maxsum') stat(j) = sum(statobs(posclusobs==j)); - elseif strcmp(cfg.clusterstatistic, 'wcm'), + elseif strcmp(cfg.clusterstatistic, 'wcm') stat(j) = sum((statobs(posclusobs==j)-postailcritval).^cfg.wcm_weight); else - error('unknown clusterstatistic'); + ft_error('unknown clusterstatistic'); end end % sort the clusters based on their statistical value @@ -440,16 +445,16 @@ negclusters = []; stat = zeros(1,Nobsneg); for j = 1:Nobsneg - if strcmp(cfg.clusterstatistic, 'max'), + if strcmp(cfg.clusterstatistic, 'max') stat(j) = min(statobs(negclusobs==j)); - elseif strcmp(cfg.clusterstatistic, 'maxsize'), + elseif strcmp(cfg.clusterstatistic, 'maxsize') stat(j) = -length(find(negclusobs==j)); % encode the size of a negative cluster as a negative value - elseif strcmp(cfg.clusterstatistic, 'maxsum'), + elseif strcmp(cfg.clusterstatistic, 'maxsum') stat(j) = sum(statobs(negclusobs==j)); - elseif strcmp(cfg.clusterstatistic, 'wcm'), + elseif strcmp(cfg.clusterstatistic, 'wcm') stat(j) = -sum((abs(statobs(negclusobs==j)-negtailcritval)).^cfg.wcm_weight); % encoded as a negative value else - error('unknown clusterstatistic'); + ft_error('unknown clusterstatistic'); end end % sort the clusters based on their statistical value @@ -526,12 +531,12 @@ % collect the remaining details in the output structure stat = struct(); % see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2972 stat.prob = prob; -if needpos, +if needpos stat.posclusters = posclusters; stat.posclusterslabelmat = posclusobs; stat.posdistribution = posdistribution; end -if needneg, +if needneg stat.negclusters = negclusters; stat.negclusterslabelmat = negclusobs; stat.negdistribution = negdistribution; diff --git a/external/fieldtrip/private/convert_event.m b/external/fieldtrip/private/convert_event.m index a7bce4b6..13ebf952 100644 --- a/external/fieldtrip/private/convert_event.m +++ b/external/fieldtrip/private/convert_event.m @@ -46,7 +46,7 @@ % Check if target is specified correctly if sum(strcmp(target, {'event', 'trl', 'artifact', 'boolvec'})) < 1 - error('target has to be ''event'', ''trl'', ''artifact'', or ''boolvec''.') + ft_error('target has to be ''event'', ''trl'', ''artifact'', or ''boolvec''.') end % Get the options @@ -74,7 +74,7 @@ end end else - error('incorrect input object, see help for what is allowed.') + ft_error('incorrect input object, see help for what is allowed.') end elseif islogical(obj) input_obj = 'boolvec'; @@ -94,7 +94,7 @@ obj = obj(:,1:3); end else - error('incorrect input object, see help for what is allowed.') + ft_error('incorrect input object, see help for what is allowed.') end % do conversion @@ -136,7 +136,7 @@ elseif strcmp(input_obj, 'empty') obj = []; else - warning('conversion not supported yet') %FIXME + ft_warning('conversion not supported yet') %FIXME end @@ -153,23 +153,23 @@ if length(varargin) == 1 if ~iscell(artifact) % assume only one artifact is given if isempty(artifact) - error('When input object is empty ''endsample'' must be specified to convert into boolvec') + ft_error('When input object is empty ''endsample'' must be specified to convert into boolvec') else endsample = max(artifact(:,2)); end elseif length(artifact) == 1 if isempty(artifact{1}) - error('When input object is empty ''endsample'' must be specified to convert into boolvec') + ft_error('When input object is empty ''endsample'' must be specified to convert into boolvec') else endsample = max(artifact{1}(:,2)); end else - error('when giving multiple artifact definitions, endsample should be specified to assure all output vectors are of the same length') + ft_error('when giving multiple artifact definitions, endsample should be specified to assure all output vectors are of the same length') end elseif length(varargin) == 2 endsample = varargin{2}; elseif length(varargin) > 2 - error('too many input arguments') + ft_error('too many input arguments') end if ~iscell(artifact) artifact = {artifact}; @@ -183,10 +183,10 @@ artbegsample = artifact{i}(j,1); artendsample = artifact{i}(j,2); if artbegsample > endsample - warning('artifact definition contains later samples than endsample, these samples are ignored') + ft_warning('artifact definition contains later samples than endsample, these samples are ignored') break elseif artendsample > endsample - warning('artifact definition contains later samples than endsample, these samples are ignored') + ft_warning('artifact definition contains later samples than endsample, these samples are ignored') artendsample = endsample; breakflag = 1; end @@ -227,7 +227,7 @@ if ~isempty(typenames) if length(artifact) ~= length(typenames) - error('length typenames should be the same as length artifact') + ft_error('length typenames should be the same as length artifact') end end diff --git a/external/fieldtrip/private/coordsys2label.m b/external/fieldtrip/private/coordsys2label.m new file mode 100644 index 00000000..de55e2ed --- /dev/null +++ b/external/fieldtrip/private/coordsys2label.m @@ -0,0 +1,169 @@ +function [labelx, labely, labelz] = coordsys2label(coordsys, format, both) + +% COORDSYS2LABEL returns the labels for the three axes, given the symbolic +% string representation of the coordinate system. +% +% Use as +% [labelx, labely, labelz] = coordsys2label(coordsys, format, both) +% +% The scalar argument 'format' results in return values like these +% 1) 'right' +% 2) 'the right' +% 3) '+X (right)' +% +% The boolean argument 'both' results in return values like these +% 0) 'right' i.e. only the direction that it is pointing to +% 1) {'left' 'right'} i.e. both the directions that it is pointing from and to +% +% See also FT_DETERMINE_COORDSYS, FT_PLOT_AXES, FT_HEADCOORDINATES, SETVIEWPOINT + +% Copyright (C) 2017, Robert Oostenveld +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + + +% FIXME this function could also rerturn a label for the origin +% see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=3304 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +if ~isempty(coordsys) && ~strcmp(coordsys, 'unknown') + + % the coordsys consists of three letters for the direction of the positive axes + % or of a string that relates to external software, an atlas or a template + if length(coordsys)==3 && length(intersect(coordsys, 'rlasif'))==3 + axis = 'XYZ'; + label = cell(1,3); + for i=1:3 + switch coordsys(i) + case 'l' + label{i} = {['-' axis(i) ' (right)'], ['+' axis(i) ' (left)']}; + case 'r' + label{i} = {['-' axis(i) ' (left)'], ['+' axis(i) ' (right)']}; + case 'i' + label{i} = {['-' axis(i) ' (superior)'], ['+' axis(i) ' (inferior)']}; + case 's' + label{i} = {['-' axis(i) ' (inferior)'], ['+' axis(i) ' (superior)']}; + case 'a' + label{i} = {['-' axis(i) ' (posterior)'], ['+' axis(i) ' (anterior)']}; + case 'p' + label{i} = {['-' axis(i) ' (anterior)'], ['+' axis(i) ' (posterior)']}; + otherwise + ft_error('incorrect letter in the coordsys'); + end % switch + end % for each of the three axes + + labelx = label{1}; + labely = label{2}; + labelz = label{3}; + + else + switch lower(coordsys) + case {'ras' 'itab' 'neuromag' 'acpc' 'spm' 'mni' 'tal'} + labelx = {'-X (left)' '+X (right)' }; + labely = {'-Y (posterior)' '+Y (anterior)'}; + labelz = {'-Z (inferior)' '+Z (superior)'}; + case {'als' 'ctf' '4d' 'bti'} + labelx = {'-X (posterior)' '+X (anterior)'}; + labely = {'-Y (right)' '+Y (left)'}; + labelz = {'-Z (inferior)' '+Z (superior)'}; + case {'rsp' 'paxinos'} + labelx = {'-X (left)' '+X (right)'}; + labely = {'-Y (inferior)' '+Y (superior)'}; + labelz = {'-Z (anterior)' '+Z (posterior)'}; + case {'lps'} + labelx = {'-X (right)' '+X (left)'}; + labely = {'-Y (anterior)' '+Y (posterior)'}; + labelz = {'-Z (inferior)' '+Z (superior)'}; + otherwise + % the coordinate system is unknown + ft_warning('unknown coordsys ''%s''', coordsys); + labelx = {'-X (unknown)' '+X (unknown)'}; + labely = {'-Y (unknown)' '+Y (unknown)'}; + labelz = {'-Z (unknown)' '+Z (unknown)'}; + end + + end % if it matches with 'rlasif' + +else + % the coordinate system is not specified + labelx = {'-X (unknown)' '+X (unknown)'}; + labely = {'-Y (unknown)' '+Y (unknown)'}; + labelz = {'-Z (unknown)' '+Z (unknown)'}; +end + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +switch format + case 1 + % remove the -, +, X, Y, Z , (, ) and space + labelx{1} = trim(labelx{1}); + labelx{2} = trim(labelx{2}); + labely{1} = trim(labely{1}); + labely{2} = trim(labely{2}); + labelz{1} = trim(labelz{1}); + labelz{2} = trim(labelz{2}); + + case 2 + % remove the -, +, X, Y, Z , (, ) and space + labelx{1} = trim(labelx{1}); + labelx{2} = trim(labelx{2}); + labely{1} = trim(labely{1}); + labely{2} = trim(labely{2}); + labelz{1} = trim(labelz{1}); + labelz{2} = trim(labelz{2}); + % insert 'the' for left and right + if any(strcmp(labelx{1}, {'left', 'right'})), labelx{1} = ['the ' labelx{1}]; end + if any(strcmp(labelx{2}, {'left', 'right'})), labelx{2} = ['the ' labelx{2}]; end + if any(strcmp(labely{1}, {'left', 'right'})), labely{1} = ['the ' labely{1}]; end + if any(strcmp(labely{2}, {'left', 'right'})), labely{2} = ['the ' labely{2}]; end + if any(strcmp(labelz{1}, {'left', 'right'})), labelz{1} = ['the ' labelz{1}]; end + if any(strcmp(labelz{2}, {'left', 'right'})), labelz{2} = ['the ' labelz{2}]; end + + case 3 + % keep it as it is + + otherwise + ft_error('unsupported option') +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +switch both + case false + % only keep the direction that is it pointing towards + labelx = labelx{2}; + labely = labely{2}; + labelz = labelz{2}; + case true + % keep it as it is + otherwise + ft_error('unsupported option') +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function str = trim(str) +str(str=='+') = []; +str(str=='-') = []; +str(str=='(') = []; +str(str==')') = []; +str(str=='X') = []; +str(str=='Y') = []; +str(str=='Z') = []; +str(str==' ') = []; diff --git a/external/fieldtrip/private/crosshair.m b/external/fieldtrip/private/crosshair.m deleted file mode 100644 index 53371ce7..00000000 --- a/external/fieldtrip/private/crosshair.m +++ /dev/null @@ -1,106 +0,0 @@ -function [h] = crosshair(pos, varargin) - -% CROSSHAIR adds a crosshair at position (x,y[,z]) to the current axes -% additional options are passed to the builtin line function -% the handles of the lines are returned -% -% h = crosshair([x,y]) or crosshair([x,y,z]) -% -% You can specify the handle to the axes in which to plot the crosshair -% with: h = crosshair(pos, 'parent', hparent), where hparent is an -% axes-handle. -% -% see also: LINE, TEXT - -% Undocumented you can specify the handles of existing line objects which -% will be then updated, rather than creating a new set of lines, with: -% h=crosshair(pos, 'handle', h), where h is a set of line handles -% (either 2 or 3 depending on whether pos has 2 or three elements. If both -% parent and handles ar specified, the handles prevail. - -% Copyright (C) 2003, Robert Oostenveld -% -% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org -% for the documentation and details. -% -% FieldTrip is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. -% -% FieldTrip is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with FieldTrip. If not, see . -% -% $Id$ - -parent = ft_getopt(varargin, 'parent'); -h = ft_getopt(varargin, 'handle'); -if ~isempty(h) - % make the parent to the first handle current axes - set(gcf,'currentaxes',get(h(1),'parent')); -elseif ~isempty(parent) - % make parent current axes - set(gcf,'currentaxes',parent); -end -border = [get(gca, 'xlim') get(gca, 'ylim') get(gca, 'zlim')]; - -if numel(pos)==2 - x = [ border(1) pos(1) - border(2) pos(1) ]; - - y = [ pos(2) border(3) - pos(2) border(4) ]; - - if isempty(h) && (~ishold) - hold on - h = line(x, y, varargin{:}); - hold off - elseif isempty(h) - h = line(x, y, varargin{:}); - else - set(h(1),'xdata',x(:,1)'); - set(h(1),'ydata',y(:,1)'); - set(h(2),'xdata',x(:,2)'); - set(h(2),'ydata',y(:,2)'); - end - - % make both lines the same color - set(h(2), 'Color', get(h(1), 'Color')); -elseif numel(pos)==3 - - x = [ border(1) pos(1) pos(1) - border(2) pos(1) pos(1)]; - - y = [ pos(2) border(3) pos(2) - pos(2) border(4) pos(2)]; - - z = [ pos(3) pos(3) border(5) - pos(3) pos(3) border(6)]; - - if isempty(h) && (~ishold) - hold on - h = line(x, y, z, varargin{:}); - hold off - elseif isempty(h) - h = line(x, y, z, varargin{:}); - else - set(h(1),'xdata',x(:,1)'); - set(h(1),'ydata',y(:,1)'); - set(h(1),'zdata',z(:,1)'); - set(h(2),'xdata',x(:,2)'); - set(h(2),'ydata',y(:,2)'); - set(h(2),'zdata',z(:,2)'); - set(h(3),'xdata',x(:,3)'); - set(h(3),'ydata',y(:,3)'); - set(h(3),'zdata',z(:,3)'); - end - - % make all lines the same color - set(h(2), 'Color', get(h(1), 'Color')); - set(h(3), 'Color', get(h(1), 'Color')); -end diff --git a/external/fieldtrip/private/ctf2grad.m b/external/fieldtrip/private/ctf2grad.m index 52be35c6..30c48ea6 100644 --- a/external/fieldtrip/private/ctf2grad.m +++ b/external/fieldtrip/private/ctf2grad.m @@ -1,11 +1,11 @@ -function [grad] = ctf2grad(hdr, dewar, coilaccuracy) +function [grad, elec] = ctf2grad(hdr, dewar, coilaccuracy) % CTF2GRAD converts a CTF header to a gradiometer structure that can be understood by % the FieldTrip low-level forward and inverse routines. The fieldtrip/fileio % read_header function can use three different implementations of the low-level code % for CTF data. Each of these implementations is dealt with here. % -% Use as +% Use as % grad = ctf2grad(hdr, dewar, coilaccuracy) % where % dewar = boolean, whether to return it in dewar or head coordinates (default is head coordinates) @@ -14,7 +14,7 @@ % See also BTI2GRAD, FIF2GRAD, MNE2GRAD, ITAB2GRAD, YOKOGAWA2GRAD, % FT_READ_SENS, FT_READ_HEADER -% Copyright (C) 2004-2016, Robert Oostenveld +% Copyright (C) 2004-2017, Robert Oostenveld % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -41,19 +41,22 @@ if nargin<3 || isempty(coilaccuracy) % if empty it will use the original code % otherwise it will use the specified accuracy coil definition from the MNE coil_def.dat - coilaccuracy = []; + coilaccuracy = []; end if isfield(hdr, 'orig') hdr = hdr.orig; % use the original CTF header, not the FieldTrip header end -% start with empty gradiometer +% start with empty gradiometer structure grad = []; grad.coilpos = []; grad.coilori = []; grad.tra = []; +% start with empty electrode structure +elec = []; + % meg channels are 5, refmag 0, refgrad 1, ADCs 18 % UPPT001 is 11 % UTRG001 is 11 @@ -69,7 +72,7 @@ if ~isempty(coilaccuracy) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % use the coil definitions from the MNE coil_def.dat file - % these allow for varying accuracy which is specified by + % these allow for varying accuracy which is specified by % coilaccuracy = 0, 1 or 2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -80,11 +83,11 @@ k = 1; for i=1:length(hdr.res4.senres) switch hdr.res4.senres(i).sensorTypeIndex - case 5; % 5001 + case 5 % 5001 thisdef = def([def.id]==5001 & [def.accuracy]==coilaccuracy); - case 0; % 5002 + case 0 % 5002 thisdef = def([def.id]==5002 & [def.accuracy]==coilaccuracy); - case 1; % 5003 + case 1 % 5003 thisdef = def([def.id]==5003 & [def.accuracy]==coilaccuracy); otherwise % do not add this as sensor to the gradiometer definition @@ -171,10 +174,13 @@ sensType = [hdr.res4.senres.sensorTypeIndex]; selMEG = find(sensType==5); selREF = find(sensType==0 | sensType==1); + selEEG = find(sensType==9); selMEG = selMEG(:)'; selREF = selREF(:)'; + selEEG = selEEG(:)'; numMEG = length(selMEG); numREF = length(selREF); + numEEG = length(selEEG); % determine the number of channels and coils coilcount = 0; @@ -186,6 +192,26 @@ grad.coilori = zeros(coilcount, 3); % this will hold the orientation of each coil grad.tra = zeros(chancount, coilcount); % this describes how each coil contributes to each channel + if numEEG>0 + for i=1:numEEG + n = selEEG(i); + if dewar + pos = hdr.res4.senres(n).pos0'; + else + pos = hdr.res4.senres(n).pos'; + end + if hdr.res4.senres(n).numCoils~=1 + ft_error('unexpected number of electrode positions in EEG channel'); + end + % add this position + elec.elecpos(i ,:) = pos(1,:); + end + % add the electrode names + elec.label = cellstr(hdr.res4.chanNames(selEEG,:)); + else + elec = []; + end + % combine the bottom and top coil of each MEG channel for i=1:numMEG n = selMEG(i); @@ -198,7 +224,7 @@ ori = hdr.res4.senres(n).ori'; end if hdr.res4.senres(n).numCoils~=2 - error('unexpected number of coils in MEG channel'); + ft_error('unexpected number of coils in MEG channel'); end % add the coils of this channel to the gradiometer array grad.coilpos(i ,:) = pos(1,:); @@ -257,7 +283,7 @@ reflabel = label(hdr.BalanceCoefs.G1BR.Refindex); nmeg = length(meglabel); nref = length(reflabel); - montage.labelorg = cat(1, meglabel, reflabel); + montage.labelold = cat(1, meglabel, reflabel); montage.labelnew = cat(1, meglabel, reflabel); montage.tra = [eye(nmeg, nmeg), -hdr.BalanceCoefs.G1BR.alphaMEG'; zeros(nref, nmeg), eye(nref, nref)]; grad.balance.G1BR = montage; @@ -268,7 +294,7 @@ reflabel = label(hdr.BalanceCoefs.G2BR.Refindex); nmeg = length(meglabel); nref = length(reflabel); - montage.labelorg = cat(1, meglabel, reflabel); + montage.labelold = cat(1, meglabel, reflabel); montage.labelnew = cat(1, meglabel, reflabel); montage.tra = [eye(nmeg, nmeg), -hdr.BalanceCoefs.G2BR.alphaMEG'; zeros(nref, nmeg), eye(nref, nref)]; grad.balance.G2BR = montage; @@ -279,7 +305,7 @@ reflabel = label(hdr.BalanceCoefs.G3BR.Refindex); nmeg = length(meglabel); nref = length(reflabel); - montage.labelorg = cat(1, meglabel, reflabel); + montage.labelold = cat(1, meglabel, reflabel); montage.labelnew = cat(1, meglabel, reflabel); montage.tra = [eye(nmeg, nmeg), -hdr.BalanceCoefs.G3BR.alphaMEG'; zeros(nref, nmeg), eye(nref, nref)]; grad.balance.G3BR = montage; @@ -290,7 +316,7 @@ reflabel = label(hdr.BalanceCoefs.G3AR.Refindex); nmeg = length(meglabel); nref = length(reflabel); - montage.labelorg = cat(1, meglabel, reflabel); + montage.labelold = cat(1, meglabel, reflabel); montage.labelnew = cat(1, meglabel, reflabel); montage.tra = [eye(nmeg, nmeg), -hdr.BalanceCoefs.G3AR.alphaMEG'; zeros(nref, nmeg), eye(nref, nref)]; grad.balance.G3AR = montage; @@ -307,7 +333,7 @@ elseif all([hdr.res4.senres(selMEG).grad_order_no]==13) grad.balance.current = 'G3AR'; else - warning('cannot determine balancing of CTF gradiometers'); + ft_warning('cannot determine balancing of CTF gradiometers'); grad = rmfield(grad, 'balance'); end @@ -345,7 +371,7 @@ % determine the number of coils for this channel numcoils = sum(sum(pos.^2, 2)~=0); if numcoils~=2 - error('unexpected number of coils in MEG channel'); + ft_error('unexpected number of coils in MEG channel'); end % add the coils of this channel to the gradiometer array grad.coilpos(i ,:) = pos(1,:); @@ -394,7 +420,7 @@ if dewar % this does not work for Daren Webers implementation - error('cannot return the gradiometer definition in dewar coordinates'); + ft_error('cannot return the gradiometer definition in dewar coordinates'); end % only work on the MEG channels @@ -416,7 +442,7 @@ % assume that the orientation of the upper coil is opposite to the lower coil ori = [ori; -ori]; else - error('do not know how to deal with higher order gradiometer hardware') + ft_error('do not know how to deal with higher order gradiometer hardware') end % add this channels coil positions and orientations @@ -434,14 +460,14 @@ grad.tra(i,end+1) = 1; grad.tra(i,end+1) = 1; else - error('do not know how to deal with higher order gradiometer hardware') + ft_error('do not know how to deal with higher order gradiometer hardware') end end % prefer to have the labels in a column vector grad.label = grad.label(:); grad.unit = 'cm'; % the res4 file represents it in centimeter - + % reorder the coils, such that the bottom coils are at the first N % locations and the top coils at the last N positions. This makes it % easier to use a selection of the coils for topographic plotting @@ -454,5 +480,5 @@ end else - error('unknown header to contruct gradiometer definition'); + ft_error('unknown header to contruct gradiometer definition'); end diff --git a/external/fieldtrip/private/dataset2files.m b/external/fieldtrip/private/dataset2files.m index 5c321e49..cf88647a 100644 --- a/external/fieldtrip/private/dataset2files.m +++ b/external/fieldtrip/private/dataset2files.m @@ -46,7 +46,7 @@ if d==0 [f, p] = uigetfile; if f==0 - error('You should select a dataset file or directory'); + ft_error('You should select a dataset file or directory'); else d = fullfile(p, f); end diff --git a/external/fieldtrip/private/defaultId.m b/external/fieldtrip/private/defaultId.m new file mode 100644 index 00000000..f4e1ee99 --- /dev/null +++ b/external/fieldtrip/private/defaultId.m @@ -0,0 +1,57 @@ +function id = defaultId + +% DEFAULTID returns a string that can serve as warning or error identifier, +% for example 'FieldTip:ft_read_header:line345'. +% +% See also WARNING, ERROR, FT_NOTICE, FT_INFO, FT_DEBUG + +% Copyright (C) 2017, Robert Oostenveld +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +stack = dbstack('-completenames'); + +% remove the functions that pertain to the notification system itself +keep = true(size(stack)); +keep(strcmp({stack.name}, 'defaultId')) = false; % this function itself +keep(strcmp({stack.name}, 'ft_notification')) = false; % this one is doing the work underneath ft_error/ft_warning/ft_notice/etc. +keep(strcmp({stack.name}, 'ft_error')) = false; +keep(strcmp({stack.name}, 'ft_warning')) = false; +keep(strcmp({stack.name}, 'ft_notice')) = false; +keep(strcmp({stack.name}, 'ft_info')) = false; +keep(strcmp({stack.name}, 'ft_debug')) = false; +stack = stack(keep); + +% remove the non-FieldTrip functions from the path, these should not be part of the default message identifier +keep = true(size(stack)); +[v, p] = ft_version; +for i=1:numel(stack) + keep(i) = strncmp(p, stack(i).file, length(p)); +end +stack = stack(keep); + +if ~isempty(stack) + % it is called from within a function + stack = flipud(stack); + name = {stack.name}; + id = ['FieldTrip' sprintf(':%s', name{:}) ':line' num2str(stack(end).line)]; +else + % it is called from the command line + id = 'FieldTrip:commandline'; +end diff --git a/external/fieldtrip/private/dftfilter.m b/external/fieldtrip/private/dftfilter.m index aa8088d2..415cc443 100644 --- a/external/fieldtrip/private/dftfilter.m +++ b/external/fieldtrip/private/dftfilter.m @@ -39,7 +39,7 @@ % % $Id$ -if nargin<3 | isempty(Fl) +if nargin<3 || isempty(Fl) Fl = 50; end @@ -51,7 +51,7 @@ % fit a sin and cos to the signal and subtract them time = (0:Nsamples-1)/Fs; -tmp = exp(j*2*pi*Fl*time); % complex sin and cos +tmp = exp(1i*2*pi*Fl*time); % complex sin and cos % ampl = 2*dat*tmp'/Nsamples; % estimated amplitude of complex sin and cos ampl = 2*dat(:,sel)*tmp(sel)'/length(sel); % estimated amplitude of complex sin and cos on integer number of cycles est = ampl*tmp; % estimated signal at this frequency diff --git a/external/fieldtrip/private/dimassign.m b/external/fieldtrip/private/dimassign.m index a26b411d..7309e583 100644 --- a/external/fieldtrip/private/dimassign.m +++ b/external/fieldtrip/private/dimassign.m @@ -38,23 +38,23 @@ if(~iscell(idx)) if(~any(size(dim)==1)||~any(size(idx)==1)||ndims(dim)>2||ndims(idx)>2||... length(dim)~=length(idx)) - error('dim and idx must be both scalars oor both must have the same length'); - end; + ft_error('dim and idx must be both scalars oor both must have the same length'); + end dummi=[]; for(i=1:length(idx)) dummi{i}=idx(i); - end; + end idx=dummi; clear dummi; -end; +end if(~any(size(dim)==1)||~any(size(idx)==1)||ndims(dim)>2||ndims(idx)>2||... length(dim)~=length(idx)) - error('dim and idx must be both scalars or both must have the same length'); -end; + ft_error('dim and idx must be both scalars or both must have the same length'); +end if(~isequal(unique(dim),sort(dim))) - error('dim must be unique, every dimention can be addressed only once'); -end; + ft_error('dim must be unique, every dimention can be addressed only once'); +end Na=ndims(A); for(i=1:max([max(dim),Na])) @@ -63,11 +63,11 @@ C{i}=':'; else C{i}=idx{ref}; - end; -end; + end +end M=A; try M(C{:})=B; catch - error('Subscripted assignment dimension mismatch.'); -end; + ft_error('Subscripted assignment dimension mismatch.'); +end diff --git a/external/fieldtrip/private/dimindex.m b/external/fieldtrip/private/dimindex.m index 4934c03b..c3ebda52 100644 --- a/external/fieldtrip/private/dimindex.m +++ b/external/fieldtrip/private/dimindex.m @@ -36,7 +36,7 @@ if (~iscell(idx)) if (~any(size(dim)==1) || ~any(size(idx)==1) || ndims(dim)>2 || ndims(idx)>2 || length(dim)~=length(idx)) - error('dim and idx must be both scalars or both vectors of the same size'); + ft_error('dim and idx must be both scalars or both vectors of the same size'); end dummi = []; for i=1:length(idx) @@ -46,15 +46,15 @@ clear dummi; end if (~any(size(dim)==1) || ~any(size(idx)==1) || ndims(dim)>2 || ndims(idx)>2 || length(dim)~=length(idx)) - error('dim and idx must be both scalars or both must have the same length'); + ft_error('dim and idx must be both scalars or both must have the same length'); end if (length(dim)>ndims(A)||any(dim>ndims(A))) - error('dim, or one of its contents are larger than the number of dimentions in A'); + ft_error('dim, or one of its contents are larger than the number of dimentions in A'); end if (~isequal(unique(dim),sort(dim))) - error('dim must be unique, every dimention can be addressed only once'); + ft_error('dim must be unique, every dimention can be addressed only once'); end N = ndims(A); diff --git a/external/fieldtrip/private/dimlength.m b/external/fieldtrip/private/dimlength.m index 4f207f3c..f318db55 100644 --- a/external/fieldtrip/private/dimlength.m +++ b/external/fieldtrip/private/dimlength.m @@ -122,7 +122,7 @@ if isfield(data, 'individual'), n = [n size(data.individual, 1)]; end if isfield(data, 'stat'), n = [n size(data.stat, 1)]; end if ~all(n==n(1)) - error('inconsistent number of repetitions for dim "%s"', seldim); + ft_error('inconsistent number of repetitions for dim "%s"', seldim); end n = n(1); @@ -156,7 +156,7 @@ if isfield(data, 'trial'), n = [n size(data.trial, 1)]; end if isfield(data, 'fourierspctrm'), n = [n size(data.fourierspctrm, 1)]; end if ~all(n==n(1)) - error('inconsistent number of repetitions for dim "%s"', seldim); + ft_error('inconsistent number of repetitions for dim "%s"', seldim); end n = n(1); @@ -175,7 +175,7 @@ if isfield(data, 'powspctrm'), n = [n size(data.powspctrm, 1)]; end if isfield(data, 'trial'), n = [n size(data.trial, 1)]; end - if ~all(n==n(1)), error('inconsistent number of repetitions for dim "%s"', seldim); end + if ~all(n==n(1)), ft_error('inconsistent number of repetitions for dim "%s"', seldim); end n = n(1); case 'chan' @@ -225,7 +225,7 @@ end otherwise - error('unsupported dim "%s"', seldim); + ft_error('unsupported dim "%s"', seldim); end end % if nargin diff --git a/external/fieldtrip/private/elec1020_follow.m b/external/fieldtrip/private/elec1020_follow.m new file mode 100644 index 00000000..b2574baf --- /dev/null +++ b/external/fieldtrip/private/elec1020_follow.m @@ -0,0 +1,224 @@ +function [cnt1, cnt2] = elec1020_follow(pnt, dhk, v1, v2, v3, feedback) + +% ELEC1020_FOLLOW + +% Copyright (C) 2003, Robert Oostenveld +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . + +if nargin<6 + feedback = false; +end + +% compute the distribution of edge lengths +edge = [ + pnt(dhk(:,1),:) - pnt(dhk(:,2),:) + pnt(dhk(:,2),:) - pnt(dhk(:,3),:) + pnt(dhk(:,3),:) - pnt(dhk(:,1),:) + ]; +edgelength = sqrt(sum(edge.^2,2)); + +% the tolerance depends on the edge length +tolerance = min(edgelength)*1e-6; +tolerance_limit = min(edgelength)*1e-3; + +npnt = size(pnt,1); +ndhk = size(dhk,1); + +pside = nan(1,npnt); +for i=1:npnt + % determine on which side of the plane each vertex lies + pside(i) = ptriside(v1, v2, v3, pnt(i,:), tolerance); +end + +% dcut = zeros(ndhk,1); +% for i=1:ndhk +% % find the triangles that are intersected by the plane +% if sum(pside(dhk(i,:))==0)==2 +% dcut(i) = 1; +% elseif sum(pside(dhk(i,:))==0)==1 & sum(pside(dhk(i,:))==1)==1 & sum(pside(dhk(i,:))==-1)==1 +% dcut(i) = 1; +% elseif sum(pside(dhk(i,:))==1)==2 & sum(pside(dhk(i,:))==-1)==1 +% dcut(i) = 1; +% elseif sum(pside(dhk(i,:))==1)==1 & sum(pside(dhk(i,:))==-1)==2 +% dcut(i) = 1; +% end +% end +tmp = pside(dhk); +dcut = true(ndhk,1); +dcut(all(tmp== 1,2)) = false; +dcut(all(tmp==-1,2)) = false; + +% continue working with only the intersecting triangles +dhk = dhk(dcut,:); +ndhk = size(dhk,1); + +% for each triangle determine the neighbouring triangles +neighb = zeros(ndhk,ndhk); +for i=1:ndhk + for j=(i+1):ndhk + if dhk(i,1)==dhk(j,1) + neighb(i,j) = 1; + elseif dhk(i,1)==dhk(j,2) + neighb(i,j) = 1; + elseif dhk(i,1)==dhk(j,3) + neighb(i,j) = 1; + elseif dhk(i,2)==dhk(j,1) + neighb(i,j) = 1; + elseif dhk(i,2)==dhk(j,2) + neighb(i,j) = 1; + elseif dhk(i,2)==dhk(j,3) + neighb(i,j) = 1; + elseif dhk(i,3)==dhk(j,1) + neighb(i,j) = 1; + elseif dhk(i,3)==dhk(j,2) + neighb(i,j) = 1; + elseif dhk(i,3)==dhk(j,3) + neighb(i,j) = 1; + else + neighb(i,j) = 0; + end + neighb(j,i) = neighb(i,j); + end +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% make a contour from v1 via v2 to v3 + +% find the nearest triangle on which point v1 projects +v1_dist = inf; +for i=1:ndhk + % shift a fraction towards v2 to avoid starting in the vertex of a wrong triangle + [proj, dist] = ptriproj(pnt(dhk(i,1),:), pnt(dhk(i,2),:), pnt(dhk(i,3),:), v1+tolerance*(v2-v1)/norm(v2-v1), 1); + if distncnt) + tolerance = 2*tolerance; + if tolerance>=tolerance_limit + ft_warning('premature end of contour') + break + else + ft_warning('increasing tolerance'); + end + end + + % stop if we arrive on the triangle with the endpoint + if pntdist(prev_proj, v3_proj). + +ncnt = size(cnt1,1); + +% determine the total length of the contour +tot_l = 0; +for i=1:ncnt + tot_l = tot_l + pntdist(cnt1(i,:), cnt2(i,:)); +end + +frac_l = fraction * tot_l; + +% propagate along the contour untill we get at the desired fraction +sum_l = 0; +for i=1:ncnt + seg_l = pntdist(cnt1(i,:), cnt2(i,:)); + if (sum_l+seg_l)>=frac_l + % the desired point lies on this segment + la = frac_l - sum_l; + vec = cnt2(i,:)-cnt1(i,:); + pnt = cnt1(i,:) + la * vec/norm(vec); + return + else + sum_l = sum_l + seg_l; + sum_f = sum_l/tot_l; + end +end + +pnt = [nan nan nan]; + diff --git a/external/fieldtrip/private/elec1020_intersect.m b/external/fieldtrip/private/elec1020_intersect.m new file mode 100644 index 00000000..ac7bd44c --- /dev/null +++ b/external/fieldtrip/private/elec1020_intersect.m @@ -0,0 +1,122 @@ +function [cnt1, cnt2] = elec1020_intersect(pnt, dhk, v1, v2, v3, flag); + +% ELEC1020_INTERSECT determines the intersection of a mesh with a plane + +% Copyright (C) 2003, Robert Oostenveld +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . + +% Copyright (C) 2002 Robert Oostenveld + +if nargin<6 + flag = 0; +end + +npnt = size(pnt, 1); +ndhk = size(dhk, 1); + +for i=1:npnt + % determine on which side of the plane each vertex lies + pside(i) = ptriside(v1, v2, v3, pnt(i,:)); +end + +for i=1:ndhk + % find the triangles that are intersected by the plane + dcut(i) = abs(sum(pside(dhk(i,:))))<2; +end + +% further computations will only be done on those selected triangles +sel = dhk(find(dcut),:); +nsel = length(find(dcut)); + +cnt1 = []; +cnt2 = []; +for i=1:nsel + [l1, l2] = tritrisect(v1, v2, v3, pnt(sel(i,1),:), pnt(sel(i,2),:), pnt(sel(i,3),:)); + cnt1 = [cnt1; l1]; + cnt2 = [cnt2; l2]; +end + +% determine which segments connect to each other +indx = 1; +for i=1:nsel + for j=setdiff(1:nsel, indx) + d1 = pntdist(cnt2(i,:), cnt1(j,:)); + d2 = pntdist(cnt2(i,:), cnt2(j,:)); + if d1. + +if nargin<7 + feedback = false; +end + + +% determine the approximate location of the vertex +ori = (lpa+rpa+nas+ini)/4; % center of head +ver = cross(rpa-lpa, nas-ini); % orientation +ver = ver /sqrt(norm(ver)); % make correct length +ver = ori + 0.7*ver; % location from center of head + +if feedback + figure + ft_plot_mesh(struct('pos', pnt, 'tri', dhk), 'edgecolor', 'none', 'facecolor', 'skin') + alpha 0.5 + ft_plot_mesh(nas, 'vertexsize', 30) + ft_plot_mesh(lpa, 'vertexsize', 30) + ft_plot_mesh(ini, 'vertexsize', 30) + ft_plot_mesh(rpa, 'vertexsize', 30) + ft_plot_mesh(ver, 'vertexsize', 30) + axis equal + axis vis3d + grid on + hold on +end + + +% point near LPA that is at 50% of left lower contour +[cnt1, cnt2] = elec1020_follow(pnt, dhk, nas, lpa, ini, feedback); +mle = elec1020_fraction(cnt1, cnt2, 0.5); + +% point near RPA that is at 50% of right lower contour +[cnt1, cnt2] = elec1020_follow(pnt, dhk, nas, rpa, ini, feedback); +mre = elec1020_fraction(cnt1, cnt2, 0.5); + +% determine two points that approximate the vertex +[cnt1, cnt2] = elec1020_follow(pnt, dhk, nas, ver, ini, feedback); +ver1 = elec1020_fraction(cnt1, cnt2, 0.5); +[cnt1, cnt2] = elec1020_follow(pnt, dhk, mle, ver, mre, feedback); +ver2 = elec1020_fraction(cnt1, cnt2, 0.5); + +% refined estimate is the average of these two +ver = (ver1+ver2)/2; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% start contouring +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% ant-post contour through vertex +fprintf('constructing vertical ant-post contour\n'); +[cnt1, cnt2] = elec1020_follow(pnt, dhk, nas, ver, ini, feedback); +Nz = elec1020_fraction(cnt1, cnt2, 0/20); +NFpz = elec1020_fraction(cnt1, cnt2, 1/20); +Fpz = elec1020_fraction(cnt1, cnt2, 2/20); +AFpz = elec1020_fraction(cnt1, cnt2, 3/20); +AFz = elec1020_fraction(cnt1, cnt2, 4/20); +AFFz = elec1020_fraction(cnt1, cnt2, 5/20); +Fz = elec1020_fraction(cnt1, cnt2, 6/20); +FFCz = elec1020_fraction(cnt1, cnt2, 7/20); +FCz = elec1020_fraction(cnt1, cnt2, 8/20); +FCCz = elec1020_fraction(cnt1, cnt2, 9/20); +Cz = elec1020_fraction(cnt1, cnt2, 10/20); +CCPz = elec1020_fraction(cnt1, cnt2, 11/20); +CPz = elec1020_fraction(cnt1, cnt2, 12/20); +CPPz = elec1020_fraction(cnt1, cnt2, 13/20); +Pz = elec1020_fraction(cnt1, cnt2, 14/20); +PPOz = elec1020_fraction(cnt1, cnt2, 15/20); +POz = elec1020_fraction(cnt1, cnt2, 16/20); +POOz = elec1020_fraction(cnt1, cnt2, 17/20); +Oz = elec1020_fraction(cnt1, cnt2, 18/20); +OIz = elec1020_fraction(cnt1, cnt2, 19/20); +Iz = elec1020_fraction(cnt1, cnt2, 20/20); + +% left-right through vertex +fprintf('constructing C contour\n'); +[cnt1, cnt2] = elec1020_follow(pnt, dhk, mle, ver, mre, feedback); +T9 = elec1020_fraction(cnt1, cnt2, 0/20); +T9h = elec1020_fraction(cnt1, cnt2, 1/20); +T7 = elec1020_fraction(cnt1, cnt2, 2/20); +T7h = elec1020_fraction(cnt1, cnt2, 3/20); +C5 = elec1020_fraction(cnt1, cnt2, 4/20); +C5h = elec1020_fraction(cnt1, cnt2, 5/20); +C3 = elec1020_fraction(cnt1, cnt2, 6/20); +C3h = elec1020_fraction(cnt1, cnt2, 7/20); +C1 = elec1020_fraction(cnt1, cnt2, 8/20); +C1h = elec1020_fraction(cnt1, cnt2, 9/20); +Cz = elec1020_fraction(cnt1, cnt2, 10/20); +C2h = elec1020_fraction(cnt1, cnt2, 11/20); +C2 = elec1020_fraction(cnt1, cnt2, 12/20); +C4h = elec1020_fraction(cnt1, cnt2, 13/20); +C4 = elec1020_fraction(cnt1, cnt2, 14/20); +C6h = elec1020_fraction(cnt1, cnt2, 15/20); +C6 = elec1020_fraction(cnt1, cnt2, 16/20); +T8h = elec1020_fraction(cnt1, cnt2, 17/20); +T8 = elec1020_fraction(cnt1, cnt2, 18/20); +T10h = elec1020_fraction(cnt1, cnt2, 19/20); +T10 = elec1020_fraction(cnt1, cnt2, 20/20); + +% horizontal ant-post through T7 +fprintf('constructing horizontal left contour\n'); +[cnt1, cnt2] = elec1020_follow(pnt, dhk, Fpz, T7, Oz, feedback); +Fp1h = elec1020_fraction(cnt1, cnt2, 1/20); +Fp1 = elec1020_fraction(cnt1, cnt2, 2/20); +AFp7 = elec1020_fraction(cnt1, cnt2, 3/20); +AF7 = elec1020_fraction(cnt1, cnt2, 4/20); +AFF7 = elec1020_fraction(cnt1, cnt2, 5/20); +F7 = elec1020_fraction(cnt1, cnt2, 6/20); +FFT7 = elec1020_fraction(cnt1, cnt2, 7/20); +FT7 = elec1020_fraction(cnt1, cnt2, 8/20); +FTT7 = elec1020_fraction(cnt1, cnt2, 9/20); +T7 = elec1020_fraction(cnt1, cnt2, 10/20); +TTP7 = elec1020_fraction(cnt1, cnt2, 11/20); +TP7 = elec1020_fraction(cnt1, cnt2, 12/20); +TPP7 = elec1020_fraction(cnt1, cnt2, 13/20); +P7 = elec1020_fraction(cnt1, cnt2, 14/20); +PPO7 = elec1020_fraction(cnt1, cnt2, 15/20); +PO7 = elec1020_fraction(cnt1, cnt2, 16/20); +POO7 = elec1020_fraction(cnt1, cnt2, 17/20); +O1 = elec1020_fraction(cnt1, cnt2, 18/20); +O1h = elec1020_fraction(cnt1, cnt2, 19/20); + +% horizontal ant-post through T8 +fprintf('constructing horizontal right contour\n'); +[cnt1, cnt2] = elec1020_follow(pnt, dhk, Fpz, T8, Oz, feedback); +Fp2h = elec1020_fraction(cnt1, cnt2, 1/20); +Fp2 = elec1020_fraction(cnt1, cnt2, 2/20); +AFp8 = elec1020_fraction(cnt1, cnt2, 3/20); +AF8 = elec1020_fraction(cnt1, cnt2, 4/20); +AFF8 = elec1020_fraction(cnt1, cnt2, 5/20); +F8 = elec1020_fraction(cnt1, cnt2, 6/20); +FFT8 = elec1020_fraction(cnt1, cnt2, 7/20); +FT8 = elec1020_fraction(cnt1, cnt2, 8/20); +FTT8 = elec1020_fraction(cnt1, cnt2, 9/20); +T8 = elec1020_fraction(cnt1, cnt2, 10/20); +TTP8 = elec1020_fraction(cnt1, cnt2, 11/20); +TP8 = elec1020_fraction(cnt1, cnt2, 12/20); +TPP8 = elec1020_fraction(cnt1, cnt2, 13/20); +P8 = elec1020_fraction(cnt1, cnt2, 14/20); +PPO8 = elec1020_fraction(cnt1, cnt2, 15/20); +PO8 = elec1020_fraction(cnt1, cnt2, 16/20); +POO8 = elec1020_fraction(cnt1, cnt2, 17/20); +O2 = elec1020_fraction(cnt1, cnt2, 18/20); +O2h = elec1020_fraction(cnt1, cnt2, 19/20); + +fprintf('constructing AFp contour\n'); +[cnt1, cnt2] = elec1020_follow(pnt, dhk, AFp7, AFpz, AFp8, feedback); +AFp7h = elec1020_fraction(cnt1, cnt2, 1/16); +AFp5 = elec1020_fraction(cnt1, cnt2, 2/16); +AFp5h = elec1020_fraction(cnt1, cnt2, 3/16); +AFp3 = elec1020_fraction(cnt1, cnt2, 4/16); +AFp3h = elec1020_fraction(cnt1, cnt2, 5/16); +AFp1 = elec1020_fraction(cnt1, cnt2, 6/16); +AFp1h = elec1020_fraction(cnt1, cnt2, 7/16); +AFp2h = elec1020_fraction(cnt1, cnt2, 9/16); +AFp2 = elec1020_fraction(cnt1, cnt2, 10/16); +AFp4h = elec1020_fraction(cnt1, cnt2, 11/16); +AFp4 = elec1020_fraction(cnt1, cnt2, 12/16); +AFp6h = elec1020_fraction(cnt1, cnt2, 13/16); +AFp6 = elec1020_fraction(cnt1, cnt2, 14/16); +AFp8h = elec1020_fraction(cnt1, cnt2, 15/16); + +fprintf('constructing AF contour\n'); +[cnt1, cnt2] = elec1020_follow(pnt, dhk, AF7, AFz, AF8, feedback); +AF7h = elec1020_fraction(cnt1, cnt2, 1/16); +AF5 = elec1020_fraction(cnt1, cnt2, 2/16); +AF5h = elec1020_fraction(cnt1, cnt2, 3/16); +AF3 = elec1020_fraction(cnt1, cnt2, 4/16); +AF3h = elec1020_fraction(cnt1, cnt2, 5/16); +AF1 = elec1020_fraction(cnt1, cnt2, 6/16); +AF1h = elec1020_fraction(cnt1, cnt2, 7/16); +AF2h = elec1020_fraction(cnt1, cnt2, 9/16); +AF2 = elec1020_fraction(cnt1, cnt2, 10/16); +AF4h = elec1020_fraction(cnt1, cnt2, 11/16); +AF4 = elec1020_fraction(cnt1, cnt2, 12/16); +AF6h = elec1020_fraction(cnt1, cnt2, 13/16); +AF6 = elec1020_fraction(cnt1, cnt2, 14/16); +AF8h = elec1020_fraction(cnt1, cnt2, 15/16); + +fprintf('constructing AFF contour\n'); +[cnt1, cnt2] = elec1020_follow(pnt, dhk, AFF7, AFFz, AFF8, feedback); +AFF7h = elec1020_fraction(cnt1, cnt2, 1/16); +AFF5 = elec1020_fraction(cnt1, cnt2, 2/16); +AFF5h = elec1020_fraction(cnt1, cnt2, 3/16); +AFF3 = elec1020_fraction(cnt1, cnt2, 4/16); +AFF3h = elec1020_fraction(cnt1, cnt2, 5/16); +AFF1 = elec1020_fraction(cnt1, cnt2, 6/16); +AFF1h = elec1020_fraction(cnt1, cnt2, 7/16); +AFF2h = elec1020_fraction(cnt1, cnt2, 9/16); +AFF2 = elec1020_fraction(cnt1, cnt2, 10/16); +AFF4h = elec1020_fraction(cnt1, cnt2, 11/16); +AFF4 = elec1020_fraction(cnt1, cnt2, 12/16); +AFF6h = elec1020_fraction(cnt1, cnt2, 13/16); +AFF6 = elec1020_fraction(cnt1, cnt2, 14/16); +AFF8h = elec1020_fraction(cnt1, cnt2, 15/16); + +fprintf('constructing F contour\n'); +[cnt1, cnt2] = elec1020_follow(pnt, dhk, F7, Fz, F8, feedback); +F7h = elec1020_fraction(cnt1, cnt2, 1/16); +F5 = elec1020_fraction(cnt1, cnt2, 2/16); +F5h = elec1020_fraction(cnt1, cnt2, 3/16); +F3 = elec1020_fraction(cnt1, cnt2, 4/16); +F3h = elec1020_fraction(cnt1, cnt2, 5/16); +F1 = elec1020_fraction(cnt1, cnt2, 6/16); +F1h = elec1020_fraction(cnt1, cnt2, 7/16); +F2h = elec1020_fraction(cnt1, cnt2, 9/16); +F2 = elec1020_fraction(cnt1, cnt2, 10/16); +F4h = elec1020_fraction(cnt1, cnt2, 11/16); +F4 = elec1020_fraction(cnt1, cnt2, 12/16); +F6h = elec1020_fraction(cnt1, cnt2, 13/16); +F6 = elec1020_fraction(cnt1, cnt2, 14/16); +F8h = elec1020_fraction(cnt1, cnt2, 15/16); + +fprintf('constructing FFC contour\n'); +[cnt1, cnt2] = elec1020_follow(pnt, dhk, FFT7, FFCz, FFT8, feedback); +FFT7h = elec1020_fraction(cnt1, cnt2, 1/16); +FFC5 = elec1020_fraction(cnt1, cnt2, 2/16); +FFC5h = elec1020_fraction(cnt1, cnt2, 3/16); +FFC3 = elec1020_fraction(cnt1, cnt2, 4/16); +FFC3h = elec1020_fraction(cnt1, cnt2, 5/16); +FFC1 = elec1020_fraction(cnt1, cnt2, 6/16); +FFC1h = elec1020_fraction(cnt1, cnt2, 7/16); +FFC2h = elec1020_fraction(cnt1, cnt2, 9/16); +FFC2 = elec1020_fraction(cnt1, cnt2, 10/16); +FFC4h = elec1020_fraction(cnt1, cnt2, 11/16); +FFC4 = elec1020_fraction(cnt1, cnt2, 12/16); +FFC6h = elec1020_fraction(cnt1, cnt2, 13/16); +FFC6 = elec1020_fraction(cnt1, cnt2, 14/16); +FFT8h = elec1020_fraction(cnt1, cnt2, 15/16); + +fprintf('constructing FC contour\n'); +[cnt1, cnt2] = elec1020_follow(pnt, dhk, FT7, FCz, FT8, feedback); +FT7h = elec1020_fraction(cnt1, cnt2, 1/16); +FC5 = elec1020_fraction(cnt1, cnt2, 2/16); +FC5h = elec1020_fraction(cnt1, cnt2, 3/16); +FC3 = elec1020_fraction(cnt1, cnt2, 4/16); +FC3h = elec1020_fraction(cnt1, cnt2, 5/16); +FC1 = elec1020_fraction(cnt1, cnt2, 6/16); +FC1h = elec1020_fraction(cnt1, cnt2, 7/16); +FC2h = elec1020_fraction(cnt1, cnt2, 9/16); +FC2 = elec1020_fraction(cnt1, cnt2, 10/16); +FC4h = elec1020_fraction(cnt1, cnt2, 11/16); +FC4 = elec1020_fraction(cnt1, cnt2, 12/16); +FC6h = elec1020_fraction(cnt1, cnt2, 13/16); +FC6 = elec1020_fraction(cnt1, cnt2, 14/16); +FT8h = elec1020_fraction(cnt1, cnt2, 15/16); + +fprintf('constructing FCC contour\n'); +[cnt1, cnt2] = elec1020_follow(pnt, dhk, FTT7, FCCz, FTT8, feedback); +FTT7h = elec1020_fraction(cnt1, cnt2, 1/16); +FCC5 = elec1020_fraction(cnt1, cnt2, 2/16); +FCC5h = elec1020_fraction(cnt1, cnt2, 3/16); +FCC3 = elec1020_fraction(cnt1, cnt2, 4/16); +FCC3h = elec1020_fraction(cnt1, cnt2, 5/16); +FCC1 = elec1020_fraction(cnt1, cnt2, 6/16); +FCC1h = elec1020_fraction(cnt1, cnt2, 7/16); +FCC2h = elec1020_fraction(cnt1, cnt2, 9/16); +FCC2 = elec1020_fraction(cnt1, cnt2, 10/16); +FCC4h = elec1020_fraction(cnt1, cnt2, 11/16); +FCC4 = elec1020_fraction(cnt1, cnt2, 12/16); +FCC6h = elec1020_fraction(cnt1, cnt2, 13/16); +FCC6 = elec1020_fraction(cnt1, cnt2, 14/16); +FTT8h = elec1020_fraction(cnt1, cnt2, 15/16); + +fprintf('constructing CCP contour\n'); +[cnt1, cnt2] = elec1020_follow(pnt, dhk, TTP7, CCPz, TTP8, feedback); +TTP7h = elec1020_fraction(cnt1, cnt2, 1/16); +CCP5 = elec1020_fraction(cnt1, cnt2, 2/16); +CCP5h = elec1020_fraction(cnt1, cnt2, 3/16); +CCP3 = elec1020_fraction(cnt1, cnt2, 4/16); +CCP3h = elec1020_fraction(cnt1, cnt2, 5/16); +CCP1 = elec1020_fraction(cnt1, cnt2, 6/16); +CCP1h = elec1020_fraction(cnt1, cnt2, 7/16); +CCP2h = elec1020_fraction(cnt1, cnt2, 9/16); +CCP2 = elec1020_fraction(cnt1, cnt2, 10/16); +CCP4h = elec1020_fraction(cnt1, cnt2, 11/16); +CCP4 = elec1020_fraction(cnt1, cnt2, 12/16); +CCP6h = elec1020_fraction(cnt1, cnt2, 13/16); +CCP6 = elec1020_fraction(cnt1, cnt2, 14/16); +TTP8h = elec1020_fraction(cnt1, cnt2, 15/16); + +fprintf('constructing CP contour\n'); +[cnt1, cnt2] = elec1020_follow(pnt, dhk, TP7, CPz, TP8, feedback); +TP7h = elec1020_fraction(cnt1, cnt2, 1/16); +CP5 = elec1020_fraction(cnt1, cnt2, 2/16); +CP5h = elec1020_fraction(cnt1, cnt2, 3/16); +CP3 = elec1020_fraction(cnt1, cnt2, 4/16); +CP3h = elec1020_fraction(cnt1, cnt2, 5/16); +CP1 = elec1020_fraction(cnt1, cnt2, 6/16); +CP1h = elec1020_fraction(cnt1, cnt2, 7/16); +CP2h = elec1020_fraction(cnt1, cnt2, 9/16); +CP2 = elec1020_fraction(cnt1, cnt2, 10/16); +CP4h = elec1020_fraction(cnt1, cnt2, 11/16); +CP4 = elec1020_fraction(cnt1, cnt2, 12/16); +CP6h = elec1020_fraction(cnt1, cnt2, 13/16); +CP6 = elec1020_fraction(cnt1, cnt2, 14/16); +TP8h = elec1020_fraction(cnt1, cnt2, 15/16); + +fprintf('constructing CPP contour\n'); +[cnt1, cnt2] = elec1020_follow(pnt, dhk, TPP7, CPPz, TPP8, feedback); +TPP7h = elec1020_fraction(cnt1, cnt2, 1/16); +CPP5 = elec1020_fraction(cnt1, cnt2, 2/16); +CPP5h = elec1020_fraction(cnt1, cnt2, 3/16); +CPP3 = elec1020_fraction(cnt1, cnt2, 4/16); +CPP3h = elec1020_fraction(cnt1, cnt2, 5/16); +CPP1 = elec1020_fraction(cnt1, cnt2, 6/16); +CPP1h = elec1020_fraction(cnt1, cnt2, 7/16); +CPP2h = elec1020_fraction(cnt1, cnt2, 9/16); +CPP2 = elec1020_fraction(cnt1, cnt2, 10/16); +CPP4h = elec1020_fraction(cnt1, cnt2, 11/16); +CPP4 = elec1020_fraction(cnt1, cnt2, 12/16); +CPP6h = elec1020_fraction(cnt1, cnt2, 13/16); +CPP6 = elec1020_fraction(cnt1, cnt2, 14/16); +TPP8h = elec1020_fraction(cnt1, cnt2, 15/16); + +fprintf('constructing P contour\n'); +[cnt1, cnt2] = elec1020_follow(pnt, dhk, P7, Pz, P8, feedback); +P7h = elec1020_fraction(cnt1, cnt2, 1/16); +P5 = elec1020_fraction(cnt1, cnt2, 2/16); +P5h = elec1020_fraction(cnt1, cnt2, 3/16); +P3 = elec1020_fraction(cnt1, cnt2, 4/16); +P3h = elec1020_fraction(cnt1, cnt2, 5/16); +P1 = elec1020_fraction(cnt1, cnt2, 6/16); +P1h = elec1020_fraction(cnt1, cnt2, 7/16); +P2h = elec1020_fraction(cnt1, cnt2, 9/16); +P2 = elec1020_fraction(cnt1, cnt2, 10/16); +P4h = elec1020_fraction(cnt1, cnt2, 11/16); +P4 = elec1020_fraction(cnt1, cnt2, 12/16); +P6h = elec1020_fraction(cnt1, cnt2, 13/16); +P6 = elec1020_fraction(cnt1, cnt2, 14/16); +P8h = elec1020_fraction(cnt1, cnt2, 15/16); + +fprintf('constructing PPO contour\n'); +[cnt1, cnt2] = elec1020_follow(pnt, dhk, PPO7, PPOz, PPO8, feedback); +PPO7h = elec1020_fraction(cnt1, cnt2, 1/16); +PPO5 = elec1020_fraction(cnt1, cnt2, 2/16); +PPO5h = elec1020_fraction(cnt1, cnt2, 3/16); +PPO3 = elec1020_fraction(cnt1, cnt2, 4/16); +PPO3h = elec1020_fraction(cnt1, cnt2, 5/16); +PPO1 = elec1020_fraction(cnt1, cnt2, 6/16); +PPO1h = elec1020_fraction(cnt1, cnt2, 7/16); +PPO2h = elec1020_fraction(cnt1, cnt2, 9/16); +PPO2 = elec1020_fraction(cnt1, cnt2, 10/16); +PPO4h = elec1020_fraction(cnt1, cnt2, 11/16); +PPO4 = elec1020_fraction(cnt1, cnt2, 12/16); +PPO6h = elec1020_fraction(cnt1, cnt2, 13/16); +PPO6 = elec1020_fraction(cnt1, cnt2, 14/16); +PPO8h = elec1020_fraction(cnt1, cnt2, 15/16); + +fprintf('constructing PO contour\n'); +[cnt1, cnt2] = elec1020_follow(pnt, dhk, PO7, POz, PO8, feedback); +PO7h = elec1020_fraction(cnt1, cnt2, 1/16); +PO5 = elec1020_fraction(cnt1, cnt2, 2/16); +PO5h = elec1020_fraction(cnt1, cnt2, 3/16); +PO3 = elec1020_fraction(cnt1, cnt2, 4/16); +PO3h = elec1020_fraction(cnt1, cnt2, 5/16); +PO1 = elec1020_fraction(cnt1, cnt2, 6/16); +PO1h = elec1020_fraction(cnt1, cnt2, 7/16); +PO2h = elec1020_fraction(cnt1, cnt2, 9/16); +PO2 = elec1020_fraction(cnt1, cnt2, 10/16); +PO4h = elec1020_fraction(cnt1, cnt2, 11/16); +PO4 = elec1020_fraction(cnt1, cnt2, 12/16); +PO6h = elec1020_fraction(cnt1, cnt2, 13/16); +PO6 = elec1020_fraction(cnt1, cnt2, 14/16); +PO8h = elec1020_fraction(cnt1, cnt2, 15/16); + +fprintf('constructing POO contour\n'); +[cnt1, cnt2] = elec1020_follow(pnt, dhk, POO7, POOz, POO8, feedback); +POO7h = elec1020_fraction(cnt1, cnt2, 1/16); +POO5 = elec1020_fraction(cnt1, cnt2, 2/16); +POO5h = elec1020_fraction(cnt1, cnt2, 3/16); +POO3 = elec1020_fraction(cnt1, cnt2, 4/16); +POO3h = elec1020_fraction(cnt1, cnt2, 5/16); +POO1 = elec1020_fraction(cnt1, cnt2, 6/16); +POO1h = elec1020_fraction(cnt1, cnt2, 7/16); +POO2h = elec1020_fraction(cnt1, cnt2, 9/16); +POO2 = elec1020_fraction(cnt1, cnt2, 10/16); +POO4h = elec1020_fraction(cnt1, cnt2, 11/16); +POO4 = elec1020_fraction(cnt1, cnt2, 12/16); +POO6h = elec1020_fraction(cnt1, cnt2, 13/16); +POO6 = elec1020_fraction(cnt1, cnt2, 14/16); +POO8h = elec1020_fraction(cnt1, cnt2, 15/16); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% start contouring the low electrode locations +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% low horizontal ant-post through T9 +fprintf('constructing low horizontal left contour\n'); +[cnt1, cnt2] = elec1020_follow(pnt, dhk, Nz, T9, Iz, feedback); +AFp9 = elec1020_fraction(cnt1, cnt2, 3/20); +AF9 = elec1020_fraction(cnt1, cnt2, 4/20); +AFF9 = elec1020_fraction(cnt1, cnt2, 5/20); +F9 = elec1020_fraction(cnt1, cnt2, 6/20); +FFT9 = elec1020_fraction(cnt1, cnt2, 7/20); +FT9 = elec1020_fraction(cnt1, cnt2, 8/20); +FTT9 = elec1020_fraction(cnt1, cnt2, 9/20); +T9 = elec1020_fraction(cnt1, cnt2, 10/20); +TTP9 = elec1020_fraction(cnt1, cnt2, 11/20); +TP9 = elec1020_fraction(cnt1, cnt2, 12/20); +TPP9 = elec1020_fraction(cnt1, cnt2, 13/20); +P9 = elec1020_fraction(cnt1, cnt2, 14/20); +PPO9 = elec1020_fraction(cnt1, cnt2, 15/20); +PO9 = elec1020_fraction(cnt1, cnt2, 16/20); +POO9 = elec1020_fraction(cnt1, cnt2, 17/20); +I1 = elec1020_fraction(cnt1, cnt2, 18/20); +I1h = elec1020_fraction(cnt1, cnt2, 19/20); + +[cnt1, cnt2] = elec1020_follow(pnt, dhk, NFpz, T9h, OIz, feedback); +AFp9h = elec1020_fraction(cnt1, cnt2, 3/20); +AF9h = elec1020_fraction(cnt1, cnt2, 4/20); +AFF9h = elec1020_fraction(cnt1, cnt2, 5/20); +F9h = elec1020_fraction(cnt1, cnt2, 6/20); +FFT9h = elec1020_fraction(cnt1, cnt2, 7/20); +FT9h = elec1020_fraction(cnt1, cnt2, 8/20); +FTT9h = elec1020_fraction(cnt1, cnt2, 9/20); +T9h = elec1020_fraction(cnt1, cnt2, 10/20); +TTP9h = elec1020_fraction(cnt1, cnt2, 11/20); +TP9h = elec1020_fraction(cnt1, cnt2, 12/20); +TPP9h = elec1020_fraction(cnt1, cnt2, 13/20); +P9h = elec1020_fraction(cnt1, cnt2, 14/20); +PPO9h = elec1020_fraction(cnt1, cnt2, 15/20); +PO9h = elec1020_fraction(cnt1, cnt2, 16/20); +POO9h = elec1020_fraction(cnt1, cnt2, 17/20); +OI1 = elec1020_fraction(cnt1, cnt2, 18/20); +OI1h = elec1020_fraction(cnt1, cnt2, 19/20); + +% low horizontal ant-post through T10 +fprintf('constructing low horizontal right contour\n'); +[cnt1, cnt2] = elec1020_follow(pnt, dhk, Nz, T10, Iz, feedback); +AFp10 = elec1020_fraction(cnt1, cnt2, 3/20); +AF10 = elec1020_fraction(cnt1, cnt2, 4/20); +AFF10 = elec1020_fraction(cnt1, cnt2, 5/20); +F10 = elec1020_fraction(cnt1, cnt2, 6/20); +FFT10 = elec1020_fraction(cnt1, cnt2, 7/20); +FT10 = elec1020_fraction(cnt1, cnt2, 8/20); +FTT10 = elec1020_fraction(cnt1, cnt2, 9/20); +T10 = elec1020_fraction(cnt1, cnt2, 10/20); +TTP10 = elec1020_fraction(cnt1, cnt2, 11/20); +TP10 = elec1020_fraction(cnt1, cnt2, 12/20); +TPP10 = elec1020_fraction(cnt1, cnt2, 13/20); +P10 = elec1020_fraction(cnt1, cnt2, 14/20); +PPO10 = elec1020_fraction(cnt1, cnt2, 15/20); +PO10 = elec1020_fraction(cnt1, cnt2, 16/20); +POO10 = elec1020_fraction(cnt1, cnt2, 17/20); +I2 = elec1020_fraction(cnt1, cnt2, 18/20); +I2h = elec1020_fraction(cnt1, cnt2, 19/20); + +[cnt1, cnt2] = elec1020_follow(pnt, dhk, NFpz, T10h, OIz, feedback); +AFp10h = elec1020_fraction(cnt1, cnt2, 3/20); +AF10h = elec1020_fraction(cnt1, cnt2, 4/20); +AFF10h = elec1020_fraction(cnt1, cnt2, 5/20); +F10h = elec1020_fraction(cnt1, cnt2, 6/20); +FFT10h = elec1020_fraction(cnt1, cnt2, 7/20); +FT10h = elec1020_fraction(cnt1, cnt2, 8/20); +FTT10h = elec1020_fraction(cnt1, cnt2, 9/20); +T10h = elec1020_fraction(cnt1, cnt2, 10/20); +TTP10h = elec1020_fraction(cnt1, cnt2, 11/20); +TP10h = elec1020_fraction(cnt1, cnt2, 12/20); +TPP10h = elec1020_fraction(cnt1, cnt2, 13/20); +P10h = elec1020_fraction(cnt1, cnt2, 14/20); +PPO10h = elec1020_fraction(cnt1, cnt2, 15/20); +PO10h = elec1020_fraction(cnt1, cnt2, 16/20); +POO10h = elec1020_fraction(cnt1, cnt2, 17/20); +OI2 = elec1020_fraction(cnt1, cnt2, 18/20); +OI2h = elec1020_fraction(cnt1, cnt2, 19/20); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% collect all the computed electrode locations +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +lab = { + 'LPA' + 'RPA' + 'NAS' + 'INI' + 'Nz' + 'Fp1' + 'Fpz' + 'Fp2' + 'AF9' + 'AF7' + 'AF5' + 'AF3' + 'AF1' + 'AFz' + 'AF2' + 'AF4' + 'AF6' + 'AF8' + 'AF10' + 'F9' + 'F7' + 'F5' + 'F3' + 'F1' + 'Fz' + 'F2' + 'F4' + 'F6' + 'F8' + 'F10' + 'FT9' + 'FT7' + 'FC5' + 'FC3' + 'FC1' + 'FCz' + 'FC2' + 'FC4' + 'FC6' + 'FT8' + 'FT10' + 'T9' + 'T7' + 'C5' + 'C3' + 'C1' + 'Cz' + 'C2' + 'C4' + 'C6' + 'T8' + 'T10' + 'TP9' + 'TP7' + 'CP5' + 'CP3' + 'CP1' + 'CPz' + 'CP2' + 'CP4' + 'CP6' + 'TP8' + 'TP10' + 'P9' + 'P7' + 'P5' + 'P3' + 'P1' + 'Pz' + 'P2' + 'P4' + 'P6' + 'P8' + 'P10' + 'PO9' + 'PO7' + 'PO5' + 'PO3' + 'PO1' + 'POz' + 'PO2' + 'PO4' + 'PO6' + 'PO8' + 'PO10' + 'O1' + 'Oz' + 'O2' + 'I1' + 'Iz' + 'I2' + 'AFp9h' + 'AFp7h' + 'AFp5h' + 'AFp3h' + 'AFp1h' + 'AFp2h' + 'AFp4h' + 'AFp6h' + 'AFp8h' + 'AFp10h' + 'AFF9h' + 'AFF7h' + 'AFF5h' + 'AFF3h' + 'AFF1h' + 'AFF2h' + 'AFF4h' + 'AFF6h' + 'AFF8h' + 'AFF10h' + 'FFT9h' + 'FFT7h' + 'FFC5h' + 'FFC3h' + 'FFC1h' + 'FFC2h' + 'FFC4h' + 'FFC6h' + 'FFT8h' + 'FFT10h' + 'FTT9h' + 'FTT7h' + 'FCC5h' + 'FCC3h' + 'FCC1h' + 'FCC2h' + 'FCC4h' + 'FCC6h' + 'FTT8h' + 'FTT10h' + 'TTP9h' + 'TTP7h' + 'CCP5h' + 'CCP3h' + 'CCP1h' + 'CCP2h' + 'CCP4h' + 'CCP6h' + 'TTP8h' + 'TTP10h' + 'TPP9h' + 'TPP7h' + 'CPP5h' + 'CPP3h' + 'CPP1h' + 'CPP2h' + 'CPP4h' + 'CPP6h' + 'TPP8h' + 'TPP10h' + 'PPO9h' + 'PPO7h' + 'PPO5h' + 'PPO3h' + 'PPO1h' + 'PPO2h' + 'PPO4h' + 'PPO6h' + 'PPO8h' + 'PPO10h' + 'POO9h' + 'POO7h' + 'POO5h' + 'POO3h' + 'POO1h' + 'POO2h' + 'POO4h' + 'POO6h' + 'POO8h' + 'POO10h' + 'OI1h' + 'OI2h' + 'Fp1h' + 'Fp2h' + 'AF9h' + 'AF7h' + 'AF5h' + 'AF3h' + 'AF1h' + 'AF2h' + 'AF4h' + 'AF6h' + 'AF8h' + 'AF10h' + 'F9h' + 'F7h' + 'F5h' + 'F3h' + 'F1h' + 'F2h' + 'F4h' + 'F6h' + 'F8h' + 'F10h' + 'FT9h' + 'FT7h' + 'FC5h' + 'FC3h' + 'FC1h' + 'FC2h' + 'FC4h' + 'FC6h' + 'FT8h' + 'FT10h' + 'T9h' + 'T7h' + 'C5h' + 'C3h' + 'C1h' + 'C2h' + 'C4h' + 'C6h' + 'T8h' + 'T10h' + 'TP9h' + 'TP7h' + 'CP5h' + 'CP3h' + 'CP1h' + 'CP2h' + 'CP4h' + 'CP6h' + 'TP8h' + 'TP10h' + 'P9h' + 'P7h' + 'P5h' + 'P3h' + 'P1h' + 'P2h' + 'P4h' + 'P6h' + 'P8h' + 'P10h' + 'PO9h' + 'PO7h' + 'PO5h' + 'PO3h' + 'PO1h' + 'PO2h' + 'PO4h' + 'PO6h' + 'PO8h' + 'PO10h' + 'O1h' + 'O2h' + 'I1h' + 'I2h' + 'AFp9' + 'AFp7' + 'AFp5' + 'AFp3' + 'AFp1' + 'AFpz' + 'AFp2' + 'AFp4' + 'AFp6' + 'AFp8' + 'AFp10' + 'AFF9' + 'AFF7' + 'AFF5' + 'AFF3' + 'AFF1' + 'AFFz' + 'AFF2' + 'AFF4' + 'AFF6' + 'AFF8' + 'AFF10' + 'FFT9' + 'FFT7' + 'FFC5' + 'FFC3' + 'FFC1' + 'FFCz' + 'FFC2' + 'FFC4' + 'FFC6' + 'FFT8' + 'FFT10' + 'FTT9' + 'FTT7' + 'FCC5' + 'FCC3' + 'FCC1' + 'FCCz' + 'FCC2' + 'FCC4' + 'FCC6' + 'FTT8' + 'FTT10' + 'TTP9' + 'TTP7' + 'CCP5' + 'CCP3' + 'CCP1' + 'CCPz' + 'CCP2' + 'CCP4' + 'CCP6' + 'TTP8' + 'TTP10' + 'TPP9' + 'TPP7' + 'CPP5' + 'CPP3' + 'CPP1' + 'CPPz' + 'CPP2' + 'CPP4' + 'CPP6' + 'TPP8' + 'TPP10' + 'PPO9' + 'PPO7' + 'PPO5' + 'PPO3' + 'PPO1' + 'PPOz' + 'PPO2' + 'PPO4' + 'PPO6' + 'PPO8' + 'PPO10' + 'POO9' + 'POO7' + 'POO5' + 'POO3' + 'POO1' + 'POOz' + 'POO2' + 'POO4' + 'POO6' + 'POO8' + 'POO10' + 'OI1' + 'OIz' + 'OI2' + 'T3' % this is now called T7 + 'T4' % this is now called T8 + 'T5' % this is now called P7 + 'T6' % this is now called P8 + 'M1' % left mastoid + 'M2' % right mastoid + 'A1' % left ear lobe + 'A2' % right ear lobe + }; + +% allow for upper case electrode position labels +NAS = nas; +INI = ini; +LPA = lpa; +RPA = rpa; + +% it would be possible to assign locations to these old locations +% but there are no locations determined for M1/2 and A1/2 +if false + T3 = T7; + T4 = T8; + T5 = P7; + T6 = P8; +end + +% assign the known local electrode positions to the output matrix +nlab = numel(lab); +elc = ones(nlab,3) * nan; +for i=1:nlab + if exist(lab{i}, 'var') + eval(sprintf('elc(%d,:) = %s;', i, lab{i})); + else + fprintf('not placing electrode %s\n', lab{i}); + end +end + +% remove unknown electrode positions +sel = ~isnan(elc(:,1)); +elc = elc(sel, :); +lab = lab(sel); + +if feedback + ft_plot_mesh(elc, 'vertexsize', 10, 'vertexcolor', 'b') +end diff --git a/external/fieldtrip/private/elproj.m b/external/fieldtrip/private/elproj.m index 94ff2578..1fb7f3be 100644 --- a/external/fieldtrip/private/elproj.m +++ b/external/fieldtrip/private/elproj.m @@ -61,7 +61,7 @@ num = length(find(z<0)); str = sprintf('%d electrodes may be folded inwards in orthographic projection\n', num); if num - warning(str); + ft_warning(str); end proj = [xp yp]; @@ -77,7 +77,7 @@ num = length(find(th==pi/2 | z<0)); str = sprintf('removing %d electrodes from gnomic projection\n', num); if num - warning(str); + ft_warning(str); end xp(find(th==pi/2 | z<0)) = NaN; yp(find(th==pi/2 | z<0)) = NaN; @@ -94,7 +94,7 @@ num = length(find(th==pi/2 | z<0)); str = sprintf('removing %d electrodes from stereographic projection\n', num); if num - warning(str); + ft_warning(str); end xp(find(th==pi/2 | z<0)) = NaN; yp(find(th==pi/2 | z<0)) = NaN; @@ -113,5 +113,5 @@ proj = [x, y]; else - error('unsupported method (%s)', method); + ft_error('unsupported method (%s)', method); end diff --git a/external/fieldtrip/private/estimate_fwhm1.m b/external/fieldtrip/private/estimate_fwhm1.m index 6c6e6bef..d52aed0f 100644 --- a/external/fieldtrip/private/estimate_fwhm1.m +++ b/external/fieldtrip/private/estimate_fwhm1.m @@ -19,13 +19,13 @@ ninside = length(inside); if ~isfield(source.avg, 'filter') - error('the input should contain spatial filters in'); + ft_error('the input should contain spatial filters in'); end nchan = size(source.avg.filter{inside(1)},2); ndir = size(source.avg.filter{inside(1)},1); if ndir~=1, - error('only scalar filters are allowed as input'); + ft_error('only scalar filters are allowed as input'); end %create insidevol as a binary volume diff --git a/external/fieldtrip/private/estimate_fwhm2.m b/external/fieldtrip/private/estimate_fwhm2.m index 40f91904..5c9d81e5 100644 --- a/external/fieldtrip/private/estimate_fwhm2.m +++ b/external/fieldtrip/private/estimate_fwhm2.m @@ -20,13 +20,13 @@ ninside = numel(inside); if ~isfield(source.avg, 'filter') - error('the input should contain spatial filters in'); + ft_error('the input should contain spatial filters in'); end nchan = size(source.avg.filter{inside(1)},2); ndir = size(source.avg.filter{inside(1)},1); if ndir~=1, - error('only scalar filters are allowed as input'); + ft_error('only scalar filters are allowed as input'); end %get filters and positions diff --git a/external/fieldtrip/private/expand_orthogonal.m b/external/fieldtrip/private/expand_orthogonal.m index ae8523c1..4ee050da 100644 --- a/external/fieldtrip/private/expand_orthogonal.m +++ b/external/fieldtrip/private/expand_orthogonal.m @@ -60,24 +60,24 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % check the input arguments %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -if (nargin<1) || (nargin>3), error('incorrect number of input arrguments'); end; -if (nargin<3), method = 'svd'; end; -if (nargin<2), flg = 0; end; +if (nargin<1) || (nargin>3), ft_error('incorrect number of input arrguments'); end +if (nargin<3), method = 'svd'; end +if (nargin<2), flg = 0; end % A must be a matrix with more rows than columns containing only real numbers if isempty(A) || ~isnumeric(A) || ~isreal(A) || any(~isfinite(A(:))) ... || (ndims(A)>2) || (size(A,1)3 - error(sprintf('more than three neighbours found for triangle %d', i)); + ft_error('more than three neighbours found for triangle %d', i); else for j=1:length(sel) if isempty(setdiff(intersect(tri(i,:), tri(sel(j),:)), tri(i,[1 2]))) diff --git a/external/fieldtrip/private/findcluster.m b/external/fieldtrip/private/findcluster.m index 56d9aa20..c1c3fd00 100644 --- a/external/fieldtrip/private/findcluster.m +++ b/external/fieldtrip/private/findcluster.m @@ -46,24 +46,18 @@ nfreq = size(onoff, 2); ntime = size(onoff, 3); -% ensure that spm8 (preferred) or spm2 is available, needed for spm_bwlabeln -hasspm = ft_hastoolbox('spm12', 3) || ft_hastoolbox('spm8', 3) || ft_hastoolbox('spm2', 3); -if ~hasspm - error('the spm_bwlabeln function from SPM is needed for clustering'); -end - if length(size(spatdimneighbstructmat))~=2 || ~all(size(spatdimneighbstructmat)==spatdimlength) - error('invalid dimension of spatdimneighbstructmat'); + ft_error('invalid dimension of spatdimneighbstructmat'); end minnbchan=0; if length(varargin)==1 minnbchan=varargin{1}; -end; +end if length(varargin)==2 spatdimneighbselmat=varargin{1}; minnbchan=varargin{2}; -end; +end if minnbchan>0 % For every (time,frequency)-element, it is calculated how many significant @@ -72,18 +66,18 @@ if length(varargin)==1 selectmat = single(spatdimneighbstructmat | spatdimneighbstructmat'); - end; + end if length(varargin)==2 selectmat = single(spatdimneighbselmat | spatdimneighbselmat'); - end; + end nremoved=1; while nremoved>0 nsigneighb=reshape(selectmat*reshape(single(onoff),[spatdimlength (nfreq*ntime)]),[spatdimlength nfreq ntime]); remove=(onoff.*nsigneighb). +% +% $Id$ + +data.coordsys = lower(data.coordsys); + +% see also http://www.fieldtriptoolbox.org/faq/how_are_the_different_head_and_mri_coordinate_systems_defined +if strcmpi(data.coordsys, 'mni') || strcmpi(data.coordsys, 'spm') + data.coordsys = 'mni'; +elseif strcmpi(data.coordsys, 'ctf') || strcmpi(data.coordsys, '4d') || strcmpi(data.coordsys, 'bti') + data.coordsys = 'ctf'; +end + diff --git a/external/fieldtrip/private/fixdimord.m b/external/fieldtrip/private/fixdimord.m index 3786e1a8..b2b05928 100644 --- a/external/fieldtrip/private/fixdimord.m +++ b/external/fieldtrip/private/fixdimord.m @@ -50,7 +50,7 @@ % % if any(ft_datatype(data, {'source', 'volume'})) && isfield(data, 'dimord') && ~keepsourcedimord % % the old source data representation does not have a dimord, whereas the new source data representation does have a dimord -% warning(sprintf('removing dimord "%s" from source representation data', data.dimord)); +% ft_warning(sprintf('removing dimord "%s" from source representation data', data.dimord)); % data = rmfield(data, 'dimord'); % return % else @@ -68,24 +68,17 @@ elseif ft_datatype(data, 'volume') % it is volume data, which does not have a dimord -> this is ok return + elseif ft_datatype(data, 'source') || ft_datatype(data, 'parcellation') + % it is old-style source data -> this is ok + return else + % find the XXXdimord fields fn = fieldnames(data); sel = true(size(fn)); for i=1:length(fn) sel(i) = ~isempty(strfind(fn{i}, 'dimord')); end df = fn(sel); - - if isempty(df) - if ft_datatype(data, 'source') || ft_datatype(data, 'parcellation') - % it is old-style source data -> this is ok - % ft_checkdata will convert it to new-style - return - else - error('the data does not contain a dimord, but it also does not resemble raw or component data'); - end - end - % use this function recursively on the XXXdimord fields for i=1:length(df) data.dimord = data.(df{i}); @@ -96,7 +89,7 @@ % after the recursive call it should be ok return end -end +end % if no dimord if strcmp(data.dimord, 'voxel') % this means that it is position @@ -155,12 +148,12 @@ case {'{pos}' '{pos}_rpt' '{pos}_rpttap'} % this is for source data on a 3-d grid, a cortical sheet, or unstructured positions % the data itself is represented in a cell-array, e.g. source.mom or source.leadfield - + case {'{pos_pos}'} % this is for bivariate source data on a 3-d grid, a cortical sheet, or unstructured positions otherwise - error(sprintf('unexpected dimord "%s"', data.dimord)); + ft_error('unexpected dimord "%s"', data.dimord); end % switch dimtok end % for length dimtok @@ -217,4 +210,3 @@ for i=2:length(dimtok) data.dimord = [data.dimord '_' dimtok{i}]; end - diff --git a/external/fieldtrip/private/fixdipole.m b/external/fieldtrip/private/fixdipole.m index 2d691a78..14d94b56 100644 --- a/external/fieldtrip/private/fixdipole.m +++ b/external/fieldtrip/private/fixdipole.m @@ -29,15 +29,15 @@ % the input representation is Nx3, which is what we want elseif m==3 % it is possible to translate it into a Nx3 unambiguously - warning('input dipole positions should be specified as Nx3 matrix'); + ft_warning('input dipole positions should be specified as Nx3 matrix'); dip.pos = dip.pos'; elseif m==1 % it is possible to translate it into a Nx3 unambiguously - warning('input dipole positions should be specified as Nx3 matrix'); + ft_warning('input dipole positions should be specified as Nx3 matrix'); dip.pos = reshape(dip.pos, 3, n/3)'; else % it is not clear how to convert to a Nx3 matrix - error('input dipole positions should be specified as Nx3 matrix'); + ft_error('input dipole positions should be specified as Nx3 matrix'); end if isfield(dip, 'mom') diff --git a/external/fieldtrip/private/fixname.m b/external/fieldtrip/private/fixname.m index 96a345ec..76fd5951 100644 --- a/external/fieldtrip/private/fixname.m +++ b/external/fieldtrip/private/fixname.m @@ -1,19 +1,20 @@ -function str = fixname(str) +function str = fixname(str, version) % FIXNAME changes all inappropriate characters in a sting into '_' -% such that it can be used as a filename or as a structure field name. If -% the string begins with a numeric digit, an 'x' is prepended. +% so that it can be used as a filename or as a field name in a structure. +% If the string begins with a digit, an 'x' is prepended. % % Use as % str = fixname(str) % % MATLAB 2014a introduces the matlab.lang.makeValidName and -% matlab.lang.makeUniqueStrings functions for constructing unique MATLAB identifiers, -% but this particular implementation also works with older MATLAB versions. +% matlab.lang.makeUniqueStrings functions for constructing unique +% identifiers, but this particular implementation also works with +% older MATLAB versions. % % See also DEBLANK -% Copyright (C) 2012-2016, Robert Oostenveld +% Copyright (C) 2012-2017, Robert Oostenveld % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -33,19 +34,48 @@ % % $Id$ -str = lower(str); -str(regexp(str,'\W')) = '_'; - -while(str(1) == '_'), str = str(2:end); end; % remove all underscore at the begin of the string -while(str(end) == '_'), str = str(1:end-1); end; % remove all underscore at the end of the string - -if int8(str(1))<58 && int8(str(1))>47 - % the string begins with a digit, prepend an 'x' - str = ['x' str]; +if nargin<2 + version = 'default'; end -% truncate the string if it's too long: MATLAB maximizes the string length to 63 characters (and throws a warning when truncating) -if numel(str)>63 - str = str(1:63); - ft_warning(sprintf('%s exceeds MATLAB''s maximum name length of 63 characters and has been truncated to %s', str, str(1:63))); +switch version + case 'default' + if isempty(str) + str='x'; + end + str = lower(str); + str(regexp(str,'\W')) = '_'; + while(str(1) == '_'), str = str(2:end); end % remove all underscore at the begin of the string + while(str(end) == '_'), str = str(1:end-1); end % remove all underscore at the end of the string + if int8(str(1))<58 && int8(str(1))>47 + % the string begins with a digit, prepend an 'x' + str = ['x' str]; + end + % truncate the string if it's too long: MATLAB maximizes the string length to 63 characters (and throws a warning when truncating) + if numel(str)>63 + str = str(1:63); + warning('%s exceeds MATLAB''s maximum name length of 63 characters and has been truncated to %s', str, str(1:63)); + end + + case '2014a' + str = matlab.lang.makeValidName(str); + + case 'X_base64encode_X' + % this uses some code from Mathworks file exchange + ft_hastoolbox('fileexchange', 1); + % the following is an encoding that can be reverted + str = strtrim(base64encode(str)); + str(str=='=') = '_'; % replace the '=' sign with '_' + str = ['X' str 'X']; % start and end with an 'X' + + case 'X_base64decode_X' + % this uses some code from Mathworks file exchange + ft_hastoolbox('fileexchange', 1); + % revert the encoding + str = str(2:end-1); % it starts and ends with 'X' + str(str=='_') = '='; % the '=' sign has been replaced with '_' + str = char(base64decode(str)); + + otherwise + error('unsupported version "%s"', version); end diff --git a/external/fieldtrip/private/fixpos.m b/external/fieldtrip/private/fixpos.m index 31cee40f..88408288 100644 --- a/external/fieldtrip/private/fixpos.m +++ b/external/fieldtrip/private/fixpos.m @@ -10,7 +10,7 @@ % convert to structure, otherwise the code below won't work properly ws = warning('off', 'MATLAB:structOnObject'); mesh = struct(mesh); - warning(ws); + ft_warning(ws); end if ~isa(mesh, 'struct') @@ -42,7 +42,7 @@ case 8 mesh.hex = mesh.ConnectivityList; otherwise - error('unsupported ConnectivityList') + ft_error('unsupported ConnectivityList') end % switch mesh = removefields(mesh, {'Points', 'ConnectivityList', 'Constraints', 'UnderlyingObj'}); end diff --git a/external/fieldtrip/private/fourier2crsspctrm.m b/external/fieldtrip/private/fourier2crsspctrm.m index 98d3e517..51581ff8 100644 --- a/external/fieldtrip/private/fourier2crsspctrm.m +++ b/external/fieldtrip/private/fourier2crsspctrm.m @@ -68,7 +68,7 @@ Ncmb = size(cmbindx,1); %%FIXME -%if Ntim>1, error('correct handling of time-frequency data is not yet implemented, no information about tapers is available'); end +%if Ntim>1, ft_error('correct handling of time-frequency data is not yet implemented, no information about tapers is available'); end %keeping track of the tapers %in the case of tfr fourier-data cumtapcnt is highly redundant; for each frequency @@ -107,14 +107,14 @@ output.labelcmb(:,1) = freq.label(cmbindx(:,1)); output.labelcmb(:,2) = freq.label(cmbindx(:,2)); output.cumtapcnt = freq.cumtapcnt; -try, output.grad = freq.grad; end; -try, output.time = freq.time; end; +try, output.grad = freq.grad; end +try, output.time = freq.time; end output.powspctrm = powspctrm; output.crsspctrm = crsspctrm; if strcmp(cfg.keepfourier, 'yes'), output.fourierspctrm = freq.fourierspctrm; end -if isempty(output.crsspctrm), output = rmfield(output, 'crsspctrm'); end; -if isempty(output.labelcmb ), output = rmfield(output, 'labelcmb' ); end; +if isempty(output.crsspctrm), output = rmfield(output, 'crsspctrm'); end +if isempty(output.labelcmb ), output = rmfield(output, 'labelcmb' ); end % add information about the version of this function to the configuration cfg.version.name = mfilename('fullpath'); diff --git a/external/fieldtrip/private/freq2cumtapcnt.m b/external/fieldtrip/private/freq2cumtapcnt.m index ec3f6022..b069f640 100644 --- a/external/fieldtrip/private/freq2cumtapcnt.m +++ b/external/fieldtrip/private/freq2cumtapcnt.m @@ -4,7 +4,7 @@ hastim = ~isempty(strfind(freq.dimord, 'time')); if ~hasrpt, - error('computation of number of tapers is not possible, there is not enough information'); + ft_error('computation of number of tapers is not possible, there is not enough information'); end if hastim, diff --git a/external/fieldtrip/private/freq2timelock.m b/external/fieldtrip/private/freq2timelock.m index 0c37e214..ac043259 100644 --- a/external/fieldtrip/private/freq2timelock.m +++ b/external/fieldtrip/private/freq2timelock.m @@ -68,7 +68,7 @@ % concatenate the real and imaginary part avg = [real(spctrm) imag(spctrm)]; else - error('unknown representation of frequency domain data'); + ft_error('unknown representation of frequency domain data'); end timelock = []; diff --git a/external/fieldtrip/private/ft_fetch_sens.m b/external/fieldtrip/private/ft_fetch_sens.m index 7afeee3d..410ff3f6 100644 --- a/external/fieldtrip/private/ft_fetch_sens.m +++ b/external/fieldtrip/private/ft_fetch_sens.m @@ -4,29 +4,29 @@ % data structure or a FieldTrip configuration instead of a file on disk. % % Use as +% [sens] = ft_fetch_sens(cfg) +% or as % [sens] = ft_fetch_sens(cfg, data) -% where either of the two input arguments may be empty. % -% The positions of the sensors are specified in a gradiometer, electrode or optode -% configuration or from a layout. The sensor configuration can be passed into this -% function in four ways: +% The sensor configuration can be passed into this function in four ways: % -% (1) in a file whose name is passed in a configuration field, and that can be imported using FT_READ_SENS, -% (2) in a configuration field, -% (3) in a data field, or -% (4) in a layout file, see FT_PREPARE_LAYOUT +% (1) in a configuration field, +% (2) in a file whose name is passed in a configuration field, see FT_READ_SENS, +% (3) in a layout file, see FT_PREPARE_LAYOUT, or +% (4) in a data field % -% Allowed configuration or data fields: -% gradfile = sensor definition file to be read for MEG data -% elecfile = sensor definition file to be read for EEG data -% optofile = sensor definition file to be read for NIRS data -% grad = sensor definition from MEG data -% elec = sensor definition from EEG data -% opto = sensor definition from NIRS data +% The following fields are used from the configuration: +% cfg.gradfile = sensor definition file to be read for MEG data +% cfg.elecfile = sensor definition file to be read for EEG data +% cfg.optofile = sensor definition file to be read for NIRS data +% cfg.grad = sensor definition from MEG data +% cfg.elec = sensor definition from EEG data +% cfg.opto = sensor definition from NIRS data +% cfg.layout = layout definition or file name, see FT_PREPARE_LAYOUT +% cfg.senstype = string, can be 'meg', 'eeg', or 'nirs', this is used to choose in combined data (default = 'eeg') % -% Allowed configuration fields: -% layout = reference to a layout, see FT_PREPARE_LAYOUT -% senstype = string, can be 'meg', 'eeg', or 'nirs', this is used to choose in combined data (default = 'eeg') +% When not specified in the configuration, this function will fetch the grad, elec or +% opto field from the data. % % See also FT_READ_SENS, FT_PREPARE_LAYOUT, FT_FETCH_DATA @@ -58,6 +58,9 @@ cfg = ft_checkconfig(cfg); +% set the defaults +cfg.senstype = ft_getopt(cfg, 'senstype'); + % meg booleans hasgradfile = isfield(cfg, 'gradfile'); hascfggrad = isfield(cfg, 'grad'); @@ -77,48 +80,49 @@ haslayout = isfield(cfg, 'layout'); iscfgsens = isfield(cfg, 'pnt') || isfield(cfg, 'chanpos'); isdatasens = isfield(data, 'pnt') || isfield(data, 'chanpos'); -hassenstype = isfield(cfg, 'senstype'); -if (hasgradfile || hascfggrad || hasdatagrad) && (haselecfile || hascfgelec || hasdataelec) && ~hassenstype - error('Cannot determine whether you need gradiometer or electrode sensor definition. Specify cfg.senstype as ''MEG'' or ''EEG'''); +if isempty(cfg.senstype) && ((hasgradfile || hascfggrad || hasdatagrad) + (haselecfile || hascfgelec || hasdataelec) + (hasoptofile || hascfgopto || hasdataopto))>1 + ft_error('Cannot determine which sensor information you need. Specify cfg.senstype as ''meg'', ''eeg'' or ''nirs'''); -elseif hassenstype && iscell(cfg.senstype) - % this represents combined EEG and MEG sensors, where each modality has its own sensor definition - % use recursion to fetch all sensor descriptions - sens = cell(size(cfg.senstype)); - for i=1:numel(cfg.senstype) - tmpcfg = cfg; - tmpcfg.senstype = cfg.senstype{i}; - sens{i} = ft_fetch_sens(tmpcfg, data); +elseif ~isempty(cfg.senstype) + if iscell(cfg.senstype) + % this represents combined EEG and MEG sensors, where each modality has its own sensor definition + % use recursion to fetch all sensor descriptions + sens = cell(size(cfg.senstype)); + for i=1:numel(cfg.senstype) + tmpcfg = cfg; + tmpcfg.senstype = cfg.senstype{i}; + sens{i} = ft_fetch_sens(tmpcfg, data); + end + return + + else + switch lower(cfg.senstype) + case 'meg' + haselecfile = false; + hascfgelec = false; + hasdataelec = false; + hasoptofile = false; + hascfgopto = false; + hasdataopto = false; + case 'eeg' + hasgradfile = false; + hascfggrad = false; + hasdatagrad = false; + hasoptofile = false; + hascfgopto = false; + hasdataopto = false; + case 'nirs' + haselecfile = false; + hascfgelec = false; + hasdataelec = false; + hasgradfile = false; + hascfggrad = false; + hasdatagrad = false; + otherwise + ft_error('unsupported specification of cfg.senstype as "%s"', cfg.senstype); + end end - return - -elseif hassenstype - switch lower(cfg.senstype) - case 'meg' - haselecfile = false; - hascfgelec = false; - hasdataelec = false; - hasoptofile = false; - hascfgopto = false; - hasdataopto = false; - case 'eeg' - hasgradfile = false; - hascfggrad = false; - hasdatagrad = false; - hasoptofile = false; - hascfgopto = false; - hasdataopto = false; - case 'nirs' - haselecfile = false; - hascfgelec = false; - hasdataelec = false; - hasgradfile = false; - hascfggrad = false; - hasdatagrad = false; - otherwise - error('Senstype not specified correctly, please see the documentation of FT_FETCH_SENS'); - end; end if (hasgradfile + hascfggrad + hasdatagrad + ... @@ -196,7 +200,7 @@ sens = data; else - error('no electrodes, gradiometers or optodes specified.'); + ft_error('no electrodes, gradiometers or optodes specified.'); end % ensure that the sensor description is up-to-date diff --git a/external/fieldtrip/private/ft_fetch_vol.m b/external/fieldtrip/private/ft_fetch_vol.m index fb445571..5a26992f 100644 --- a/external/fieldtrip/private/ft_fetch_vol.m +++ b/external/fieldtrip/private/ft_fetch_vol.m @@ -32,7 +32,7 @@ % check input arguments if nargin > 1 - error('something is wrong'); + ft_error('something is wrong'); end % get the headmodel definition/volume conduction model @@ -45,7 +45,7 @@ % this might represent combined EEG, ECoG and/or MEG headmodel = cfg.headmodel; else - error('no headmodel specified'); + ft_error('no headmodel specified'); end % ensure that the headmodel description is up-to-date diff --git a/external/fieldtrip/private/ft_getuserfun.m b/external/fieldtrip/private/ft_getuserfun.m index e2540dc3..028c84d2 100644 --- a/external/fieldtrip/private/ft_getuserfun.m +++ b/external/fieldtrip/private/ft_getuserfun.m @@ -44,7 +44,7 @@ elseif isfunction(['ft_' prefix '_' func]) func = str2func(['ft_' prefix '_' func]); else - warning(['no function by the name ''' func ''', ''' prefix '_' func... - ''', or ''ft_' prefix '_' func ''' could not be found']); + ft_warning(['no function by the name ''' func ''', ''' prefix '_' func... + ''', or ''ft_' prefix '_' func ''' could be found']); func = []; end diff --git a/external/fieldtrip/private/getdimord.m b/external/fieldtrip/private/getdimord.m index e87e1f11..50c59d3c 100644 --- a/external/fieldtrip/private/getdimord.m +++ b/external/fieldtrip/private/getdimord.m @@ -7,12 +7,16 @@ % % See also GETDIMSIZ, GETDATFIELD +% Please note that this function is called from many other FT functions. To avoid +% unwanted recursion, you should avoid (where possible) calling other FT functions +% inside this one. + if ~isfield(data, field) && isfield(data, 'avg') && isfield(data.avg, field) field = ['avg.' field]; elseif ~isfield(data, field) && isfield(data, 'trial') && isfield(data.trial, field) field = ['trial.' field]; elseif ~isfield(data, field) - error('field "%s" not present in data', field); + ft_error('field "%s" not present in data', field); end if strncmp(field, 'avg.', 4) @@ -90,11 +94,13 @@ nfreq = length(data.freq); end -if isfield(data, 'trial') && ft_datatype(data, 'raw') +if isfield(data, 'trial') && iscell(data.trial) + % raw data nrpt = length(data.trial); end -if isfield(data, 'trialtime') && ft_datatype(data, 'spike') +if isfield(data, 'trialtime') && isfield(data, 'timestamp') && isfield(data, 'label') + % spike data nrpt = size(data.trialtime,1); end @@ -108,7 +114,7 @@ % this happens after mtmconvol with keeptrials nrpttap = sum(data.cumtapcnt,2); if any(nrpttap~=nrpttap(1)) - warning('unexpected variation of the number of tapers over trials') + ft_warning('unexpected variation of the number of tapers over trials') nrpttap = nan; else nrpttap = nrpttap(1); @@ -156,7 +162,8 @@ nspike = length(data.timestamp{1}); % spike data: only for the first channel end -if ft_datatype(data, 'mvar') && isfield(data, 'coeffs') +if isfield(data, 'dimord') && ~isempty(strfind(data.dimord, 'lag')) && isfield(data, 'coeffs') + % mvar data nlag = size(data.coeffs,3); end @@ -316,7 +323,8 @@ if isequal(datsiz, [npos nfreq ntime]) dimord = 'pos_freq_time'; end - case {'pow'} + + case {'pow' 'noise' 'rv'} if isequal(datsiz, [npos ntime]) dimord = 'pos_time'; elseif isequal(datsiz, [npos nfreq]) @@ -341,7 +349,7 @@ dimord = 'rpt_pos_freq'; end - case {'mom','itc','aa','stat','pval','statitc','pitc'} + case {'mom' 'itc' 'aa' 'stat','pval' 'statitc' 'pitc'} if isequal(datsiz, [npos nori nrpt]) dimord = 'pos_ori_rpt'; elseif isequal(datsiz, [npos nori ntime]) @@ -360,6 +368,8 @@ dimord = 'pos_rpt'; elseif isequalwithoutnans(datsiz, [npos nori nrpt]) dimord = 'pos_ori_rpt'; + elseif isequalwithoutnans(datsiz, [npos nori nrpttap]) + dimord = 'pos_ori_rpttap'; elseif isequalwithoutnans(datsiz, [npos nori ntime]) dimord = 'pos_ori_time'; elseif isequalwithoutnans(datsiz, [npos nori nfreq]) @@ -417,7 +427,11 @@ end case {'cumtapcnt' 'cumsumcnt'} - if isequalwithoutnans(datsiz, [nrpt nan]) + if isequalwithoutnans(datsiz, [nrpt 1]) + dimord = 'rpt'; + elseif isequalwithoutnans(datsiz, [nrpt nfreq]) + dimord = 'rpt_freq'; + elseif isequalwithoutnans(datsiz, [nrpt nan]) dimord = 'rpt_other'; end @@ -431,18 +445,25 @@ dimord = 'chan_topochan'; end - case {'inside'} - if isequalwithoutnans(datsiz, [npos]) + case {'anatomy' 'inside'} + if isfield(data, 'dim') && isequal(datsiz, data.dim) + dimord = 'dim1_dim2_dim3'; + elseif isequalwithoutnans(datsiz, [npos 1]) || isequalwithoutnans(datsiz, [1 npos]) dimord = 'pos'; end - case {'timestamp' 'time'} - if ft_datatype(data, 'spike') && iscell(data.(field)) && datsiz(1)==nchan + case {'timestamp'} + if iscell(data.(field)) && isfield(data, 'label') && datsiz(1)==nchan dimord = '{chan}_spike'; - elseif ft_datatype(data, 'raw') && iscell(data.(field)) && datsiz(1)==nrpt + end + + case {'time'} + if iscell(data.(field)) && isfield(data, 'label') && datsiz(1)==nrpt dimord = '{rpt}_time'; elseif isvector(data.(field)) && isequal(datsiz, [1 ntime ones(1,numel(datsiz)-2)]) dimord = 'time'; + elseif iscell(data.(field)) && isfield(data, 'label') && isfield(data, 'timestamp') && isequal(getdimsiz(data, 'timestamp'), datsiz) && datsiz(1)==nchan + dimord = '{chan}_spike'; end case {'freq'} @@ -548,8 +569,7 @@ % if it does, it might help in diagnosis to have a very informative warning message % since there have been problems with trials not being selected correctly due to the warning going unnoticed % it is better to throw an error than a warning - warning('could not determine dimord of "%s" in the following data', field) - disp(data); + warning_dimord_could_not_be_determined(field,data); dimtok(cellfun(@isempty, dimtok)) = {'unknown'}; if all(~cellfun(@isempty, dimtok)) @@ -567,6 +587,43 @@ end % function +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function warning_dimord_could_not_be_determined(field,data) + msg=sprintf('could not determine dimord of "%s" in:',field); + + if isempty(which('evalc')) + % May not be available in Octave + content=sprintf('object of type ''%s''',class(data)); + else + % in Octave, disp typically shows full data arrays which can result in + % very long output. Here we take out the middle part of the output if + % the output is very long (more than 40 lines) + full_content=evalc('disp(data)'); + max_pre_post_lines=20; + + newline_pos=find(full_content==sprintf('\n')); + newline_pos=newline_pos(max_pre_post_lines:(end-max_pre_post_lines)); + + if numel(newline_pos)>=2 + pre_end=newline_pos(1)-1; + post_end=newline_pos(end)+1; + + content=sprintf('%s\n\n... long output omitted ...\n\n%s',... + full_content(1:pre_end),... + full_content(post_end:end)); + else + content=full_content; + end + end + + id = 'FieldTrip:getdimord:warning_dimord_could_not_be_determined'; + msg = sprintf('%s\n\n%s', msg, content); + ft_warning(id, msg); +end % function warning_dimord_could_not_be_determined + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % SUBFUNCTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -601,11 +658,11 @@ case 'chan' ok = numel(data.label)==1; otherwise - if isfield(data, dimtok{k}); % check whether field exists + if isfield(data, dimtok{k}) % check whether field exists ok = numel(data.(dimtok{k}))==1; - end; + end end - if ok, + if ok break; end end diff --git a/external/fieldtrip/private/getdimsiz.m b/external/fieldtrip/private/getdimsiz.m index 90e27771..11b17abe 100644 --- a/external/fieldtrip/private/getdimsiz.m +++ b/external/fieldtrip/private/getdimsiz.m @@ -22,7 +22,7 @@ elseif ~isfield(data, field) && isfield(data, 'trial') && isfield(data.trial, field) field = ['trial.' field]; elseif ~isfield(data, field) - error('field "%s" not present in data', field); + ft_error('field "%s" not present in data', field); end if strncmp(field, 'avg.', 4) diff --git a/external/fieldtrip/private/grid2transform.m b/external/fieldtrip/private/grid2transform.m index 0bdbf2a5..305cf7b7 100644 --- a/external/fieldtrip/private/grid2transform.m +++ b/external/fieldtrip/private/grid2transform.m @@ -19,13 +19,13 @@ % check the input arguments if any(size(oldtransform)~=[4 4]) - error('incorrect size of homogenous transformation matrix'); + ft_error('incorrect size of homogenous transformation matrix'); elseif ~all(abs(diff(xgrid,2))<=100*eps*max(abs(xgrid))) - error('xgrid is not monotonously decreasing or increasing'); + ft_error('xgrid is not monotonously decreasing or increasing'); elseif ~all(abs(diff(ygrid,2))<=100*eps*max(abs(ygrid))) - error('ygrid is not monotonously decreasing or increasing'); + ft_error('ygrid is not monotonously decreasing or increasing'); elseif ~all(abs(diff(zgrid,2))<=100*eps*max(abs(zgrid))) - error('zgrid is not monotonously decreasing or increasing'); + ft_error('zgrid is not monotonously decreasing or increasing'); end Nx = length(xgrid); @@ -33,7 +33,7 @@ Nz = length(zgrid); if any(volume.dim(1:3)~=[Nx Ny Nz]) - error('dimensions do not correspond'); + ft_error('dimensions do not correspond'); end xmin = min(xgrid); diff --git a/external/fieldtrip/private/headsurface.m b/external/fieldtrip/private/headsurface.m index 0c77bc32..1e5677d3 100644 --- a/external/fieldtrip/private/headsurface.m +++ b/external/fieldtrip/private/headsurface.m @@ -87,7 +87,7 @@ % using innermost sphere radius = min(headmodel.r); otherwise - error('other surfaces cannot be constructed this way'); + ft_error('other surfaces cannot be constructed this way'); end if isfield(headmodel, 'o') origin = headmodel.o; @@ -125,13 +125,13 @@ % local spheres MEG model, this also requires a gradiometer structure grad = sens; if ~isfield(grad, 'tra') || ~isfield(grad, 'coilpos') - error('incorrect specification for the gradiometer array'); + ft_error('incorrect specification for the gradiometer array'); end Nchans = size(grad.tra, 1); Ncoils = size(grad.tra, 2); Nspheres = size(headmodel.o, 1); if Nspheres~=Ncoils - error('there should be just as many spheres as coils'); + ft_error('there should be just as many spheres as coils'); end % for each coil, determine a surface point using the corresponding sphere vec = grad.coilpos - headmodel.o; @@ -172,7 +172,7 @@ pos = headmodel.bnd(headmodel.source).pos; tri = headmodel.bnd(headmodel.source).tri; otherwise - error('other surfaces cannot be constructed this way'); + ft_error('other surfaces cannot be constructed this way'); end end @@ -211,7 +211,7 @@ tri = fliplr(tri); ori = -ori; else - warning('cannot determine the orientation of the vertex normals'); + ft_warning('cannot determine the orientation of the vertex normals'); % nothing to do end % the orientation is outward, hence shift with a negative amount diff --git a/external/fieldtrip/private/highpassfilter.m b/external/fieldtrip/private/highpassfilter.m index eb90f2e2..88c94a3d 100644 --- a/external/fieldtrip/private/highpassfilter.m +++ b/external/fieldtrip/private/highpassfilter.m @@ -72,7 +72,8 @@ if isempty(N) N = 25; end - [B, A] = fir1(N, max(Fhp)/Fn, 'high'); + B = fir1(N, max(Fhp)/Fn, 'high'); + A = 1; end % apply filter to the data diff --git a/external/fieldtrip/private/icosahedron.m b/external/fieldtrip/private/icosahedron.m index 2798b1f7..b6d65c34 100644 --- a/external/fieldtrip/private/icosahedron.m +++ b/external/fieldtrip/private/icosahedron.m @@ -25,7 +25,6 @@ % You should have received a copy of the GNU General Public License % along with FieldTrip. If not, see . % -% $Id$ tri = [ 1 2 3 diff --git a/external/fieldtrip/private/icosahedron162.m b/external/fieldtrip/private/icosahedron162.m index a39f3ee9..ae3bfe69 100644 --- a/external/fieldtrip/private/icosahedron162.m +++ b/external/fieldtrip/private/icosahedron162.m @@ -20,7 +20,6 @@ % You should have received a copy of the GNU General Public License % along with FieldTrip. If not, see . % -% $Id$ [pos, tri] = icosahedron; [pos, tri] = refine(pos, tri); diff --git a/external/fieldtrip/private/icosahedron2562.m b/external/fieldtrip/private/icosahedron2562.m index 26fdf53d..11752a0c 100644 --- a/external/fieldtrip/private/icosahedron2562.m +++ b/external/fieldtrip/private/icosahedron2562.m @@ -1,4 +1,4 @@ -function [pnt, tri] = icosahedron() +function [pnt, tri] = icosahedron2562() % ICOSAHEDRON2562 creates a 4-fold refined icosahedron diff --git a/external/fieldtrip/private/icosahedron42.m b/external/fieldtrip/private/icosahedron42.m index 86a1425a..833c11eb 100644 --- a/external/fieldtrip/private/icosahedron42.m +++ b/external/fieldtrip/private/icosahedron42.m @@ -20,7 +20,6 @@ % You should have received a copy of the GNU General Public License % along with FieldTrip. If not, see . % -% $Id$ [pos, tri] = icosahedron; [pos, tri] = refine(pos, tri); diff --git a/external/fieldtrip/private/icosahedron642.m b/external/fieldtrip/private/icosahedron642.m index cc4b5a15..4d932e5c 100644 --- a/external/fieldtrip/private/icosahedron642.m +++ b/external/fieldtrip/private/icosahedron642.m @@ -20,7 +20,6 @@ % You should have received a copy of the GNU General Public License % along with FieldTrip. If not, see . % -% $Id$ [pos, tri] = icosahedron; [pos, tri] = refine(pos, tri); diff --git a/external/fieldtrip/private/ignorefields.m b/external/fieldtrip/private/ignorefields.m index 8a7f861e..5cf9f24b 100644 --- a/external/fieldtrip/private/ignorefields.m +++ b/external/fieldtrip/private/ignorefields.m @@ -6,6 +6,35 @@ switch purpose + case 'appendtimelock' + ignore = { + 'cfg' + 'label' + 'time' + 'dimord' + 'grad' + 'elec' + 'opto' + 'trialinfo' % this is dealt with explicitly + 'sampleinfo' % this is dealt with explicitly + }; + + case 'appendfreq' + ignore = { + 'cfg' + 'label' + 'time' + 'freq' + 'dimord' + 'grad' + 'elec' + 'opto' + 'trialinfo' % this is dealt with explicitly + 'sampleinfo' % this is dealt with explicitly + 'cumsumcnt' % this is dealt with explicitly + 'cumtapcnt' % this is dealt with explicitly + }; + case 'deface' ignore = { % some fields should be dealt with explicitly @@ -21,7 +50,7 @@ 'fid' 'cfg' }; - + case 'pipeline' ignore = { % some fields that are always allowed to be present in the configuration @@ -30,10 +59,11 @@ 'cfg' 'previous' }; - + case 'allowed' ignore = { % some fields that are always allowed to be present in the configuration + 'postamble' 'trackconfig' 'checkconfig' 'checksize' @@ -44,16 +74,19 @@ 'callinfo' 'version' 'warning' + 'notification' 'debug' 'previous' 'progress' 'outputfilepresent' + 'toolbox' }; case {'provenance', 'history'} ignore = { % these should not be included in the provenance or history + 'postamble' 'checkconfig' 'checksize' 'trackconfig' @@ -62,6 +95,7 @@ 'trackcallinfo' 'showcallinfo' 'warning' + 'notification' 'debug' 'progress' }; @@ -77,6 +111,7 @@ 'artifact' 'artfctdef' % these fields are for internal usage only + 'postamble' 'checkconfig' 'checksize' 'trackconfig' @@ -87,6 +122,7 @@ 'callinfo' 'version' 'warning' + 'notification' 'debug' 'previous' }; @@ -104,5 +140,5 @@ }; otherwise - error('invalid purpose'); -end % switch purpose \ No newline at end of file + ft_error('invalid purpose'); +end % switch purpose diff --git a/external/fieldtrip/private/inputlabel2outputlabel.m b/external/fieldtrip/private/inputlabel2outputlabel.m index 9cc3df90..638bb19c 100644 --- a/external/fieldtrip/private/inputlabel2outputlabel.m +++ b/external/fieldtrip/private/inputlabel2outputlabel.m @@ -28,7 +28,7 @@ % % $Id$ -if ~isfield(cfg, 'combinechan'), cfg.combinechan = 'no'; end; +if ~isfield(cfg, 'combinechan'), cfg.combinechan = 'no'; end if strcmp(cfg.combinechan, 'no') % the output labels are similar to the input labels @@ -95,5 +95,5 @@ outputlabel{i} = cell2mat(freq.label(outputindex{i})'); end else - error('unknown combination method'); + ft_error('unknown combination method'); end diff --git a/external/fieldtrip/private/interp_gridded.m b/external/fieldtrip/private/interp_gridded.m index 11a785e0..0dd12050 100644 --- a/external/fieldtrip/private/interp_gridded.m +++ b/external/fieldtrip/private/interp_gridded.m @@ -40,7 +40,7 @@ % $Id$ if nargin<3 - error('Not enough input arguments.'); + ft_error('Not enough input arguments.'); end % get the optional arguments @@ -77,7 +77,7 @@ case {'sphere_avg', 'sphere_weighteddistance', 'sphere_weightedprojection'} if isempty(sphereradius) - error('sphereradius should be specified'); + ft_error('sphereradius should be specified'); end [X, Y, Z] = ndgrid(1:dim(1), 1:dim(2), 1:dim(3)); @@ -103,7 +103,7 @@ % do nothing I believe otherwise - error('unsupported projection method'); + ft_error('unsupported projection method'); end % case projmethod end % if isempty distmat @@ -154,7 +154,7 @@ fi = find(dat < max(tmp2)); val(fi) = tmp2(fi); else - error('undefined method to combine projections; use cfg.projcomb= mean or max') + ft_error('undefined method to combine projections; use cfg.projcomb= mean or max') end end if strcmp(projcomb,'mean'), @@ -167,7 +167,7 @@ % otherwise - error('unsupported projection method'); + ft_error('unsupported projection method'); end % case projmethod if nargout==1 && ~strcmp(projmethod, 'project') diff --git a/external/fieldtrip/private/interp_ungridded.m b/external/fieldtrip/private/interp_ungridded.m index 61bfa3c4..a09eab9b 100644 --- a/external/fieldtrip/private/interp_ungridded.m +++ b/external/fieldtrip/private/interp_ungridded.m @@ -47,7 +47,7 @@ % $Id$ if nargin<3 - error('Not enough input arguments.'); + ft_error('Not enough input arguments.'); end % get the optional arguments @@ -81,7 +81,7 @@ switch projmethod case 'nearest' if ~isempty(sphereradius) - warning('sphereradius is not used for projmethod ''nearest'''); + ft_warning('sphereradius is not used for projmethod ''nearest'''); end % determine the nearest voxel for each surface point ind = find_nearest(pos_to, pos_from, 5); @@ -91,7 +91,7 @@ case {'sphere_avg', 'sphere_weighteddistance'} if isempty(sphereradius) - error('sphereradius should be specified'); + ft_error('sphereradius should be specified'); end % compute the distance between voxels and each surface point dpos_fromsq = sum(pos_from.^2,2); % squared distance to origin @@ -129,7 +129,7 @@ case 'smudge' if isempty(triout), - error('the ''smudge'' method needs a triangle definition'); + ft_error('the ''smudge'' method needs a triangle definition'); end [datin, loc] = ismember(pos_to, pos_from, 'rows'); [datout, S1] = smudge(datin, triout, 6); %FIXME 6 is number of iterations, improve here @@ -139,7 +139,7 @@ distmat = S1 * S2; otherwise - error('unsupported projection method'); + ft_error('unsupported projection method'); end % case projmethod end % if isempty distmat @@ -169,7 +169,7 @@ otherwise - error('unsupported projection method'); + ft_error('unsupported projection method'); end % case projmethod if hasdat diff --git a/external/fieldtrip/private/labelcmb2indx.m b/external/fieldtrip/private/labelcmb2indx.m index db7f97a5..8fc4dc2e 100644 --- a/external/fieldtrip/private/labelcmb2indx.m +++ b/external/fieldtrip/private/labelcmb2indx.m @@ -1,4 +1,4 @@ -function [indx] = labelcmb2indx(labelcmb, label) +function [indx, label, blockindx, blocklabel] = labelcmb2indx(labelcmb, label) % LABELCMB2INDX computes an array with indices, corresponding to the order % in a list of labels, for an Nx2 list of label combinations @@ -46,6 +46,32 @@ % % $Id$ +% check whether the labelcmb contains any square brackets, indicative of +% blockwise decompositions +if all(~cellfun('isempty',strfind(labelcmb(:),'['))) + tmp = strfind(labelcmb, '['); + tmplabelcmb = labelcmb; + tmpblock = labelcmb; + for k = 1:numel(tmplabelcmb) + tmplabelcmb{k} = labelcmb{k}( 1:(tmp{k}-1)); + tmpblock{k} = labelcmb{k}((tmp{k}+1):(end-1)); + end + blocklabel = cell(0,1); + tmp = tmpblock; + while ~isempty(tmp) + blocklabel{end+1, 1} = tmp{1}; + tmp = tmp(~strcmp(tmp(:,1),blocklabel{end}),:); + end + [indx, label] = labelcmb2indx(tmplabelcmb, unique(tmplabelcmb(:))); + [blockindx, blocklabel] = labelcmb2indx(tmpblock, blocklabel); + blockindx = blockindx(:,1); +% for k = 1:numel(blocklabel) +% nperblock(k,1) = sum(blockindx==k); +% end + return; +end + + if nargin==1, label = unique(labelcmb(:)); end @@ -62,7 +88,7 @@ if nargin==1, %autoindx = find(sel1 & sel2); autoindx = find(sel(:,1) & sel(:,2), 1, 'first'); - if isempty(autoindx), error('the required autocombination is not found in the input'); end + if isempty(autoindx), ft_error('the required autocombination is not found in the input'); end else autoindx = k; end diff --git a/external/fieldtrip/private/lmoutr.m b/external/fieldtrip/private/lmoutr.m index 121b8301..acb88964 100644 --- a/external/fieldtrip/private/lmoutr.m +++ b/external/fieldtrip/private/lmoutr.m @@ -1,4 +1,4 @@ -function [varargout] = funname(varargin) +function [varargout] = lmoutr(varargin) % LMOUTR computes the la/mu parameters of a point projected to a triangle % @@ -60,7 +60,7 @@ try % try to compile the mex file on the fly - warning('trying to compile MEX file from %s', mexsrc); + ft_warning('trying to compile MEX file from %s', mexsrc); cd(mexdir); if ispc @@ -77,7 +77,7 @@ catch % compilation failed disp(lasterr); - error('could not locate MEX file for %s', mexname); + ft_error('could not locate MEX file for %s', mexname); cd(pwdir); success = false; end diff --git a/external/fieldtrip/private/lmoutr.mexa64 b/external/fieldtrip/private/lmoutr.mexa64 index db385e19c20d6e51d3eece19e335e84627fbec09..eb8e4f4765beaef50b18b6103743f1aeffc3f2e8 100755 GIT binary patch delta 1218 zcmY*ZZA@Eb6u#&7^A6VAPx>)iU>4dJx|Z`zUMj5 zdwO%bn!1|$_6hSoF2Cka96V>M@o32!VigQJ|1u3c`|dI4)SfH9jhs%5*M2oH_Kh+N z%K+ahGrE8drWCX3HGoq%Xbw>vGjD?h`(vzKvqUa1@Uf*1IFLkrO{XZ)g<56OCg1WKOgiyamca;bG_)5~#}E z>Kaz9O0sUJtPk##liZ99YLzt|XN-~7`Zo0--(pd9pHzQuZ|rNW&X-M}xyD#d+?>gY zHl4_-Wxb-5T*tx9J6c`9$aE9C10JkW6n|sdoeDSz*gKZ`oWJKqMv7r zcuL&Hmzwbxu^eVluzpy1beXZ2e-K|fL$=9g^1SM+$i#6^-$Q9#Mzw5G(+c(0Iq`n= z*8YER!MYWm!kDexFDWg6ElGILyzs9Aa}*z64%o+n=;_=eZxe233(s};A@joZrZ7UC;u9A7A_6#oALd_q~qqaDpCP<~DyTdmYcE$TRtTa~z( zw{kU@-Ry=8MVAt|&CbId#wwx|_g5StQ+Tl=0yHO+u>BI;JZJ8$3d6aOF1G@A(k delta 1127 zcmYL}eQXnT7{`ClUEB4#Zg;n}>sn|xrCk}))+NM^KmrBpZnHzg&5Rc(3$SH>xI{t& zSybkROAaV>KDZDw1O7oWHO4JB%rJ%*oe|?7!arspFOg_C;v}wSf?M@`u7i2W@A*8> z-S2sx?{jYhodcbjox-?}<&W{ft_!lId?8pQu7*>t6W@H+C;jfa)z$Lpa4t03cd#|k zu1!M@;Iwv+5AbkCvlk2jwBadxnC!RqYS@7@WVhiGp&D8-AX zylvlA$XHJxwG;=P9_)1rum%r1n?3g(jAg~IE?YaqAx4Yp%#GZ>V)CskO@DbuCKc4rJv5B0DD(QL z>BL3Z64cL-i$4}eh19%ZB-ICc1dGHb*pJ)AN_ZLH5dBbx?~8uUH;?DU4P34O{}HQT z5`)s&+M%3byz`TIXq@y=|HNgp;f#&3y=y6Kx@c;-V}=oPoUGVtj^m#~NnQhoF)3I1 zcg^J`B_@8Wi>p)0k*1NPI+s-MC)K-pJsy`o^fiz`CH>|VMZKjLl0QMSGPBPRHkJ&- zYk0RL3<(rVgRmA?l?FM_9BwP^4un$6^iTd=m@~oj(~n)d{vNp+xaxs4G`Ls8X6$#b ztyYEFDE*U_+v7Xpuf*HF`#O`!v?%JYO4^#BON;SKO8>N7Ibxl% zRnq>4#y+o-_J5BK&oa2JMLkc#!2?wB1ZiHGHH=AO8}S$7=R^yY3Xq&2aS!oX;upl- z#O7JUI7-YtFpMvWJv96c;@IDY;p7;5o^IVL;wE|syNSd9(te_gYMTf2Y+-Of!XL_I zxPd>H$6zPQ-U`@@HDo`=7s+Pvb#KKJUQ*Ixro@Y-jRRbfjoa)jurn5!}0Jr+WH6qF7NzP)?J;(WDmbCS#t-pZ3 z28$K)O{l^h9P@=adrrIVJI}qlWIdkrk8*mM))+W%qgPM}#T*^)863^#2LWDGB@aPtzg;LHjS^pbUJfu~A17{!`M zjBI;kKZ(HWktn={LiAN&*cI)B5xg2*2WL@^#b67@WA(xdB@4BAZ7}9Be-0l#eUtkS DX~}#_ diff --git a/external/fieldtrip/private/lmoutr.mexmaci64 b/external/fieldtrip/private/lmoutr.mexmaci64 index 4079df72268abdefc3086b0facdcac955419c106..d226f9b07e5aab8aa9ae1ad2516aeb1e2293d563 100755 GIT binary patch literal 13240 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 delta 830 zcmYL{ZAcVB9L9INJ3GufPrXb%#TPCuUov!N_jYF!D_1h`&=XH111khGEfOt?@Qg$7 zSjuX_K4jnrr6l@LXMHH6Lcd2$tFkzP`!^g^?8O9M0W{D05GyfD*K)>C#V zoK^LAxsHjnAQP3f5f~Z9Oo7^IYg6Juk?vCyqwE1ApwYhowncf8^bF&j)YrP@E~^|} zUrp9@>%hATx-7D}hJ>_Q*J)~TWHAi+Fl9qUK2^%}0n_5nD~#HCN3$V{3?818V$<8jlb;$wf-2>660i=g6g6-O?w0 zCpJ~PV_iOJmBdlq%Cv%3;FErnUoc85uDPZUZjmOZ3kz_BX*miv0251Yzkj z$aTqqR8pWSDJ_spvQ<@;siYV=#c9N*&SZM4aeB-tz5RlJz&N4@?TTnxpkt1?1&IEB z^GTgD1T0q)#z2MtUIGTx`j%K^I<%Rw(8ZWSI`2{ntu}y^N~_HGbL! z@wX)3HFzvA38ukpxD{@PyP*@-!zS1a&%jX_p>T0#xAlp?g)308{}?qx4Ea> zG&j$!adD0`N3F-v;5h9#=g8sn`JMa${siB}zvn;jpZPHVhmR393B^LU;1#Y44}>Y< zweVI52}?pEw&5IHfQzvMmtrSw#D{SUK8`!_S$rP%;eI@Tuj65S3;XdyJb_>0863bN d{1vZYAezJkFo&G diff --git a/external/fieldtrip/private/lmoutr.mexw64 b/external/fieldtrip/private/lmoutr.mexw64 index 8ad4f5717ed062ac51e339371314fb2148f44c0d..ab5adac34f0bc2b9a2a4442b63d695307ddb8702 100755 GIT binary patch delta 1664 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 && numel(default)==numel(input) + % create an empty structure that has all the fields + tmp = emptystruct(allfields); + for i=1:numel(input) + for j=1:numel(allfields) + if isfield(input(i), allfields{j}) + tmp(i).(allfields{j}) = input(i).(allfields{j}); + else + tmp(i).(allfields{j}) = default(i).(allfields{j}); + end + end + end + input = tmp; - if ~isfield(input, fn) && ~isstruct(default.(fn)) - % simply copy the value over - input.(fn) = default.(fn); - elseif ~isfield(input, fn) && isstruct(default.(fn)) - % simply copy the substructure over - input.(fn) = default.(fn); - elseif isfield(input, fn) && ~isstruct(default.(fn)) - % do not copy it over, keep the original value - elseif isfield(input, fn) && isstruct(default.(fn)) - % merge the two substructures - input.(fn) = mergeconfig(input.(fn), default.(fn)); +elseif numel(default)~=numel(input) + for j=1:numel(allfields) + % ensure that the input has all fields + if ~isfield(input, allfields{j}) + input(1).(allfields{j}) = []; + end + % ensure that the default has all fields + if ~isfield(default, allfields{j}) + default(1).(allfields{j}) = []; + end end + % simply concatenate them + input = cat(1, input(:), default(:)); + +else + for i=1:length(defaultfields) + fn = defaultfields{i}; + if ~isfield(input, fn) && ~isstruct(default.(fn)) + % simply copy the value over + input.(fn) = default.(fn); + elseif ~isfield(input, fn) && isstruct(default.(fn)) + % simply copy the substructure over + input.(fn) = default.(fn); + elseif isfield(input, fn) && ~isstruct(default.(fn)) + % do not copy it over, keep the original value + elseif isfield(input, fn) && isstruct(default.(fn)) + % merge the two substructures using recursive call + input.(fn) = mergeconfig(input.(fn), default.(fn)); + end + end % for all default fields -end % for all fields +end % dealing with struct-arrays + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function s = emptystruct(fn) +s = struct; +for i=1:numel(fn) + s.(fn{i}) = []; +end +s = s([]); \ No newline at end of file diff --git a/external/fieldtrip/private/mesh2edge.m b/external/fieldtrip/private/mesh2edge.m index 71b4c0e4..4fc082ae 100644 --- a/external/fieldtrip/private/mesh2edge.m +++ b/external/fieldtrip/private/mesh2edge.m @@ -99,7 +99,7 @@ end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% SUBFUNCTION, see http://bugzilla.fcdonders.nl/show_bug.cgi?id=1833#c12 +% SUBFUNCTION, see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=1833#c12 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function indx = findsingleoccurringrows(X) [X, indx] = sortrows(X); diff --git a/external/fieldtrip/private/mesh_spectrum.m b/external/fieldtrip/private/mesh_spectrum.m index 65cc7d2c..14c6fcc6 100644 --- a/external/fieldtrip/private/mesh_spectrum.m +++ b/external/fieldtrip/private/mesh_spectrum.m @@ -1,6 +1,6 @@ % Mesh spectrum -function [L,H,d] = ct_mesh_spectrum(S,n,varargin) +function [L,H,d] = mesh_spectrum(S,n,varargin) %[L,H,d] = ct_mesh_spectrum(S,n,mode) % Compute the mesh laplace matrix and its spectrum diff --git a/external/fieldtrip/private/mesh_spherify.m b/external/fieldtrip/private/mesh_spherify.m index ee83d58a..ceacc013 100644 --- a/external/fieldtrip/private/mesh_spherify.m +++ b/external/fieldtrip/private/mesh_spherify.m @@ -175,7 +175,7 @@ end if mod(length(varargin),2) - error('optional input arguments should come in key-value pairs, i.e. there should be an even number'); + ft_error('optional input arguments should come in key-value pairs, i.e. there should be an even number'); end keys = varargin(1:2:end); @@ -189,5 +189,5 @@ % the requested key was found val = vals{hit}; else - error('multiple input arguments with the same name'); + ft_error('multiple input arguments with the same name'); end diff --git a/external/fieldtrip/private/mni2tal.m b/external/fieldtrip/private/mni2tal.m index 36b7df9f..cdf93faf 100644 --- a/external/fieldtrip/private/mni2tal.m +++ b/external/fieldtrip/private/mni2tal.m @@ -7,15 +7,12 @@ % outpoints is the coordinate matrix with Talairach points % Matthew Brett 10/8/99 -% ensure that SPM8 (preferred) or SPM2 is available, needed for spm_matrix -hasspm = ft_hastoolbox('SPM8', 3) || ft_hastoolbox('SPM2', 3); -if ~hasspm - error('this function depends on the SPM toolbox, see see http://www.fil.ion.ucl.ac.uk/spm'); -end +% ensure that SPM is available, needed for spm_matrix +hasspm = ft_hastoolbox('spm8up', 3) || ft_hastoolbox('spm2', 1); dimdim = find(size(inpoints) == 3); if isempty(dimdim) - error('input must be a N by 3 or 3 by N matrix') + ft_error('input must be a N by 3 or 3 by N matrix') end if dimdim == 2 inpoints = inpoints'; diff --git a/external/fieldtrip/private/mollify.m b/external/fieldtrip/private/mollify.m index 8d9a77be..7f18a5b9 100644 --- a/external/fieldtrip/private/mollify.m +++ b/external/fieldtrip/private/mollify.m @@ -37,7 +37,7 @@ Ncomp = size(grid.leadfield{grid.inside(1)}, 2); if isempty(cfg.sphereradius) - error('cfg.sphereradius should be specified'); + ft_error('cfg.sphereradius should be specified'); end % the distance only has to be computed to voxels inside the brain pos = grid.pos(grid.inside,:); diff --git a/external/fieldtrip/private/moveinward.m b/external/fieldtrip/private/moveinward.m new file mode 100644 index 00000000..046dbcf7 --- /dev/null +++ b/external/fieldtrip/private/moveinward.m @@ -0,0 +1,18 @@ +function [pos] = moveinward(pos, move) +%This functions moves 'pos' inward according to their normals by 'move' +%units +propos = elproj(pos); % projection to 2D +tri = delaunay(propos); %creates delaunay triangulation of 2D plane, which will be used for the the 3D case +nor = normals(pos,tri); %compute normals of surface +ori = surfaceorientation(pos, tri, nor); +if ori==1 + % the normals are outward oriented +elseif ori==-1 + % the normals are inward oriented + nor = -nor; +else + ft_warning('cannot determine the orientation of the vertex normals'); +end +pos = pos-move*nor; % moves pos inwards according to their normals +end + diff --git a/external/fieldtrip/private/moviefunction.m b/external/fieldtrip/private/moviefunction.m index b8988846..5fcec105 100644 --- a/external/fieldtrip/private/moviefunction.m +++ b/external/fieldtrip/private/moviefunction.m @@ -64,7 +64,7 @@ function moviefunction(cfg, varargin) for i=1:numel(varargin) if ~isempty(cfg.yparam) && ~isfield(varargin{i}, 'freq') - error('data argument %i does not have a .freq field, while all former had', i); + ft_error('data argument %i does not have a .freq field, while all former had', i); elseif isempty(cfg.yparam) && isfield(varargin{i}, 'freq') cfg.yparam = 'freq'; else @@ -96,25 +96,25 @@ function moviefunction(cfg, varargin) opt.isfreq(i) = ft_datatype(varargin{i}, 'freq'); opt.istimelock(i) = ft_datatype(varargin{i}, 'timelock'); if opt.issource(i)+opt.isfreq(i)+opt.istimelock(i) ~= 1 - error('data argument %i cannot be definitely identified as frequency, timelock or source data', i); + ft_error('data argument %i cannot be definitely identified as frequency, timelock or source data', i); end end if Ndata>1, if all(opt.issource==1), % this is allowed maybe in the future: multiple source input arguments - error('currently, not more than 1 data argument is allowed, unless one of them is a parcellation, and the other a channel level structure'); + ft_error('currently, not more than 1 data argument is allowed, unless one of them is a parcellation, and the other a channel level structure'); elseif all(opt.isfreq==1), % this is allowed maybe in the future: multiple freq input arguments - error('currently, not more than 1 data argument is allowed, unless one of them is a parcellation, and the other a channel level structure'); + ft_error('currently, not more than 1 data argument is allowed, unless one of them is a parcellation, and the other a channel level structure'); elseif all(opt.istimelock==1), % this is allowed maybe in the future: multiple timelock input arguments - error('currently, not more than 1 data argument is allowed, unless one of them is a parcellation, and the other a channel level structure'); + ft_error('currently, not more than 1 data argument is allowed, unless one of them is a parcellation, and the other a channel level structure'); elseif Ndata==2 && sum(opt.issource==1) % this may be allowed, provided the source data is a parcellation and % the other argument a parcellated data structure if ~ft_datatype(varargin{opt.issource}, 'parcellation') - error('the source data structure should be a parcellation'); + ft_error('the source data structure should be a parcellation'); end end end @@ -167,14 +167,14 @@ function moviefunction(cfg, varargin) dimtok = tokenize(opt.dimord, '_'); if any(strcmp(dimtok, 'rpt') | strcmp(dimtok, 'subj')) - error('the input data cannot contain trials or subjects, please average first using ft_selectdata'); + ft_error('the input data cannot contain trials or subjects, please average first using ft_selectdata'); end opt.ydim = find(strcmp(cfg.yparam, dimtok)); opt.xdim = find(strcmp(cfg.xparam, dimtok)); opt.zdim = setdiff(1:ndims(opt.dat{1}), [opt.ydim opt.xdim]); if opt.zdim ~=1 - error('input %i data does not have the correct format of N x time (x freq)', i); + ft_error('input %i data does not have the correct format of N x time (x freq)', i); end % permute the data matrix @@ -888,7 +888,7 @@ function cb_recordbutton(h, eventdata) % open a save-file dialog [FileName,PathName,FilterIndex] = uiputfile('*.avi', 'Save AVI-file' , 'ft_movie'); - if (FileName == 0 & PathName == 0) % aborted + if (FileName == 0 && PathName == 0) % aborted cb_recordbutton(h); return; end @@ -971,7 +971,7 @@ function cb_recordbutton(h, eventdata) % F(iFrame) = getframe; % end % else -% error('Either moviefreq or movietime should contain a bin number') +% ft_error('Either moviefreq or movietime should contain a bin number') % end % else % for iFrame = 1:floor(size(opt.dat, opt.xdim)/cfg.samperframe) diff --git a/external/fieldtrip/private/mutexlock.m b/external/fieldtrip/private/mutexlock.m index 4e6d86dd..9362c967 100644 --- a/external/fieldtrip/private/mutexlock.m +++ b/external/fieldtrip/private/mutexlock.m @@ -25,13 +25,13 @@ function mutexlock(lockfile, timeout) % wait untill another process removes the lockfile pause(1); if toc(stopwatch)>timeout - error('timeout exceeded waiting for the lockfile to be removed'); + ft_error('timeout exceeded waiting for the lockfile to be removed'); end end % create the lockfile fid = fopen(lockfile, 'wb'); if fid<0 - error('cannot open lockfile'); + ft_error('cannot open lockfile'); end flose(fid); diff --git a/external/fieldtrip/private/mxDeserialize.m b/external/fieldtrip/private/mxDeserialize.m index 696f4ff8..d9b4843f 100644 --- a/external/fieldtrip/private/mxDeserialize.m +++ b/external/fieldtrip/private/mxDeserialize.m @@ -31,7 +31,7 @@ argout = mxDeserialize_c(argin); else % use the C++ implementation of the mex file - % see http://bugzilla.fcdonders.nl/show_bug.cgi?id=2452 + % see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2452 argout = mxDeserialize_cpp(argin); end diff --git a/external/fieldtrip/private/mxSerialize.m b/external/fieldtrip/private/mxSerialize.m index 78befccb..a2534051 100644 --- a/external/fieldtrip/private/mxSerialize.m +++ b/external/fieldtrip/private/mxSerialize.m @@ -31,7 +31,7 @@ argout = mxSerialize_c(argin); else % use the C++ implementation of the mex file - % see http://bugzilla.fcdonders.nl/show_bug.cgi?id=2452 + % see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2452 argout = mxSerialize_cpp(argin); end diff --git a/external/fieldtrip/private/ndgrid.m b/external/fieldtrip/private/ndgrid.m index c88a655c..cfc6870f 100644 --- a/external/fieldtrip/private/ndgrid.m +++ b/external/fieldtrip/private/ndgrid.m @@ -50,7 +50,7 @@ % $Id$ if nargin==0 - error('MATLAB:ndgrid:NotEnoughInputs', 'Not enough input arguments.'); + ft_error('MATLAB:ndgrid:NotEnoughInputs', 'Not enough input arguments.'); end if nargin==1, varargin = repmat(varargin,[1 max(nargout,2)]); end @@ -117,7 +117,7 @@ varargout{4} = xx(ones1, ones2, ones3, :,ones5); varargout{5} = yy(ones1, ones2, ones3, :,ones5); otherwise - error('this version of ndgrid supports inputs up to 5 dimensions'); + ft_error('this version of ndgrid supports inputs up to 5 dimensions'); %call the ndgrid from elmat %FIXME this has to be done end diff --git a/external/fieldtrip/private/nimh2grad.m b/external/fieldtrip/private/nimh2grad.m index e5e64358..f5439aab 100644 --- a/external/fieldtrip/private/nimh2grad.m +++ b/external/fieldtrip/private/nimh2grad.m @@ -56,7 +56,7 @@ % assume that the orientation of the upper coil is opposite to the lower coil ori = [ori; -ori]; else - error('do not know how to deal with higher order gradiometer hardware') + ft_error('do not know how to deal with higher order gradiometer hardware') end % add this channels coil positions and orientations @@ -73,7 +73,7 @@ grad.tra(i,end+1) = 1; grad.tra(i,end+1) = 1; else - error('do not know how to deal with higher order gradiometer hardware') + ft_error('do not know how to deal with higher order gradiometer hardware') end end diff --git a/external/fieldtrip/private/normals.m b/external/fieldtrip/private/normals.m index 67eca678..03c0f8c3 100644 --- a/external/fieldtrip/private/normals.m +++ b/external/fieldtrip/private/normals.m @@ -28,12 +28,12 @@ if nargin<3 opt='vertex'; -elseif (opt(1)=='v' | opt(1)=='V') +elseif (opt(1)=='v' || opt(1)=='V') opt='vertex'; -elseif (opt(1)=='t' | opt(1)=='T') +elseif (opt(1)=='t' || opt(1)=='T') opt='triangle'; else - error('invalid optional argument'); + ft_error('invalid optional argument'); end npnt = size(pnt,1); diff --git a/external/fieldtrip/private/peakdetect2.m b/external/fieldtrip/private/peakdetect2.m index 09876e06..07a6acb1 100644 --- a/external/fieldtrip/private/peakdetect2.m +++ b/external/fieldtrip/private/peakdetect2.m @@ -45,7 +45,7 @@ p = [p i(sect)]; else s = []; - while ~jump(sect) & sect +#include "mex.h" + +double legendre_Pmm(double m, double x) +{ + if(m == 0) + { + return 1.0; + } + else + { + double p_mm = 1.0; + double root_factor = sqrt(1.0-x)*sqrt(1.0+x); + double fact_coeff = 1.0; + int i; + for(i=1; i<=m; i++) + { + p_mm *= -fact_coeff * root_factor; + fact_coeff += 2.0; + } + return p_mm; + } +} + +double plgndr(int l, int m, double x) +{ + /* these are constant, but can only be assigned after checking the input arguments */ + double dif, sum, t_d, t_s, exp_check, err_amp; + + double p_mm, p_mmp1; + double result; + + /* determine whether we have correct input arguments */ + if (m < 0 || m > l || fabs(x) > 1.0) + mexErrMsgTxt ("Bad arguments in routine plgndr"); + + dif = l-m; + sum = l+m; + t_d = ( dif == 0.0 ? 0.0 : 0.5 * dif * (log(dif)-1.0) ); + t_s = ( dif == 0.0 ? 0.0 : 0.5 * sum * (log(sum)-1.0) ); + exp_check = 0.5 * log(2.0*l+1.0) + t_d - t_s; + err_amp = 1.0 / (0.00000000001 + fabs(1.0-fabs(x))); + p_mm = legendre_Pmm(m, x); + p_mmp1 = x * (2*m + 1) * p_mm; + + /* P_m^m(x) and P_{m+1}^m(x) */ + + if(l == m) + { + result = p_mm; + } + else if(l == m + 1) + { + result = p_mmp1; + } + else + { + /* + * upward recurrence: (l-m) P(l,m) = (2l-1) z P(l-1,m) - (l+m-1) P(l-2,m) + * start at P(m,m), P(m+1,m) + */ + + double p_ellm2 = p_mm; + double p_ellm1 = p_mmp1; + double p_ell = 0.0; + int ell; + + for(ell=(int)m+2; ell <= l; ell++) + { + p_ell = (x*(2*ell-1)*p_ellm1 - (ell+m-1)*p_ellm2) / (ell-m); + p_ellm2 = p_ellm1; + p_ellm1 = p_ell; + } + result = p_ell; + } + return result; +} + +void +mexFunction (int nlhs, mxArray * plhs[], int nrhs, const mxArray * prhs[]) +{ + int l, m; + double x; + double *pd; + + if (nrhs != 3) + mexErrMsgTxt ("invalid number of arguments for PLGNDR"); + + l = mxGetScalar (prhs[0]); + m = mxGetScalar (prhs[1]); + x = mxGetScalar (prhs[2]); + + plhs[0] = mxCreateDoubleMatrix (1, 1, mxREAL); + pd = mxGetData (plhs[0]); + pd[0] = plgndr(l, m, x); + + return; +} diff --git a/external/fieldtrip/private/plgndr.m b/external/fieldtrip/private/plgndr.m index 4796f6c8..8012d84a 100644 --- a/external/fieldtrip/private/plgndr.m +++ b/external/fieldtrip/private/plgndr.m @@ -1,4 +1,4 @@ -function [varargout] = funname(varargin) +function [varargout] = plgndr(varargin) % PLGNDR associated Legendre function % @@ -33,31 +33,30 @@ % compile the missing mex file on the fly % remember the original working directory pwdir = pwd; +pwdir_ressetter=onCleanup(@()cd(pwdir)); % determine the name and full path of this function funname = mfilename('fullpath'); mexsrc = [funname '.c']; [mexdir, mexname] = fileparts(funname); -try +mexfullpath=fullfile(mexdir,sprintf('%s.%s',mexname,mexext())); +disp(mexfullpath); +has_mex_func=@()exist(mexfullpath,'file'); + +if ~has_mex_func() % try to compile the mex file on the fly - warning('trying to compile MEX file from %s', mexsrc); + ft_warning('trying to compile MEX file from %s', mexsrc); cd(mexdir); mex(mexsrc); - cd(pwdir); - success = true; - -catch - % compilation failed - disp(lasterr); - error('could not locate MEX file for %s', mexname); - cd(pwdir); - success = false; -end -if success - % execute the mex file that was juist created - funname = mfilename; - funhandle = str2func(funname); - [varargout{1:nargout}] = funhandle(varargin{:}); + if ~has_mex_func() + ft_error('could not locate / compile MEX file for %s in %s', ... + mexname, mexfullpath); + end end + +% execute the mex file that was juist created +funname = mfilename; +funhandle = str2func(funname); +[varargout{1:nargout}] = funhandle(varargin{:}); diff --git a/external/fieldtrip/private/plgndr.mexmaci64 b/external/fieldtrip/private/plgndr.mexmaci64 index 150761817ac3a5560e95ce3bad034bb254698484..4433ed690bfec047ba593a38df65b483a1457369 100755 GIT binary patch literal 8768 zcmeHNU2GIp6uz@9w3NbZ2_jmQ!B|uIDQ!#?VhFpim2E5tv_Mhdy6w)k8}^Uc*}4UR z#@fgVCHv@u55^}SG||KueL&l-S}aBcBLXGZ#7GvaNnH~{h++NC%$>5`TH}KcKFmq( zJ@@>5_uMmgvO9C<{GH$KmN6!kFviN!oM^E*jP-*PJ%E;UFvfXnV_U1Cn%+@BAqg3n z3^0s15$C#^)XlLePsbadZ`$6*Ttp<7nnSZMWxa(W=W#vJ9-mSb=l9A&)3j80kStAk zW32*juF#oyyh{zmR1Lafyf+2jI^j>UNY&KL$gd+BiQijrG2Xbqa|t|>r>$4$Eyj6A zT-Sn;PN68qQ)JVyMc6Ibil3G%l$<9bF9joh9*hK{hCKaxbP2qD0)XUV3=5k$=V})Z zXuhy&YK!wbEAZ+?5XrRXW+U2nSv1Z)?pAk!m$lz!;k4ff*UFXiNQlRK!tK!zkLlX1 zcorPp0EKzc{wTaIoQHh>gy$4M3gU=JF2tk!tUX6|TBjF{^X8^)&o+9Rtb0s>lE_L- zF(l>^3nQGu{rm`Hz4hdxnD=oxxV85UHRLu7lHjz535M*GkmrHFvx2cV!09&Jjz&a2 zR-+ow{X84>BEI5pjMdQ5Jfp9D_(A&lb>$~2GR;pucW~lS=!~V!LsUftTWQJQM3rc? z9*U(LEOKcvpWd}L6l@PC>-;_7rsZGwtAznG{gVKa*xE!~BXnvVt5(%Dh)KwQ9ooHo z&Y&dI{abqCx*D$ARG8Oeh@o}9ubBLCArC?(T7^b-l4-p**%h!WU{}DdfL($Aq5`|T zshy2V9Y5vdwo!15 z_g?#$eu5EDa|Q$OHSZaLwYjuhdkzk8-1`lt`5Hmr%X@C+TJn;_ds@3FYn7AMVuM{;_1Wd;Rs7mjHRrK?AvU1i^DQV%)vNJFubKn6~O@ zHajjE2^`J#kLgFqzZ$0gv12`$@;e}&Mf&HF_E#AHh-@xnJcjJ9OfBI-1IxMQ7a+lD zGC))(FMri2x49mmOs(gO!u4E21lBXL5K}LB3kVaXG%2!APzi@7jtzLKCFJrg5Pm?r zFtAzjte-TjnTZz%Hak$JL1>P*!n5QPB*Rh}grY6?FgBo<|B1^5gi91n;P8i-fjELT zgau|yj|(~ZK&CI_7|`cS`618xTgQgHeV;pDa37#ro9i*^y~n-V-D=d_n>yE&y4825 zM6X0yH(~+V)5ySk^66|Zc+MlQzU@7Eq&!Q{KqQSra%TM`$yJS)KSKojl)8qC*-cpf-({vy1NL^N1-iQ`+Y~;O6^>)0EFh*0RK@vUh(*H|ped5`W#`Nq^i6@X{ z!ZS@F4ko1$ST(;?TEQFy$re)wk`C`=Qqn0oE6d8$u*{}6y=V6Cin%`$d{FRF!DmL; z8oL5^1?&pg6|gH{SHP}-T>-lSb_MJT*cGrVU{~P(UV*9=PUFOJu?vT3e&bM`x8qzG zhu}L7u{1m6ta9;ia7DFNpJ~?nalZbTa!Dxi74g^E0rXETJHP!En1-n%(PWpxt zHeQVvA(Qm}Wc>cLH0hu>8z$YkUP;H2tIFeTF$3Waj7DNp4}$yM)J_$zoK(I&9A;d+f1)Z*Rgi>Pia5RgvtLnItZQiw#Z{cKJIp-UU&E+b-2eap literal 8800 zcmeHNU2GIp6u#STVUfaYi5di?1F;DLE+v4rQFIr!vK5MjE>N`bvfG_)S9fR2>@1WY zV@=g$gH8H?@$W%=(8LE5^ohhoTBuqSu^Jv46Jrx&vKUNs!H5JIzcX{E-Q8Nki-`|& zl6%iR=iYPfIp3Yxow;|ux&G_T*^Id=8Dk!lc_`Pa7<(C<=pK~b3dT4OH?@aNRcYld z6`7FXlfexmPQ@n;4hd8f-mN5i6b;&Pe_g`gv%U7 z4kcq#_A~jj-O=@H+fG?cwK!LC%~_XTkFHIN&nq0+{zxufOS;~QapXK1xs^XzIFdyO zBp3UmeC=zPh7fKc6wbFbZ{OM!Y_{)N8A>8MFxiyYKH-e~6yG0C!KM#1TJZ$%-Z_^HtR z6bJoo%tSq~zoV#gP`2A12JQ+x}%&1e*7&Iv^ z`KlW5hqfy&tr!dCem=Z3yQCm_A6O0DIp{t+E7kTDjllLI_~nAsF%P@?A;9^&>@h3zvhK^Cp-Ga&Yj_T2Y%`S>9&^V&+ z9@tue=!OD~=Z`*-8y(Q+7z5$C#{J{K5@WtMhEabD`wRV_SAd-{&e)D9n=gS6Jg*!w z$U{MTX7qW=YBMaqg@Ih*j@0Q)|v$Z42eTLT+;Z^-7%*xPs*K^kg17_Hh0v zIHf!uI(Ed9SA{eI$(!E?Y3+BPB2{*pDifOgqiBV4Uo_|3_vPvT8W6xbXF@SikXBzq z`JI&c{F^ro14fmIPd4K->ULwrjkejW<=*PC@+1D5C*&Nv@|c0<`Yx1-qIW-%?GBY$w2q_wDMO$Yi8PT9(F7o<#R_)XiX_a{^*~vu|hm3+9k69}OuNR#5 zWJpiDA4_RVM9^K}^C8>c5BP+9oDLX40Tk-T{*6gb3K@GjChbAJ6bFv>c{v?lOBi1- z&iiRc&&6Dm+eLkrj1d;SRVKezCVyN-vd~u+&m6Ac`}`TF5AO+Qt48#L#Oc8RElx2T_@951hVxNL57tq ZLFp>byuRqMSJrBZH7yO!{73(h&KFq2f44b_fXNrLZHop*;-~a&Q3=D<< delta 33 mcmZp0XmFVDgT?RPr_hOie3+jwGj8@~oGAtt*!)6Vf&%~p{|ghFfn~|_r;!uC_%QQGGH!NebQA{*Z0?Y#-~<5p5e>iq delta 33 lcmZp0X>ghFfhCmrbLhk`KFpmS44a)99mT-{n>!>bI04-E3>g3b diff --git a/external/fieldtrip/private/pntdist.m b/external/fieldtrip/private/pntdist.m new file mode 100644 index 00000000..f1292f87 --- /dev/null +++ b/external/fieldtrip/private/pntdist.m @@ -0,0 +1,24 @@ +function dist = pntdist(p1, p2) + +% PNTDIST returns the euclidian distance between two points +% +% [dist] = pntdist(pnt1, pnt2) +% +% where pnt1 and pnt2 must be Npnt x 3 +% or either one can be Npnt x 1 + +% Copyright (C) 2002, Robert Oostenveld +% +% $Log: pntdist.m,v $ +% Revision 1.2 2003/03/04 21:46:19 roberto +% added CVS log entry and synchronized all copyright labels +% + +if size(p1,1)==1 + p1 = repmat(p1, size(p2,1), 1); +elseif size(p2,1)==1 + p2 = repmat(p2, size(p1,1), 1); +end + +dist = sqrt(sum((p1-p2).^2, 2)); + diff --git a/external/fieldtrip/private/poly2tri.m b/external/fieldtrip/private/poly2tri.m index 99cd3833..05c7b5b6 100644 --- a/external/fieldtrip/private/poly2tri.m +++ b/external/fieldtrip/private/poly2tri.m @@ -11,9 +11,9 @@ % See also MESH2EDGE if ~isfield(mesh, 'poly') - error('the mesh does not contain polygons') + ft_error('the mesh does not contain polygons') elseif ~size(mesh.poly,2)==4 - error('this is only implemented for polygons with 4 corner points') + ft_error('this is only implemented for polygons with 4 corner points') end % there are 4 vertices per polygon, which do not have to ly in a single plane diff --git a/external/fieldtrip/private/pos2dim.m b/external/fieldtrip/private/pos2dim.m index 6c96f6ff..26622c0a 100644 --- a/external/fieldtrip/private/pos2dim.m +++ b/external/fieldtrip/private/pos2dim.m @@ -5,7 +5,7 @@ % % Use as % [dim] = pos2dim(pos) -% where pos is an ordered list of positions +% where pos is an ordered list of positions. % % The output dim is a 3-element vector which correspond to the 3D % volumetric dimensions @@ -15,6 +15,7 @@ % Copyright (C) 2009, Jan-Mathijs Schoffelen if isstruct(pos) + % the input is a FieldTrip data structure pos = pos.pos; end diff --git a/external/fieldtrip/private/pos2dim3d.m b/external/fieldtrip/private/pos2dim3d.m index 366654de..757b14f8 100644 --- a/external/fieldtrip/private/pos2dim3d.m +++ b/external/fieldtrip/private/pos2dim3d.m @@ -5,10 +5,13 @@ % elements are appended to the output. % % Use as -% [dim] = pos2dim3d(pos, dimold) where pos is an ordered list of positions -% and dimold optionally the original dimensionality of the functional data -% The output dim is a 3+ element vector of which the first three elements -% correspond to the 3D volumetric dimensions +% [dim] = pos2dim3d(pos, dimold) +% where pos is an ordered list of positions and where the (optional) +% dimold is a vector with the original dimensionality of the anatomical +% or functional data. +% +% The output dim is a 1x3 or 1xN vector of which the first three elements +% correspond to the 3D volumetric dimensions. % % See also POS2DIM, POS2TRANSFORM @@ -17,7 +20,7 @@ if nargin==1 && ~isstruct(pos), dimold = zeros(0,2); elseif isstruct(pos), - %the input is a structure + % the input is a FieldTrip data structure dimord = pos.dimord; dimtok = tokenize(dimord, '_'); for i = 1:length(dimtok) @@ -27,10 +30,10 @@ dimold(i,1) = numel(getfield(pos, dimtok{i})); end end - pos = pos.pos; + pos = pos.pos; else if size(pos,1)~=dimold(1), - error('the first element in the second input should be equal to the number of positions'); + ft_error('the first element in the second input should be equal to the number of positions'); end end diff --git a/external/fieldtrip/private/pos2transform.m b/external/fieldtrip/private/pos2transform.m index 3030bc97..a15403c4 100644 --- a/external/fieldtrip/private/pos2transform.m +++ b/external/fieldtrip/private/pos2transform.m @@ -4,8 +4,8 @@ % of positions. % % Use as -% [transform] = pos2transform(pos, dim) where pos is an ordered list of positions -% and should specify a full 3D volume +% [transform] = pos2transform(pos, dim) +% where pos is an ordered list of positions that should specify a full 3D volume. % % The output transform is a 4x4 homogenous transformation matrix which transforms % from 'voxelspace' into the positions provided in the input diff --git a/external/fieldtrip/private/prepare_design.m b/external/fieldtrip/private/prepare_design.m index a4fb1b2e..f3b5803e 100644 --- a/external/fieldtrip/private/prepare_design.m +++ b/external/fieldtrip/private/prepare_design.m @@ -66,18 +66,18 @@ % determine whether a beween or a within-units design is requested. if any(strcmp(cfg.statistic,{'indepsamplesT','indepsamplesregrT','indepsamplesZcoh','indepsamplesF'})) designtype = 'between'; -end; +end if any(strcmp(cfg.statistic,{'depsamplesregrT','depsamplesT','actvsblT','depsamplesFmultivariate'})) designtype = 'within'; -end; +end if ~(exist('designtype')==1) - warning('Unknown test statistic.'); + ft_warning('Unknown test statistic.'); return -end; +end if ~isfield(cfg,'design') - error('You should specify an initial design in cfg.design.'); -end; + ft_error('You should specify an initial design in cfg.design.'); +end initialdesign=cfg.design; if strcmp(designtype,'between') % between-units conditions @@ -85,15 +85,15 @@ cfg.design=initialdesign(:,end); % the default option if ~isfield(cfg,'ivar') cfg.ivar = 1; - end; + end % overwrite the default option if there is a .ext-field in the % configuration if isfield(cfg,'ext') if size(cfg.ext,1)~=size(initialdesign,1) - error('Incompatible number of replications in cfg.ext.'); - end; + ft_error('Incompatible number of replications in cfg.ext.'); + end design=cfg.ext; - end; + end elseif strcmp(designtype,'within') % within-units conditions % construct the design matrix @@ -110,16 +110,16 @@ for wcondindx=1:nwcond selvec = (cfg.design(:,1)==wcondlabels(wcondindx)); unitsthiscond = sort(cfg.design(selvec,2)); - if length(unitthiscond)==length(unitlabels) & ~all(unitthiscond==unitlabels) - error('The last two columns of initialdesign do not specify a within-units design.'); - end; - end; + if length(unitthiscond)==length(unitlabels) && ~all(unitthiscond==unitlabels) + ft_error('The last two columns of initialdesign do not specify a within-units design.'); + end + end if ~isfield(cfg,'ivar') cfg.ivar = 1; - end; + end if ~isfield(cfg,'uvar') cfg.uvar = 2; - end; + end % overwrite the default option if there is a .ext-field in the % configuration if isfield(cfg,'ext') @@ -129,17 +129,17 @@ for wcondindx=1:nwcond for unitindx=1:nunits cfg.design(((wcondindx-1)*nunits + unitindx),[1:dimext(2)])=cfg.ext; - end; - end; + end + end elseif dimext(1)==nrepl cfg.design(:,[1:dimext(2)])=cfg.ext; else - error('The number of rows in cfg.ext must be equal to the number of conditions or the number of replications (number of conditions times number of units-of-observation).'); - end; + ft_error('The number of rows in cfg.ext must be equal to the number of conditions or the number of replications (number of conditions times number of units-of-observation).'); + end cfg.design(:,dimext(2)+1)=initialdesign(:,(end-1)); cfg.uvar = size(design,2); - end; -end; + end +end % add version information to the configuration cfg.version.name = mfilename('fullpath'); diff --git a/external/fieldtrip/private/prepare_freq_matrices.m b/external/fieldtrip/private/prepare_freq_matrices.m index e1f5ee35..b197ba06 100644 --- a/external/fieldtrip/private/prepare_freq_matrices.m +++ b/external/fieldtrip/private/prepare_freq_matrices.m @@ -32,8 +32,9 @@ cfg = ft_checkconfig(cfg, 'deprecated', 'dicsfix'); if ~isfield(cfg, 'keeptrials'), cfg.keeptrials = 1; end if ~isfield(cfg, 'refchan'), cfg.refchan = []; end +if ~isfield(cfg, 'rawtrial'), cfg.rawtrial = []; end -keeptrials = istrue(cfg.keeptrials); +keeptrials = istrue(cfg.keeptrials) || istrue(cfg.rawtrial); Cf = []; Cr = []; @@ -102,7 +103,7 @@ if isfield(cfg, 'refchan') && ~isempty(cfg.refchan) refindx = match_str(freq.label, cfg.refchan); if isempty(refindx), - error('the requested reference channel is not found in the data'); + ft_error('the requested reference channel is not found in the data'); end if any(strncmp(tok, 'rpt', 3)), Cr = freq.crsspctrm(:,chanindx,refindx); @@ -115,9 +116,9 @@ % do a sanity check on the cross-spectral-density matrix if any(isnan(Cf(:))) - error('The cross-spectral-density matrix is not complete'); + ft_error('The cross-spectral-density matrix is not complete'); end if any(isnan(Cr(:))) - error('The cross-spectral-density with the reference channel is not complete'); + ft_error('The cross-spectral-density with the reference channel is not complete'); end diff --git a/external/fieldtrip/private/prepare_headmodel.m b/external/fieldtrip/private/prepare_headmodel.m index e3d5276e..24565c16 100644 --- a/external/fieldtrip/private/prepare_headmodel.m +++ b/external/fieldtrip/private/prepare_headmodel.m @@ -43,15 +43,32 @@ cfg.order = ft_getopt(cfg, 'order', 10); % order of expansion for Nolte method; 10 should be enough for real applications; in simulations it makes sense to go higher cfg.siunits = ft_getopt(cfg, 'siunits', 'no'); % yes/no, ensure that SI units are used consistently -if nargin<2 - data = []; +hasdata = (nargin>1); + +if hasdata + % check if the input data is valid for this function + data = ft_checkdata(data); + % set the default for senstype depending on the data + if isfield(data, 'grad') + cfg.senstype = ft_getopt(cfg, 'senstype', 'meg'); + elseif isfield(data, 'elec') + cfg.senstype = ft_getopt(cfg, 'senstype', 'eeg'); + elseif isfield(data, 'opto') + cfg.senstype = ft_getopt(cfg, 'senstype', 'opto'); + else + cfg.senstype = ft_getopt(cfg, 'senstype', []); + end end % get the volume conduction model headmodel = ft_fetch_vol(cfg); % get the gradiometer or electrode definition, these can be in the cfg or in the data -sens = ft_fetch_sens(cfg, data); +if hasdata + sens = ft_fetch_sens(cfg, data); +else + sens = ft_fetch_sens(cfg); +end if istrue(cfg.siunits) % ensure that the geometrical units are in SI units @@ -72,11 +89,11 @@ end end -if isfield(data, 'topolabel') +if hasdata && isfield(data, 'topolabel') % the data reflects a componentanalysis, where the topographic and the % timecourse labels are different cfg.channel = ft_channelselection(cfg.channel, data.topolabel); -elseif isfield(data, 'label') +elseif hasdata && isfield(data, 'label') % In the subsequent code, the matching channels in the sensor array and % in the configuration will be selected. To ensure that these channels % are also present in the data, update the configuration to match the data. diff --git a/external/fieldtrip/private/prepare_cortexhull.m b/external/fieldtrip/private/prepare_mesh_cortexhull.m similarity index 55% rename from external/fieldtrip/private/prepare_cortexhull.m rename to external/fieldtrip/private/prepare_mesh_cortexhull.m index 6af5a653..a71888f4 100644 --- a/external/fieldtrip/private/prepare_cortexhull.m +++ b/external/fieldtrip/private/prepare_mesh_cortexhull.m @@ -1,29 +1,27 @@ -function headshape = prepare_cortexhull(cfg) +function headshape = prepare_mesh_cortexhull(cfg) -% PREPARE_CORTEXHULL creates a mesh representing the cortex hull, i.e. the -% smoothed envelope around the pial surface created by freesurfer. -% PREPARE_CORTEXHULL relies on freesurfer's command line functions and -% 'make_outer_surface' in the freesurfer/matlab folder +% PREPARE_MESH_CORTEXHULL creates a mesh representing the cortex hull, i.e. the +% smoothed envelope around the pial surface created by FreeSurfer. +% +% This function relies on FreeSurfer's command line functions and +% 'make_outer_surface' in the FreeSurfer/matlab folder % % Configuration options: -% cfg.method = 'cortexhull' -% cfg.headshape = a filename containing the pial surface computed by -% freesurfer recon-all ('/path/to/surf/lh.pial') -% cfg.resolution = (optional, default: 1) resolution of the volume +% cfg.method = 'cortexhull' +% cfg.headshape = a filename containing the pial surface computed by +% FreeSurfer recon-all ('/path/to/surf/lh.pial') +% cfg.resolution = (optional, default: 1) resolution of the volume % delimited by headshape being floodfilled by mris_fill +% cfg.fshome = FreeSurfer folder location (default: '/Applications/freesurfer') % cfg.outer_surface_sphere = (optional, default: 15) diameter of the sphere % used by make_outer_surface to close the sulci using % morphological operations. % cfg.smooth_steps = (optional, default: 60) number of smoothing iterations % performed by mris_smooth % -% Error that 'mris_fill' was not found means that freesurfer is not installed. -% Error that 'make_outer_surface' is not in matlab, means that you need to add -% 'freesurfer/matlab' to your path. -% % See also FT_PREPARE_MESH -% Copyright (C) 2012-2016, Gio Piantoni, Andrew Dykstra +% Copyright (C) 2012-2016, Gio Piantoni, Andrew Dykstra, Arjen Stolk % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -46,16 +44,23 @@ disp('Please cite: Dykstra et al. 2012 Neuroimage PMID: 22155045') % get the default options -resolution = ft_getopt(cfg, 'resolution', 1); +resolution = ft_getopt(cfg, 'resolution', 1); outer_surface_sphere = ft_getopt(cfg, 'outer_surface_sphere', 15); -smooth_steps = ft_getopt(cfg, 'smooth_steps', 60); +smooth_steps = ft_getopt(cfg, 'smooth_steps', 60); +headshape = ft_getopt(cfg, 'headshape'); +fshome = ft_getopt(cfg, 'fshome', '/Applications/freesurfer'); -headshape = ft_getopt(cfg, 'headshape'); +% add the FreeSurfer environment +fprintf('adding the FreeSurfer environment\n') +addpath([fshome '/matlab']); % where make_outer_surface is located +setenv('FREESURFER_HOME', fshome); +PATH = getenv('PATH'); +setenv('PATH', [PATH ':' fshome '/bin']); % where mris_fill is located % temporary files -surf_filled = [tempname() '_pial.filled.mgz']; -surf_outer = [tempname() '_pial_outer']; -surf_smooth = [tempname() '_pial_smooth']; +surf_filled = [tempname() '_pial.filled.mgz']; +surf_outer = [tempname() '_pial_outer']; +surf_smooth = [tempname() '_pial_smooth']; cmd = sprintf('mris_fill -c -r %d %s %s', resolution, headshape, ... surf_filled); diff --git a/external/fieldtrip/private/prepare_mesh_headshape.m b/external/fieldtrip/private/prepare_mesh_headshape.m index f9835c6b..a5ad80ac 100644 --- a/external/fieldtrip/private/prepare_mesh_headshape.m +++ b/external/fieldtrip/private/prepare_mesh_headshape.m @@ -2,6 +2,12 @@ % PREPARE_MESH_HEADSHAPE % +% Configuration options: +% cfg.headshape = a filename containing headshape, a Nx3 matrix with surface +% points, or a structure with a single or multiple boundaries +% cfg.smooth = a scalar indicating the number of non-shrinking +% smoothing iterations (default = no smoothing) +% % See also PREPARE_MESH_MANUAL, PREPARE_MESH_SEGMENTATION % Copyrights (C) 2009, Robert Oostenveld @@ -26,6 +32,7 @@ % get the specific options cfg.headshape = ft_getopt(cfg, 'headshape'); +cfg.smooth = ft_getopt(cfg, 'smooth'); % no default if isa(cfg, 'config') % convert the config-object back into a normal structure @@ -51,7 +58,7 @@ % read the headshape from file headshape = ft_read_headshape(cfg.headshape); else - error('cfg.headshape is not specified correctly') + ft_error('cfg.headshape is not specified correctly') end % usually a headshape only describes a single surface boundaries, but there are cases @@ -95,9 +102,16 @@ end end +% smooth the mesh +if ~isempty(cfg.smooth) + for i=1:nmesh + [headshape(i).pos,headshape(i).tri] = fairsurface(headshape(i).pos, headshape(i).tri, cfg.smooth); + end +end + % the output should only describe one or multiple boundaries and should not % include any other fields -mesh = rmfield(headshape, setdiff(fieldnames(headshape), {'pos', 'tri'})); +mesh = keepfields(headshape, {'pos', 'tri'}); function [tri1, pos1] = refinepatch(tri, pos, numvertices) fprintf('the original mesh has %d vertices against the %d requested\n',size(pos,1),numvertices/3); @@ -134,7 +148,7 @@ phi(end+1) = newphi; th(end+1) = (j/Q)*2*pi; % in case of even number of contours - if mod(M,2) & k>(M/2) + if mod(M,2) && k>(M/2) th(end) = th(end) + pi/Q; end end diff --git a/external/fieldtrip/private/prepare_mesh_hexahedral.m b/external/fieldtrip/private/prepare_mesh_hexahedral.m index a9e1922b..003d331d 100644 --- a/external/fieldtrip/private/prepare_mesh_hexahedral.m +++ b/external/fieldtrip/private/prepare_mesh_hexahedral.m @@ -26,7 +26,7 @@ if isempty(cfg.tissue) mri = ft_datatype_segmentation(mri, 'segmentationstyle', 'indexed'); fn = fieldnames(mri); - for i = 1:numel(fn), + for i = 1:numel(fn) if (numel(mri.(fn{i})) == prod(mri.dim)) && (~strcmp(fn{i}, 'inside')) segfield = fn{i}; end @@ -52,10 +52,10 @@ end if isempty(cfg.shift) - warning('No node-shift selected') + ft_warning('No node-shift selected') cfg.shift = 0; elseif cfg.shift > 0.3 - warning('Node-shift should not be larger than 0.3') + ft_warning('Node-shift should not be larger than 0.3') cfg.shift = 0.3; end @@ -74,7 +74,7 @@ seg = seg - 1; seg = reshape(seg, mri.dim); catch - error('Please specify cfg.tissue to correspond to tissue types in the segmented MRI') + ft_error('Please specify cfg.tissue to correspond to tissue types in the segmented MRI') end tissue = cfg.tissue; else @@ -88,7 +88,7 @@ try tissue{i} = mri.seglabel{cfg.tissue(i)}; catch - error('Please specify cfg.tissue to correspond to (the name or number of) tissue types in the segmented MRI') + ft_error('Please specify cfg.tissue to correspond to (the name or number of) tissue types in the segmented MRI') end else tissue{i} = sprintf('tissue %d', i); @@ -118,10 +118,10 @@ seg_array = [seg_array, seg_build.anatomy(:)]; - clear seg_reslice; + clear seg_reslice end - [max_seg seg_build.seg] = max(seg_array, [], 2); + [max_seg, seg_build.seg] = max(seg_array, [], 2); clear max_seg seg_array; @@ -129,35 +129,33 @@ seg_build.seg = seg_indices(seg_build.seg); seg_build.transform = mri.transform; - clear seg_build.anatomy; + clear seg_build.anatomy else seg_build.seg = seg; seg_build.dim = mri.dim; - clear seg; + clear seg end % ensure that the segmentation is binary and that there is a single contiguous region % FIXME is this still needed when it is already binary? %seg = volumethreshold(seg, 0.5, tissue); +% the following requires the simbio toolbox to be on the path ft_hastoolbox('simbio', 1); % build the mesh - mesh = build_mesh_hexahedral(cfg, seg_build); -% converting position of meshpoints to the head coordinate system - if (cfg.resolution ~= 1) - mesh.pnt = cfg.resolution * mesh.pnt; + mesh.pos = cfg.resolution * mesh.pos; end -mesh.pnt = ft_warp_apply(mri.transform, mesh.pnt, 'homogeneous'); +% converting position of meshpoints to the head coordinate system +mesh.pos = ft_warp_apply(mri.transform, mesh.pos, 'homogeneous'); labels = mesh.labels; - -clear mesh.labels; +mesh = rmfield(mesh, 'labels'); mesh.tissue = zeros(size(labels)); numlabels = size(unique(labels), 1); @@ -168,10 +166,11 @@ mesh.tissuelabel{i} = tissue{i}; end - end % function -%% subfunctions %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTIONS +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function mesh = build_mesh_hexahedral(cfg, mri) @@ -202,19 +201,15 @@ mesh.hex = create_elements(x_dim, y_dim, z_dim); fprintf('Created elements...\n' ) - % create nodes -mesh.pnt = create_nodes(x_dim, y_dim, z_dim); +mesh.pos = create_nodes(x_dim, y_dim, z_dim); fprintf('Created nodes...\n' ) - -if(shift < 0 | shift > 0.3) - error('Please choose a shift parameter between 0 and 0.3!'); -elseif(shift > 0) - - mesh.pnt = shift_nodes(mesh.pnt, mesh.hex, labels, shift, x_dim, y_dim, z_dim); - +if shift < 0 || shift > 0.3 + ft_error('Please choose a shift parameter between 0 and 0.3!'); +elseif shift > 0 + mesh.pos = shift_nodes(mesh.pos, mesh.hex, labels, shift, x_dim, y_dim, z_dim); end %background = 1; @@ -229,8 +224,8 @@ % delete unused nodes [C, ia, ic] = unique(mesh.hex(:)); -mesh.pnt = mesh.pnt(C, :, :, :); -mesh.pnt = mesh.pnt + repmat(shift_coord, size(mesh.pnt, 1), 1); +mesh.pos = mesh.pos(C, :, :, :); +mesh.pos = mesh.pos + repmat(shift_coord, size(mesh.pos, 1), 1); mesh.hex(:) = ic; end % subfunction @@ -257,10 +252,10 @@ % x_dim+1) b = b(mod(b, (x_dim+1)) ~= 0); % repeat offset to make it fit the number of elements -b = repmat(b, 1, (z_dim)); +b = repmat(b, 1, z_dim); % create vector accounting for the offset of the nodes in z-direction -c = fix([0:((x_dim)*(y_dim)*(z_dim)-1)]/((x_dim)*(y_dim))) * (x_dim+1)*(y_dim+1); +c = fix( (0:(x_dim*y_dim*z_dim-1)) / (x_dim*y_dim)) * (x_dim+1)*(y_dim+1); % create the elements by assigning the nodes to them. entries 1 through 4 % describe the bottom square of the hexahedron, entries 5 through 8 the top @@ -269,13 +264,13 @@ elements(:, 2) = b + c + 1; elements(:, 3) = b + c + (x_dim+1) + 1; elements(:, 4) = b + c + (x_dim+1); -elements(:, 5) = b + c + (x_dim + 1)*(y_dim+1); -elements(:, 6) = b + c + (x_dim + 1)*(y_dim+1) + 1; -elements(:, 7) = b + c + (x_dim + 1)*(y_dim+1) + (x_dim+1) + 1; -elements(:, 8) = b + c + (x_dim + 1)*(y_dim+1) + (x_dim+1); +elements(:, 5) = b + c + (x_dim+1) * (y_dim+1); +elements(:, 6) = b + c + (x_dim+1) * (y_dim+1) + 1; +elements(:, 7) = b + c + (x_dim+1) * (y_dim+1) + (x_dim+1) + 1; +elements(:, 8) = b + c + (x_dim+1) * (y_dim+1) + (x_dim+1); clear b; clear c; -end %subfunction +end % subfunction % function creating the nodes and assigning coordinates in the % [0, x_dim]x[0, y_dim]x[0, z_dim] box. for details on the node-numbering see @@ -283,20 +278,19 @@ function nodes = create_nodes(x_dim, y_dim, z_dim) nodes = zeros(((x_dim+1)*(y_dim+1)*(z_dim + 1)), 3); % offset vector for node coordinates -b = [0:((x_dim+1)*(y_dim+1)*(z_dim+1)-1)]; +b = 0:((x_dim+1)*(y_dim+1)*(z_dim+1)-1); % assign coordinates within the box nodes(:, 1) = mod(b, (x_dim+1)); nodes(:, 2) = mod(fix(b/(x_dim+1)), (y_dim+1)); nodes(:, 3) = fix(b/((x_dim + 1)*(y_dim+1))); -clear b; +clear b -end +end % subfunction % function shifting the nodes function nodes = shift_nodes(points, hex, labels, sh, x_dim, y_dim, z_dim) -cfg = []; fprintf('Applying shift %f\n', sh); nodes = points; @@ -376,7 +370,7 @@ end % fill up the last column with the amount of background labels -distribution(:, (size(unique(labels), 1))) = 8 - sum(distribution(:, 1:size(unique(labels), 1))'); +distribution(:, (size(unique(labels), 1))) = 8 - sum(distribution(:, 1:size(unique(labels), 1)),2); % how many different labels are there around each node distsum = sum(distribution>0, 2); @@ -401,7 +395,6 @@ tbc = zeros(size(surroundinglabels)); % helper matrix, c(i, j, k) is one when surroundinglabels(i, j) == k for i = 1:size(unique(labels), 1)+1 - c = zeros(size(surroundinglabels, 2), size(unique(labels), 1)+1); if (i == size(unique(labels), 1)+1) c = surroundinglabels == 0; else @@ -428,7 +421,8 @@ % for i = 1:size(unique(labels), 1)+1 % tbc(ismember(minpos, i) == 1, :) = c(ismember(minpos, i) == 1, :, i); % end -clear c; + +clear c % delete cases in which we don't have a real minimum tbcsum = sum(tbc, 2); @@ -449,17 +443,16 @@ surroundingconsidered(nodes(b, 3) > 0, 6) = (offset(nodes(b, 3) > 0, 1) - (x_dim)*(y_dim) - 1).*tbc(nodes(b, 3) > 0, 6); surroundingconsidered(nodes(b, 3) > 0, 7) = (offset(nodes(b, 3) > 0, 1) - (x_dim)*(y_dim) - x_dim).*tbc(nodes(b, 3) > 0, 7); surroundingconsidered((nodes(b, 3) > 0) & (nodes(b, 2) > 0), 8) = (offset((nodes(b, 3) > 0) & (nodes(b, 2) > 0), 1) - (x_dim)*(y_dim) - (x_dim) -1).*tbc((nodes(b, 3) > 0) & (nodes(b, 2) > 0), 8); -%clear surrounding; -clear tbc; +%clear surrounding +clear tbc tbcsum(tbcsum == 8) = 0; tbcsum(tbcsum == 4) = 0; tbcsum((distsum>2) & (mins > 1)) = 0; -clear distsum; +clear distsum % get the surrounding elements which are to be considered for the shift - % use the dummy centroid to make computations easier surroundingconsidered(surroundingconsidered == 0) = size(centroids, 1); @@ -478,7 +471,4 @@ nodes(tbcsum == 0, :) = points(tbcsum == 0, :); nodes(tbcsum ~= 0, :) = (1-sh)*nodes(tbcsum ~= 0, :) + sh*centroidcomb(tbcsum ~= 0, :); -end %subfunction - - - +end % subfunction diff --git a/external/fieldtrip/private/prepare_mesh_manual.m b/external/fieldtrip/private/prepare_mesh_manual.m index 87349bec..f23df6dd 100644 --- a/external/fieldtrip/private/prepare_mesh_manual.m +++ b/external/fieldtrip/private/prepare_mesh_manual.m @@ -50,7 +50,7 @@ % check the consistency of the input arguments if hasheadshape && hasbnd - error('you should not specify cfg.headshape and cfg.bnd simultaneously'); + ft_error('you should not specify cfg.headshape and cfg.bnd simultaneously'); end % check the consistency of the input arguments @@ -487,7 +487,7 @@ function keypress(h, eventdata, handles, varargin) setappdata(fig,'slicedata',slicedata); end otherwise - warning('invalid button (%d)', k); + ft_warning('invalid button (%d)', k); end end diff --git a/external/fieldtrip/private/prepare_mesh_segmentation.m b/external/fieldtrip/private/prepare_mesh_segmentation.m index 1a3894fa..c1515203 100644 --- a/external/fieldtrip/private/prepare_mesh_segmentation.m +++ b/external/fieldtrip/private/prepare_mesh_segmentation.m @@ -2,7 +2,15 @@ % PREPARE_MESH_SEGMENTATION % -% See also PREPARE_MESH_MANUAL, PREPARE_MESH_HEADSHAPE, PREPARE_MESH_HEXAHEDRAL +% The following configuration options can be specified if cfg.method = iso2mesh: +% cfg.maxsurf = 1 = only use the largest disjointed surface +% 0 = use all surfaces for that levelset +% cfg.radbound = a scalar indicating the radius of the target surface +% mesh element bounding sphere +% +% See also PREPARE_MESH_MANUAL, PREPARE_MESH_HEADSHAPE, +% PREPARE_MESH_HEXAHEDRAL, PREPARE_MESH_TETRAHEDRAL + % Copyrights (C) 2009, Robert Oostenveld % @@ -24,13 +32,14 @@ % % $Id$ - % ensure that the input is consistent with what this function expects mri = ft_checkdata(mri, 'datatype', {'volume', 'segmentation'}, 'hasunit', 'yes'); % get the default options cfg.spmversion = ft_getopt(cfg, 'spmversion', 'spm8'); cfg.method = ft_getopt(cfg, 'method', 'projectmesh'); +cfg.maxsurf = ft_getopt(cfg, 'maxsurf', 1); +cfg.radbound = ft_getopt(cfg, 'radbound', 3); if all(isfield(mri, {'gray', 'white', 'csf'})) cfg.tissue = ft_getopt(cfg, 'tissue', 'brain'); % set the default cfg.numvertices = ft_getopt(cfg, 'numvertices', 3000); % set the default @@ -40,28 +49,24 @@ cfg.numvertices = ft_getopt(cfg, 'numvertices'); end -% check that SPM is on the path, try to add the preferred version -if strcmpi(cfg.spmversion, 'spm2'), - ft_hastoolbox('SPM2',1); -elseif strcmpi(cfg.spmversion, 'spm8'), - ft_hastoolbox('SPM8',1); -end +% check that the preferred SPM version is on the path +ft_hastoolbox(cfg.spmversion, 1); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % try to determine the tissue (if not specified) % special exceptional case first if isempty(cfg.tissue) && numel(cfg.numvertices)==1 && isfield(mri,'white') && isfield(mri,'gray') && isfield(mri,'csf') - mri=ft_datatype_segmentation(mri, 'segmentationstyle', 'probabilistic', 'hasbrain', 'yes'); - cfg.tissue='brain'; + mri = ft_datatype_segmentation(mri, 'segmentationstyle', 'probabilistic', 'hasbrain', 'yes'); + cfg.tissue = 'brain'; end if isempty(cfg.tissue) mri = ft_datatype_segmentation(mri, 'segmentationstyle', 'indexed'); fn = fieldnames(mri); for i=1:numel(fn) - if numel(mri.(fn{i}))==prod(mri.dim) && isfield(mri, [fn{i},'label']) - segfield=fn{i}; + if numel(mri.(fn{i}))==prod(mri.dim) && isfield(mri, [fn{i}, 'label']) + segfield = fn{i}; end end if isfield(mri, [segfield 'label']) @@ -82,8 +87,6 @@ if numel(cfg.tissue)>1 && numel(cfg.numvertices)==1 % use the same number of vertices for each tissue cfg.numvertices = repmat(cfg.numvertices, size(cfg.tissue)); -elseif numel(cfg.tissue)~=numel(cfg.numvertices) - error('you should specify the number of vertices for each tissue type'); end if iscell(cfg.tissue) @@ -108,7 +111,7 @@ try seg = mri.(fixname(cfg.tissue{i})); catch - error('Please specify cfg.tissue to correspond to tissue types in the segmented MRI') + ft_error('Please specify cfg.tissue to correspond to tissue types in the segmented MRI') end tissue = cfg.tissue{i}; else @@ -119,7 +122,7 @@ try tissue = mri.seglabel{cfg.tissue(i)}; catch - error('Please specify cfg.tissue to correspond to (the name or number of) tissue types in the segmented MRI') + ft_error('Please specify cfg.tissue to correspond to (the name or number of) tissue types in the segmented MRI') end else tissue = sprintf('tissue %d', i); @@ -144,18 +147,28 @@ switch cfg.method case 'isosurface' - [tri, pos] = isosurface(seg, 0.5); + [tri, pos] = isosurface(seg); + if ~isempty(cfg.numvertices) + npos = cfg.numvertices(i); + ntri = 2*(npos-2); + [tri, pos] = reducepatch(tri, pos, ntri); + end pos = pos(:,[2 1 3]); % Mathworks isosurface indexes differently case 'iso2mesh' + % this requires the external iso2mesh toolbox ft_hastoolbox('iso2mesh', 1); - opt = []; - opt.radbound = 3; % set the target surface mesh element bounding sphere be <3 pixels in radius - opt.maxnode = cfg.numvertices(i); - opt.maxsurf = 1; + opt = []; + opt.radbound = cfg.radbound; % set the target surface mesh element bounding sphere be <3 pixels in radius + opt.maxnode = cfg.numvertices(i); + opt.maxsurf = cfg.maxsurf; + + method = 'cgalsurf'; + isovalues = 0.5; + + [pos, tri, regions, holes] = v2s(seg, isovalues, opt, method); - [pos, tri] = v2s(seg, 1, opt, 'cgalsurf'); tri = tri(:,1:3); case 'projectmesh' @@ -167,7 +180,7 @@ [pos, tri] = triangulate_seg(seg, cfg.numvertices(i), ori); otherwise - error('unsupported method "%s"', cfg.method); + ft_error('unsupported method "%s"', cfg.method); end % case numvoxels(i) = sum(find(seg(:))); % the number of voxels in this tissue @@ -176,7 +189,6 @@ bnd(i).tri = tri; bnd(i).unit = mri.unit; - end % for each tissue if strcmp(cfg.method, 'iso2surf') @@ -198,10 +210,9 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function bnd = decouplesurf(bnd) for ii = 1:length(bnd)-1 - % Despite what the instructions for surfboolean says, surfaces should - % be ordered from inside-out!! + % Despite what the instructions for surfboolean says, surfaces should be ordered from inside-out!! [newnode, newelem] = surfboolean(bnd(ii+1).pos,bnd(ii+1).tri,'decouple',bnd(ii).pos,bnd(ii).tri); bnd(ii+1).tri = newelem(newelem(:,4)==2,1:3) - size(bnd(ii+1).pos,1); bnd(ii+1).pos = newnode(newnode(:,4)==2,1:3); end % for -end %function +end % function diff --git a/external/fieldtrip/private/prepare_mesh_tetrahedral.m b/external/fieldtrip/private/prepare_mesh_tetrahedral.m new file mode 100644 index 00000000..176fbbdf --- /dev/null +++ b/external/fieldtrip/private/prepare_mesh_tetrahedral.m @@ -0,0 +1,77 @@ +function mesh = prepare_mesh_tetrahedral(cfg, mri) + +% PREPARE_MESH_TETRAHEDRAL +% +% See also PREPARE_MESH_MANUAL, PREPARE_MESH_HEADSHAPE, +% PREPARE_MESH_HEXAHEDRAL, PREPARE_MESH_SEGMENTATION + +% Copyrights (C) 2016, Robert Oostenveld +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +% ensure that the input is consistent with what this function expects +mri = ft_checkdata(mri, 'datatype', {'volume', 'segmentation'}, 'hasunit', 'yes'); + +% get the default options +cfg.tissue = ft_getopt(cfg, 'tissue'); + +if isempty(cfg.tissue) + mri = ft_datatype_segmentation(mri, 'segmentationstyle', 'indexed'); + fn = fieldnames(mri); + for i = 1:numel(fn) + if (numel(mri.(fn{i})) == prod(mri.dim)) && (~strcmp(fn{i}, 'inside')) + segfield = fn{i}; + end + end + cfg.tissue = setdiff(unique(mri.(segfield)(:)), 0); +end + +if ischar(cfg.tissue) + % it should either be something like {'brain', 'skull', 'scalp'}, or something like [1 2 3] + cfg.tissue = {cfg.tissue}; +end + +if iscell(cfg.tissue) + % the code below assumes that it is a probabilistic representation + if any(strcmp(cfg.tissue, 'brain')) + mri = ft_datatype_segmentation(mri, 'segmentationstyle', 'probabilistic', 'hasbrain', 'yes'); + else + mri = ft_datatype_segmentation(mri, 'segmentationstyle', 'probabilistic'); + end + % combine all tissue types + seg = false(mri.dim); + for i=1:numel(cfg.tissue) + seg = seg | mri.(cfg.tissue{i}); + end +else + % the code below assumes that it is an indexed representation + mri = ft_datatype_segmentation(mri, 'segmentationstyle', 'indexed'); + % combine all tissue types + seg = (mri.seg>0); +end + +% this requires the external iso2mesh toolbox +ft_hastoolbox('iso2mesh', 1); + +isovalue = 0.5; +[node, elem, face] = vol2mesh(seg, 1:mri.dim(1), 1:mri.dim(2), 1:mri.dim(3), 2, 2, isovalue); + +mesh = keepfields(mri, {'coordsys', 'unit'}); +mesh.pos = ft_warp_apply(mri.transform, node); +mesh.tet = elem(:,1:4); diff --git a/external/fieldtrip/private/prepare_resampled_data.m b/external/fieldtrip/private/prepare_resampled_data.m index c53be43d..c9a042b3 100644 --- a/external/fieldtrip/private/prepare_resampled_data.m +++ b/external/fieldtrip/private/prepare_resampled_data.m @@ -92,7 +92,7 @@ tmp = resamplejackknife+resamplebootstrap+resamplepseudovalue+resamplerandomization+resamplepermutation; if tmp>1 - error('only one resampling strategy should be specified'); + ft_error('only one resampling strategy should be specified'); elseif tmp<1 % default is to average over trials resampleaverage = 1; @@ -115,7 +115,7 @@ Ndata = (nargin-1)/Ncondition; % the first argument is the cfg if Ndata~=round(Ndata) % this should not be fractional - error('incorrect number of input arguments'); + ft_error('incorrect number of input arguments'); else for c=1:Ncondition for d=1:Ndata @@ -146,7 +146,7 @@ elseif siz(1)==1 dataout{c,d} = datain{c,d}; else - error('inconsistent number of replications in data'); + ft_error('inconsistent number of replications in data'); end end end @@ -154,7 +154,7 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% elseif resamplejackknife if Ncondition>1 - error('jackknife requires exactly one condition'); + ft_error('jackknife requires exactly one condition'); end % the number of replications of all dataobjects should be the same Nreplication = max(Nreplication(:)); @@ -172,14 +172,14 @@ elseif siz(1)==1 dataout{1,d} = datain{1,d}; else - error('inconsistent number of replications in data'); + ft_error('inconsistent number of replications in data'); end end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% elseif resamplebootstrap if Ncondition>1 - error('bootstrap requires exactly one condition'); + ft_error('bootstrap requires exactly one condition'); end % the number of replications of all dataobjects should be the same Nreplication = max(Nreplication(:)); @@ -197,14 +197,14 @@ elseif siz(1)==1 dataout{1,d} = datain{1,d}; else - error('inconsistent number of replications in data'); + ft_error('inconsistent number of replications in data'); end end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% elseif resamplepseudovalue if Ncondition>1 - error('pseudovalue requires exactly one condition'); + ft_error('pseudovalue requires exactly one condition'); end % the number of replications of all dataobjects should be the same Nreplication = max(Nreplication(:)); @@ -223,16 +223,16 @@ dataout{1,d}(r+1,:) = (s(:)' - datain{1,d}(r,:))./(Nreplication-1); end elseif siz(1)==1 - error('multiple replications are required in data'); + ft_error('multiple replications are required in data'); else - error('inconsistent number of replications in data'); + ft_error('inconsistent number of replications in data'); end end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% elseif resamplerandomization if Ncondition<2 - error('randomization requires at least two conditions'); + ft_error('randomization requires at least two conditions'); end % the number of replications should be the same for the different dataobjects @@ -256,7 +256,7 @@ end for c=2:Ncondition if ~all(siz(c, 2:end)==siz(1, 2:end)) - error('the dimensions should be the same for every replication in every condition') + ft_error('the dimensions should be the same for every replication in every condition') end end % concatenate the data in all conditions to facilitate the random resamplings @@ -279,14 +279,14 @@ dataout{c,d} = datain{c,d}; end else - error('inconsistent number of replications in data'); + ft_error('inconsistent number of replications in data'); end end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% elseif resamplepermutation if Ncondition<2 - error('permutation requires at least two conditions'); + ft_error('permutation requires at least two conditions'); end % the number of replications should be the same for all dataobjects in both conditions @@ -317,7 +317,7 @@ % a list of unique random numbers, and keep extending that list untill I % have enough unique numbers. if cfg.numpermutation>2^Nreplication - error(sprintf('it is not possible to make more random permutations than %d', 2^Nreplication)); + ft_error('it is not possible to make more random permutations than %d', 2^Nreplication); end number = []; while length(number)0 || endpadding>0 - error('multiple preprocessing stages are not supported in combination with filter padding'); + ft_error('multiple preprocessing stages are not supported in combination with filter padding'); end for i=1:length(cfg) tmpcfg = cfg{i}; @@ -221,33 +224,33 @@ % test whether the MATLAB signal processing toolbox is available if strcmp(cfg.medianfilter, 'yes') && ~ft_hastoolbox('signal') - error('median filtering requires the MATLAB signal processing toolbox'); + ft_error('median filtering requires the MATLAB signal processing toolbox'); end % do a sanity check on the filter configuration if strcmp(cfg.bpfilter, 'yes') && ... - (strcmp(cfg.hpfilter, 'yes') || strcmp(cfg.lpfilter,'yes')), - error('you should not apply both a bandpass AND a lowpass/highpass filter'); + (strcmp(cfg.hpfilter, 'yes') || strcmp(cfg.lpfilter,'yes')) + ft_error('you should not apply both a bandpass AND a lowpass/highpass filter'); end % do a sanity check on the hilbert transform configuration if strcmp(cfg.hilbert, 'yes') && ~strcmp(cfg.bpfilter, 'yes') - warning('hilbert transform should be applied in conjunction with bandpass filter') + ft_warning('hilbert transform should be applied in conjunction with bandpass filter') end % do a sanity check on hilbert and rectification if strcmp(cfg.hilbert, 'yes') && strcmp(cfg.rectify, 'yes') - error('hilbert transform and rectification should not be applied both') + ft_error('hilbert transform and rectification should not be applied both') end % do a sanity check on the rereferencing/montage if ~strcmp(cfg.reref, 'no') && ~strcmp(cfg.montage, 'no') - error('cfg.reref and cfg.montage are mutually exclusive') + ft_error('cfg.reref and cfg.montage are mutually exclusive') end % lnfilter is no longer used if isfield(cfg, 'lnfilter') && strcmp(cfg.lnfilter, 'yes') - error('line noise filtering using the option cfg.lnfilter is not supported any more, use cfg.bsfilter instead') + ft_error('line noise filtering using the option cfg.lnfilter is not supported any more, use cfg.bsfilter instead') end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -258,11 +261,11 @@ dat(end+1,:) = 0; end -if strcmp(cfg.reref, 'yes'), +if strcmp(cfg.reref, 'yes') cfg.refchannel = ft_channelselection(cfg.refchannel, label); refindx = match_str(label, cfg.refchannel); if isempty(refindx) - error('reference channel was not found') + ft_error('reference channel was not found') end dat = ft_preproc_rereference(dat, refindx, cfg.refmethod); end @@ -358,7 +361,20 @@ end if strcmp(cfg.dftfilter, 'yes') datorig = dat; - dat = ft_preproc_dftfilter(dat, fsample, cfg.dftfreq); + optarg = {}; + if isfield(cfg, 'dftreplace') + optarg = cat(2, optarg, {'dftreplace', cfg.dftreplace}); + if strcmp(cfg.dftreplace, 'neighbour') && (begpadding>0 || endpadding>0) + ft_error('Padding by data mirroring is not supported for spectrum interpolation.'); + end + end + if isfield(cfg, 'dftbandwidth') + optarg = cat(2, optarg, {'dftbandwidth', cfg.dftbandwidth}); + end + if isfield(cfg, 'dftneighbourwidth') + optarg = cat(2, optarg, {'dftneighbourwidth', cfg.dftneighbourwidth}); + end + dat = ft_preproc_dftfilter(dat, fsample, cfg.dftfreq, optarg{:}); if strcmp(cfg.dftinvert, 'yes'), dat = datorig - dat; end diff --git a/external/fieldtrip/private/procrustes_trans.m b/external/fieldtrip/private/procrustes_trans.m index 01a7c682..871b9557 100644 --- a/external/fieldtrip/private/procrustes_trans.m +++ b/external/fieldtrip/private/procrustes_trans.m @@ -40,10 +40,10 @@ % do basic checks if ninp ~= ntarg, - error('you must specify same number of points for input and target'); + ft_error('you must specify same number of points for input and target'); end if ninp < 3, - error('you must specify at least three points for matching'); + ft_error('you must specify at least three points for matching'); end % calculate the center fo gravity diff --git a/external/fieldtrip/private/project_elec.m b/external/fieldtrip/private/project_elec.m index 9cb599e0..0454e10a 100644 --- a/external/fieldtrip/private/project_elec.m +++ b/external/fieldtrip/private/project_elec.m @@ -34,7 +34,7 @@ Nelc = size(elc,1); el = zeros(Nelc, 4); -% this is a work-around for http://bugzilla.fcdonders.nl/show_bug.cgi?id=2369 +% this is a work-around for http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2369 elc = double(elc); pnt = double(pnt); tri = double(tri); diff --git a/external/fieldtrip/private/projecttri.m b/external/fieldtrip/private/projecttri.m index 729f0ab5..f18a34e7 100644 --- a/external/fieldtrip/private/projecttri.m +++ b/external/fieldtrip/private/projecttri.m @@ -48,7 +48,7 @@ prj = elproj(pnt); tri = delaunay(prj(:,1), prj(:,2)); otherwise - error('unsupported method'); + ft_error('unsupported method'); end diff --git a/external/fieldtrip/private/ptriproj.m b/external/fieldtrip/private/ptriproj.m index 49b78585..2f482b1a 100644 --- a/external/fieldtrip/private/ptriproj.m +++ b/external/fieldtrip/private/ptriproj.m @@ -1,4 +1,4 @@ -function [varargout] = funname(varargin) +function [varargout] = ptriproj(varargin) % PTRIPROJ projects a point onto the plane going through a triangle % @@ -42,7 +42,7 @@ try % try to compile the mex file on the fly - warning('trying to compile MEX file from %s', mexsrc); + ft_warning('trying to compile MEX file from %s', mexsrc); cd(mexdir); if ispc @@ -59,7 +59,7 @@ catch % compilation failed disp(lasterr); - error('could not locate MEX file for %s', mexname); + ft_error('could not locate MEX file for %s', mexname); cd(pwdir); success = false; end diff --git a/external/fieldtrip/private/ptriproj.mexa64 b/external/fieldtrip/private/ptriproj.mexa64 index f81b3dc2867014088cf87682d39cefede563e615..1717147bf2c1be2e3467712a33a9e0b6279d7765 100755 GIT binary patch delta 1189 zcmY*ZZERCz6u#&7dtbMAZS8KM-G==@a4iy&(adZsv~p{@1jm**M4b`0OwA0+wArGQ z)UO*>DV&99GD3*{FflR8oyh_O!7T!R6pe`k&4`J{4JTpMIoPJJ=WXZ2H@WAz=Q;0r z-se3{?`ZdEcdpYGUn3M&{BX}_@^Do#Sw)P(ap$I`)2A{WTN0h^k-*TmjlulL1H<|( zI7QL#)vh8~sJ@l{+{(U_Bj>LbtTewtI=Ol(sNkiQA+W*n>H#1{&}a$qQcm zO7e+j(>uDUU9D%oRts?}T78mj1%?~?j>~2Gd4u{9Zlv8VLMIh2g0G-jFpLk5TyBT zA&k>6wU;pWH|-~Mk~Uw^-zq@bj@PPW7{R%!2-IM$QVp9iM)7HUg5pU$pj6jhA!qHp zC01eI{)Sj?7I&6etb*VtYL=b~JgIb$*W0jmmyLr7r~&wE1R@{)et(<|aT-j5-zCw&*p zBqs+VwzQicCkSaw2I_6Ol`MxEW&eE!E(PjK>`HN`UC~Q|XN}bV;|7;O5^{uY`ghA4 zT}D};YUReD2+bI+i%{&Tdx`I)_ZgJKkHa&#FWe2|cqQCKb5kM_n8ajchwW5lQQfD% O8*u~wvYgx`8vX%q)043P delta 1131 zcmYL}eQXnT7{`Cl^<}-TPG4;22@}OY~c@^IM)Cp zYRop|ghKJr1#krMuYrjXZx3WT`(t1a6wngJ^*+cCv73Je(^p?W0GtuzC<>Kr^F%HhpqNUpcjwXZ^IFMz5H=l zhu@Wt+jf*Q)?J%jg4Z2xEI341g+Dmb?wfYTO465?EbY>=Lc5f{Qj%oLs9jG~WMI>F zk!svo*D%+sYNn)S4kWb%`!xf+O3tk{45M9&RK$3q(6xws%L?u&W!NGI zVFbJ63l04kn^foksMf~x&kEGK`Mc4d4{Kc1`{ zfETc#Dg+7KRuzEN*jp74+*5e2DpOmZU0QtSuem)FteC&++KPST>Q6eGfHa(NHPVgx z-nB-MOXytu_hScdaY36cDveQlM(Uo8KNsH;-+KA0d_KQX)qYlUmIPf|h@Vn>CT!{< z%Ry@$<=-*7JZjFjAD?kAg>n5A_r37yUh4Q3Xj1l5i;!nhniDqh5OL79lUBvao zPl!8->Dz{Jm^d?O7@rcmY58l!^ZyuzLtyL)`s*GdZlIg6lQ{4%^VF`wuE1J{P%cB$wpohUnH+PAXHd|l%veXSb%<-pmPI) zH)Od;x&|@qt#;;x*~`3Q37uSY3^#lI(2x7PQ8!EVhW?|%KL)?Fl-D*$?gvC w;g#fni%Mi0Jt!|mI$#h-BWu8do@f-_!(_BcJY6~8Lq8F91OGmJ^nhUc4`;P_#Q*>R diff --git a/external/fieldtrip/private/ptriproj.mexmaci64 b/external/fieldtrip/private/ptriproj.mexmaci64 index 0a66a1cda8966143afc6d31867cf79fdfa0eb53a..4e2c04d79783bfa34c33d91e64371f8faffe78e3 100755 GIT binary patch literal 13304 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 Hn}+%ii(P(s literal 13360 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 diff --git a/external/fieldtrip/private/ptriproj.mexw32 b/external/fieldtrip/private/ptriproj.mexw32 index 1c274de1ec0d8e87e575dd4dc4ec7aab1898613d..caf4b04a31c23b3580069fdcff64e55851170fbe 100755 GIT binary patch delta 964 zcmYk4e{2(F7{}jtz3WEpi=(?r8k=VHv_ zMi8Zh{-MpQX8I-=)EG1o30ur!6NiZtjYX712)Mum8W6Mj8bJ##P=PSt>sI6aanJMp zem{5blPB+%t}R_7LKzIs_PljA2+Mp4Y^yo4jYr{5IF|nflA27}3qZD@Jd$EVP0Sk? zCl_?K42Lv!eL{R!)t(pY)2rHnR&`iPNs3RaDI98Gol0E1Q#D*%ckxAst*J|hOf_}! zR9#Y}|8rcvge0F{U|6R=F5>^^*Z32HR1FvZ-o+Ok7D$SK40Fz0We%V0-6L~OSzJ?P zpYkVj&Q)C(@=oj*Qv$Dbj4IeS=OAR{ZYH$(SUsVLBFRTioCRC3;Q7} ziJelUSXu0rbuF6~AMqYF2siLy^*#TD^oqTuqC9hqhrCnp7{B11fUSIY?aG!p4*(}a zBXT9DPG2lMu#^o#NjoKRg8x}N0H5dU>MmK4pHCNWVl%zpigB5;M|C;#3Fm6DMeLAz zK`wrRB=y`T1<2>8U5zxxZwN&bpi8iPTzg zCO_(X7}ie)|jv?TA*Tj6HDQD5f$Cj_+moAdALKBaR1^1Fghs2N30 zeIt4h4Wp0I6zU5f5C0v0sG}<~7r7h(hS%^LjfQUAYS_j>&g*&i? zyKpb=!<+FoJc`Hh=lC!_iqGKl_!7Q`n@NZuaxYm;5~Pm|kWGY>aWX-^B;Sw&WQxp? zn&{F@^!DgW(NCg(MT4}57zWJf~wYkq6wl-OBSfkcn zYoB$G-C;-VRd%=ixV_%qY9F+JvVXIEw3)7;chWGW^cngb9i}hSt@JheCjEep(a-1} z`V}qE1N1PRrl;sEJxAwg+Z76y1Aye+@}TR`4X72}f$m0OWT8%!K)vW`G>A5!S5Ovh MM?26i-oE0{zd@{9Hvj+t delta 952 zcmXw%YiLwQ7=~xESJRC-rfG7z*|m{Gp<=@Cq`*xvyxSbTIi3Mu9rgE zNCn#j7Ang~8y&F41PLvT7t~r-+p4IjiwQLlXtg(7OiEhE3t@?xhG?74N!h*Oqx?- z+|n^mG-*B)e@dN5D~TCL(k$*MVRiLNL=4VCyAZM_P33`Wz*K--aS*q~q4-K-DPbJ4 ztT-r}7@HD@WL?jG69@Q4hYxP$yBs~9Ba&q{XEXB7Uha3^gadrS`8_P;$6ZUkV>SS8 z`@7{x?u<;PR~E8%DAQ(E+~DJ`?QjckasN|Q`TI!bW%k$RYobrOtXa)?#X(D%zKkmN zS*o#oE-^I3KbyA~PV&_0pJjwSgxF`44qBgiEHC$9<$6|oqV@i=DgYGeT{CS*4jU6AJwjY9S6n&_XF9$WZ+pKPjhQU+H2Y+?MLlr?Y1_mJ<%Zc;YwVE zF>b^$yc2(ddvG7_$5-%m{1YCO0&vW+B2A2~u!kZ;L(k|wvv z1exh1rNMac^WdGJCv-V95V{o_3H=?K4i)NNeYxJCH|zWK{rYMBtlk>l7XB#Q6aFTA zHoVZNG?p632pemRW~1G>WLz_THKq+0eUX;Y3R+Fq(H7cDx6^j|A^n(sN_**-^e8<= z&(QPq3LT`w^cR|;W3>7KeMFy9P!7N{`KN5C5UI$IDo_;)pgPouqUas8741Opqa^A^ KU+|iW;r{^%8&mlJ diff --git a/external/fieldtrip/private/ptriproj.mexw64 b/external/fieldtrip/private/ptriproj.mexw64 index 997761e6be39b826caa6b71bd051d63817d256d9..0421d849afc5d1449461b2f6a0dc51f234a0444f 100755 GIT binary patch delta 1756 zcmYjRe{54#6u!6Z!){&IcH0}<*r45BVGM?a4jeL|!>V_-8puWhI246UO#EZfK7ybb zNvTqvgUJnlh$N0E5u<->G|>#BjK~i&#?K|noC!og-yD%Sfek`@e)o05H9hD1&N<(E z=iGbWdpjC-G_+mwefr1EwPgG^OiH~Di=B`>By!Tp5U2EU%bodr0sWdTOAXS9rRBFw zLYU^z&kKx?Q8imc$I_8Cmc?3~t9^u|Gg`#1AD$4pmk_2t%@nV`dL0tDyukz!ZC`ycskh4v>t}L>@lxAAJueyFKC^1j%io)oqW6GrSnq< zr3iH`#3qh}UG9q`F867DR_fjq52bR-Za+fl8@w|k@ZvrT6r#95BBZI-HSfeWODqSO zGrIRtW`!Ekryv?}RiOD!#f?EmTpptTZTml2Fp>OqJjnx@`)MR~Iul3t3164hWbN(k z<;Sx^bp1YO4ej7dou6CAM)~hfg={KzM-5|;W0C0JsD$7*DGa{y3m(q?Y@;oo z5W{~@7G5{~FQ)G`{r9FnV){~eG#meg>RJ4jw~JsvL!OEf(|*KO8M0OI!~jc5_Z6_D z^e2zF-hC>JAkppG(~U`L=bTDPK_r6R!%~ZxwIZd_4<&tR=cZ7%Mc{GV_97@Fub0RLmOJoTICsH zh*qZ^5KdMWLZsiZnX61}H4Foan_`Mq=T88=52Z8G?NUPUbdbcoYV|RUatkqwFMS9g zF(0)5fa%Yew~2Y8+NongU8nULaz83zT6uuK2pn=DAW3} zq3tLba*rFsiMIwH0z-8$?W`ehL2gLx!aG3pS8-(<)Nh*VgOAjjbB&qV&9CPwMGMWm zG!H4JMU{{tm!&g#+?UsE-|i86R1)JKvSbvD#ZQ+1VEALu8vZS&-)j18PJYR9@@PRh zrGeD!!rN3{jn}FwNQf`fLNa$bNHZRi)x2`r$36w;Wx=RdO9(kRoseOez<$I%KrbJh zHpe4Wc(usSc;u?Eb1S*Oc)2{0{l-Vg4cM^2)Z4}1T5aN6pQ`qHZ7mb61-?>%8)6KB zXJKyei@>`@glqs0Oe17JY%6#>@GA_l1H1!x8^d&five>n#u0EYa51bMJOoU@hQZr` z&tlB1Dzc8O1bH21t0JTsxC=HHybag~s{+3UEW`9+@DAV*tPxzS$b+>vfCqr}uy?>W M0B5G=`!Cr31BCYdCIA2c delta 1741 zcmYjRZERCj7(S=%g>GxtyN_GDjlu1>l?}Er=)j4?b)mprS`}m%z=5z~I)dcIOL9+|J~ zm!U+Z9Fs?UM&o>`�U)eVj`x*_fkf-AooY8*xVUN#m~!7o+;LaV5ijYBH>Zj8SB9 zQ{YLR#$C$BDON2kUH%3dCn@$~V=%4i->G=Z%hr<@qPk&pfHvvpRsE6?V=o9Y^{0*r z5$XwG6K{k);_wZR__c9YYHC3qr9#T-JV9v->(8or=#UKx-YgRcX>IgWpMKsJ%SUC< z5bsphYPH6cgZn?Ih%j-(lShoJvjyK=VH5>cpM8{WPK{*axISR5u2weeYM}d>=&q+} z_JI4i%{k4c+zP$IN^+MJe|g(9Cm2?R30ss9;yy)1tQug=x$o^Q^b%qQ7Fcmw;`|RQ z{%pkyR{YG0s}axL`GvNr@jvAO0%xYQ3@ugv276;l1)L|w)TEFV080up>`~848=4hD z5^2wCX*g+IaW*MzKp~i(jC%U3c7Vnfx3+fUZ@{qgH?G0Gob9edS2J{BIV%y17cE0( zN?XxZ6F8;mSd*%|v#nx1+bS+oTxglne+AauLrX0f1_Z~FrF}eowX~ld6Kgs;k;KZ> z`vzmhvy<+|Lzq@l!s9n-ZZlcTW1B8=R z6%ZMJJFHbE+D+4h;ud$&<^CODTtsV7Fv|$Rbs&kUI&C4W{EJ+TuXo{L67xfA=damh zy(X3y)z6;f>L&f1DNR5crd7Qxp0}f74U)u&R&cMh8BEK;>RJ?e;vB^B85$GfGd3-# z>Ov87z5&)-ddWt9a_?Ri%wWa5ZDbFP^aRrMdSp?zqW(oZ7H z@y`TbzNzJ?`uC=E2(@e404_Z-p2U;gP`_fSKfI&X-ECIoZFaLjDc)$+h5J!b^{5gu zrC_F_uvLWzoO&MLqtb)y{X*3l$s}R+PvL3$FgqpfT)iU~Rsy@M7_;KDR%}Pa6)eYc zH4$5Q*#k@30#mxqHhKN@6V~Rvo4(0j_ZF?$=jKzlC^e?^1ZY^l)D#>urN`#+om|ot zRqE!NTi7q&wG~;V*!p6&S5B#%swlcn zr6zn(wLwDs**21WIENg-C23++CGYqPab7l99l{GgUQEb12FGuap9G3*qGUxLSK-ql zgSc`Eb}qyMiyEZ4>Ty3IqZs2HQ_n3rWq0s@?x{Lic67{5&2hVr5E(W&et{u^r-4_C z3E2ZKm*5&~jDB diff --git a/external/fieldtrip/private/ptriside.m b/external/fieldtrip/private/ptriside.m new file mode 100644 index 00000000..df119914 --- /dev/null +++ b/external/fieldtrip/private/ptriside.m @@ -0,0 +1,55 @@ +function [side] = ptriside(v1, v2, v3, r, tolerance) + +% PTRISIDE determines the side of a plane on which a set of points lie. It +% returns 0 for the points that lie exactly on the plane. +% +% [side] = ptriside(v1, v2, v3, r) +% +% the side of points r is determined relative to the plane spanned by +% vertices v1, v2 and v3. v1,v2 and v3 should be 1x3 vectors. r should be a +% Nx3 matrix + +% Copyright (C) 2002, Robert Oostenveld +% +% $Log: ptriside.m,v $ +% Revision 1.3 2003/03/11 15:35:20 roberto +% converted all files from DOS to UNIX +% +% Revision 1.2 2003/03/04 21:46:19 roberto +% added CVS log entry and synchronized all copyright labels +% + +if nargin<5 + tolerance = 100*eps; +end + +n = size(r,1); +a = r - ones(n,1)*v1; +b = v2 - v1; +c = v3 - v1; +d = crossproduct(b, c); +val = dotproduct(a, d); + +side = zeros(n, 1); +side(val > tolerance) = 1; +side(val < -tolerance) = -1; + +%if val>tolerance +% side=1; +%elseif val<-tolerance +% side=-1; +%else +% side=0; +%end + +% subfunction without overhead to speed up +function c = crossproduct(a, b) + +c(1) = a(2)*b(3)-a(3)*b(2); +c(2) = a(3)*b(1)-a(1)*b(3); +c(3) = a(1)*b(2)-a(2)*b(1); + +% subfunction without overhead to speed up, input a can be a matrix +function d = dotproduct(a, b) + +d = a(:,1)*b(1)+a(:,2)*b(2)+a(:,3)*b(3); diff --git a/external/fieldtrip/private/quaternion.m b/external/fieldtrip/private/quaternion.m index ad8d5e06..bd34c4f6 100644 --- a/external/fieldtrip/private/quaternion.m +++ b/external/fieldtrip/private/quaternion.m @@ -48,7 +48,7 @@ % $Id$ if numel(q)~=7 - error('incorrect input vector'); + ft_error('incorrect input vector'); end % all of these quaternions are zero-offset in the original equation, but one-offset in the MATLAB vector diff --git a/external/fieldtrip/private/randstatprob.m b/external/fieldtrip/private/randstatprob.m index da9c8501..f7150595 100644 --- a/external/fieldtrip/private/randstatprob.m +++ b/external/fieldtrip/private/randstatprob.m @@ -53,7 +53,7 @@ Nrnd = size(randobs,2); Nobs = size(realobs,2); if size(realobs,1)~=Nvox - error('dimensions of input arguments does not match'); + ft_error('dimensions of input arguments does not match'); end p = zeros(size(realobs)); @@ -89,7 +89,7 @@ p(:,i) = sum(randobs <= repmat(realobs(:,i),1,Nrnd), 2)./Nrnd; otherwise - error('incorrect specification of tail'); + ft_error('incorrect specification of tail'); end elseif correctm==1 % apply multiple comparison correction using the maximum statistic @@ -107,7 +107,7 @@ p(:,i) = sum(repmat(mindist,Nvox,1) <= repmat(realobs(:,i),1,Nrnd), 2)./Nrnd; otherwise - error('incorrect specification of tail'); + ft_error('incorrect specification of tail'); end end end diff --git a/external/fieldtrip/private/raw2data.m b/external/fieldtrip/private/raw2data.m index e1d99d57..2d806ad9 100644 --- a/external/fieldtrip/private/raw2data.m +++ b/external/fieldtrip/private/raw2data.m @@ -72,6 +72,6 @@ data.dimord = dimord; otherwise - warning('unrecognized dimord'); + ft_warning('unrecognized dimord'); end diff --git a/external/fieldtrip/private/read_besa_avr.m b/external/fieldtrip/private/read_besa_avr.m index 20534492..6d433f92 100644 --- a/external/fieldtrip/private/read_besa_avr.m +++ b/external/fieldtrip/private/read_besa_avr.m @@ -88,7 +88,7 @@ end if ~ok - error('Could not interpret the header information.'); + ft_error('Could not interpret the header information.'); end % rewind to the beginning of the file, skip the header line @@ -117,7 +117,7 @@ lbl = strrep(lbl ,'EEG ', ''); % remove the channel type avr.label = lbl; else - warning('Could not create channels labels.'); + ft_warning('Could not create channels labels.'); end end diff --git a/external/fieldtrip/private/read_besa_src.m b/external/fieldtrip/private/read_besa_src.m index 619ccd61..d573da01 100644 --- a/external/fieldtrip/private/read_besa_src.m +++ b/external/fieldtrip/private/read_besa_src.m @@ -55,7 +55,7 @@ for i=1:nz % search up to the next slice - while isempty(strmatch(sprintf('Z: %d', i-1), line)), line = fgetl(fid); check_feof(fid, filename); end; + while isempty(strmatch(sprintf('Z: %d', i-1), line)), line = fgetl(fid); check_feof(fid, filename); end % read all the values for this slice buf = fscanf(fid, '%f', [nx ny]); src.vol(:,:,i) = buf; @@ -66,6 +66,6 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function check_feof(fid, filename) if feof(fid) - error(sprintf('could not read all information from file ''%s''', filename)); + ft_error('could not read all information from file ''%s''', filename); end diff --git a/external/fieldtrip/private/read_ctf_hc.m b/external/fieldtrip/private/read_ctf_hc.m index 61ab60de..ccb0d10c 100644 --- a/external/fieldtrip/private/read_ctf_hc.m +++ b/external/fieldtrip/private/read_ctf_hc.m @@ -67,7 +67,7 @@ fid = fopen(filename, 'r'); if fid==-1 - error(sprintf('could not open file %s', filename)); + ft_error('could not open file %s', filename); end fseek(fid, 0, 'bof'); @@ -81,23 +81,23 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% while ~strcmp(line, 'standard nasion coil position relative to dewar (cm):') line = fgetl(fid); - if ~ischar(line) & line==-1, error('premature end of file'), end + if ~ischar(line) && line==-1, ft_error('premature end of file'), end end line = fgetl(fid); [t, r] = strtok(line, '='); hc.standard.nas(1) = str2num(r(2:end)); line = fgetl(fid); [t, r] = strtok(line, '='); hc.standard.nas(2) = str2num(r(2:end)); line = fgetl(fid); [t, r] = strtok(line, '='); hc.standard.nas(3) = str2num(r(2:end)); % NOTE THAT THERE IS AN TYPING ERROR IN SOME CTF FILES WHICH I HAVE TO REPRODUCE HERE (staNdard) -while ~(strcmp(line, 'stadard left ear coil position relative to dewar (cm):') | ... +while ~(strcmp(line, 'stadard left ear coil position relative to dewar (cm):') || ... strcmp(line, 'standard left ear coil position relative to dewar (cm):')) line = fgetl(fid); - if ~ischar(line) & line==-1, error('premature end of file'), end + if ~ischar(line) && line==-1, ft_error('premature end of file'), end end line = fgetl(fid); [t, r] = strtok(line, '='); hc.standard.lpa(1) = str2num(r(2:end)); line = fgetl(fid); [t, r] = strtok(line, '='); hc.standard.lpa(2) = str2num(r(2:end)); line = fgetl(fid); [t, r] = strtok(line, '='); hc.standard.lpa(3) = str2num(r(2:end)); while ~strcmp(line, 'standard right ear coil position relative to dewar (cm):') line = fgetl(fid); - if ~ischar(line) & line==-1, error('premature end of file'), end + if ~ischar(line) && line==-1, ft_error('premature end of file'), end end line = fgetl(fid); [t, r] = strtok(line, '='); hc.standard.rpa(1) = str2num(r(2:end)); line = fgetl(fid); [t, r] = strtok(line, '='); hc.standard.rpa(2) = str2num(r(2:end)); @@ -111,21 +111,21 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% while ~strcmp(line, 'measured nasion coil position relative to dewar (cm):') line = fgetl(fid); - if ~ischar(line) & line==-1, error('premature end of file'), end + if ~ischar(line) && line==-1, ft_error('premature end of file'), end end line = fgetl(fid); [t, r] = strtok(line, '='); hc.dewar.nas(1) = str2num(r(2:end)); line = fgetl(fid); [t, r] = strtok(line, '='); hc.dewar.nas(2) = str2num(r(2:end)); line = fgetl(fid); [t, r] = strtok(line, '='); hc.dewar.nas(3) = str2num(r(2:end)); while ~strcmp(line, 'measured left ear coil position relative to dewar (cm):') line = fgetl(fid); - if ~ischar(line) & line==-1, error('premature end of file'), end + if ~ischar(line) && line==-1, ft_error('premature end of file'), end end line = fgetl(fid); [t, r] = strtok(line, '='); hc.dewar.lpa(1) = str2num(r(2:end)); line = fgetl(fid); [t, r] = strtok(line, '='); hc.dewar.lpa(2) = str2num(r(2:end)); line = fgetl(fid); [t, r] = strtok(line, '='); hc.dewar.lpa(3) = str2num(r(2:end)); while ~strcmp(line, 'measured right ear coil position relative to dewar (cm):') line = fgetl(fid); - if ~ischar(line) & line==-1, error('premature end of file'), end + if ~ischar(line) && line==-1, ft_error('premature end of file'), end end line = fgetl(fid); [t, r] = strtok(line, '='); hc.dewar.rpa(1) = str2num(r(2:end)); line = fgetl(fid); [t, r] = strtok(line, '='); hc.dewar.rpa(2) = str2num(r(2:end)); @@ -139,21 +139,21 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% while ~strcmp(line, 'measured nasion coil position relative to head (cm):') line = fgetl(fid); - if ~ischar(line) & line==-1, error('premature end of file'), end + if ~ischar(line) && line==-1, ft_error('premature end of file'), end end line = fgetl(fid); [t, r] = strtok(line, '='); hc.head.nas(1) = str2num(r(2:end)); line = fgetl(fid); [t, r] = strtok(line, '='); hc.head.nas(2) = str2num(r(2:end)); line = fgetl(fid); [t, r] = strtok(line, '='); hc.head.nas(3) = str2num(r(2:end)); while ~strcmp(line, 'measured left ear coil position relative to head (cm):') line = fgetl(fid); - if ~ischar(line) & line==-1, error('premature end of file'), end + if ~ischar(line) && line==-1, ft_error('premature end of file'), end end line = fgetl(fid); [t, r] = strtok(line, '='); hc.head.lpa(1) = str2num(r(2:end)); line = fgetl(fid); [t, r] = strtok(line, '='); hc.head.lpa(2) = str2num(r(2:end)); line = fgetl(fid); [t, r] = strtok(line, '='); hc.head.lpa(3) = str2num(r(2:end)); while ~strcmp(line, 'measured right ear coil position relative to head (cm):') line = fgetl(fid); - if ~ischar(line) & line==-1, error('premature end of file'), end + if ~ischar(line) && line==-1, ft_error('premature end of file'), end end line = fgetl(fid); [t, r] = strtok(line, '='); hc.head.rpa(1) = str2num(r(2:end)); line = fgetl(fid); [t, r] = strtok(line, '='); hc.head.rpa(2) = str2num(r(2:end)); diff --git a/external/fieldtrip/private/read_labview_dtlg.m b/external/fieldtrip/private/read_labview_dtlg.m index fecaa981..96c26242 100644 --- a/external/fieldtrip/private/read_labview_dtlg.m +++ b/external/fieldtrip/private/read_labview_dtlg.m @@ -33,7 +33,7 @@ header = fread(fid, 4, 'uint8=>char')'; if ~strcmp(header, 'DTLG') - error('unsupported file, header should start with DTLG'); + ft_error('unsupported file, header should start with DTLG'); end version = fread(fid, 4, 'char')'; % clear version @@ -83,7 +83,7 @@ case 'int16' datasize = 2; otherwise - error('unsupported datatype'); + ft_error('unsupported datatype'); end % If the data sets are n-dimensional arrays, the first n u32 longwords in each data @@ -101,7 +101,7 @@ % determine the number and size of additional array dimensions n = cat(1, n, fread(fid, 1, 'int32')); if datasize*prod(n)>estimate - error('could not determine array size'); + ft_error('could not determine array size'); end end ndim = length(n); @@ -114,7 +114,7 @@ % determine the number and size of additional array dimensions n = cat(1, n, fread(fid, 1, 'int32')); if datasize*prod(n)>estimate - error('could not determine array size'); + ft_error('could not determine array size'); end end ndim = length(n); diff --git a/external/fieldtrip/private/read_neuralynx_dma.m b/external/fieldtrip/private/read_neuralynx_dma.m index a8e75386..5085d2c2 100644 --- a/external/fieldtrip/private/read_neuralynx_dma.m +++ b/external/fieldtrip/private/read_neuralynx_dma.m @@ -120,7 +120,7 @@ fclose(fid); if ~nboards - error('could not determine the number of boards and channels'); + ft_error('could not determine the number of boards and channels'); end % deal with ascii and numeric input for the channel selection @@ -168,7 +168,7 @@ case 'all' chanindx = 1:blocksize; otherwise - error('unknown value in channel'); + ft_error('unknown value in channel'); end elseif nargin<4 channel = 'all'; @@ -233,11 +233,11 @@ fclose(fid); % check that the junk at the beginning was correctly detected if (beg_stx~=2048) - error('problem with STX at the begin of the file'); + ft_error('problem with STX at the begin of the file'); end % check that the file is truely continuous, i.e. no gaps with junk in between if (end_stx~=2048) - error('problem with STX at the end of the file'); + ft_error('problem with STX at the end of the file'); end % combine the two uint32 words into a uint64 hdr.FirstTimeStamp = timestamp_neuralynx(beg_tsl, beg_tsh); @@ -257,7 +257,7 @@ dat = fread(fid, [blocksize (endsample-begsample+1)], 'int32=>int32'); fclose(fid); if size(dat,2)<(endsample-begsample+1) - error('could not read all samples'); + ft_error('could not read all samples'); end if ~strcmp(channel, 'all') % select the subset of desired channels @@ -273,7 +273,7 @@ % Note that the last block with 274*4 bytes can sometimes be incomplete, which is relevant when endsample=inf dat = fread(fid, [1 (endsample-begsample+1)], 'int32=>int32', (nboards*32+18-1)*4); if size(dat,2)<(endsample-begsample+1) - error('could not read all samples'); + ft_error('could not read all samples'); end fclose(fid); end diff --git a/external/fieldtrip/private/refine.m b/external/fieldtrip/private/refine.m index c2c2fb1d..9dc242d4 100644 --- a/external/fieldtrip/private/refine.m +++ b/external/fieldtrip/private/refine.m @@ -45,7 +45,6 @@ % You should have received a copy of the GNU General Public License % along with FieldTrip. If not, see . % -% $Id$ if nargin<3 method = 'banks'; @@ -190,6 +189,6 @@ [trir, pntr] = reducepatch(tri, pnt, numtri); otherwise - error('unsupported method "%s"', method); + ft_error('unsupported method "%s"', method); end diff --git a/external/fieldtrip/private/rejectvisual_summary.m b/external/fieldtrip/private/rejectvisual_summary.m index b6c0ebee..e59a619c 100644 --- a/external/fieldtrip/private/rejectvisual_summary.m +++ b/external/fieldtrip/private/rejectvisual_summary.m @@ -165,37 +165,37 @@ function compute_metric(h) runnum = 0; for i=1:info.ntrl dat = preproc(info.data.trial{i}, info.data.label, offset2time(info.offset(i), info.fsample, size(info.data.trial{i}, 2)), info.cfg.preproc); % not entirely sure whether info.data.time{i} is correct, so making it on the fly - runsum = runsum + sum(dat, 2); - runss = runss + sum(dat.^2, 2); - runnum = runnum + size(dat, 2); + runsum = runsum + nansum(dat, 2); + runss = runss + nansum(dat.^2, 2); + runnum = runnum + sum(isfinite(dat), 2); end - mval = runsum/runnum; - sd = sqrt(runss/runnum - (runsum./runnum).^2); + mval = runsum./runnum; + sd = sqrt(runss./runnum - (runsum./runnum).^2); end for i=1:info.ntrl ft_progress(i/info.ntrl, 'computing metric %d of %d\n', i, info.ntrl); dat = preproc(info.data.trial{i}, info.data.label, offset2time(info.offset(i), info.fsample, size(info.data.trial{i}, 2)), info.cfg.preproc); % not entirely sure whether info.data.time{i} is correct, so making it on the fly switch info.metric case 'var' - level(:, i) = std(dat, [], 2).^2; + level(:, i) = nanstd(dat, [], 2).^2; case 'min' - level(:, i) = min(dat, [], 2); + level(:, i) = nanmin(dat, [], 2); case 'max' - level(:, i) = max(dat, [], 2); + level(:, i) = nanmax(dat, [], 2); case 'maxabs' - level(:, i) = max(abs(dat), [], 2); + level(:, i) = nanmax(abs(dat), [], 2); case 'range' - level(:, i) = max(dat, [], 2) - min(dat, [], 2); + level(:, i) = nanmax(dat, [], 2) - nanmin(dat, [], 2); case 'kurtosis' level(:, i) = kurtosis(dat, [], 2); case '1/var' - level(:, i) = 1./(std(dat, [], 2).^2); + level(:, i) = 1./(nanstd(dat, [], 2).^2); case 'zvalue' - level(:, i) = mean( (dat-repmat(mval, 1, size(dat, 2)) )./repmat(sd, 1, size(dat, 2)) , 2); + level(:, i) = nanmean( (dat-repmat(mval, 1, size(dat, 2)) )./repmat(sd, 1, size(dat, 2)) , 2); case 'maxzvalue' - level(:, i) = max( ( dat-repmat(mval, 1, size(dat, 2)) )./repmat(sd, 1, size(dat, 2)) , [], 2); + level(:, i) = nanmax( ( dat-repmat(mval, 1, size(dat, 2)) )./repmat(sd, 1, size(dat, 2)) , [], 2); otherwise - error('unsupported method'); + ft_error('unsupported method'); end end ft_progress('close'); @@ -611,10 +611,17 @@ function display_trial(h, eventdata) cfg_mp.channel = info.data.label(info.chansel); currfig = gcf; for n = 1:length(trls) + % ft_multiplotER should be able to make the selection, but fails due to http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2978 + % that bug is hard to fix, hence it is solved here with a work-around + cfg_sd = []; + cfg_sd.trials = trls(n); + cfg_sd.avgoverrpt = 'yes'; + cfg_sd.keeprpt = 'no'; + tmpdata = ft_selectdata(cfg_sd, info.data); + figure() - cfg_mp.trials = trls(n); cfg_mp.interactive = 'yes'; - ft_multiplotER(cfg_mp, info.data); + ft_multiplotER(cfg_mp, tmpdata); title(sprintf('Trial %i', trls(n))); end figure(currfig); diff --git a/external/fieldtrip/private/resampledesign.m b/external/fieldtrip/private/resampledesign.m index 9b009b69..ebeec88f 100644 --- a/external/fieldtrip/private/resampledesign.m +++ b/external/fieldtrip/private/resampledesign.m @@ -91,12 +91,12 @@ Nvar = size(design,1); % number of factors or regressors Nrepl = size(design,2); % number of replications -if ~isempty(intersect(cfg.ivar, cfg.uvar)), warning('there is an intersection between cfg.ivar and cfg.uvar'); end -if ~isempty(intersect(cfg.ivar, cfg.wvar)), warning('there is an intersection between cfg.ivar and cfg.wvar'); end -if ~isempty(intersect(cfg.ivar, cfg.cvar)), warning('there is an intersection between cfg.ivar and cfg.cvar'); end -if ~isempty(intersect(cfg.uvar, cfg.wvar)), warning('there is an intersection between cfg.uvar and cfg.wvar'); end -if ~isempty(intersect(cfg.uvar, cfg.cvar)), warning('there is an intersection between cfg.uvar and cfg.cvar'); end -if ~isempty(intersect(cfg.wvar, cfg.cvar)), warning('there is an intersection between cfg.wvar and cfg.cvar'); end +if ~isempty(intersect(cfg.ivar, cfg.uvar)), ft_warning('there is an intersection between cfg.ivar and cfg.uvar'); end +if ~isempty(intersect(cfg.ivar, cfg.wvar)), ft_warning('there is an intersection between cfg.ivar and cfg.wvar'); end +if ~isempty(intersect(cfg.ivar, cfg.cvar)), ft_warning('there is an intersection between cfg.ivar and cfg.cvar'); end +if ~isempty(intersect(cfg.uvar, cfg.wvar)), ft_warning('there is an intersection between cfg.uvar and cfg.wvar'); end +if ~isempty(intersect(cfg.uvar, cfg.cvar)), ft_warning('there is an intersection between cfg.uvar and cfg.cvar'); end +if ~isempty(intersect(cfg.wvar, cfg.cvar)), ft_warning('there is an intersection between cfg.wvar and cfg.cvar'); end fprintf('total number of measurements = %d\n', Nrepl); fprintf('total number of variables = %d\n', Nvar); @@ -146,11 +146,11 @@ blklen(i) = length(blksel{i}); end if any(blklen~=blklen(1)) - error('the number of repetitions per block should be constant'); + ft_error('the number of repetitions per block should be constant'); end for i=1:size(blkmeas,2) if any(diff(design(:, blksel{i}), 1, 2)~=0) - error('the design matrix variables should be constant within a block'); + ft_error('the design matrix variables should be constant within a block'); end end orig_design = design; @@ -165,7 +165,7 @@ % do some validity checks if Nvar==1 && ~isempty(cfg.uvar) - error('A within-units shuffling requires a at least one unit variable and at least one independent variable'); + ft_error('A within-units shuffling requires a at least one unit variable and at least one independent variable'); end if isempty(cfg.uvar) && strcmp(cfg.resampling, 'permutation') @@ -210,7 +210,7 @@ if ischar(cfg.numrandomization) && strcmp(cfg.numrandomization, 'all') % create all possible permutations by systematic assignment if any(unitlen~=2) - error('cfg.numrandomization=''all'' is only supported for two repeated measurements'); + ft_error('cfg.numrandomization=''all'' is only supported for two repeated measurements'); end Nperm = 2^(length(unitlevel)); fprintf('creating all possible permutations (%d)\n', 2^(length(unitlevel))); @@ -254,10 +254,10 @@ resample = zeros(cfg.numrandomization, Nrepl); %sanity check on number of repetitions - if any(Nrep~=Nrep(1)), error('all units of observation should have an equal number of repetitions'); end + if any(Nrep~=Nrep(1)), ft_error('all units of observation should have an equal number of repetitions'); end if max(units(:))<20, - warning('fewer than 20 units warrants explicit checking of double occurrences of ''bootstraps'''); + ft_warning('fewer than 20 units warrants explicit checking of double occurrences of ''bootstraps'''); checkunique = 1; else checkunique = 0; @@ -298,7 +298,7 @@ end else - error('Unsupported configuration for resampling.'); + ft_error('Unsupported configuration for resampling.'); end if ~isempty(cfg.wvar) @@ -319,10 +319,10 @@ % but important is that the relative requencies of the condition sequences remains the same if strcmp(efficient, 'yes') if numel(cfg.ivar)<1 - error('this reqiures at least one independent variable to be specified (ivar)'); + ft_error('this reqiures at least one independent variable to be specified (ivar)'); end if numel(cfg.uvar)>0 - error('this is not yet supported in combination with a unit of observation (uvar)'); + ft_error('this is not yet supported in combination with a unit of observation (uvar)'); end original = zeros(size(resample,1), numel(cfg.ivar)*size(resample,2)); diff --git a/external/fieldtrip/private/rigidbody.m b/external/fieldtrip/private/rigidbody.m index 8f74ee43..cd02a500 100644 --- a/external/fieldtrip/private/rigidbody.m +++ b/external/fieldtrip/private/rigidbody.m @@ -50,7 +50,7 @@ % $Id$ if numel(f)~=6 - error('incorrect input vector'); + ft_error('incorrect input vector'); end % compute the homogenous transformation matrix for the translation diff --git a/external/fieldtrip/private/rotate.m b/external/fieldtrip/private/rotate.m index d6b05256..2512a5a8 100644 --- a/external/fieldtrip/private/rotate.m +++ b/external/fieldtrip/private/rotate.m @@ -49,7 +49,7 @@ % $Id$ if numel(f)~=3 - error('incorrect input vector'); + ft_error('incorrect input vector'); end % convert degrees to radians diff --git a/external/fieldtrip/private/routlm.m b/external/fieldtrip/private/routlm.m index 4ce17d0b..428efa85 100644 --- a/external/fieldtrip/private/routlm.m +++ b/external/fieldtrip/private/routlm.m @@ -1,4 +1,4 @@ -function [varargout] = funname(varargin) +function [varargout] = routlm(varargin) % ROUTLM computes the projection of a point from its la/mu parameters % these equal the "Barycentric" coordinates @@ -45,7 +45,7 @@ try % try to compile the mex file on the fly - warning('trying to compile MEX file from %s', mexsrc); + ft_warning('trying to compile MEX file from %s', mexsrc); cd(mexdir); if ispc @@ -62,7 +62,7 @@ catch % compilation failed disp(lasterr); - error('could not locate MEX file for %s', mexname); + ft_error('could not locate MEX file for %s', mexname); cd(pwdir); success = false; end diff --git a/external/fieldtrip/private/routlm.mexa64 b/external/fieldtrip/private/routlm.mexa64 index c1433c22c11571f1b18658f2e0cf8a62a9ceae72..5c50308b475a182ab63c9708e92871f4ff3e8a48 100755 GIT binary patch delta 1259 zcmY*ZYitx%6rMBt=4-D8gq#8AaK$K`CF&ax~8dxOl7Q*$+PK)hLX1+P! zIp@3Ixi^_}E$3Q#_t*ygTy72a?Y$tIy+-gq;?r>2z5c`D*5Ll+Xyf5;AKQ0w#ZMLI zlT4cgHxGjvn75eVh^FLy4Sd9jGeSg%kgbdlJ26GD+=*?rH-$Va$JMGuVeF6!(P@|A z6fU#hgU`^DpMo9uV*U;5p?r=z7{or=Z@WZ3n#Gu98@}RbD6~={BMy&Qn#Hp5X0hRN zMs!*3XjdJr&~d;Fy6nrc;ZxK>SaH&xJ^Ts_r{F_KzRuNU%dPF;4h{=KQW zx4kOYHsQ`PmJwH8%!rc7VEB0^Axh@3!A;G~RS`!Ul+gxh{M@ zuoFXK2-aaj3_t*Pivga^;@jdz9t0c~Bk&#G6u)`$&;!Pf{3aeAB->;&Ii~xXqChFyo+b#QrLr6-Ca1b!Tqw36AW%-j??;=)&Pv+U3VpPW3-?OQn;^Rx_YQP1KBXtnk6#t808#t7kcW;j z(mqaeIWmlm5^f;;i|_+NGs!+A3=<~F<7UE-37ZHj?lE?ZaGDP0JYhQ>*6)O8=;j?f z$8DkGtsrcoi)tbqcu4hxZqn8l9NfymeiuIDm0&f#;Eh8y_IZn8E1soyH(vG@C$8LK ztVS@-M_j6T}*rT0zmnR_h9tX+Agf8mirZWB_N$>JJ+ z1d6one#Ya8zyL3Jv{dktl@~;mOJa7xqi@J@f(KJ2Ywe-AFyz5*3K#q+~AM zotiCj!CXGyYmmm<#EIOz$YS2bnNeC*V3N2_OKa{4*MZ11QCI o!+m@$)&e7VJyu0UzIYs7#@cv|EhQU@LG7cs2k8HF_Hi)%2j7B{n*aa+ delta 1175 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 literal 13360 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 TwbJRa=WLAJZKd%L|2z2)Sw*#( diff --git a/external/fieldtrip/private/routlm.mexw32 b/external/fieldtrip/private/routlm.mexw32 index 62cc27d65aa872ca63a7ecee2ae5b08ae9533f03..f32719c33d0cf3a23addb300635502876961433c 100755 GIT binary patch delta 32 lcmZp$Xt0>@gQZjES>(h&K1@;%HhVFi5(4u#ONhK+2LR;v4MqR} delta 32 lcmZp$Xt0>@gC+3ar_hOie3*{R-t5JAN(ju~EFtoO9RLBy4-WtU diff --git a/external/fieldtrip/private/routlm.mexw64 b/external/fieldtrip/private/routlm.mexw64 index 7433da2005bcdcf1a21bd6cf2a94984cc59e8725..c48f43521e995b7e3fdfdd3d30794e2006fb7626 100755 GIT binary patch delta 32 lcmZp0XmFVDfMx0Pr;!t%_%L;3Z#H6V5(V=&?-29g1OWUX4w3)> delta 32 lcmZp0XmFVDfF*+YbLhk;K1>|5HybfFiGul?cZhj#0szq(3-ka0 diff --git a/external/fieldtrip/private/scale.m b/external/fieldtrip/private/scale.m index 7ba67e67..c77b0340 100644 --- a/external/fieldtrip/private/scale.m +++ b/external/fieldtrip/private/scale.m @@ -44,7 +44,7 @@ % $Id$ if numel(f)~=3 - error('incorrect input vector'); + ft_error('incorrect input vector'); end H = [ diff --git a/external/fieldtrip/private/select3d.m b/external/fieldtrip/private/select3d.m index 61405261..4ee6b63b 100644 --- a/external/fieldtrip/private/select3d.m +++ b/external/fieldtrip/private/select3d.m @@ -63,16 +63,16 @@ % other variables ERRMSG = 'Input argument must be a valid graphics handle'; -isline = logical(0); -isperspective = logical(0); +isline = false; +isperspective = false; % Parse input arguments if nargin<1 obj = gco; end -if isempty(obj) | ~ishandle(obj) | length(obj)~=1 - error(ERRMSG); +if isempty(obj) || ~ishandle(obj) || length(obj)~=1 + ft_error(ERRMSG); end % if obj is a figure @@ -121,7 +121,7 @@ [a b] = view(ax); xform = viewmtx(a,b); if is_perspective - warning('%s does not support perspective axes projection.',mfilename); + ft_warning('%s does not support perspective axes projection.',mfilename); d = norm(camtarget(ax)-campos(ax)) P = [1 0 0 0; 0 1 0 0; @@ -154,7 +154,7 @@ zdata = get(axchild,'zdata'); vert = [xdata', ydata',zdata']; faces = []; - isline = logical(1); + isline = true; % Ignore all other objects else @@ -172,8 +172,8 @@ % NaN and Inf check nan_inf_test1 = isnan(faces) | isinf(faces); nan_inf_test2 = isnan(vert) | isinf(vert); -if any(nan_inf_test1(:)) | any(nan_inf_test2(:)) - warning('%s does not support NaNs or Infs in face/vertex data.',mfilename); +if any(nan_inf_test1(:)) || any(nan_inf_test2(:)) + ft_warning('%s does not support NaNs or Infs in face/vertex data.',mfilename); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -259,7 +259,7 @@ vert_with_negative_y = zeros(size(faces)); face_y_vert = xvert(2,faces); ind_vert_with_negative_y = find(face_y_vert<0); -vert_with_negative_y(ind_vert_with_negative_y) = logical(1); +vert_with_negative_y(ind_vert_with_negative_y) = true; % Find all the line segments that span the x axis is_line_segment_spanning_x = abs(diff([vert_with_negative_y, vert_with_negative_y(:,1)],1,2)); @@ -308,7 +308,7 @@ % three vertices since that is all we need to define a plane). % assuming planar polygons. candidate_faces = candidate_faces(ind_intersection_test,1:3); -candidate_faces = reshape(candidate_faces',1,prod(size(candidate_faces))); +candidate_faces = reshape(candidate_faces',1,numel(candidate_faces)); vert = vert'; candidate_facev = vert(:,candidate_faces); candidate_facev = reshape(candidate_facev,3,3,length(ind_intersection_test)); @@ -319,8 +319,8 @@ v3 = squeeze(candidate_facev(:,3,:)); % Get normal to face plane -vec1 = [v2-v1]; -vec2 = [v3-v2]; +vec1 = v2-v1; +vec2 = v3-v2; crs = cross(vec1,vec2); mag = sqrt(sum(crs.*crs)); nplane(1,:) = crs(1,:)./mag; diff --git a/external/fieldtrip/private/select_channel_list.m b/external/fieldtrip/private/select_channel_list.m index abc48ab9..721b6223 100644 --- a/external/fieldtrip/private/select_channel_list.m +++ b/external/fieldtrip/private/select_channel_list.m @@ -81,14 +81,14 @@ function label_redraw(h) % set the active element in the select listbox, based on the previous active element tmp = min(get(findobj(h, 'tag', 'lbsel'), 'value')); tmp = min(tmp, length(get(findobj(h, 'tag', 'lbsel'), 'string'))); -if isempty(tmp) | tmp==0 +if isempty(tmp) || tmp==0 tmp = 1; end set(findobj(h, 'tag', 'lbsel' ), 'value', tmp); % set the active element in the unselect listbox, based on the previous active element tmp = min(get(findobj(h, 'tag', 'lbunsel'), 'value')); tmp = min(tmp, length(get(findobj(h, 'tag', 'lbunsel'), 'string'))); -if isempty(tmp) | tmp==0 +if isempty(tmp) || tmp==0 tmp = 1; end set(findobj(h, 'tag', 'lbunsel' ), 'value', tmp); diff --git a/external/fieldtrip/private/setviewpoint.m b/external/fieldtrip/private/setviewpoint.m new file mode 100644 index 00000000..ec3bc639 --- /dev/null +++ b/external/fieldtrip/private/setviewpoint.m @@ -0,0 +1,91 @@ +function setviewpoint(ax, coordsys, viewpoint) + +% SETVIEWPOINT changes the viewpoint for a 3D image that contains data in a known coordinate system +% +% Use as +% setviewport(ax, coordsys, viewpoint) +% +% For example +% setviewport(gca, 'mni', 'left') +% +% See alo FT_PREPARE_LAYOUT>getorthoviewpos, COORDSYS2LABEL + +if isempty(coordsys) + coordsys = 'unknown'; +end + +switch viewpoint + case 'front' + viewpoint = 'anterior'; + case 'back' + viewpoint = 'posterior'; + case 'top' + viewpoint = 'superior'; + case 'bottom' + viewpoint = 'inferior'; +end + +switch lower(coordsys) + case {'ras' 'itab' 'neuromag' 'acpc' 'spm' 'mni' 'tal'} + switch viewpoint + case 'superior' + view(ax, [0 0 1]); % the nose is pointing up + case 'inferior' + view(ax, [180 -90]); % not exactly the same as [0 0 -1], this causes the nose pointing up + case 'left' + view(ax, [-1 0 0]); + case 'right' + view(ax, [1 0 0]); + case 'anterior' + view(ax, [0 1 0]); + case 'posterior' + view(ax, [0 -1 0]); + end % switch viewpoint + case {'als' 'ctf' '4d' 'bti'} + switch viewpoint + case 'superior' + view(ax, [-90 90]); % not exactly the same as [0 0 1], this causes the nose pointing up + case 'inferior' + view(ax, [90 -90]); % not exactly the same as [0 0 -1], this causes the noise pointing up + case 'left' + view(ax, [0 1 0]); + case 'right' + view(ax, [0 -1 0]); + case 'anterior' + view(ax, [1 0 0]); + case 'posterior' + view(ax, [-1 0 0]); + end % switch viewpoint + case {'rsp' 'paxinos'} + switch viewpoint + case 'superior' + view(ax, [0 1 0]); + case 'inferior' + view(ax, [0 -1 0]); + case 'left' + view(ax, [-1 0 0]); + case 'right' + view(ax, [1 0 0]); + case 'anterior' + view(ax, [0 0 -1]); + case 'posterior' + view(ax, [0 0 1]); + end % switch viewpoint + case {'lps'} + switch viewpoint + case 'superior' + view(ax, [0 0 1]); + case 'inferior' + view(ax, [0 0 -1]); + case 'left' + view(ax, [1 0 0]); + case 'right' + view(ax, [-1 0 0]); + case 'anterior' + view(ax, [0 -1 0]); + case 'posterior' + view(ax, [0 1 0]); + end % switch viewpoint + otherwise + ft_warning('cannot change the viewpoint for "%s" coordinate system', coordsys); +end % switch coordsys diff --git a/external/fieldtrip/private/shiftpredict.m b/external/fieldtrip/private/shiftpredict.m index e774697d..38d903c9 100644 --- a/external/fieldtrip/private/shiftpredict.m +++ b/external/fieldtrip/private/shiftpredict.m @@ -83,7 +83,7 @@ case {'abscoh', 'imagcoh', 'absimagcoh', 'atanh', 'atanh_randphase'} % normalise, so that the complex conjugate multiplication immediately results in coherence if ~all(trltapcnt==trltapcnt(1)) - error('all trials should have the same number of tapers'); + ft_error('all trials should have the same number of tapers'); end for i=1:nsgn for k=1:nfrq @@ -109,7 +109,7 @@ dat = dat./sqrt(ntrl); otherwise - error('unknown method for shift-predictor') + ft_error('unknown method for shift-predictor') end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -219,7 +219,7 @@ case 'absamplcorr' coh(:,:,i) = abs( datref(:,:,i) * dat(:,:,i)'); otherwise - error('unsupported method'); + ft_error('unsupported method'); end end @@ -241,12 +241,12 @@ case 'absamplcorr' coh(i,k,:) = abs( sum(datref(i,:,:) .* conj(dat(k,:,:)), 2)); otherwise - error('unsupported method'); + ft_error('unsupported method'); end end end otherwise - error('unsupported loopdim'); + ft_error('unsupported loopdim'); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/external/fieldtrip/private/sine_taper.m b/external/fieldtrip/private/sine_taper.m index 563bbb5b..2a888f27 100644 --- a/external/fieldtrip/private/sine_taper.m +++ b/external/fieldtrip/private/sine_taper.m @@ -25,12 +25,12 @@ % $Id$ if nargin < 2 - error('usage: sine_taper(n, k)'); + ft_error('usage: sine_taper(n, k)'); end k = round(k * 2); if k <= 0 || k > n - error('sine_taper: k is %g, must be in (1:n)/2', k) + ft_error('sine_taper: k is %g, must be in (1:n)/2', k) end x = (1:k) .* (pi / (n + 1)); diff --git a/external/fieldtrip/private/smooth_source.m b/external/fieldtrip/private/smooth_source.m index d4d3e9ee..8180cca8 100644 --- a/external/fieldtrip/private/smooth_source.m +++ b/external/fieldtrip/private/smooth_source.m @@ -17,7 +17,7 @@ maxdist = ft_getopt(varargin, 'maxdist', []); if ischar(parameter) && strcmp(parameter, 'all') - error('not yet implemented'); + ft_error('not yet implemented'); elseif ischar(parameter) parameter = {parameter}; end diff --git a/external/fieldtrip/private/solid_angle.m b/external/fieldtrip/private/solid_angle.m index c984e803..47e65c67 100644 --- a/external/fieldtrip/private/solid_angle.m +++ b/external/fieldtrip/private/solid_angle.m @@ -1,4 +1,4 @@ -function [varargout] = funname(varargin) +function [varargout] = solid_angle(varargin) % SOLID_ANGLE of a planar triangle as seen from the origin % @@ -33,7 +33,6 @@ % You should have received a copy of the GNU General Public License % along with FieldTrip. If not, see . % -% $Id$ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % The first section contains the plain MATLAB implementation. The mex file @@ -79,7 +78,7 @@ % w = 2 * atan2 (nom, den); % return % else -% error('invalid input'); +% ft_error('invalid input'); % end % compile the missing mex file on the fly @@ -93,7 +92,7 @@ try % try to compile the mex file on the fly - warning('trying to compile MEX file from %s', mexsrc); + ft_warning('trying to compile MEX file from %s', mexsrc); cd(mexdir); if ispc @@ -111,7 +110,7 @@ catch % compilation failed disp(lasterr); - error('could not locate MEX file for %s', mexname); + ft_error('could not locate MEX file for %s', mexname); cd(pwdir); success = false; end diff --git a/external/fieldtrip/private/solid_angle.mexa64 b/external/fieldtrip/private/solid_angle.mexa64 index d94d91903daba7af06c027953cbd8f5bc78e29f4..a09e02e630aae3124abc1c336d5d1a1d3a101109 100755 GIT binary patch delta 1247 zcmY*Ze@v8R9Dl#>{osx}?!6Ze4v)J7-3df;7v>T&g;%|JX-6Y}Y>{TNAx!^>t-(ym z%t7hfaRq&~x#lJsHC_JUdaKdahJY(wwPD#t!^vVb&&3d~j31Ft-{+2@KHK|#p6~C^ z_xrr>6K#q%b?vcsc!lKZ=-$^a-&md!mJrL~j7yk5)~k#UdiE|ff7P1#W{>;F6W#g* zEC6)qcMN_5oYXC87r|TR6omNC_Zh2>9=62y(?)HdHMH2(*oLq^Y&i~a6YJ8CiFOB$ zrx%Io4z$~fM2iETvh9W*JZW1EALF1c2&Zw{b`L(q+xF*RC$7mDGq>3U;gBEeT^{SV zM6po{nzrH7j_uiIG9;wItENV&Xt+_@emx;MP1Aa>qZy7Iv{I0}HLH&|rD}$1%^0ZG z!onR5c#tzz$rz(l8MWL|Y;o|kTlju+V^?cMGAwSKVJsmPUrtD}A*D(Dv#3!d*%(Oa zZat)<0!36Hf(M){tuOt{SVWtNXW}_$4eY`xXFjY)S@wYsL$Xg~^Z2~HNdyaiAQ!*@ zel35wu5E#_w@0OpFNikL3}5BECe4EI+A}29T;`O=xLCrQPDn5ErhUKQCz~FkFid|85+$ugsn8Ln}iqV7_*Cl@GK2@Enx#4RRiHA`q(=OU6h+I zIJ8xO*PWQ>k-?6oo)A=Gy(bU0;!%3Pi)TG~%1<S{(}djWB`(#cr6Qcb35^+`ws)YIW=5 zg(AF#r6nP{5b8?~klU}cuSRR|75Ek6w|59(@~XcJ>F(S&BIL2W~+jiF6{u+bR%NUKeo4v|#BAao&K&n$}ZCU?Gb z?m727?%bLFuKup{4trC8%a5j`-J|m0$|Yr)SO*_^hT4wo>#_1X8?&ivSDrn&nQLWP zeF_!atpNUw!+UKFfVeP@%>+nwe%mf8GA|4`sOXYMOx}nL7%X_4)6(XaU9_< zy6}c0%wKR}ku%JXyYOM>HrR{rI9I_gJnM|WR-AUuLMPrXY6U;8ab35qcXHf;@n2&SnsT@^od_BBImTv0*IYF*pE)R5;o&1ISA{pRSxpL1?-j^`KyKaxm*p$@CW&eweK!6cIb-u z+DWR1@;8s03C|aB+`bK@ww*C+`Px)#&2DDI4zru!FrF!14{zXNadmK4E?-jf$gk_v z7N(c_Z03yL{}pYtP4J;GK&a zcg%XW2$hsY>pNHZl)6=YTHSX3+jKhJt|f12DWQr?%leaA-;_=37s5g%`OmZ7m0Bw3 z7x0_1dwAtH{dyU|%Vx|$Dmpg9*g4`$#GAw)iB<~s*dL6Ah=+(x#LL9p#NJuP28aRb z`V{d4;#FeyE@MSJ$2~)5_Yg5oZ(%p_6kX2&qK9Ie0}edF!HW`Z_sI~$=Y0yig2#Oo z@HURo^8)_jt5A!nhN$VRx~0bt^R5EEv8d2SIce!4%{sET|IfZLZx7Mh6wNrQ{u<$D zs(1){{AHdrpEsL3%n)Wf9r(V#0=~qr{0f}LNq@~6g&MI?q0344yk&XQni2*I`U)+V zU^zlQ2}R&@*chmWu-+X|0Mmg6%mjxaqqmfg7Vw6Ij;e?~Q)cGmxD2XQYwg4TXv6p_ zY5#ruW28yGB~M9*>QO6XaO^%W4AZmJB5{K_O`4?J@2}yZ0UxMU=wj@w-A`_pNRFUA ovYni}BV90r*+@O?L0M6NM^%a1S;<-cg=8Pt+u=(n`X%~8lp{Y(Ku+i@=8}&jE~#=#9@}%=LY@i+7t1{ zmfbc-uDnCGyx-XU4(M%WJUtiRbE+Ez&Te4Mr>;X^vXdT>XyP@-%x8ar)fN9{SxnY?xtG`nUPB zxI8vYN9E&@wdJ?~>2H+l$Tp0YCZqj{=3T8#Mq46&Q+bX!%5%m-j6(llTsV(m>~5Xi zg&Xx#Jr<`khIp>LTO46%4WlXY-|4puS!@y75bo$0Jlu(7$mOg;3fk5iE z1%(eooQ1r%qGa0v=$z;D{fct?9Eye9frj&Z_RFWfy=2c1fB&oB_PzMMbIso^1x+Q( z0!Y2(7G;%#lZJ=$LRC4I^E;0(-WEwT+}G5&tGT1B{t2{J&)49OW)HZLzXO6?%6-Z9 zIHj}HtzKPLVNXK-btqhmrOz|iiMjk+pJ-1+o69z2>va$KxlYx#^Sw6i1BG6>ofoC272(SD|suif3&cI#3HTdhl_4gl*~VX672qYNv6YL z6cTOC=3GF|MvGI;Y|iFXGl6W*B66;moa-|y*_s1V-t7{84zQXjmhjLYdC_^6RmDi= zB2LSoIap<0$z%X(X1~_c(}YD-nIBh~pH`VunPoyzCWX7;;4`Evi3OQ7I7!jEySUye zvm6FF1{KD}Aok$YJkfP>t~m}<_Q9)`0Tx1!%&$2y4e(@k*HU)vmtE^KwQNo5UXrPi z@F0!p;{dZ?lGjSO>v3AW?s~O(#a>s?yq>wu>eJAtnM0WcQo=x>>kIMscS5_3J%#Hv zvnzz|K*bkgPit7G3G7nFiB?+TlsDX6;aA&*o_?nEV@h3d<$65LDl^ zRyQ&!)WX+blE9G-JyrLD@;oUol5(`tHI|L1f?1utU@x1)emIA{FIYG1$m(j7lUI7D zIlEfe5BXgkpjEmuvy{LAt>?)jT2Hc9>v@VJ>>bTK@@Lq#jlx}c+1bj4nfcsYNefO7 z2EKbmbbWapBdm?px_d0^m0*A0h5gRce~)2E<~7`4>Hgmjq?5O4zZhU({M4`eYyCU@ zMs0uQKhWRX+spWYro||aluU|nk=OxSh0*{w0}s7`j)zoWn^1+0)%M5aQzlj(;&v$Z z_=mu&KH~7nq53f_ejdnDHoI=M#puK6d6*++rriXL{c_L-wYEP;KDyMOaKvM(@V*D$ z_W`d$*+Akx5U+xG9RfZ^`yG@wQ9cKL4y^$u9V5a}Df~L%<7m06(15+5-1W>TmYTH( zJZ9D$DOzJv)TAr{Hyf`PVWwFbI&B)x7Npaz;T&nP*j#y)LKRphj11@-fFLFy^b>&Y zN7+*{=@76k+Z*0z=&iJ=EQ( z^s@ju3H(WTX|xZ(F)F-6&N!_4Bv&5ui?VcbdFLI_%Dn)C=s@luDwUq#4q_Y0lS+Cz zS2#R$6t|x|w7=W0LfP7Ws2HB4+9EWLX~xigiuM}Xuh2rrol}9XRAK>kBPPn;*uMgp zPdqgUIrG27Zxs-)ir=JshsKiyRJBrs(=ZYC%hD}83{f-sg<+16!TG}~81!4f8h+k3 z8|@F&HTkz$l2gYVLlk+;D9$P7a^m}@psyDs|H(Eo3B)v{Z-vha+lNvtZJZz`XEXx zgF$}dmXp0p*x*S-r4yrZAiYh z2oA|NZowhGa8SnnfZx6p0jn|SARQs4zf4k#6nKdO5kFxF@-pXe){~$;2N&1~cg`O>3x~qE2{3&w=f=(;UiEPx9Qi)=0S$unQP8G|T*C-ByChx}Uc{1<7aRj2 zgJefNma}slWfbLVOx#E z;@)PiReBTiR`?Zk9ixy>7?u|>I)t=^DPCglaaJ#pMR;E!{G~&XKtJYTM1d^yA$GmX zY7*E-=z0=s2!9M4(h67DbJ;cx3=1XwV)1w^AO_!30EXo%7&XX9Si^_tSxhO%Vq!3* zK*jJV*!0WfI74Nrg8oiSEItFSA&Uzk6ceFyAV9YzDG1t`LFHa8Es4On2LM=hq~IaU zgzlC5N`Nl+oFp5e90CjvIA~x`ob||CfIlGID!~hIvn!Y?{JHSrG6=`QK2u8g zLsp-_JQ84f3?oMMcL)r^5pYeyxylt@#sbIDGSW}^<^2|3Q8wa#22rW(cULeXh~lO< zT`4wYFi_>rs#=NgrU76vsGcXO!BPug_!O!T!k^yGi%0lvv~N=Mnf;3)R9s@RebN7{ zEq6T7bx|Dp9CKEgfj(ZN50yZJDzo}-6PwQ1Jdhp`xSH4LDxEoIG%$wrl%LF=O7xvoZ!qDmgY3Rb-g&8z9NsDPdVy8UUO z+nevHVC+2q3 ze{i`#G{`H4pT@);W9)YJ19WNKfj;o~W_f%L&n0Mpu0Q`B=kvY|cAZxz9butgK=~A_ z^yx(Ifr5%44S?S%3+WyrL~6o4d%9UegM z7jno1^27y_ra5**jy-|>4#_JVHXN5CU|*4h1k;LxT7NGl+9oPva9{wR5I7$bI+3$L zc7BEhAC3ukIkaT1pTZEN-<>!@+&&fQLCZRa#Y&%bpT`c%!&VycJ21+AdGx^#)iM;` z3uqGcdnmks>$Hf@l+M$U`JS;SR9pi==QTA3RENImqXbS^!S;giB6h;#pdjZnEz8UK zduVxjz5}|v8RBNfQ&64|qX1+^N92VDjxxgFM#uNxTESpQA7w0vP57OXmG6egC6DpH zga-Sdu=+55FhBYg?Qx5u#S!s@pV``{5lUw#yn^^4+kX7n>A<%NN9-F z3Rbw)$dm3}d+X-L>I9K-?*lVUhV1SG`S9ff5_B9BZYJ5t`0ESUEcy>-G?_B1pJofBRx8JP^dNN%C?K$yQKQLd1Cj6I`d zm3a?oCnS$u*=c(}IHa3iLMJ^kjLaE&*}0G0-s#3poQN+Ra?$RHQ~cVj;RcBC{92G| z`|-Qed3YWT6?eMkDZF@<7uWVr-|fK-Y5MNFWL+xjdt~jE^(tAfk#!krWVoK?Z$qws z>-60(qwQ@VaqJ^_LW76USwa%&@g2n|DRyp4M2-gtLEI zhMMDCQ}&a}MgSkM@dMnFJ5gx3Qk%$D8WMltIT4!g;@`G^02<3@_TQ-q^Mbqxf5G(P z??8B5J`fHRDXw&}GOrvzK8`F@TwCz&A>t}y?_lYOfC;#n#J@?TuadUK}6C zAIRXHjeK0a%HCyepV8d0F&>R1qLr=5T}{#I2tIu8FdlrMTtUA__CFL&R7MgJ61)zf znpnAmZ6>yE28&4CcN>I9I|A`|b^GpZ`2Pdo(Q;IcMH-t(-vT}ta`yf7RQHb~9qa!{)LLokGe>AWiU7`cRebiN5FfSQSN$3|&>36&OAh|;Iry^{?$}9r z$-*JRdOpg*CvxyFb8x=0np9gU?P0fnY zgr4?j9Y+yrtdA;2duvk!|5t=QJL9iJZsM|YVpRsf9Eugab~MZlpqs}kdYmY=z-p*N Q(q^YcOx}I65m9k*&SodWF-&$LWEO-WXkY)SYd#u%_Mr49-7$`D7$#4#pe z`#k5KEA84A^`Fl4$DWz<@qV87yyrb1dv^Dymwx%tB1Lf(D~jSlUW|OPL{WxNGkprV zuSii0quw8?7pVNgn-3}yhE4@)6xK|JkqGxC?6wW(>+8SHrZsAIP1rrpPM|**G>rJe z-L0`MBc4dMuDa5`*FJ4?-ywwvyK)qGq`p##GmN%)qPH`;bq>zA&+`X1;jbl~Fn#7E zxF|0{Uo0A*AMoY=+bi`|Nh!j4IE!ig(5dL`k!W~AWx1~F53tVpBMXAptoklp`@>!BQU=vR`W$uC=g7`W&9@9AikP!QuP4!a zg+2}POpZRnxv{}`bJhg;45O>%K)fsdu5&4|(!CX&>~`_A+Gph<)Yyr=}~` z(jM+LdRh`4pX=&u?e42YKy**d-B!>{&IHXJ z7xl;9oq=5gmx^@rx$0~-s}4qSgbZ9NPW+*szV8P(CamA7I1W?ICxfZ*nP3XCDafXF zT$~zHm-ll}dg=?-Su$lO)xmOzLvjYNHHIRP`qm0hT{^MCV;yvOPEaU)-}~hGJISL3 z(oHKg>jw_c_idhw3V%F=O3pY^Hbr78d6p-j@Nr^N7s=9jKMRO^$_A_U$! z!69kZM@yh~;9{{l)BwLtH=z(?wceT|+(^Q5L4ff`=J2n71pLoYMAYTA&;tMMmBd6D z9P=*#tnZ+(6+W3u`w3|e2^w_99VVZ7(29`H9IBBW(hClm9`gZMbzE=zP(Ru7 zz^dI|A^#j*;xi}AA^OW_j_YavUcU>PpRW)MLsh8Wxzl!xjIWfbm3*!>C`GucVK z?U*m^F3nB_QuQw@*`vDIuvg*)Mt=&JeSuW%0nF8I4na5l8NF@Pmo8gkqfP&C9^5ts zmZv~F0+F;mc>jprcF>pp{5?`+sE3+zQEeCC`95I5@oNY^XFJ8;Z#{+2a(eL|&dRJ> zUYu$;Jak+gd=oKbJ%W1;anmONalvC`iyBaT)ibL$mSXXvT8DP1q=-?khDJ%$h}GbR z(5SPJrN4zJ6+B?`*c#SAL(?QWx=u=Ki=bf%@*1!S%382!Dh1IHT{f0FB#qm}AcFxG zXi*RKf1UhmwTN1A0F8(yI@0ceEG_&K;9o-fC^BZR@xPJZK>ig}Vg{QIBmXC0njwa2 za5PO24ULW20c4lZrHbLuD$EQ0kpb7@^SD8yo&>`KloeRWZ^$et-?T)?H_;o7j>zI? za}~jcHJ53Vj+IqIMBVfYsPTQxZyv-TU-to1aUx*8?5oHAylQHrZhoi_yt_s6>uL89 z`c2P{>H{Azpvy}2^z~>oVJ^ypB^V5B@u^yE3C7b@gfYDcLT$;29Mj3*?eO_5m1I9`3ic{*IBW)eZZHE}#zg+y2`;3YC+IW$5F~wiXadB8c=^wOQan z8x5N0f+pwQ4^5$B?!oRABoKwE3*GM_4nqK!filiqJ{qQ=m0sRYZmx0_KbURT=cU5$EyanCUqK`#JAx)9wSTG3SVN&F!-181swK zYHltuOgX^4v-blY4P-L`987cQ;pFprdXLy_(n(Cqj=eYst!2N3Z_+!C>E;{O3m@_< z+BCI~$0w#@blWFZWl&G5f0@Dd_}Dm&`UY$j@xb`K5HOE3gg4ch6Y#+~*zfxq8gC=N zQD+|YHTdc|ntc$&r2%W)jwF`OcxG2)YaYd@s$uF~UM0e;c@WGN{ z;HSjs_UDZ*gb67hEaBL|!2mg#96^|4KiPo&VZ%!p#KC0c_LYGNenwOR6XLNdFySYp zU}Q8niW4wdNuCZ65+Hn6AqN z)BZ_bW}RCs_Q{@rc_C;vJdF($+oz6Q&1%GMGjuwbYIs^5+=Cg0H4T#p+tZlSm*VSC zzNUV6KL}_wXVmZh6`DR1-F<*TiXG=SR)ZL4xqlyo{rj$d@ex*oUdPpPsP`Wc{reGw z*t{xB_TcSy+wSe(BTgtj8>F4DT01ex?>rl+%sCG+F7pHSgRwbmVX_V2E}vtVkpGVl z#9aFKO}E0aIaF+vuUdaQN38{w@yz?b?ac6*I&<9d9Nb0s!g*My88{$dVv6n1GY?r2 zbPr?9A%<4a{FyL5Ykd{y)NbPJJKWIm z3&+KXCz7KHmmr)=P{jr=2Mg(9bU2}*o2P6KG7N&IZ7&!`!0j<7>P`3eNDIEd06vX95X`T~$R z0w}f_hkH5iUyWkxp#j)4o5rNFgcnru1dk1_u}3joZ_U=K8jd=Y4{DKGwIa*rT2I8MR%F0)*Q{S{yo5$2wt~h{ zqF*4#a@c%?jjbM*F=}YKD5O}N2AP+ow zheI229ta-ZB?bAw9C_U4#>v5M4iEx2Ahluw+!I7#X>K^pv786xjIfDl49A8>360Vq z9y-5(?#A~)nN+&X}y& z=}{IF7N3-%uw)wb)EHh7YOslAZ(A)&+%C~xBT8MAYegAE$rOnGSxZ-EySKfwI~Ha?MWuQExlWlz$U!-p6QzS@J4-2e0R_DMU&mF;a+bna#^2o+q?zJnJ-I1 z#$mvUVEVQL>jU>yxB(wW zDv+62W6d&=th^X15p@mP%q}kqq#9((mEjwZDqF%ea-C8%jCX)4O>t-NWkStTrFdp3 zi1_jW-vJ_qT&@>AZrAmYV{&bOP;vEXF0E{lhsN9s9PN4hm#_}$U3S3arU^^5?-aR- zSzPM&pc+`Tv(&u|ja|i0xYG=!h4iijje5QB*?JKoc5+in=;agtV(0rv@&}QtB!38P zk=*1E{G6pc{%--XMe?@`W)$=Mv@?(YpMe;W{GXrWU)Y}4!LwKLul`^7Ye6rA%Z^F@ z$HWW*IqyeaYT-xD^b^Hyeu?NbC~As#AiCk&RxasGC)tb-8Z1(?2Ac9`(EVVa*P*j zJA-U9&FkTCWWT$L2Nt<+126qdOtU=35MGRV`>t)>}>!_^P%DP(Cx69g=DwG8e6g*Jy zK*0kA4-`C5@Ib)>1rHQFQ1C#(0|gHhJn;X)1Le1PH_?t|HT<2l{Uh^M{4N|nGT-n` zZCLrHcUg_ml4yzEr2wc{T4QvF`~1DVb@8qB_&q;xRpr3--QOE-NrY=-$=0rLT?>9m z-)H>s-BqMl3;F}$L@m@1QR5)$2M%xm2lvT81Wdy$s!#f&D zic-qALe^EXu9kI;taVwhmo=YNZg$>8(5A8_fSvyzR7&_szWN~fkV)s8BGVdV!p9_B zC*dmm#ER+b$fS=*xJANeB-|-syibb6_g(Vyt&-^xWWsp26lqApc*7JaE#dXT3yQ*@ znu-4Sx`*`l$b`j@tx-LLd^4W(oc{y-8(yvWIhN)4c z^CE`bEBT>}KXo|&o3Q^4U_=m3MprEMr^z10XpbcnqpddP?P0~}>IMpb1|Y`f=^`!M2Kjibs|9~6 u@$&y0Ui<$W=qWd-<@(BBSqrZzP@L6dH|wB|sC7<_wUh4x@s|<$Q~4i@Mau*L diff --git a/external/fieldtrip/private/solid_angle.mexw32 b/external/fieldtrip/private/solid_angle.mexw32 index dda325cac0d7aa134388ff413a50572953861617..6ffabebf93b9126092295ed7c1f25ba324aa865b 100755 GIT binary patch delta 32 lcmZp0XmFVDgQZ30S>(h&K1{byZT4c+5(o1)S4ecQ0|4tG4PXEO delta 32 kcmZp0XmFVDgC*eKr_hOie3*LMHhVE@iG%r@D0 ) Gss = Gss+lambda*eye(size(Gss)); end; +if ( lambda>0 ) Gss = Gss+lambda*eye(size(Gss)); end % Compute the mapping to the polynomial coefficients space % [nSrc+1 x nSrc+1] % N.B. this can be numerically unstable so use the PINV to solve.. @@ -64,7 +64,7 @@ %-------------------------------------------------------------------------- function [G,H]=interpMx(cosEE,order,tol) % compute the interpolation matrix for this set of point pairs -if ( nargin < 3 || isempty(tol) ) tol=1e-10; end; +if ( nargin < 3 || isempty(tol) ) tol=1e-10; end G=zeros(size(cosEE)); H=zeros(size(cosEE)); for i=1:numel(cosEE); x = cosEE(i); @@ -81,7 +81,7 @@ H(i) = H(i) + (n*n+n)*tmp; % update function estimate, SLAP dG = (abs(oGi-G(i))+dG)/2; dH=(abs(oHi-H(i))+dH)/2; % moving ave gradient est for convergence %fprintf('%d) dG =%g \t dH = %g\n',n,dG,dH);%abs(oGi-G(i)),abs(oHi-H(i))); - if ( dG2 - error('not yet supported'); + ft_error('not yet supported'); end for i1=1:siz(1) for i2=1:siz(2) @@ -41,7 +41,7 @@ siz = size(value0); dim = numel(siz); if dim>2 - error('not yet supported'); + ft_error('not yet supported'); end for i1=1:siz(1) for i2=1:siz(2) diff --git a/external/fieldtrip/private/standardise.m b/external/fieldtrip/private/standardise.m index ad494025..33d4cc32 100644 --- a/external/fieldtrip/private/standardise.m +++ b/external/fieldtrip/private/standardise.m @@ -33,7 +33,7 @@ end if nargin == 3, - error('third input argument is not used'); + ft_error('third input argument is not used'); end switch dim @@ -86,5 +86,5 @@ sx = sqrt(sum(abs(x).^2,dim)./n); x = x./sx(:,:,:,:,:,:,:,ones(1,n)); otherwise - error('dim too large, standardise currently supports dimensionality up to 8'); + ft_error('dim too large, standardise currently supports dimensionality up to 8'); end diff --git a/external/fieldtrip/private/statistics_wrapper.m b/external/fieldtrip/private/statistics_wrapper.m index f903ceca..aad4c2f4 100644 --- a/external/fieldtrip/private/statistics_wrapper.m +++ b/external/fieldtrip/private/statistics_wrapper.m @@ -89,7 +89,7 @@ end if (istimelock+isfreq+issource)~=1 - error('Could not determine the type of the input data'); + ft_error('Could not determine the type of the input data'); end if istimelock || isfreq, @@ -107,13 +107,13 @@ % test that all source inputs have the same dimensions and are spatially aligned for i=2:length(varargin) if isfield(varargin{1}, 'dim') && (length(varargin{i}.dim)~=length(varargin{1}.dim) || ~all(varargin{i}.dim==varargin{1}.dim)) - error('dimensions of the source reconstructions do not match, use FT_VOLUMENORMALISE first'); + ft_error('dimensions of the source reconstructions do not match, use FT_VOLUMENORMALISE first'); end if isfield(varargin{1}, 'pos') && (length(varargin{i}.pos(:))~=length(varargin{1}.pos(:)) || ~all(varargin{i}.pos(:)==varargin{1}.pos(:))) - error('grid locations of the source reconstructions do not match, use FT_VOLUMENORMALISE first'); + ft_error('grid locations of the source reconstructions do not match, use FT_VOLUMENORMALISE first'); end if isfield(varargin{1}, 'transform') && ~all(varargin{i}.transform(:)==varargin{1}.transform(:)) - error('spatial coordinates of the source reconstructions do not match, use FT_VOLUMENORMALISE first'); + ft_error('spatial coordinates of the source reconstructions do not match, use FT_VOLUMENORMALISE first'); end end @@ -174,7 +174,7 @@ end else - error('incorrect specification of cfg.hemisphere'); + ft_error('incorrect specification of cfg.hemisphere'); end clear tmp end % for each roi @@ -258,7 +258,7 @@ % averaging over channels) if ~(isfield(cfg, 'avgoverchan') && istrue(cfg.avgoverchan)) &&... ~isfield(cfg,'neighbours') && isfield(cfg, 'correctm') && strcmp(cfg.correctm, 'cluster') - error('You need to specify a neighbourstructure'); + ft_error('You need to specify a neighbourstructure'); %cfg.neighbours = ft_neighbourselection(cfg,varargin{1}); end @@ -266,7 +266,7 @@ % get the design from the information in cfg and data. if ~isfield(cfg,'design') - warning('Please think about how you would create cfg.design. Soon the call to prepare_design will be deprecated') + ft_warning('Please think about how you would create cfg.design. Soon the call to prepare_design will be deprecated') cfg.design = data.design; [cfg] = prepare_design(cfg); end @@ -283,13 +283,13 @@ if exist(['ft_statistics_' cfg.method], 'file') statmethod = str2func(['ft_statistics_' cfg.method]); else - error(sprintf('could not find the corresponding function for cfg.method="%s"\n', cfg.method)); + ft_error('could not find the corresponding function for cfg.method="%s"\n', cfg.method); end fprintf('using "%s" for the statistical testing\n', func2str(statmethod)); % check that the design completely describes the data if size(dat,2) ~= size(cfg.design,2) - error('the size of the design matrix (%d) does not match the number of observations in the data (%d)', size(cfg.design,2), size(dat,2)); + ft_error('the size of the design matrix (%d) does not match the number of observations in the data (%d)', size(cfg.design,2), size(dat,2)); end % determine the number of output arguments @@ -557,10 +557,10 @@ dim = [Nvoxel size(tmp{varargin{i}.inside(1)})]; end if i==1 && j==1 && numel(tmp)~=Nvoxel, - warning('the input-data contains more entries than the number of voxels in the volume, the data will be concatenated'); + ft_warning('the input-data contains more entries than the number of voxels in the volume, the data will be concatenated'); dat = zeros(prod(dim), sum(Ntrial)); %FIXME this is old code should be removed elseif i==1 && j==1 && iscell(tmp), - warning('the input-data contains more entries than the number of voxels in the volume, the data will be concatenated'); + ft_warning('the input-data contains more entries than the number of voxels in the volume, the data will be concatenated'); dat = zeros(Nvoxel*numel(tmp{varargin{i}.inside(1)}), sum(Ntrial)); elseif i==1 && j==1, dat = zeros(Nvoxel, sum(Ntrial)); diff --git a/external/fieldtrip/private/swapmemfile.m b/external/fieldtrip/private/swapmemfile.m index 5841dbe6..38edf413 100644 --- a/external/fieldtrip/private/swapmemfile.m +++ b/external/fieldtrip/private/swapmemfile.m @@ -66,8 +66,8 @@ % select the single variable that is inside the MATLAB file data = getfield(data, str{1}); else - error('Matlab file should contain only one variable'); + ft_error('Matlab file should contain only one variable'); end else - error('Unknown combination of input variable and file history'); + ft_error('Unknown combination of input variable and file history'); end diff --git a/external/fieldtrip/private/tal2mni.m b/external/fieldtrip/private/tal2mni.m index 198375be..c74ddb0a 100644 --- a/external/fieldtrip/private/tal2mni.m +++ b/external/fieldtrip/private/tal2mni.m @@ -7,23 +7,20 @@ % outpoints is the coordinate matrix with MNI points % Matthew Brett 2/2/01 -% ensure that SPM8 (preferred) or SPM2 is available, needed for spm_matrix -hasspm = ft_hastoolbox('SPM8', 3) || ft_hastoolbox('SPM2', 3); -if ~hasspm - error('this function depends on the SPM toolbox, see see http://www.fil.ion.ucl.ac.uk/spm'); -end +% ensure that SPM is available, needed for spm_matrix +hasspm = ft_hastoolbox('spm8up', 3) || ft_hastoolbox('spm2', 1); dimdim = find(size(inpoints) == 3); if isempty(dimdim) - error('input must be a N by 3 or 3 by N matrix') + ft_error('input must be a N by 3 or 3 by N matrix') end if dimdim == 2 inpoints = inpoints'; end % Transformation matrices, different zooms above/below AC -rotn = spm_matrix([0 0 0 0.05]); -upz = spm_matrix([0 0 0 0 0 0 0.99 0.97 0.92]); +rotn = spm_matrix([0 0 0 0.05]); +upz = spm_matrix([0 0 0 0 0 0 0.99 0.97 0.92]); downz = spm_matrix([0 0 0 0 0 0 0.99 0.97 0.84]); inpoints = [inpoints; ones(1, size(inpoints, 2))]; diff --git a/external/fieldtrip/private/topoplot_common.m b/external/fieldtrip/private/topoplot_common.m index 7dde1097..55f964b8 100644 --- a/external/fieldtrip/private/topoplot_common.m +++ b/external/fieldtrip/private/topoplot_common.m @@ -23,7 +23,16 @@ % % $Id$ -revision = '$Id$'; +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% DEVELOPERS NOTE: This code is organized in a similar fashion for multiplot/singleplot/topoplot +% and for ER/TFR and should remain consistent over those 6 functions. +% Section 1: general cfg handling that is independent from the data +% Section 2: data handling, this also includes converting bivariate (chan_chan and chancmb) into univariate data +% Section 3: select the data to be plotted and determine min/max range +% Section 4: do the actual plotting +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Section 1: general cfg handling that is independent from the data % check if the input cfg is valid for this function cfg = ft_checkconfig(cfg, 'unused', {'cohtargetchannel'}); @@ -32,44 +41,52 @@ cfg = ft_checkconfig(cfg, 'deprecated', {'xparam'}); Ndata = numel(varargin); -if ~isempty(varargin) && isnumeric(varargin{end}) +if isnumeric(varargin{end}) + % the call with multiple inputs is done by ft_topoplotIC and recursively by ft_topoplotER/TFR itself + % the last input argument points to the specific data to be plotted Ndata = Ndata - 1; indx = varargin{end}; -else +elseif isstruct(varargin{end}) indx = 1; end -% the call with multiple inputs is done by ft_topoplotIC and recursively by ft_topoplotTFR itself +% the call with multiple inputs is done by ft_topoplotIC and recursively by ft_topoplotER/TFR itself +% the last input argument points to the specific data to be plotted if Ndata>1 && ~isnumeric(varargin{end}) for k=1:Ndata if k>1 % create a new figure for the additional input arguments - % ensure new figures are all in the same size/position - p = get(gcf, 'Position'); - f = figure(); - set(f, 'Position', p); + % ensure that the new figure appears at the same position + figure('Position', get(gcf, 'Position'), 'Visible', get(gcf, 'Visible')); end + + % the indexing is necessary if ft_topoplotER/TFR is called from + % ft_singleplotER/TFR when more input data structures exist. Somehow we need to + % keep track of which of the data arguments is to be plotted (otherwise the first + % data argument is only plotted). Yet, we cannot throw away the other data + % structures, because in the interactive mode ft_singleplotER/TFR needs all data + % again and the entry into ft_singleplotER/TFR will be through one of the figures, + % which thus needs to have all data avalaible. At the moment I couldn't think of + % anything better than using an additional indx variable and letting the function + % recursively call itself. if isfield(cfg, 'inputfile') - cfg = rmfield(cfg, 'inputfile'); + tmpcfg = rmfield(cfg, 'inputfile'); + else + tmpcfg = cfg; end - - % the indexing is necessary if ft_topoplotTFR is called from - % ft_singleplotER when more input data structures exist. somehow we need to - % keep track of which of the data arguments is to be plotted (otherwise the - % first data argument is only plotted). yet, we cannot throw away the - % other data structures, because in the interactive mode - % ft_singleplotER needs all data again and the entry into - % ft_singleplotER will be through one of the figures (which thus needs - % to have all data avalaible. at the moment I couldn't think of - % anything better than using an additional indx variable and letting the - % function recursively call itself. - topoplot_common(cfg, varargin{1:Ndata}, indx); + topoplot_common(tmpcfg, varargin{1:Ndata}, indx); indx = indx + 1; end return end +if iscell(cfg.dataname) + dataname = cfg.dataname{indx}; +else + dataname = cfg.dataname; +end + data = varargin{indx}; data = ft_checkdata(data, 'datatype', {'comp', 'timelock', 'freq'}); @@ -78,6 +95,7 @@ cfg = ft_checkconfig(cfg, 'renamedval', {'zlim', 'absmax', 'maxabs'}); cfg = ft_checkconfig(cfg, 'renamedval', {'directionality', 'feedforward', 'outflow'}); cfg = ft_checkconfig(cfg, 'renamedval', {'directionality', 'feedback', 'inflow'}); +cfg = ft_checkconfig(cfg, 'renamedval', {'highlight', 'yes', 'on'}); % check for renamed options cfg = ft_checkconfig(cfg, 'renamed', {'matrixside', 'directionality'}); @@ -110,39 +128,40 @@ 'showlabels'}); if ft_platform_supports('griddata-v4') - default_interpmethod='v4'; + default_interpmethod = 'v4'; else % Octave does not support 'v4', and 'cubic' not yet implemented - default_interpmethod='linear'; + default_interpmethod = 'linear'; end % Set other config defaults -cfg.xlim = ft_getopt(cfg, 'xlim', 'maxmin'); -cfg.ylim = ft_getopt(cfg, 'ylim', 'maxmin'); -cfg.zlim = ft_getopt(cfg, 'zlim', 'maxmin'); -cfg.style = ft_getopt(cfg, 'style', 'both'); -cfg.gridscale = ft_getopt(cfg, 'gridscale', 67); -cfg.interplimits = ft_getopt(cfg, 'interplimits', 'head'); -cfg.interpolation = ft_getopt(cfg, 'interpolation', default_interpmethod); -cfg.contournum = ft_getopt(cfg, 'contournum', 6); -cfg.colorbar = ft_getopt(cfg, 'colorbar', 'no'); -cfg.shading = ft_getopt(cfg, 'shading', 'flat'); -cfg.comment = ft_getopt(cfg, 'comment', 'auto'); -cfg.commentpos = ft_getopt(cfg, 'commentpos', 'leftbottom'); -cfg.fontsize = ft_getopt(cfg, 'fontsize', 8); -cfg.baseline = ft_getopt(cfg, 'baseline', 'no'); %to avoid warning in timelock/freqbaseline -cfg.trials = ft_getopt(cfg, 'trials', 'all', 1); -cfg.interactive = ft_getopt(cfg, 'interactive', 'yes'); -cfg.hotkeys = ft_getopt(cfg, 'hotkeys', 'no'); -cfg.renderer = ft_getopt(cfg, 'renderer', []); % MATLAB sets the default -cfg.marker = ft_getopt(cfg, 'marker', 'on'); -cfg.markersymbol = ft_getopt(cfg, 'markersymbol', 'o'); -cfg.markercolor = ft_getopt(cfg, 'markercolor', [0 0 0]); -cfg.markersize = ft_getopt(cfg, 'markersize', 2); -cfg.markerfontsize = ft_getopt(cfg, 'markerfontsize', 8); -cfg.highlight = ft_getopt(cfg, 'highlight', 'off'); -cfg.highlightchannel = ft_getopt(cfg, 'highlightchannel', 'all', 1); % highlight may be 'on', making highlightchannel {} meaningful -cfg.highlightsymbol = ft_getopt(cfg, 'highlightsymbol', '*'); +cfg.xlim = ft_getopt(cfg, 'xlim', 'maxmin'); +cfg.ylim = ft_getopt(cfg, 'ylim', 'maxmin'); +cfg.zlim = ft_getopt(cfg, 'zlim', 'maxmin'); +cfg.style = ft_getopt(cfg, 'style', 'both'); +cfg.gridscale = ft_getopt(cfg, 'gridscale', 67); +cfg.interplimits = ft_getopt(cfg, 'interplimits', 'head'); +cfg.interpolation = ft_getopt(cfg, 'interpolation', default_interpmethod); +cfg.contournum = ft_getopt(cfg, 'contournum', 6); +cfg.colorbar = ft_getopt(cfg, 'colorbar', 'no'); +cfg.shading = ft_getopt(cfg, 'shading', 'flat'); +cfg.comment = ft_getopt(cfg, 'comment', 'auto'); +cfg.commentpos = ft_getopt(cfg, 'commentpos', []); % default is handled further down +cfg.fontsize = ft_getopt(cfg, 'fontsize', 8); +cfg.fontweight = ft_getopt(cfg, 'fontweight', 'normal'); +cfg.baseline = ft_getopt(cfg, 'baseline', 'no'); % to avoid warning in timelock/freqbaseline +cfg.trials = ft_getopt(cfg, 'trials', 'all', 1); +cfg.interactive = ft_getopt(cfg, 'interactive', 'yes'); +cfg.hotkeys = ft_getopt(cfg, 'hotkeys', 'yes'); +cfg.renderer = ft_getopt(cfg, 'renderer', []); % MATLAB sets the default +cfg.marker = ft_getopt(cfg, 'marker', 'on'); +cfg.markersymbol = ft_getopt(cfg, 'markersymbol', 'o'); +cfg.markercolor = ft_getopt(cfg, 'markercolor', [0 0 0]); +cfg.markersize = ft_getopt(cfg, 'markersize', 2); +cfg.markerfontsize = ft_getopt(cfg, 'markerfontsize', 8); +cfg.highlight = ft_getopt(cfg, 'highlight', 'off'); +cfg.highlightchannel = ft_getopt(cfg, 'highlightchannel', 'all', 1); % highlight may be 'on', making highlightchannel {} meaningful +cfg.highlightsymbol = ft_getopt(cfg, 'highlightsymbol', '*'); cfg.highlightcolor = ft_getopt(cfg, 'highlightcolor', [0 0 0]); cfg.highlightsize = ft_getopt(cfg, 'highlightsize', 6); cfg.highlightfontsize = ft_getopt(cfg, 'highlightfontsize', 8); @@ -150,41 +169,48 @@ cfg.maskparameter = ft_getopt(cfg, 'maskparameter', []); cfg.component = ft_getopt(cfg, 'component', []); cfg.directionality = ft_getopt(cfg, 'directionality', []); -cfg.channel = ft_getopt(cfg, 'channel', 'all'); +cfg.channel = ft_getopt(cfg, 'channel', 'all'); +cfg.refchannel = ft_getopt(cfg, 'refchannel', []); cfg.figurename = ft_getopt(cfg, 'figurename', []); -cfg.interpolatenan = ft_getopt(cfg, 'interpolatenan', 'yes'); - -% compatibility for previous highlighting option -if isnumeric(cfg.highlight) - cfg.highlightchannel = cfg.highlight; - cfg.highlight = 'on'; - warning('cfg.highlight is now used for specifying highlighting-mode, use cfg.highlightchannel instead of cfg.highlight for specifying channels') -elseif iscell(cfg.highlight) - if ~iscell(cfg.highlightchannel) - cfg.highlightchannel = cell(1,length(cfg.highlight)); - end - for icell = 1:length(cfg.highlight) - if isnumeric(cfg.highlight{icell}) - cfg.highlightchannel{icell} = cfg.highlight{icell}; - cfg.highlight{icell} = 'on'; - warning('cfg.highlight is now used for specifying highlighting-mode, use cfg.highlightchannel instead of cfg.highlight for specifying channels') - end +cfg.interpolatenan = ft_getopt(cfg, 'interpolatenan', 'yes'); + +% default commentpos +if isempty(cfg.commentpos) + if any(ismember(cfg.layout.label, 'COMNT')) + % layout went through ft_prepare_layout in ft_topoplotER/TFR + % use the position that is specified in the layout + cfg.commentpos = 'layout'; + else + % put it in the left bottom + cfg.commentpos = 'leftbottom'; end end -% Converting all highlight options to cell-arrays if they're not cell-arrays, -% to make defaulting, checking for backwards compatibility and error -% checking easier -if ~iscell(cfg.highlight), cfg.highlight = {cfg.highlight}; end -if isempty(cfg.highlightchannel), cfg.highlightchannel = ''; end -if ~iscell(cfg.highlightchannel), cfg.highlightchannel = {cfg.highlightchannel}; end -if ischar(cfg.highlightchannel{1}), cfg.highlightchannel = {cfg.highlightchannel}; end % {'all'} is valid input to channelselection, {1:5} isn't -if ~iscell(cfg.highlightsymbol), cfg.highlightsymbol = {cfg.highlightsymbol}; end -if ~iscell(cfg.highlightcolor), cfg.highlightcolor = {cfg.highlightcolor}; end -if ~iscell(cfg.highlightsize), cfg.highlightsize = {cfg.highlightsize}; end -if ~iscell(cfg.highlightfontsize), cfg.highlightfontsize = {cfg.highlightfontsize}; end +% the user can either specify a single group of channels for highlighting (all in the +% same style), or multiple groups with a different style for each group. The latter +% is used by ft_clusterplot. +if ~iscell(cfg.highlight) + cfg.highlight = {cfg.highlight}; +end +if iscell(cfg.highlightchannel) && ~(iscell(cfg.highlightchannel{1}) || isnumeric(cfg.highlightchannel{1})) + cfg.highlightchannel = {cfg.highlightchannel}; +elseif ischar(cfg.highlightchannel) + cfg.highlightchannel = {{cfg.highlightchannel}}; +end +if ~iscell(cfg.highlightsymbol) + cfg.highlightsymbol = {cfg.highlightsymbol}; +end +if ~iscell(cfg.highlightcolor) + cfg.highlightcolor = {cfg.highlightcolor}; +end +if ~iscell(cfg.highlightsize) + cfg.highlightsize = {cfg.highlightsize}; +end +if ~iscell(cfg.highlightfontsize) + cfg.highlightfontsize = {cfg.highlightfontsize}; +end % then make sure all cell-arrays for options have length ncellhigh and default the last element if not present -ncellhigh = length(cfg.highlight); +ncellhigh = length(cfg.highlightchannel); if length(cfg.highlightsymbol) < ncellhigh, cfg.highlightsymbol{ncellhigh} = 'o'; end if length(cfg.highlightcolor) < ncellhigh, cfg.highlightcolor{ncellhigh} = [0 0 0]; end if length(cfg.highlightsize) < ncellhigh, cfg.highlightsize{ncellhigh} = 6; end @@ -198,44 +224,45 @@ end % for backwards compatability -if strcmp(cfg.marker,'highlights') - warning('using cfg.marker option -highlights- is no longer used, please use cfg.highlight') +if strcmp(cfg.marker, 'highlights') + ft_warning('using cfg.marker option -highlights- is no longer used, please use cfg.highlight') cfg.marker = 'off'; end % check colormap is proper format and set it -if isfield(cfg,'colormap') - if size(cfg.colormap,2)~=3, error('topoplot(): Colormap must be a n x 3 matrix'); end +if isfield(cfg, 'colormap') + if ~isnumeric(cfg.colormap) + cfg.colormap = colormap(cfg.colormap); + end + if size(cfg.colormap,2)~=3 + ft_error('cfg.colormap must be Nx3'); + end colormap(cfg.colormap); ncolors = size(cfg.colormap,1); else - ncolors =[]; % let the low-level function deal with this + ncolors = []; % let the low-level function deal with this end -dtype = ft_datatype(data); -% identify the interpretation of the functional data -switch dtype - case 'raw' - data = ft_checkdata(data, 'datatype', 'timelock'); - dtype = ft_datatype(data); - dimord = data.dimord; - case {'timelock' 'freq' 'chan' 'unknown'} - dimord = data.dimord; - case 'comp' - dimord = 'chan_comp'; - otherwise -end -dimtok = tokenize(dimord, '_'); +%% Section 2: data handling, this also includes converting bivariate (chan_chan and chancmb) into univariate data + +dtype = ft_datatype(data); +hastime = isfield(data, 'time'); % Set x/y/parameter defaults according to datatype and dimord switch dtype case 'timelock' xparam = 'time'; yparam = ''; - cfg.parameter = ft_getopt(cfg, 'parameter', 'avg'); + if isfield(data, 'trial') + cfg.parameter = ft_getopt(cfg, 'parameter', 'trial'); + elseif isfield(data, 'individual') + cfg.parameter = ft_getopt(cfg, 'parameter', 'individual'); + elseif isfield(data, 'avg') + cfg.parameter = ft_getopt(cfg, 'parameter', 'avg'); + end case 'freq' - if any(ismember(dimtok, 'time')) + if hastime xparam = 'time'; yparam = 'freq'; cfg.parameter = ft_getopt(cfg, 'parameter', 'powspctrm'); @@ -245,97 +272,131 @@ cfg.parameter = ft_getopt(cfg, 'parameter', 'powspctrm'); end case 'comp' - % Add a pseudo-axis with the component numbers: + % Add a pseudo-axis with the component numbers data.comp = 1:size(data.topo,2); - % Specify the components if ~isempty(cfg.component) - data.comp = cfg.component; - data.topo = data.topo(:,cfg.component); + % make a selection of components + data.comp = data.comp(cfg.component); + data.topo = data.topo(:,cfg.component); + try, data.label = data.label(cfg.component); end + try, data.unmixing = data.unmixing(cfg.component,:); end end - % Rename the field with topographic label information: - data.label = data.topolabel; + % Rename the field with topographic label information + data.label = data.topolabel; + data.topodimord = 'chan_comp'; + data = removefields(data, {'topolabel', 'unmixing', 'unmixingdimord'}); % not needed any more xparam = 'comp'; yparam = ''; cfg.parameter = ft_getopt(cfg, 'parameter', 'topo'); otherwise - % if the input data is not one of the standard data types, or if - % the functional data is just one value per channel - % in this case xparam, yparam are not defined + % if the input data is not one of the standard data types, or if the functional + % data is just one value per channel: in this case xparam, yparam are not defined % and the user should define the parameter - if ~isfield(data, 'label'), error('the input data should at least contain a label-field'); end - if ~isfield(cfg, 'parameter'), error('the configuration should at least contain a ''parameter'' field'); end - if ~isfield(cfg, 'xparam'), - cfg.xlim = [1 1]; - xparam = ''; + if ~isfield(data, 'label'), ft_error('the input data should at least contain a label-field'); end + if ~isfield(cfg, 'parameter'), ft_error('the configuration should at least contain a ''parameter'' field'); end + if ~isfield(cfg, 'xparam') + cfg.xlim = [1 1]; + xparam = ''; end end -if isfield(cfg, 'parameter') && ~isfield(data, cfg.parameter) - error('cfg.parameter=%s is not present in data structure', cfg.parameter); +% check whether rpt/subj is present and remove if necessary +dimord = getdimord(data, cfg.parameter); +dimtok = tokenize(dimord, '_'); +hasrpt = any(ismember(dimtok, {'rpt' 'subj'})); + +if ~hasrpt + assert(isequal(cfg.trials, 'all') || isequal(cfg.trials, 1), 'incorrect specification of cfg.trials for data without repetitions'); +else + assert(~isempty(cfg.trials), 'empty specification of cfg.trials for data with repetitions'); end -% user specified own fields, but no yparam (which is not asked in help) -if exist('xparam', 'var') && isfield(cfg, 'parameter') && ~exist('yparam', 'var') - yparam = ''; +% parse cfg.channel +if isfield(cfg, 'channel') && isfield(data, 'label') + cfg.channel = ft_channelselection(cfg.channel, data.label); +elseif isfield(cfg, 'channel') && isfield(data, 'labelcmb') + cfg.channel = ft_channelselection(cfg.channel, unique(data.labelcmb(:))); end -% check whether rpt/subj is present and remove if necessary and whether -hasrpt = any(ismember(dimtok, {'rpt' 'subj'})); -if strcmp(dtype, 'timelock') && hasrpt, - if ~isfield(data, cfg.parameter) || strcmp(cfg.parameter, 'individual') - tmpcfg = []; - tmpcfg.trials = cfg.trials; - data = ft_timelockanalysis(tmpcfg, data); - if ~strcmp(cfg.parameter, 'avg') - % rename avg back into the parameter - data.(cfg.parameter) = data.avg; - data = rmfield(data, 'avg'); - end - dimord = data.dimord; - dimtok = tokenize(dimord, '_'); - else - fprintf('input data contains repetitions, ignoring these and using ''%s'' field\n', cfg.parameter); +% Apply baseline correction +if ~strcmp(cfg.baseline, 'no') + % keep mask-parameter if it is set + if ~isempty(cfg.maskparameter) + tempmask = data.(cfg.maskparameter); end -elseif strcmp(dtype, 'freq') && hasrpt, - % this also deals with fourier-spectra in the input - % or with multiple subjects in a frequency domain stat-structure - % on the fly computation of coherence spectrum is not supported - if isfield(data, 'crsspctrm'), data = rmfield(data, 'crsspctrm'); end - tmpcfg = []; - tmpcfg.trials = cfg.trials; - tmpcfg.jackknife = 'no'; - if isfield(cfg, 'parameter') && ~strcmp(cfg.parameter,'powspctrm') - % freqdesctiptives will only work on the powspctrm field - % hence a temporary copy of the data is needed - tempdata.dimord = data.dimord; - tempdata.freq = data.freq; - tempdata.label = data.label; - tempdata.powspctrm = data.(cfg.parameter); - if isfield(data, 'cfg'), tempdata.cfg = data.cfg; end - tempdata = ft_freqdescriptives(tmpcfg, tempdata); - data.(cfg.parameter) = tempdata.powspctrm; - clear tempdata - else - data = ft_freqdescriptives(tmpcfg, data); + if strcmp(xparam, 'time') && strcmp(yparam, 'freq') + data = ft_freqbaseline(cfg, data); + elseif strcmp(xparam, 'time') && strcmp(yparam, '') + data = ft_timelockbaseline(cfg, data); + end + % put mask-parameter back if it is set + if ~isempty(cfg.maskparameter) + data.(cfg.maskparameter) = tempmask; end - dimord = data.dimord; - dimtok = tokenize(dimord, '_'); end -if isfield(data, 'label') - cfg.channel = ft_channelselection(cfg.channel, data.label); -elseif isfield(data, 'labelcmb') - cfg.channel = ft_channelselection(cfg.channel, unique(data.labelcmb(:))); +% time and/or frequency should NOT be selected and averaged here, since a singleplot might follow in interactive mode +tmpcfg = keepfields(cfg, {'channel', 'showcallinfo', 'trials'}); +if hasrpt + tmpcfg.avgoverrpt = 'yes'; +else + tmpcfg.avgoverrpt = 'no'; +end +tmpvar = data; +[data] = ft_selectdata(tmpcfg, data); +% restore the provenance information +[cfg, data] = rollback_provenance(cfg, data); + +if isfield(tmpvar, cfg.maskparameter) && ~isfield(data, cfg.maskparameter) + % the mask parameter is not present after ft_selectdata, because it is + % not included in all input arguments. Make the same selection and copy + % it over + tmpvar = ft_selectdata(tmpcfg, tmpvar); + data.(cfg.maskparameter) = tmpvar.(cfg.maskparameter); +end + +clear tmpvar tmpcfg dimord dimtok hastime hasfreq hasrpt + +% ensure that the preproc specific options are located in the cfg.preproc +% substructure, but also ensure that the field 'refchannel' remains at the +% highest level in the structure. This is a little hack by JM because the field +% refchannel can relate to connectivity or to an EEG reference. + +if isfield(cfg, 'refchannel'), refchannelincfg = cfg.refchannel; cfg = rmfield(cfg, 'refchannel'); end +cfg = ft_checkconfig(cfg, 'createsubcfg', {'preproc'}); +if exist('refchannelincfg', 'var'), cfg.refchannel = refchannelincfg; end + +if ~isempty(cfg.preproc) + % preprocess the data, i.e. apply filtering, baselinecorrection, etc. + fprintf('applying preprocessing options\n'); + if ~isfield(cfg.preproc, 'feedback') + cfg.preproc.feedback = cfg.interactive; + end + data = ft_preprocessing(cfg.preproc, data); end -% perform channel selection but only allow this when cfg.interactive = 'no' -if isfield(data, 'label') && strcmp(cfg.interactive, 'no') - selchannel = ft_channelselection(cfg.channel, data.label); -elseif isfield(data, 'labelcmb') && strcmp(cfg.interactive, 'no') - selchannel = ft_channelselection(cfg.channel, unique(data.labelcmb(:))); +% Handle the bivariate case +dimord = getdimord(varargin{1}, cfg.parameter); +if startsWith(dimord, 'chan_chan_') || startsWith(dimord, 'chancmb_') + % convert the bivariate data to univariate and call the parent plotting function again + s = dbstack; + cfg.originalfunction = s(2).name; + cfg.trials = 'all'; % trial selection has been taken care off + bivariate_common(cfg, varargin{:}); + return end -% Create time-series of small topoplots: +% Apply channel-type specific scaling +tmpcfg = keepfields(cfg, {'parameter', 'chanscale', 'ecgscale', 'eegscale', 'emgscale', 'eogscale', 'gradscale', 'magscale', 'megscale', 'mychan', 'mychanscale'}); +data = chanscale_common(tmpcfg, data); + + +%% Section 3: select the data to be plotted and determine min/max range + +dimord = getdimord(varargin{1}, cfg.parameter); +dimtok = tokenize(dimord, '_'); + +% Create time-series of small topoplots if ~ischar(cfg.xlim) && length(cfg.xlim)>2 %&& any(ismember(dimtok, 'time')) % Switch off interactive mode: cfg.interactive = 'no'; @@ -352,171 +413,37 @@ return end -% Apply baseline correction: -if ~strcmp(cfg.baseline, 'no') - if strcmp(xparam, 'freq') || strcmp(yparam, 'freq') - data = ft_freqbaseline(cfg, data); - else - data = ft_timelockbaseline(cfg, data); - end -end - -% Handle the bivariate case - -% Check for bivariate metric with 'chan_chan' in the dimord: -selchan = strmatch('chan', dimtok); -isfull = length(selchan)>1; - -% Check for bivariate metric with a labelcmb field: -haslabelcmb = isfield(data, 'labelcmb'); - -if (isfull || haslabelcmb) && (isfield(data, cfg.parameter) && ~strcmp(cfg.parameter, 'powspctrm')) - % A reference channel is required: - if ~isfield(cfg, 'refchannel') - error('no reference channel is specified'); - end - - % check for refchannel being part of selection - if ~strcmp(cfg.refchannel,'gui') - if haslabelcmb - cfg.refchannel = ft_channelselection(cfg.refchannel, unique(data.labelcmb(:))); - else - cfg.refchannel = ft_channelselection(cfg.refchannel, data.label); - end - if (isfull && ~any(ismember(data.label, cfg.refchannel))) || ... - (haslabelcmb && ~any(ismember(data.labelcmb(:), cfg.refchannel))) - error('cfg.refchannel is a not present in the (selected) channels)') - end - end - - % Interactively select the reference channel - if strcmp(cfg.refchannel, 'gui') - % Open a single figure with the channel layout, the user can click on a reference channel - h = clf; - ft_plot_lay(cfg.layout, 'box', false); - title('Select the reference channel by dragging a selection window, more than 1 channel can be selected...'); - % add the channel information to the figure - info = guidata(gcf); - info.x = cfg.layout.pos(:,1); - info.y = cfg.layout.pos(:,2); - info.label = cfg.layout.label; - guidata(h, info); - % attach data to the figure with the current axis handle as a name - dataname = fixname(num2str(double(gca))); - setappdata(gcf,dataname,data); - %set(gcf, 'WindowButtonUpFcn', {@ft_select_channel, 'callback', {@select_topoplotER, cfg, data}}); - set(gcf, 'WindowButtonUpFcn', {@ft_select_channel, 'multiple', true, 'callback', {@select_topoplotER, cfg}, 'event', 'WindowButtonUpFcn'}); - set(gcf, 'WindowButtonDownFcn', {@ft_select_channel, 'multiple', true, 'callback', {@select_topoplotER, cfg}, 'event', 'WindowButtonDownFcn'}); - set(gcf, 'WindowButtonMotionFcn', {@ft_select_channel, 'multiple', true, 'callback', {@select_topoplotER, cfg}, 'event', 'WindowButtonMotionFcn'}); - return - end - - if ~isfull, - % Convert 2-dimensional channel matrix to a single dimension: - if isempty(cfg.directionality) - sel1 = find(strcmp(cfg.refchannel, data.labelcmb(:,2))); - sel2 = find(strcmp(cfg.refchannel, data.labelcmb(:,1))); - elseif strcmp(cfg.directionality, 'outflow') - sel1 = []; - sel2 = find(strcmp(cfg.refchannel, data.labelcmb(:,1))); - elseif strcmp(cfg.directionality, 'inflow') - sel1 = find(strcmp(cfg.refchannel, data.labelcmb(:,2))); - sel2 = []; - end - fprintf('selected %d channels for %s\n', length(sel1)+length(sel2), cfg.parameter); - if length(sel1)+length(sel2)==0 - error('there are no channels selected for plotting: you may need to look at the specification of cfg.directionality'); - end - data.(cfg.parameter) = data.(cfg.parameter)([sel1;sel2],:,:); - data.label = [data.labelcmb(sel1,1);data.labelcmb(sel2,2)]; - data.labelcmb = data.labelcmb([sel1;sel2],:); - data = rmfield(data, 'labelcmb'); - else - % General case - sel = match_str(data.label, cfg.refchannel); - siz = [size(data.(cfg.parameter)) 1]; - if strcmp(cfg.directionality, 'inflow') || isempty(cfg.directionality) - %the interpretation of 'inflow' and 'outflow' depend on - %the definition in the bivariate representation of the data - %in FieldTrip the row index 'causes' the column index channel - %data.(cfg.parameter) = reshape(mean(data.(cfg.parameter)(:,sel,:),2),[siz(1) 1 siz(3:end)]); - sel1 = 1:siz(1); - sel2 = sel; - meandir = 2; - elseif strcmp(cfg.directionality, 'outflow') - %data.(cfg.parameter) = reshape(mean(data.(cfg.parameter)(sel,:,:),1),[siz(1) 1 siz(3:end)]); - sel1 = sel; - sel2 = 1:siz(1); - meandir = 1; - - elseif strcmp(cfg.directionality, 'inflow-outflow') - % do the subtraction and recursively call the function again - tmpcfg = cfg; - tmpcfg.directionality = 'inflow'; - tmpdata = data; - tmp = data.(tmpcfg.parameter); - siz = [size(tmp) 1]; - for k = 1:siz(3) - for m = 1:siz(4) - tmp(:,:,k,m) = tmp(:,:,k,m)-tmp(:,:,k,m)'; - end - end - tmpdata.(tmpcfg.parameter) = tmp; - ft_topoplotTFR(tmpcfg, tmpdata); - return; - - elseif strcmp(cfg.directionality, 'outflow-inflow') - % do the subtraction and recursively call the function again - tmpcfg = cfg; - tmpcfg.directionality = 'outflow'; - tmpdata = data; - tmp = data.(tmpcfg.parameter); - siz = [size(tmp) 1]; - for k = 1:siz(3) - for m = 1:siz(4) - tmp(:,:,k,m) = tmp(:,:,k,m)-tmp(:,:,k,m)'; - end - end - tmpdata.(tmpcfg.parameter) = tmp; - ft_topoplotTFR(tmpcfg, tmpdata); - return; - - end - end -end - -% Get physical min/max range of x: -if strcmp(cfg.xlim,'maxmin') +% Get physical min/max range of x +if strcmp(cfg.xlim, 'maxmin') xmin = min(data.(xparam)); xmax = max(data.(xparam)); else xmin = cfg.xlim(1); xmax = cfg.xlim(2); end +xminindx = nearest(data.(xparam), xmin); +xmaxindx = nearest(data.(xparam), xmax); +xmin = data.(xparam)(xminindx); +xmax = data.(xparam)(xmaxindx); +selx = xminindx:xmaxindx; -% Replace value with the index of the nearest bin -if ~isempty(xparam) - xmin = nearest(data.(xparam), xmin); - xmax = nearest(data.(xparam), xmax); -end - -% Get physical min/max range of y: +% Get physical min/max range of y if ~isempty(yparam) - if strcmp(cfg.ylim,'maxmin') + if strcmp(cfg.ylim, 'maxmin') ymin = min(data.(yparam)); ymax = max(data.(yparam)); else ymin = cfg.ylim(1); ymax = cfg.ylim(2); end - - % Replace value with the index of the nearest bin: - ymin = nearest(data.(yparam), ymin); - ymax = nearest(data.(yparam), ymax); + yminindx = nearest(data.(yparam), ymin); + ymaxindx = nearest(data.(yparam), ymax); + ymin = data.(yparam)(yminindx); + ymax = data.(yparam)(ymaxindx); + sely = yminindx:ymaxindx; end -% Take subselection of channels, this only works -% if the interactive mode is switched off +% Take subselection of channels, this only works if the interactive mode is switched off if exist('selchannel', 'var') sellab = match_str(data.label, selchannel); label = data.label(sellab); @@ -525,53 +452,27 @@ label = data.label; end -if isfull - sel1 = intersect(sel1, sellab); - sel2 = intersect(sel2, sellab); -end +% Make data vector with one scalar value for each channel +dat = data.(cfg.parameter); +% get dimord dimensions +ydim = find(strcmp(yparam, dimtok)); +xdim = find(strcmp(xparam, dimtok)); +zdim = setdiff(1:ndims(dat), [ydim xdim]); +% and permute +dat = permute(dat, [zdim(:)' ydim xdim]); -if ~isempty(cfg.parameter) - % Make data vector with one value for each channel - dat = data.(cfg.parameter); - % get dimord dimensions - ydim = find(strcmp(yparam, dimtok)); - xdim = find(strcmp(xparam, dimtok)); - zdim = setdiff(1:ndims(dat), [ydim xdim]); - % and permute - dat = permute(dat, [zdim(:)' ydim xdim]); - - if ~isempty(yparam) - % time-frequency data - if isfull - dat = dat(sel1, sel2, ymin:ymax, xmin:xmax); - dat = nanmean(nanmean(nanmean(dat, meandir), 4), 3); - elseif haslabelcmb - dat = dat(sellab, ymin:ymax, xmin:xmax); - dat = nanmean(nanmean(dat, 3), 2); - else - dat = dat(sellab, ymin:ymax, xmin:xmax); - dat = nanmean(nanmean(dat, 3), 2); - end - elseif ~isempty(cfg.component) - % component data, nothing to do - else - % time or frequency data - if isfull - dat = dat(sel1, sel2, xmin:xmax); - dat = nanmean(nanmean(dat, meandir), 3); - elseif haslabelcmb - dat = dat(sellab, xmin:xmax); - dat = nanmean(dat, 2); - else - dat = dat(sellab, xmin:xmax); - dat = nanmean(dat, 2); - end - end - dat = dat(:); - +if ~isempty(yparam) + % time-frequency data + dat = dat(sellab, sely, selx); + dat = nanmean(nanmean(dat, 3), 2); +elseif ~isempty(cfg.component) + % component data, nothing to do else - error('cannot make selection of data'); + % time or frequency data + dat = dat(sellab, selx); + dat = nanmean(dat, 2); end +dat = dat(:); if isfield(data, cfg.maskparameter) % Make mask vector with one value for each channel @@ -585,28 +486,16 @@ if ~isempty(yparam) % time-frequency data - if isfull - msk = msk(sel1, sel2, ymin:ymax, xmin:xmax); - elseif haslabelcmb - msk = msk(sellab, ymin:ymax, xmin:xmax); - else - msk = msk(sellab, ymin:ymax, xmin:xmax); - end + msk = msk(sellab, sely, selx); elseif ~isempty(cfg.component) % component data, nothing to do else % time or frequency data - if isfull - msk = msk(sel1, sel2, xmin:xmax); - elseif haslabelcmb - msk = msk(sellab, xmin:xmax); - else - msk = msk(sellab, xmin:xmax); - end + msk = msk(sellab, selx); end if size(msk,2)>1 || size(msk,3)>1 - warning('no masking possible for average over multiple latencies or frequencies -> cfg.maskparameter cleared') + ft_warning('no masking possible for average over multiple latencies or frequencies -> cfg.maskparameter cleared') msk = []; end @@ -614,11 +503,10 @@ msk = []; end - % Select the channels in the data that match with the layout: [seldat, sellay] = match_str(label, cfg.layout.label); if isempty(seldat) - error('labels in data and labels in layout do not match'); + ft_error('labels in data and labels in layout do not match'); end dat = dat(seldat); @@ -629,19 +517,18 @@ % Select x and y coordinates and labels of the channels in the data chanX = cfg.layout.pos(sellay,1); chanY = cfg.layout.pos(sellay,2); -chanLabels = cfg.layout.label(sellay); % Get physical min/max range of z: -if strcmp(cfg.zlim,'maxmin') +if strcmp(cfg.zlim, 'maxmin') zmin = min(dat); zmax = max(dat); -elseif strcmp(cfg.zlim,'maxabs') +elseif strcmp(cfg.zlim, 'maxabs') zmin = -max(max(abs(dat))); zmax = max(max(abs(dat))); -elseif strcmp(cfg.zlim,'zeromax') +elseif strcmp(cfg.zlim, 'zeromax') zmin = 0; zmax = max(dat); -elseif strcmp(cfg.zlim,'minzero') +elseif strcmp(cfg.zlim, 'minzero') zmin = min(dat); zmax = 0; else @@ -650,75 +537,77 @@ end % make comment -if strcmp(cfg.comment, 'auto') - comment = date; - if ~isempty(xparam) - if strcmp(cfg.xlim,'maxmin') - comment = sprintf('%0s\n%0s=[%.3g %.3g]', comment, xparam, data.(xparam)(xmin), data.(xparam)(xmax)); - else - comment = sprintf('%0s\n%0s=[%.3g %.3g]', comment, xparam, data.(xparam)(xmin), data.(xparam)(xmax)); +switch cfg.comment + case 'no' + cfg.comment = ''; + case 'auto' + comment = date; + if ~isempty(xparam) + comment = sprintf('%0s\n%0s=[%.3g %.3g]', comment, xparam, xmin, xmax); end - end - if ~isempty(yparam) - if strcmp(cfg.ylim,'maxmin') - comment = sprintf('%0s\n%0s=[%.3g %.3g]', comment, yparam, data.(yparam)(ymin), data.(yparam)(ymax)); - else - comment = sprintf('%0s\n%0s=[%.3g %.3g]', comment, yparam, data.(yparam)(ymin), data.(yparam)(ymax)); + if ~isempty(yparam) + comment = sprintf('%0s\n%0s=[%.3g %.3g]', comment, yparam, ymin, ymax); end - end - if ~isempty(cfg.parameter) - comment = sprintf('%0s\n%0s=[%.3g %.3g]', comment, cfg.parameter, zmin, zmax); - end - cfg.comment = comment; -elseif strcmp(cfg.comment, 'xlim') - if strcmp(cfg.xlim,'maxmin') - comment = sprintf('%0s=[%.3g %.3g]', xparam, data.(xparam)(xmin), data.(xparam)(xmax)); - else - comment = sprintf('%0s=[%.3g %.3g]', xparam, data.(xparam)(xmin), data.(xparam)(xmax)); - end - cfg.comment = comment; -elseif ~ischar(cfg.comment) - error('cfg.comment must be string'); -end -if ~strcmp(cfg.comment, 'no') && isfield(cfg,'refchannel') + if ~isempty(cfg.parameter) + comment = sprintf('%0s\n%0s=[%.3g %.3g]', comment, cfg.parameter, zmin, zmax); + end + cfg.comment = comment; + case 'xlim' + comment = date; + if ~isempty(xparam) + cfg.comment = sprintf('%0s\n%0s=[%.3g %.3g]', comment, xparam, xmin, xmax); + end + case 'ylim' + comment = date; + if ~isempty(yparam) + cfg.comment = sprintf('%0s\n%0s=[%.3g %.3g]', comment, yparam, ymin, ymax); + end + case 'zlim' + comment = date; + if ~isempty(yparam) + cfg.comment = sprintf('%0s\n%0s=[%.3g %.3g]', comment, cfg.parameter, zmin, zmax); + end +end % switch comment + +if ~isempty(cfg.refchannel) if iscell(cfg.refchannel) - cfg.comment = sprintf('%s\nreference=%s %s', comment, cfg.refchannel{:}); + cfg.comment = sprintf('%s\nreference=%s %s', cfg.comment, cfg.refchannel{:}); else - cfg.comment = sprintf('%s\nreference=%s %s', comment, cfg.refchannel); + cfg.comment = sprintf('%s\nreference=%s %s', cfg.comment, cfg.refchannel); end end % Specify the x and y coordinates of the comment -if strcmp(cfg.commentpos,'layout') - ind_comment = strmatch('COMNT', cfg.layout.label); +if strcmp(cfg.commentpos, 'layout') + ind_comment = find(strcmp(cfg.layout.label, 'COMNT')); x_comment = cfg.layout.pos(ind_comment,1); y_comment = cfg.layout.pos(ind_comment,2); -elseif strcmp(cfg.commentpos,'lefttop') +elseif strcmp(cfg.commentpos, 'lefttop') x_comment = -0.7; y_comment = 0.6; HorAlign = 'left'; VerAlign = 'top'; -elseif strcmp(cfg.commentpos,'leftbottom') +elseif strcmp(cfg.commentpos, 'leftbottom') x_comment = -0.6; y_comment = -0.6; HorAlign = 'left'; VerAlign = 'bottom'; -elseif strcmp(cfg.commentpos,'middletop') +elseif strcmp(cfg.commentpos, 'middletop') x_comment = 0; y_comment = 0.75; HorAlign = 'center'; VerAlign = 'top'; -elseif strcmp(cfg.commentpos,'middlebottom') +elseif strcmp(cfg.commentpos, 'middlebottom') x_comment = 0; y_comment = -0.7; HorAlign = 'center'; VerAlign = 'bottom'; -elseif strcmp(cfg.commentpos,'righttop') +elseif strcmp(cfg.commentpos, 'righttop') x_comment = 0.65; y_comment = 0.6; HorAlign = 'right'; VerAlign = 'top'; -elseif strcmp(cfg.commentpos,'rightbottom') +elseif strcmp(cfg.commentpos, 'rightbottom') x_comment = 0.6; y_comment = -0.6; HorAlign = 'right'; @@ -728,31 +617,18 @@ y_comment = cfg.commentpos(2); HorAlign = 'left'; VerAlign = 'middle'; - x_comment = 0.9*((x_comment-min(x))/(max(x)-min(x))-0.5); - y_comment = 0.9*((y_comment-min(y))/(max(y)-min(y))-0.5); + x_comment = 0.9*((x_comment-min(cfg.xlim))/(max(cfg.xlim)-min(cfg.xlim))-0.5); + y_comment = 0.9*((y_comment-min(cfg.ylim))/(max(cfg.ylim)-min(cfg.ylim))-0.5); end % Draw topoplot cla hold on -% Set ft_plot_topo specific options -if strcmp(cfg.interplimits,'head') - interplimits = 'mask'; -else - interplimits = cfg.interplimits; -end -if strcmp(cfg.style,'both'); style = 'surfiso'; end -if strcmp(cfg.style,'straight'); style = 'surf'; end -if strcmp(cfg.style,'contour'); style = 'iso'; end -if strcmp(cfg.style,'fill'); style = 'isofill'; end -if strcmp(cfg.style,'straight_imsat'); style = 'imsat'; end -if strcmp(cfg.style,'both_imsat'); style = 'imsatiso'; end - % check for nans nanInds = isnan(dat); -if strcmp(cfg.interpolatenan,'yes') && any(nanInds) - warning('removing NaNs from the data'); +if strcmp(cfg.interpolatenan, 'yes') && any(nanInds) + ft_warning('removing NaNs from the data'); chanX(nanInds) = []; chanY(nanInds) = []; dat(nanInds) = []; @@ -761,114 +637,147 @@ end end +% Set ft_plot_topo specific options +if strcmp(cfg.interplimits, 'head') + interplimits = 'mask'; +else + interplimits = cfg.interplimits; +end +if strcmp(cfg.style, 'both'); style = 'surfiso'; end +if strcmp(cfg.style, 'straight'); style = 'surf'; end +if strcmp(cfg.style, 'contour'); style = 'iso'; end +if strcmp(cfg.style, 'fill'); style = 'isofill'; end +if strcmp(cfg.style, 'straight_imsat'); style = 'imsat'; end +if strcmp(cfg.style, 'both_imsat'); style = 'imsatiso'; end + % Draw plot -if ~strcmp(cfg.style,'blank') - opt = {'interpmethod',cfg.interpolation,... - 'interplim',interplimits,... - 'gridscale',cfg.gridscale,... - 'outline',cfg.layout.outline,... - 'shading',cfg.shading,... - 'isolines',cfg.contournum,... - 'mask',cfg.layout.mask,... - 'style',style,... - 'datmask', msk}; - if strcmp(style,'imsat') || strcmp(style,'imsatiso') +if ~strcmp(cfg.style, 'blank') + opt = {'interpmethod', cfg.interpolation, ... + 'interplim', interplimits, ... + 'gridscale', cfg.gridscale, ... + 'outline', cfg.layout.outline, ... + 'shading', cfg.shading, ... + 'isolines', cfg.contournum, ... + 'mask', cfg.layout.mask, ... + 'style', style, ... + 'datmask', msk}; + if strcmp(style, 'imsat') || strcmp(style, 'imsatiso') % add clim to opt - opt = [opt {'clim',[zmin zmax],'ncolors',ncolors}]; + opt = [opt {'clim', [zmin zmax], 'ncolors',ncolors}]; end - ft_plot_topo(chanX,chanY,dat,opt{:}); -elseif ~strcmp(cfg.style,'blank') - ft_plot_lay(cfg.layout,'box','no','label','no','point','no') + ft_plot_topo(chanX, chanY, dat, opt{:}); +elseif ~strcmp(cfg.style, 'blank') + ft_plot_lay(cfg.layout, 'box', 'no', 'label', 'no', 'point', 'no') end -% Plotting markers for channels and/or highlighting a selection of channels -highlightchansel = []; % used for remembering selection of channels -templay.outline = cfg.layout.outline; -templay.mask = cfg.layout.mask; % For Highlight (channel-selection) for icell = 1:length(cfg.highlight) - if ~strcmp(cfg.highlight{icell},'off') - [dum labelindex] = match_str(ft_channelselection(cfg.highlightchannel{icell}, data.label), cfg.layout.label); - highlightchansel = [highlightchansel; match_str(data.label,ft_channelselection(cfg.highlightchannel{icell}, data.label))]; - templay.pos = cfg.layout.pos(labelindex,:); - templay.width = cfg.layout.width(labelindex); - templay.height = cfg.layout.height(labelindex); - templay.label = cfg.layout.label(labelindex); + if ~strcmp(cfg.highlight{icell}, 'off') + cfg.highlightchannel{icell} = ft_channelselection(cfg.highlightchannel{icell}, data.label); + [dum, layoutindex] = match_str(cfg.highlightchannel{icell}, cfg.layout.label); + templay = []; + templay.outline = cfg.layout.outline; + templay.mask = cfg.layout.mask; + templay.pos = cfg.layout.pos(layoutindex,:); + templay.width = cfg.layout.width(layoutindex); + templay.height = cfg.layout.height(layoutindex); + templay.label = cfg.layout.label(layoutindex); if strcmp(cfg.highlight{icell}, 'labels') || strcmp(cfg.highlight{icell}, 'numbers') labelflg = 1; else labelflg = 0; end if strcmp(cfg.highlight{icell}, 'numbers') - for ichan = 1:length(labelindex) - templay.label{ichan} = num2str(match_str(data.label,templay.label{ichan})); + for ichan = 1:length(layoutindex) + templay.label{ichan} = num2str(match_str(data.label, templay.label{ichan})); end end - ft_plot_lay(templay,'box','no','label',labelflg,'point','yes',... - 'pointsymbol',cfg.highlightsymbol{icell},... - 'pointcolor',cfg.highlightcolor{icell},... - 'pointsize',cfg.highlightsize{icell},... - 'labelsize',cfg.highlightfontsize{icell},... - 'labeloffset',cfg.labeloffset) + + ft_plot_lay(templay, 'box', 'no', 'label', labelflg, 'point', ~labelflg, ... + 'pointsymbol', cfg.highlightsymbol{icell}, ... + 'pointcolor', cfg.highlightcolor{icell}, ... + 'pointsize', cfg.highlightsize{icell}, ... + 'fontsize', cfg.highlightfontsize{icell}, ... + 'labeloffset', cfg.labeloffset, ... + 'labelalignh', 'center', ... + 'labelalignv', 'middle'); end end % for icell + % For Markers (all channels) -if ~strcmp(cfg.marker,'off') +cfg = ft_checkopt(cfg, 'marker', {}, {'on', 'off', 'labels', 'numbers'}); +if ~strcmp(cfg.marker, 'off') channelsToMark = 1:length(data.label); - if strcmp(cfg.interpolatenan,'no') - channelsNotMark = highlightchansel; + channelsToHighlight = []; + for icell = 1:length(cfg.highlight) + if ~strcmp(cfg.highlight{icell}, 'off') + channelsToHighlight = [channelsToHighlight; match_str(data.label, cfg.highlightchannel{icell})]; + end + end + if strcmp(cfg.interpolatenan, 'no') + channelsNotMark = channelsToHighlight; else - channelsNotMark = union(find(isnan(dat)),highlightchansel); + channelsNotMark = union(find(isnan(dat)), channelsToHighlight); end channelsToMark(channelsNotMark) = []; - [dum labelindex] = match_str(ft_channelselection(channelsToMark, data.label),cfg.layout.label); - templay.pos = cfg.layout.pos(labelindex,:); - templay.width = cfg.layout.width(labelindex); - templay.height = cfg.layout.height(labelindex); - templay.label = cfg.layout.label(labelindex); + [dum, layoutindex] = match_str(ft_channelselection(channelsToMark, data.label), cfg.layout.label); + templay = []; + templay.outline = cfg.layout.outline; + templay.mask = cfg.layout.mask; + templay.pos = cfg.layout.pos(layoutindex,:); + templay.width = cfg.layout.width(layoutindex); + templay.height = cfg.layout.height(layoutindex); + templay.label = cfg.layout.label(layoutindex); if strcmp(cfg.marker, 'labels') || strcmp(cfg.marker, 'numbers') labelflg = 1; else labelflg = 0; end if strcmp(cfg.marker, 'numbers') - for ichan = 1:length(labelindex) + for ichan = 1:length(layoutindex) templay.label{ichan} = num2str(match_str(data.label,templay.label{ichan})); end end - ft_plot_lay(templay,'box','no','label',labelflg,'point','yes',... - 'pointsymbol',cfg.markersymbol,... - 'pointcolor',cfg.markercolor,... - 'pointsize',cfg.markersize,... - 'labelsize',cfg.markerfontsize,... - 'labeloffset',cfg.labeloffset) + ft_plot_lay(templay, 'box', 'no', 'label',labelflg, 'point', ~labelflg, ... + 'pointsymbol', cfg.markersymbol, ... + 'pointcolor', cfg.markercolor, ... + 'pointsize', cfg.markersize, ... + 'fontsize', cfg.markerfontsize, ... + 'labeloffset', cfg.labeloffset, ... + 'labelalignh', 'center', ... + 'labelalignv', 'middle'); end - -if(isfield(cfg,'vector')) - vecX = mean(real(data.(cfg.vector)(:,xmin:xmax)),2); - vecY = mean(imag(data.(cfg.vector)(:,xmin:xmax)),2); - - % scale quiver relative to largest gradiometer sample - k=0.15/max([max(abs(real(data.(cfg.vector)(:)))) max(abs(imag(data.(cfg.vector)(:))))]); - quiver(chanX, chanY, k*vecX, k*vecY,0,'red'); +if isfield(cfg, 'vector') + % FIXME this is not documented + vecX = nanmean(real(data.(cfg.vector)(:,selx)), 2); + vecY = nanmean(imag(data.(cfg.vector)(:,selx)), 2); + + % scale quiver relative to largest gradiometer sample + k = 0.15/max([max(abs(real(data.(cfg.vector)(:)))) max(abs(imag(data.(cfg.vector)(:))))]); + quiver(chanX, chanY, k*vecX, k*vecY, 0, 'red'); end % Write comment -if ~strcmp(cfg.comment,'no') +if ~strcmp(cfg.comment, 'no') if strcmp(cfg.commentpos, 'title') - title(cfg.comment, 'Fontsize', cfg.fontsize); + title(cfg.comment, 'FontSize', cfg.fontsize); else - ft_plot_text(x_comment,y_comment, cfg.comment, 'Fontsize', cfg.fontsize, 'HorizontalAlignment', 'left', 'VerticalAlignment', 'bottom'); + ft_plot_text(x_comment, y_comment, cfg.comment, 'FontSize', cfg.fontsize, 'HorizontalAlignment', 'left', 'VerticalAlignment', 'bottom', 'FontWeight', cfg.fontweight); end end -% plot colorbar: +% Set colour axis +if ~strcmp(cfg.style, 'blank') + caxis([zmin zmax]); +end + +% Plot colorbar if isfield(cfg, 'colorbar') if strcmp(cfg.colorbar, 'yes') colorbar; elseif ~strcmp(cfg.colorbar, 'no') - colorbar('location',cfg.colorbar); + colorbar('location', cfg.colorbar); end end @@ -877,69 +786,15 @@ set(gcf, 'renderer', cfg.renderer) end -% The remainder of the code is meant to make the figure interactive -hold on; - -% Set colour axis -if ~strcmp(cfg.style, 'blank') - caxis([zmin zmax]); -end - -if strcmp('yes',cfg.hotkeys) - % Attach data and cfg to figure and attach a key listener to the figure - set(gcf, 'KeyPressFcn', {@key_sub, zmin, zmax}) -end - -% Make the figure interactive -if strcmp(cfg.interactive, 'yes') - % add the channel position information to the figure - % this section is required for ft_select_channel to do its work - info = guidata(gcf); - info.x = cfg.layout.pos(:,1); - info.y = cfg.layout.pos(:,2); - info.label = cfg.layout.label; - guidata(gcf, info); - % attach data to the figure with the current axis handle as a name - dataname = fixname(num2str(double(gca))); - setappdata(gcf,dataname,varargin(1:Ndata)); - if any(strcmp(data.dimord, {'chan_time', 'chan_freq', 'subj_chan_time', 'rpt_chan_time', 'chan_chan_freq', 'chancmb_freq', 'rpt_chancmb_freq', 'subj_chancmb_freq'})) - set(gcf, 'WindowButtonUpFcn', {@ft_select_channel, 'multiple', true, 'callback', {@select_singleplotER, cfg}, 'event', 'WindowButtonUpFcn'}); - set(gcf, 'WindowButtonDownFcn', {@ft_select_channel, 'multiple', true, 'callback', {@select_singleplotER, cfg}, 'event', 'WindowButtonDownFcn'}); - set(gcf, 'WindowButtonMotionFcn', {@ft_select_channel, 'multiple', true, 'callback', {@select_singleplotER, cfg}, 'event', 'WindowButtonMotionFcn'}); - elseif any(strcmp(data.dimord, {'chan_freq_time', 'subj_chan_freq_time', 'rpt_chan_freq_time', 'rpttap_chan_freq_time', 'chan_chan_freq_time', 'chancmb_freq_time', 'rpt_chancmb_freq_time', 'subj_chancmb_freq_time'})) - set(gcf, 'WindowButtonUpFcn', {@ft_select_channel, 'multiple', true, 'callback', {@select_singleplotTFR, cfg}, 'event', 'WindowButtonUpFcn'}); - set(gcf, 'WindowButtonDownFcn', {@ft_select_channel, 'multiple', true, 'callback', {@select_singleplotTFR, cfg}, 'event', 'WindowButtonDownFcn'}); - set(gcf, 'WindowButtonMotionFcn', {@ft_select_channel, 'multiple', true, 'callback', {@select_singleplotTFR, cfg}, 'event', 'WindowButtonMotionFcn'}); - else - warning('unsupported dimord "%s" for interactive plotting', data.dimord); - end -end - % set the figure window title, but only if the user has not changed it if isempty(get(gcf, 'Name')) - if isfield(cfg,'funcname') + if isfield(cfg, 'funcname') funcname = cfg.funcname; else funcname = mfilename; end - if isfield(cfg,'dataname') - if iscell(cfg.dataname) - dataname = cfg.dataname{indx}; - else - dataname = cfg.dataname; - end - elseif nargin > 1 - dataname = {inputname(2)}; - for k = 2:Ndata - dataname{end+1} = inputname(k+1); - end - else % data provided through cfg.inputfile - dataname = cfg.inputfile; - end - if isempty(cfg.figurename) - dataname_str=join_str(', ', dataname); - + dataname_str = join_str(', ', dataname); set(gcf, 'Name', sprintf('%d: %s: %s', double(gcf), funcname, dataname_str)); set(gcf, 'NumberTitle', 'off'); else @@ -952,6 +807,40 @@ hold off axis equal +if strcmp('yes', cfg.hotkeys) + % Attach data and cfg to figure and attach a key listener to the figure + set(gcf, 'KeyPressFcn', {@key_sub, zmin, zmax}) +end + +% Make the figure interactive +if strcmp(cfg.interactive, 'yes') + % add the cfg/data/channel information to the figure under identifier linked to this axis + ident = ['axh' num2str(round(sum(clock.*1e6)))]; % unique identifier for this axis + set(gca, 'tag',ident); + info = guidata(gcf); + info.(ident).x = cfg.layout.pos(:, 1); + info.(ident).y = cfg.layout.pos(:, 2); + info.(ident).label = cfg.layout.label; + info.(ident).dataname = dataname; + info.(ident).cfg = cfg; + if ~isfield(info.(ident),'datvarargin') + info.(ident).datvarargin = varargin(1:Ndata); % add all datasets to figure + end + info.(ident).datvarargin{indx} = data; % update current dataset (e.g. baselined, channel selection, etc) + guidata(gcf, info); + if any(strcmp(data.dimord, {'chan_time', 'chan_freq', 'subj_chan_time', 'rpt_chan_time', 'chan_chan_freq', 'chancmb_freq', 'rpt_chancmb_freq', 'subj_chancmb_freq'})) + set(gcf, 'WindowButtonUpFcn', {@ft_select_channel, 'multiple', true, 'callback', {@select_singleplotER}, 'event', 'WindowButtonUpFcn'}); + set(gcf, 'WindowButtonDownFcn', {@ft_select_channel, 'multiple', true, 'callback', {@select_singleplotER}, 'event', 'WindowButtonDownFcn'}); + set(gcf, 'WindowButtonMotionFcn', {@ft_select_channel, 'multiple', true, 'callback', {@select_singleplotER}, 'event', 'WindowButtonMotionFcn'}); + elseif any(strcmp(data.dimord, {'chan_freq_time', 'subj_chan_freq_time', 'rpt_chan_freq_time', 'rpttap_chan_freq_time', 'chan_chan_freq_time', 'chancmb_freq_time', 'rpt_chancmb_freq_time', 'subj_chancmb_freq_time'})) + set(gcf, 'WindowButtonUpFcn', {@ft_select_channel, 'multiple', true, 'callback', {@select_singleplotTFR}, 'event', 'WindowButtonUpFcn'}); + set(gcf, 'WindowButtonDownFcn', {@ft_select_channel, 'multiple', true, 'callback', {@select_singleplotTFR}, 'event', 'WindowButtonDownFcn'}); + set(gcf, 'WindowButtonMotionFcn', {@ft_select_channel, 'multiple', true, 'callback', {@select_singleplotTFR}, 'event', 'WindowButtonMotionFcn'}); + else + ft_warning('unsupported dimord "%s" for interactive plotting', data.dimord); + end +end + % add a menu to the figure, but only if the current figure does not have subplots % also, delete any possibly existing previous menu, this is safe because delete([]) does nothing delete(findobj(gcf, 'type', 'uimenu', 'label', 'FieldTrip')); @@ -964,101 +853,78 @@ end end -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% SUBFUNCTION which is called after selecting channels in case of cfg.refchannel='gui' -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -function select_topoplotER(label, cfg, varargin) -% get appdata belonging to current axis -dataname = fixname(num2str(double(gca))); -data = getappdata(gcf, dataname); - -if isfield(cfg, 'inputfile') - % the reading has already been done and varargin contains the data - cfg = rmfield(cfg, 'inputfile'); -end -cfg.refchannel = label; -fprintf('selected cfg.refchannel = ''%s''\n', cfg.refchannel{:}); -p = get(gcf, 'Position'); -f = figure; -set(f, 'Position', p); -cfg.highlight = 'on'; -cfg.highlightsymbol = '.'; -cfg.highlightcolor = 'r'; -cfg.highlightsize = 20; -cfg.highlightchannel = cfg.refchannel; -ft_topoplotER(cfg, data); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % SUBFUNCTION which is called after selecting channels in case of cfg.interactive='yes' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -function select_singleplotER(label, cfg) +function select_singleplotER(label) +ident = get(gca, 'tag'); +info = guidata(gcf); +cfg = info.(ident).cfg; +datvarargin = info.(ident).datvarargin; if ~isempty(label) - % get appdata belonging to current axis - dataname = fixname(num2str(double(gca))); - data = getappdata(gcf, dataname); - - if isfield(cfg, 'inputfile') - % the reading has already been done and varargin contains the data - cfg = rmfield(cfg, 'inputfile'); - end - cfg.xlim = 'maxmin'; + cfg = removefields(cfg, 'inputfile'); % the reading has already been done and varargin contains the data + cfg.baseline = 'no'; % make sure the next function does not apply a baseline correction again cfg.channel = label; + cfg.dataname = info.(ident).dataname; % put data name in here, this cannot be resolved by other means + cfg.trials = 'all'; % trial selection has already been taken care of + cfg.xlim = 'maxmin'; % if user specified a zlim, copy it over to the ylim of singleplot if isfield(cfg, 'zlim') cfg.ylim = cfg.zlim; cfg = rmfield(cfg, 'zlim'); end - fprintf('selected cfg.channel = {'); - for i=1:(length(cfg.channel)-1) - fprintf('''%s'', ', cfg.channel{i}); - end - fprintf('''%s''}\n', cfg.channel{end}); - p = get(gcf, 'Position'); - f = figure; - set(f, 'Position', p); - ft_singleplotER(cfg, data{:}); + fprintf('selected cfg.channel = {%s}\n', join_str(', ', cfg.channel)); + % ensure that the new figure appears at the same position + f = figure('Position', get(gcf, 'Position'), 'Visible', get(gcf, 'Visible')); + ft_singleplotER(cfg, datvarargin{:}); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % SUBFUNCTION which is called after selecting channels in case of cfg.interactive='yes' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -function select_singleplotTFR(label, cfg) +function select_singleplotTFR(label) +ident = get(gca, 'tag'); +info = guidata(gcf); +cfg = info.(ident).cfg; +datvarargin = info.(ident).datvarargin; if ~isempty(label) - % get appdata belonging to current axis - dataname = fixname(num2str(double(gca))); - data = getappdata(gcf, dataname); - - if isfield(cfg, 'inputfile') - % the reading has already been done and varargin contains the data - cfg = rmfield(cfg, 'inputfile'); - end + cfg = removefields(cfg, 'inputfile'); % the reading has already been done and varargin contains the data + cfg.baseline = 'no'; % make sure the next function does not apply a baseline correction again + cfg.channel = label; + cfg.dataname = info.(ident).dataname; % put data name in here, this cannot be resolved by other means + cfg.trials = 'all'; % trial selection has already been taken care of cfg.xlim = 'maxmin'; cfg.ylim = 'maxmin'; - cfg.channel = label; - fprintf('selected cfg.channel = {'); - for i=1:(length(cfg.channel)-1) - fprintf('''%s'', ', cfg.channel{i}); - end - fprintf('''%s''}\n', cfg.channel{end}); - p = get(gcf, 'Position'); - f = figure; - set(f, 'Position', p); - ft_singleplotTFR(cfg, data{:}); + fprintf('selected cfg.channel = {%s}\n', join_str(', ', cfg.channel)); + % ensure that the new figure appears at the same position + f = figure('Position', get(gcf, 'Position'), 'Visible', get(gcf, 'Visible')); + ft_singleplotTFR(cfg, datvarargin{:}); end - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % SUBFUNCTION which handles hot keys in the current plot %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function key_sub(handle, eventdata, varargin) -incr = (max(caxis)-min(caxis)) /10; -% symmetrically scale color bar down by 10 percent -if strcmp(eventdata.Key,'uparrow') - caxis([min(caxis)-incr max(caxis)+incr]); - % symmetrically scale color bar up by 10 percent -elseif strcmp(eventdata.Key,'downarrow') - caxis([min(caxis)+incr max(caxis)-incr]); - % resort to minmax of data for colorbar -elseif strcmp(eventdata.Key,'m') - caxis([varargin{1} varargin{2}]); -end +climits = caxis; +incr_c = abs(climits(2) - climits(1)) /10; + +if length(eventdata.Modifier) == 1 && strcmp(eventdata.Modifier{:}, 'control') + % TRANSLATE by 10% + switch eventdata.Key + case 'pageup' + caxis([climits(1)+incr_c climits(2)+incr_c]); + case 'pagedown' + caxis([climits(1)-incr_c climits(2)-incr_c]); + end % switch +else + % ZOOM by 10% + switch eventdata.Key + case 'pageup' + caxis([climits(1)-incr_c climits(2)+incr_c]); + case 'pagedown' + caxis([climits(1)+incr_c climits(2)-incr_c]); + case 'm' + caxis([varargin{1} varargin{2}]); + end % switch +end % if diff --git a/external/fieldtrip/private/transform2grid.m b/external/fieldtrip/private/transform2grid.m index cc786837..1797b72d 100644 --- a/external/fieldtrip/private/transform2grid.m +++ b/external/fieldtrip/private/transform2grid.m @@ -25,7 +25,7 @@ 1 1 0 0 1 1 1 0 ]; if any(dum(:)~=0) - error('rotated coordinate system, cannot compute xgrid/ygrid/zgrid'); + ft_error('rotated coordinate system, cannot compute xgrid/ygrid/zgrid'); end % apply the homogenous coordinate transformation to each of the cardinal axes diff --git a/external/fieldtrip/private/translate.m b/external/fieldtrip/private/translate.m index 4f9c0112..6eb184eb 100644 --- a/external/fieldtrip/private/translate.m +++ b/external/fieldtrip/private/translate.m @@ -44,7 +44,7 @@ % $Id$ if numel(f)~=3 - error('incorrect input vector'); + ft_error('incorrect input vector'); end H = [ diff --git a/external/fieldtrip/private/triangulate_seg.m b/external/fieldtrip/private/triangulate_seg.m index 92b9d1a9..3fb81c04 100644 --- a/external/fieldtrip/private/triangulate_seg.m +++ b/external/fieldtrip/private/triangulate_seg.m @@ -53,7 +53,7 @@ len = ceil(sqrt(sum(dim.^2))/2); if ~any(seg(:)) - error('the segmentation is empty') + ft_error('the segmentation is empty') end % define the origin if it is not provided in the input arguments @@ -66,15 +66,17 @@ % ensure that the seg consists of only one filled blob. % if not filled: throw a warning and fill % if more than one blob: throw a warning and use the biggest -ft_hastoolbox('SPM8', 1); % look for holes seg = volumefillholes(seg); +% ensure that SPM is available, needed for spm_bwlabel +ft_hastoolbox('spm8up', 3) || ft_hastoolbox('spm2', 1); + % look for >1 blob [lab, num] = spm_bwlabel(double(seg), 26); if num>1, - warning('the segmented volume consists of more than one compartment, using only the biggest one for the segmentation'); + ft_warning('the segmented volume consists of more than one compartment, using only the biggest one for the segmentation'); for k = 1:num n(k) = sum(lab(:)==k); @@ -125,7 +127,7 @@ if ishollow % this should not have hapened, especially not after filling the holes - warning('the segmentation is not star-shaped, please check the surface mesh'); + ft_warning('the segmentation is not star-shaped, please check the surface mesh'); end % undo the shift of the origin from where the projection is done diff --git a/external/fieldtrip/private/tritrisect.m b/external/fieldtrip/private/tritrisect.m new file mode 100644 index 00000000..b13d4b88 --- /dev/null +++ b/external/fieldtrip/private/tritrisect.m @@ -0,0 +1,108 @@ +function [l1, l2] = tritrisect(v1, v2, v3, t1, t2, t3) + +% TRITRISECT computes the intersection line of a triangle with a plane +% spanned by three vertices v1, v2 and v3. +% +% [l1, l2] = tritrisect(v1, v2, v3, t1, t2, t3) + +% Copyright (C) 2002, Robert Oostenveld +% +% $Log: tritrisect.m,v $ +% Revision 1.3 2003/03/11 15:35:20 roberto +% converted all files from DOS to UNIX +% +% Revision 1.2 2003/03/04 21:46:20 roberto +% added CVS log entry and synchronized all copyright labels +% + +% determine on which side of the plane each vertex lies +p1 = ptriside(v1, v2, v3, t1); +p2 = ptriside(v1, v2, v3, t2); +p3 = ptriside(v1, v2, v3, t3); + +if all([p1 p2 p3]==0) + ft_warning('triangle lies exactly in plane'); + l1 = [nan, nan, nan]; + l2 = [nan, nan, nan]; + return +end + +if abs(sum([p1 p2 p3]))==3 + ft_warning('triangle lies on one side of plane'); + l1 = [nan, nan, nan]; + l2 = [nan, nan, nan]; + return +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +if p1==0 && p2==0 && p3~=0 + % triangle vertex 1 and 2 ly in the plane + l1 = t1; + l2 = t2; + return +end + +if p1==0 && p2~=0 && p3==0 + % triangle vertex 1 and 3 ly in the plane + l1 = t1; + l2 = t3; + return +end + +if p1~=0 && p2==0 && p3==0 + % triangle vertex 2 and 3 ly in the plane + l1 = t2; + l2 = t3; + return +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +if p1==0 && p2~=0 && p3~=0 + % triangle vertex 1 lies in the plane + l1 = t1; + % triangle edge 2-3 intersects with the plane + l2 = ltrisect(v1, v2, v3, t2, t3); + return; +end + +if p1~=0 && p2==0 && p3~=0 + % triangle vertex 2 lies in the plane + l1 = t2; + % triangle edge 3-1 intersects with the plane + l2 = ltrisect(v1, v2, v3, t3, t1); + return; +end + +if p1~=0 && p2~=0 && p3==0 + % triangle vertex 3 lies in the plane + l1 = t3; + % triangle edge 1-2 intersects with the plane + l2 = ltrisect(v1, v2, v3, t1, t2); + return; +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +if p1==p2 + % triangle vertex 3 lies on opposite side + l1 = ltrisect(v1, v2, v3, t3, t1); + l2 = ltrisect(v1, v2, v3, t3, t2); + return; +end + +if p2==p3 + % triangle vertex 1 lies on opposite side + l1 = ltrisect(v1, v2, v3, t1, t2); + l2 = ltrisect(v1, v2, v3, t1, t3); + return; +end + +if p3==p1 + % triangle vertex 2 lies on opposite side + l1 = ltrisect(v1, v2, v3, t2, t3); + l2 = ltrisect(v1, v2, v3, t2, t1); + return; +end + diff --git a/external/fieldtrip/private/undobalancing.m b/external/fieldtrip/private/undobalancing.m index 6b5c555a..e91c7e3e 100644 --- a/external/fieldtrip/private/undobalancing.m +++ b/external/fieldtrip/private/undobalancing.m @@ -21,7 +21,7 @@ tmp = tra1*tra2; tmp = null(tmp); % nullspace after ft_componentanalysis and ft_rejectcomponent tmp = tmp*tmp'; % this is the part which was removed at some point - [ix,iy] = match_str(sens.balance.comp.labelorg, sens.balance.invcomp.labelnew); + [ix,iy] = match_str(sens.balance.comp.labelold, sens.balance.invcomp.labelnew); tra3(iy,iy) = (eye(numel(ix))+tmp(ix,ix))*tra1(iy,iy); sens.balance.invcomp.tra = tra3; % FIXME check whether this is robust @@ -49,7 +49,7 @@ end else - warning('cannot undo %s balancing in the gradiometer definition\n', sens.balance.current); + ft_warning('cannot undo %s balancing in the gradiometer definition\n', sens.balance.current); break end end diff --git a/external/fieldtrip/private/univariate2bivariate.m b/external/fieldtrip/private/univariate2bivariate.m index 9160b00c..4c963560 100644 --- a/external/fieldtrip/private/univariate2bivariate.m +++ b/external/fieldtrip/private/univariate2bivariate.m @@ -50,7 +50,7 @@ end getpowindx = 0; if ncmb==0, - error('no channel combinations are specified'); + ft_error('no channel combinations are specified'); elseif ncmb==nchan^2 || ncmb==(nchan+1)*nchan*0.5, dofull = 1; else @@ -74,7 +74,7 @@ else % data = ft_checkdata(data, 'cmbrepresentation', 'full'); % this should not be possible - error('cannot convert to a full csd representation'); + ft_error('cannot convert to a full csd representation'); end elseif strcmp(inparam, 'fourierspctrm') && strcmp(outparam, 'powcovspctrm'), @@ -123,7 +123,7 @@ data = rmfield(data, 'crsspctrm'); else - error('unknown conversion from univariate to bivariate representation'); + ft_error('unknown conversion from univariate to bivariate representation'); end % if inparam is fourierspctrm or crsspctrm if ~isempty(cmb) && (ncmb < (nchan-1)*nchan*0.5 || getpowindx==1), @@ -132,7 +132,7 @@ powindx = []; end - case 'source' + case {'source' 'source+mesh'} ncmb = numel(cmb); % the code further down requires this to be a vector with indices @@ -239,23 +239,23 @@ data.outside = [data.outside(:); data.outside(:)+nvox]; data.crsspctrmdimord = 'rpttap_pos'; - elseif ncmb1 else - error('unknown conversion from univariate to bivariate representation'); + ft_error('unknown conversion from univariate to bivariate representation'); end + % the code in the caller function requires this to be a boolean vector + data = fixinside(data, 'logical'); + case 'raw' % construct a timelock-like structure that only contains the covariance, see ft_datatype_timelock timelock = []; if ~strcmp(inparam, 'trial') - error('incorrect specification of inparam') + ft_error('incorrect specification of inparam') elseif ~strcmp(outparam, 'cov'), - error('incorrect specification of outparam') + ft_error('incorrect specification of outparam') end nrpt = length(data.trial); @@ -395,7 +398,7 @@ data = timelock; otherwise - error('unsupported input data type'); + ft_error('unsupported input data type'); end % swith dtype if ~exist('hasrpt', 'var') diff --git a/external/fieldtrip/private/validate_seg.m b/external/fieldtrip/private/validate_seg.m index 7154a924..5f670ad6 100644 --- a/external/fieldtrip/private/validate_seg.m +++ b/external/fieldtrip/private/validate_seg.m @@ -76,19 +76,19 @@ if ~isequal(size(tissue1), size(tissue2)) - error('inconsistent size of segmentations') + ft_error('inconsistent size of segmentations') elseif ~isequal(size(tissue1), size(tissue3)) - error('inconsistent size of segmentations') + ft_error('inconsistent size of segmentations') elseif ~isa(tissue1, 'logical') && ~all(tissue1(:)==0 | tissue1(:)==1) - error('the first tissue is not a binary segmentation'); + ft_error('the first tissue is not a binary segmentation'); elseif ~isa(tissue2, 'logical') && ~all(tissue2(:)==0 | tissue2(:)==1) - error('the second tissue is not a binary segmentation'); + ft_error('the second tissue is not a binary segmentation'); elseif ~isa(tissue3, 'logical') && ~all(tissue3(:)==0 | tissue3(:)==1) - error('the third tissue is not a binary segmentation'); + ft_error('the third tissue is not a binary segmentation'); end @@ -104,7 +104,7 @@ air = ~imfill(tissue1|tissue2|tissue3, 'holes'); if ~all(tissue1(:)|tissue2(:)|tissue3(:)|air(:)) - error('there are voxels which do not belong to any tissue or air') + ft_error('there are voxels which do not belong to any tissue or air') end @@ -121,44 +121,44 @@ if nargin > 1 if any(tissue1(:)&~tissue2(:)) - error('the first tissue outside of the second') + ft_error('the first tissue outside of the second') end if any(tissue2(:)&~tissue3(:)) - error('the second tissue is outside of the third') + ft_error('the second tissue is outside of the third') end if any(tissue1(:)&~tissue3(:)) - error('there is first tissue is outside the third') + ft_error('there is first tissue is outside the third') end if ~any(tissue2(:)&~tissue1(:)) - error('the first two tissues are not different') + ft_error('the first two tissues are not different') end end if nargin > 2 if ~any(tissue3(:)&~tissue2(:)) - error('the last two tissues are not different') + ft_error('the last two tissues are not different') end end holes = imfill(tissue1, 'holes') & ~tissue1; if any(holes(:)) - error('there are holes in the first tissue'); + ft_error('there are holes in the first tissue'); end if nargin > 1 holes = imfill(tissue2, 'holes') & ~tissue2; if any(holes(:)) - error('there are holes in the second tissue'); + ft_error('there are holes in the second tissue'); end holes = imfill(tissue3, 'holes') & ~tissue3; if any(holes(:)) - error('there are holes in the third tissue'); + ft_error('there are holes in the third tissue'); end end diff --git a/external/fieldtrip/private/volplot.m b/external/fieldtrip/private/volplot.m index 31ecec9a..d12697c4 100644 --- a/external/fieldtrip/private/volplot.m +++ b/external/fieldtrip/private/volplot.m @@ -56,12 +56,12 @@ z = 1:size(dat,3); elseif nargin>4 if length(size(dat))==3 - if length(x)~=size(dat,1), error('incorrect x-axis specification'), end - if length(y)~=size(dat,2), error('incorrect y-axis specification'), end - if length(z)~=size(dat,3), error('incorrect z-axis specification'), end + if length(x)~=size(dat,1), ft_error('incorrect x-axis specification'), end + if length(y)~=size(dat,2), ft_error('incorrect y-axis specification'), end + if length(z)~=size(dat,3), ft_error('incorrect z-axis specification'), end end else - error('incorrect number of input arguments'); + ft_error('incorrect number of input arguments'); end if nargin==6 @@ -84,17 +84,17 @@ end % convert the selection to the indices of the x/y/z intersection -if ischar(sel) & strcmp(sel, 'min') +if ischar(sel) && strcmp(sel, 'min') [minval, minindx] = min(dat(:)); [xi, yi, zi] = ind2sub(size(dat), minindx); -elseif ischar(sel) & strcmp(sel, 'max') +elseif ischar(sel) && strcmp(sel, 'max') [maxval, maxindx] = max(dat(:)); [xi, yi, zi] = ind2sub(size(dat), maxindx); -elseif ischar(sel) & strcmp(sel, 'center') +elseif ischar(sel) && strcmp(sel, 'center') xi = round(length(x)/2); yi = round(length(y)/2); zi = round(length(z)/2); -elseif ischar(sel) & strcmp(sel, 'interactive') +elseif ischar(sel) && strcmp(sel, 'interactive') xi = round(length(x)/2); yi = round(length(y)/2); zi = round(length(z)/2); @@ -146,7 +146,7 @@ % update the view to a new position l1 = get(get(gca, 'xlabel'), 'string'); l2 = get(get(gca, 'ylabel'), 'string'); - switch l1, + switch l1 case 'x' xc = d1; case 'y' @@ -154,7 +154,7 @@ case 'z' zc = d1; end - switch l2, + switch l2 case 'x' xc = d2; case 'y' @@ -202,6 +202,12 @@ % change not-a-number values to zero dat(find(isnan(dat(:)))) = 0; + % update cmin and cmax + cmin = 0; + cmax = squeeze(max(max(sum(dat,1)))); + cmax = max(cmax, squeeze(max(max(sum(dat,2))))); + cmax = max(cmax, squeeze(max(max(sum(dat,3))))); + subplot(h1); imagesc(x, z, squeeze(sum(dat, 2))'); set(gca, 'ydir', 'normal') axis equal; axis tight; @@ -221,7 +227,8 @@ caxis([cmin cmax]); subplot(h4); - colorbar(h4, 'peer', h1); + imagesc(cmin:cmax); + caxis([cmin cmax]); xlabel('colorscale') elseif strcmp(sel, 'maxproject') @@ -256,8 +263,8 @@ else % make plot of three orthogonal slices intersecting at [xi yi zi] - if ~exist('xi', 'var') | ~exist('yi', 'var') | ~exist('zi', 'var') - error('nothing to plot, no selection given') + if ~exist('xi', 'var') || ~exist('yi', 'var') || ~exist('zi', 'var') + ft_error('nothing to plot, no selection given') end fprintf('value of %f in voxel %d at [%.02f %.02f %.02f]\n', double(dat(xi, yi, zi)), sub2ind(dim, xi, yi, zi), x(xi), y(yi), z(zi)); @@ -275,24 +282,25 @@ axis equal; axis tight; xlabel('x'); ylabel('z'); caxis([cmin cmax]); - crosshair([x(xi) z(zi)], 'color', 'yellow'); + ft_plot_crosshair([x(xi) z(zi)], 'color', 'yellow'); subplot(h2); imagesc(y, z, squeeze(dat(xi,:,:))'); set(gca, 'ydir', 'normal') axis equal; axis tight; xlabel('y'); ylabel('z'); caxis([cmin cmax]); - crosshair([y(yi) z(zi)], 'color', 'yellow'); + ft_plot_crosshair([y(yi) z(zi)], 'color', 'yellow'); subplot(h3); imagesc(x, y, squeeze(dat(:,:,zi))'); set(gca, 'ydir', 'normal') axis equal; axis tight; xlabel('x'); ylabel('y'); caxis([cmin cmax]); - crosshair([x(xi) y(yi)], 'color', 'yellow'); + ft_plot_crosshair([x(xi) y(yi)], 'color', 'yellow'); subplot(h4); - colorbar(h4, 'peer', h1); + imagesc(cmin:((cmax-cmin)./64):cmax); + caxis([cmin cmax]); xlabel('colorscale') end diff --git a/external/fieldtrip/private/volumeedit.m b/external/fieldtrip/private/volumeedit.m index 3ccdf79a..f62ed299 100644 --- a/external/fieldtrip/private/volumeedit.m +++ b/external/fieldtrip/private/volumeedit.m @@ -102,9 +102,9 @@ set(h3, 'tag', 'ik', 'clim', [0 1]); % crosshair handles -hch1 = crosshair([zi yi], 'parent', h1, 'color', 'y'); -hch2 = crosshair([xi yi], 'parent', h2, 'color', 'y'); -hch3 = crosshair([zi xi], 'parent', h3, 'color', 'y'); +hch1 = ft_plot_crosshair([zi yi], 'parent', h1, 'color', 'y'); +hch2 = ft_plot_crosshair([xi yi], 'parent', h2, 'color', 'y'); +hch3 = ft_plot_crosshair([zi xi], 'parent', h3, 'color', 'y'); % erasercontour he1(1,:) = line(zi-3.5+[0 0 7 7 0],yi-3.5+[0 7 7 0 0],'color','r','parent',h1); @@ -321,9 +321,9 @@ function cb_redraw(h, eventdata) set(opt.handlesslice(3), 'AlphaData', msk3); end -crosshair([zi yi], 'handle', opt.handlescross(1,:)); -crosshair([xi yi], 'handle', opt.handlescross(2,:)); -crosshair([zi xi], 'handle', opt.handlescross(3,:)); +ft_plot_crosshair([zi yi], 'handle', opt.handlescross(1,:)); +ft_plot_crosshair([xi yi], 'handle', opt.handlescross(2,:)); +ft_plot_crosshair([zi xi], 'handle', opt.handlescross(3,:)); cb_erasercontour(h); diff --git a/external/fieldtrip/private/volumefillholes.m b/external/fieldtrip/private/volumefillholes.m index 574f88e1..8b96d00c 100644 --- a/external/fieldtrip/private/volumefillholes.m +++ b/external/fieldtrip/private/volumefillholes.m @@ -4,11 +4,8 @@ % % See also VOLUMETHRESHOLD, VOLUMESMOOTH -% check for any version of SPM -if ~ft_hastoolbox('spm') - % add SPM8 to the path - ft_hastoolbox('spm8', 1); -end +% ensure that SPM is available, needed for spm_bwlabel +hasspm = ft_hastoolbox('spm8up', 3) || ft_hastoolbox('spm2', 1); if nargin<2 inflate = false(size(input)+2); % grow the edges along each dimension @@ -43,10 +40,10 @@ for i=1:dim(3) slice=reshape(input(:,:,i),dim([1 2])); im = imfill(slice,8,'holes'); - output(:,:,3) = im; + output(:,:,i) = im; end otherwise - error('invalid dimension along which to slice the volume'); + ft_error('invalid dimension along which to slice the volume'); end % switch end % if nargin diff --git a/external/fieldtrip/private/volumeflip.m b/external/fieldtrip/private/volumeflip.m index bd79d479..7f753a53 100644 --- a/external/fieldtrip/private/volumeflip.m +++ b/external/fieldtrip/private/volumeflip.m @@ -1,15 +1,16 @@ function [volume, flipvec] = volumeflip(volume, flipvecin) +% VOLUMEFLIP +% +% See also VOLUMEPERMUTE + if nargin<2 flipvecin = 'auto'; end % do a low-level check on the input data -if ~isfield(volume, 'transform'), error('the input volume needs a transformation matrix'); end -if ~isfield(volume, 'dim'), error('the input volume needs a dim field'); end - -if isfield(volume, 'outside') -end +if ~isfield(volume, 'transform'), ft_error('the input volume needs a transformation matrix'); end +if ~isfield(volume, 'dim'), ft_error('the input volume needs a dim field'); end isrighthanded = det(volume.transform(1:3,1:3))>0; @@ -18,21 +19,21 @@ switch flipvecin case {'left' 'lefthanded'} if isrighthanded - warning('left-handed axes system is requested, performing flip'); + ft_warning('left-handed axes system is requested, performing flip'); flipvecin = [1 0 0]; else flipvecin = [0 0 0]; end case {'right' 'righthanded'} if ~isrighthanded - warning('right-handed axes system is requested, performing flip'); + ft_warning('right-handed axes system is requested, performing flip'); flipvecin = [1 0 0]; else flipvecin = [0 0 0]; end case 'auto' otherwise - error('unsupported option specified'); + ft_error('unsupported option specified'); end end @@ -67,7 +68,7 @@ if flipvec(m) % get the reflection matrix - flipmat = eye(4); flipmat(m,m) = -1; flipmat(m,4) = dim(m)+1; + flipmat = eye(4); flipmat(m,m) = -1; flipmat(m,4) = dim(m)+1; for k = 1:numel(fnames) volume = setsubfield(volume, fnames{k}, flipdim(getsubfield(volume, fnames{k}), m)); end diff --git a/external/fieldtrip/private/volumepermute.m b/external/fieldtrip/private/volumepermute.m index 750037ec..eddd068e 100644 --- a/external/fieldtrip/private/volumepermute.m +++ b/external/fieldtrip/private/volumepermute.m @@ -1,11 +1,12 @@ function [volume, permutevec] = volumepermute(volume, permutevec) -% do a low-level check on the input data -if ~isfield(volume, 'transform'), error('the input volume needs a transformation matrix'); end -if ~isfield(volume, 'dim'), error('the input volume needs a dim field'); end +% VOLUMEPERMUTE +% +% See also VOLUMEFLIP -if isfield(volume, 'outside') -end +% do a low-level check on the input data +if ~isfield(volume, 'transform'), ft_error('the input volume needs a transformation matrix'); end +if ~isfield(volume, 'dim'), ft_error('the input volume needs a dim field'); end % define some variable locally T = volume.transform; @@ -26,12 +27,13 @@ permutevec = 'auto'; end -if ischar(permutevec) +if isequal(permutevec, 'auto') % determine the order of permutation to make the transformatiom matrix approximately diagonal [dum, m1] = max(abs(T(1,1:3))); [dum, m2] = max(abs(T(2,1:3))); - [dum, m3] = max(abs(T(3,1:3))); - permutevec = [m1 m2 m3]; + % [dum, m3] = max(abs(T(3,1:3))); + [dum, m3] = setdiff(1:3, [m1 m2]); % whichever dimension remains + permutevec = [m1 m2 m3]; end if ~all(permutevec==[1 2 3]) diff --git a/external/fieldtrip/private/volumesmooth.m b/external/fieldtrip/private/volumesmooth.m index 99e822ff..631e7271 100644 --- a/external/fieldtrip/private/volumesmooth.m +++ b/external/fieldtrip/private/volumesmooth.m @@ -4,17 +4,15 @@ % % See also VOLUMETHRESHOLD, VOLUMEFILLHOLES +% ensure that SPM is available, needed for spm_smooth +hasspm = ft_hastoolbox('spm8up', 3) || ft_hastoolbox('spm2', 1); + if nargin==3 fprintf('smoothing %s with a %d-voxel FWHM kernel\n', str, fwhm); end -% check for any version of SPM -if ~ft_hastoolbox('spm') - % add SPM8 to the path - ft_hastoolbox('spm8', 1); -end - % don't touch the input, make a deep copy output = input+0; + % the mex files underneath the spm function will change the input variable spm_smooth(output, output, fwhm); diff --git a/external/fieldtrip/private/volumethreshold.m b/external/fieldtrip/private/volumethreshold.m index ddd18aa0..830b3203 100644 --- a/external/fieldtrip/private/volumethreshold.m +++ b/external/fieldtrip/private/volumethreshold.m @@ -6,15 +6,23 @@ % % See also VOLUMEFILLHOLES, VOLUMESMOOTH -% check for SPM8 or later, add to the path if not present -ft_hastoolbox('spm8up', 1); +if nargin<2 || isempty(thresh) + thresh = 0; +end +if nargin<3 || isempty(str) + str = 'volume'; +end + +% ensure that SPM is available, needed for spm_bwlabel +hasspm = ft_hastoolbox('spm8up', 3) || ft_hastoolbox('spm2', 1); % mask by taking the negative of the segmentation, thus ensuring % that no holes are within the compartment and do a two-pass % approach to eliminate potential vitamin E capsules etc. if ~islogical(input) - fprintf('thresholding %s at a relative threshold of %0.3f\n', str, thresh); + if nargin==2, ft_error('if the input volume is not a boolean volume, you need to define a threshold value'); end + if nargin==3, fprintf('thresholding %s at a relative threshold of %0.3f\n', str, thresh); end output = double(input>(thresh*max(input(:)))); else % there is no reason to apply a threshold, but spm_bwlabel still needs a diff --git a/external/fieldtrip/private/warp_dykstra2012.m b/external/fieldtrip/private/warp_dykstra2012.m new file mode 100644 index 00000000..70d38189 --- /dev/null +++ b/external/fieldtrip/private/warp_dykstra2012.m @@ -0,0 +1,339 @@ +function [coord_snapped] = warp_dykstra2012(cfg, elec, surf) + +% WARP_DYKSTRA2012 projects the ECoG grid / strip onto a cortex hull +% while minimizing the distance from original positions and the +% deformation of the grid. To align ECoG electrodes to the pial surface, +% you first need to compute the cortex hull with FT_PREPARE_MESH. +% +% WARP_DYKSTRA2012 uses the algorithm described in Dykstra et al. (2012, +% Neuroimage) in which electrodes are projected onto pial surface while +% minimizing the displacement of the electrodes from original location +% and maintaining the grid shape. It relies on the optimization toolbox. +% +% See also FT_ELECTRODEREALIGN, FT_PREPARE_MESH + +% Copyright (C) 2012-2017, Arjen Stolk, Gio Piantoni, Andrew Dykstra +% +% This program is free software; you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation; either version 2 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program; if not, write to the Free Software +% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +% determine whether the MATLAB Optimization toolbox is available and can be used +ft_hastoolbox('optim', 1); + +disp('using warp algorithm described in Dykstra et al. 2012 Neuroimage PMID: 22155045') + +% set the defaults +cfg.feedback = ft_getopt(cfg, 'feedback', 'no'); + +% undocumented local options +cfg.pairmethod = ft_getopt(cfg, 'pairmethod', 'pos'); % eletrode pairing based on electrode 'pos' or 'label' (for computing deformation energy) +cfg.deformweight = ft_getopt(cfg, 'deformweight', 1); % weight of deformation relative to shift energy cost + +% get starting coordinates +coord0 = elec.elecpos; +coord = elec.elecpos; + +% compute pairs of neighbors +pairs = create_elecpairs(elec, cfg.pairmethod); + +% anonymous function handles +efun = @(coord_snapped) energy_electrodesnap(coord_snapped, coord, pairs, cfg.deformweight); +cfun = @(coord_snapped) dist_to_surface(coord_snapped, surf); + +% options +% 'UseParallel', 'always',... +options = optimset('Algorithm','active-set',... + 'MaxIter', 50,... + 'MaxFunEvals', Inf,... + 'GradObj', 'off',... + 'TypicalX', coord(:),... + 'DiffMaxChange', 2,... + 'DiffMinChange', 0.3,... + 'TolFun', 0.3,... + 'TolCon', 0.01 * size(coord0, 1),... + 'TolX', 0.5,... + 'Diagnostics', 'off',... + 'RelLineSrchBnd',1); + +if strcmp(cfg.feedback, 'yes') + options = optimset(options, 'Display', 'iter'); +else + options = optimset(options, 'Display', 'final'); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Energy Minimization +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% run minimization: efun (shift + deform energy) is minimized; cfun (surface distance) is a nonlinear constraint +coord_snapped = fmincon(efun, coord0, [], [], [], [], [], [], cfun, options); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function energy = energy_electrodesnap(coord, coord_orig, pairs, deformweight) % (minimized) energy function +% ENERGY_ELECTRODESNAP compute energy to be minimized, based on deformation +% and distance of the electrodes from original distance + +% energy needed to move electrodes to the surface +energy_eshift = sum((coord - coord_orig).^2, 2); + +% energy needed to deform grid shape +dist = sqrt(sum((coord(pairs(:, 1), :) - coord(pairs(:, 2), :)).^2, 2)); +dist_orig = sqrt(sum((coord_orig(pairs(:, 1), :) - coord_orig(pairs(:, 2), :)).^2, 2)); +energy_deform = (dist - dist_orig).^2; + +% (weighted) sum of the above +energy = mean(energy_eshift) + (deformweight * mean(energy_deform.^2)); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function [c, dist] = dist_to_surface(coord, surf) % (nonlinear) constraint function +% DIST_TO_SURFACE Compute distance to surface, this is the fastest way to run +% it, although running the loops in other directions might be more intuitive. + +c = []; +dist = zeros(size(coord, 1), 1); +for i0 = 1:size(coord, 1) + dist_one_elec = zeros(size(surf.pos, 1), 1); + for i1 = 1:size(surf.pos, 2) + dist_one_elec = dist_one_elec + (surf.pos(:, i1) - coord(i0, i1)) .^ 2; + end + dist(i0) = min(dist_one_elec); +end +dist = sqrt(dist); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function pairs = create_elecpairs(elec, method) + +if strcmp(method, 'label'); + + % determine grid dimensions (1st dim: number of arrays, 2nd dim: number of elecs in an array) + fprintf('creating electrode pairs based on electrode labels\n'); + GridDim = determine_griddim(elec); + + % create pairs based on dimensions + diagonal = 1; + pairs = []; + for e = 1:GridDim(1)*GridDim(2) + if isequal(mod(e,GridDim(2)), 1) % begin of each elec array + pairs(end+1,:) = [e e+1]; % following elec + pairs(end+1,:) = [e e-GridDim(2)]; % adjacent preceding elec + pairs(end+1,:) = [e e+GridDim(2)]; % adjacent following elec + if diagonal + pairs(end+1,:) = [e e-GridDim(2)+1]; % adjacent preceding elec + pairs(end+1,:) = [e e+GridDim(2)+1]; % adjacent following elec + end + elseif isequal(mod(e,GridDim(2)), 0) % end of each elec array + pairs(end+1,:) = [e e-1]; % preceding elec + pairs(end+1,:) = [e e-GridDim(2)]; % adjacent preceding elec + pairs(end+1,:) = [e e+GridDim(2)]; % adjacent following elec + if diagonal + pairs(end+1,:) = [e e-GridDim(2)-1]; % adjacent preceding elec + pairs(end+1,:) = [e e+GridDim(2)-1]; % adjacent following elec + end + else + pairs(end+1,:) = [e e-1]; % preceding elec + pairs(end+1,:) = [e e+1]; % following elec + pairs(end+1,:) = [e e-GridDim(2)]; % adjacent preceding elec + pairs(end+1,:) = [e e+GridDim(2)]; % adjacent following elec + if diagonal + pairs(end+1,:) = [e e-GridDim(2)-1]; % adjacent preceding elec + pairs(end+1,:) = [e e+GridDim(2)-1]; % adjacent following elec + pairs(end+1,:) = [e e-GridDim(2)+1]; % adjacent preceding elec + pairs(end+1,:) = [e e+GridDim(2)+1]; % adjacent following elec + end + end + end + pairs( pairs(:,2)<1 | pairs(:,2)>GridDim(1)*GridDim(2) ,:) = []; % out of bounds + pairs = unique(sort(pairs,2),'rows'); % unique pairs + +elseif strcmp(method, 'pos'); + + % KNN_PAIRS compute pairs of neighbors of the grid + fprintf('creating electrode pairs based on electrode positions\n'); + pairs = knn_pairs(elec.elecpos, 4); + +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function GridDim = determine_griddim(elec) +% assumes intact grids/strips and elec count starting at 1 +% A. Stolk, 2017 + +% extract numbers from elec labels +digits = regexp(elec.label, '\d+', 'match'); +for l=1:numel(digits) + labels{l,1} = digits{l}{1}; % use first found digit +end + +% determine grid dimensions (1st dim: number of arrays, 2nd dim: number of elecs in an array) +if isequal(numel(labels), 256) + GridDim(1) = 16; GridDim(2) = 16; +elseif isequal(numel(labels), 64) + GridDim(1) = 8; GridDim(2) = 8; +elseif isequal(numel(labels), 48) + e6 = elec.elecpos(match_str(labels, num2str(6)),:); + e7 = elec.elecpos(match_str(labels, num2str(7)),:); + e8 = elec.elecpos(match_str(labels, num2str(8)),:); + e9 = elec.elecpos(match_str(labels, num2str(9)),:); + d6to7 = sqrt(sum((e6-e7).^2)); % distance of elec 6 to 7 + d8to9 = sqrt(sum((e8-e9).^2)); % distance of elec 8 to 9 + if d8to9 >= d6to7 % break between e8 and e9 + GridDim(1) = 6; GridDim(2) = 8; + elseif d6to7 > d8to9 % break between e6 and e7 + GridDim(1) = 8; GridDim(2) = 6; + end +elseif isequal(numel(labels), 32) + e4 = elec.elecpos(match_str(labels, num2str(4)),:); + e5 = elec.elecpos(match_str(labels, num2str(5)),:); + e8 = elec.elecpos(match_str(labels, num2str(8)),:); + e9 = elec.elecpos(match_str(labels, num2str(9)),:); + d4to5 = sqrt(sum((e4-e5).^2)); % distance of elec 4 to 5 + d8to9 = sqrt(sum((e8-e9).^2)); % distance of elec 8 to 9 + if d8to9 >= d4to5 % break between e8 and e9 + GridDim(1) = 4; GridDim(2) = 8; + elseif d4to5 > d8to9 % break between e4 and e5 + GridDim(1) = 8; GridDim(2) = 4; + end +elseif isequal(numel(labels), 24) + e4 = elec.elecpos(match_str(labels, num2str(4)),:); + e5 = elec.elecpos(match_str(labels, num2str(5)),:); + e6 = elec.elecpos(match_str(labels, num2str(6)),:); + e7 = elec.elecpos(match_str(labels, num2str(7)),:); + d4to5 = sqrt(sum((e4-e5).^2)); % distance of elec 4 to 5 + d6to7 = sqrt(sum((e6-e7).^2)); % distance of elec 6 to 7 + if d6to7 >= d4to5 % break between e6 and e7 + GridDim(1) = 4; GridDim(2) = 6; + elseif d4to5 > d6to7 % break between e4 and e5 + GridDim(1) = 6; GridDim(2) = 4; + end +elseif isequal(numel(labels), 20) + e4 = elec.elecpos(match_str(labels, num2str(4)),:); + e5 = elec.elecpos(match_str(labels, num2str(5)),:); + e6 = elec.elecpos(match_str(labels, num2str(6)),:); + d4to5 = sqrt(sum((e4-e5).^2)); % distance of elec 4 to 5 + d5to6 = sqrt(sum((e5-e6).^2)); % distance of elec 5 to 6 + if d5to6 >= d4to5 % break between e5 and e6 + GridDim(1) = 4; GridDim(2) = 5; + elseif d4to5 > d5to6 % break between e4 and e5 + GridDim(1) = 5; GridDim(2) = 4; + end +elseif isequal(numel(labels), 16) + e4 = elec.elecpos(match_str(labels, num2str(4)),:); + e5 = elec.elecpos(match_str(labels, num2str(5)),:); + e8 = elec.elecpos(match_str(labels, num2str(8)),:); + e9 = elec.elecpos(match_str(labels, num2str(9)),:); + d4to5 = sqrt(sum((e4-e5).^2)); % distance of elec 4 to 5 + d8to9 = sqrt(sum((e8-e9).^2)); % distance of elec 8 to 9 + d4to8 = sqrt(sum((e4-e8).^2)); % distance of elec 4 to 8 + if d8to9 > 2*d4to5 % break between e8 and e9 + GridDim(1) = 2; GridDim(2) = 8; + elseif d4to5 > 2*d4to8 % break between e4 and e5 + GridDim(1) = 4; GridDim(2) = 4; + else + GridDim(1) = 1; GridDim(2) = 16; + end +elseif isequal(numel(labels), 12) + e4 = elec.elecpos(match_str(labels, num2str(4)),:); + e5 = elec.elecpos(match_str(labels, num2str(5)),:); + e6 = elec.elecpos(match_str(labels, num2str(6)),:); + e7 = elec.elecpos(match_str(labels, num2str(7)),:); + d4to5 = sqrt(sum((e4-e5).^2)); % distance of elec 4 to 5 + d5to6 = sqrt(sum((e5-e6).^2)); % distance of elec 5 to 6 + d6to7 = sqrt(sum((e6-e7).^2)); % distance of elec 6 to 7 + if d4to5 > 2*d5to6 % break between e4 and e5 + GridDim(1) = 3; GridDim(2) = 4; % 4x3 unsuppported + elseif d6to7 > 2*d5to6 % break between e6 and e7 + GridDim(1) = 2; GridDim(2) = 6; + else + GridDim(1) = 1; GridDim(2) = 12; + end +elseif isequal(numel(labels), 8) + e3 = elec.elecpos(match_str(labels, num2str(3)),:); + e4 = elec.elecpos(match_str(labels, num2str(4)),:); + e5 = elec.elecpos(match_str(labels, num2str(5)),:); + d3to4 = sqrt(sum((e3-e4).^2)); % distance of elec 3 to 4 + d4to5 = sqrt(sum((e4-e5).^2)); % distance of elec 4 to 5 + if d4to5 > 2*d3to4 % break between e4 and e5 + GridDim(1) = 2; GridDim(2) = 4; + else + GridDim(1) = 1; GridDim(2) = 8; + end +else + GridDim(1) = 1; GridDim(2) = numel(labels); +end + +% provide feedback of what grid dimensions were found +if any(GridDim==1) % if not because of strips, this could happen in case of missing electrodes + warning('assuming %d x %d grid dimensions: if incorrect, use cfg.pairmethod = ''pos'' instead\n', GridDim(1), GridDim(2)); +else + fprintf('assuming %d x %d grid dimensions\n', GridDim(1), GridDim(2)); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function pairs = knn_pairs(coord, k) +% KNN_PAIRS compute pairs of neighbors of the grid + +knn_ind = knn_search(coord, coord, k); +pairs = cat(3, knn_ind, repmat([1:size(coord,1)]',1,k)); +pairs = permute(pairs,[3 1 2]); +pairs = sort(reshape(pairs,2,[]),1)'; +pairs = unique(pairs,'rows'); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function idx = knn_search(Q, R, K) +%KNN_SEARCH perform search using k-Nearest Neighbors algorithm + +[N, M] = size(Q); +L = size(R, 1); +idx = zeros(N, K); +D = idx; + +for k = 1:N + d = zeros(L, 1); + for t = 1:M + d = d + (R(:, t) - Q(k, t)) .^ 2; + end + d(k) = inf; + [s, t] = sort(d); + idx(k, :) = t(1:K); + D(k, :)= s(1:K); +end diff --git a/external/fieldtrip/private/wizard_base.m b/external/fieldtrip/private/wizard_base.m index 78e7266b..c8cacc2c 100644 --- a/external/fieldtrip/private/wizard_base.m +++ b/external/fieldtrip/private/wizard_base.m @@ -1,4 +1,4 @@ -function h = wizard_gui(filename) +function h = wizard_base(filename) % This is the low level wizard function. It evaluates the MATLAB content % in the workspace of the calling function. To prevent overwriting diff --git a/external/fieldtrip/private/write_neuralynx_nse.m b/external/fieldtrip/private/write_neuralynx_nse.m index b8975177..aca0274f 100644 --- a/external/fieldtrip/private/write_neuralynx_nse.m +++ b/external/fieldtrip/private/write_neuralynx_nse.m @@ -29,7 +29,7 @@ function write_neuralynx_nse(filename, nse) % $Id$ if ~isa(nse.TimeStamp, 'uint64') - error('timestamps should be uint64'); + ft_error('timestamps should be uint64'); end % convert the data from uV into V @@ -62,7 +62,7 @@ function write_neuralynx_nse(filename, nse) case 'double' buf = [buf sprintf('-%s\t%g\r\n', f{i}, v)]; otherwise - error('unknown class in writing header'); + ft_error('unknown class in writing header'); end end diff --git a/external/fieldtrip/spass2fieldtrip.m b/external/fieldtrip/spass2fieldtrip.m index c0116d7b..9e2d6088 100644 --- a/external/fieldtrip/spass2fieldtrip.m +++ b/external/fieldtrip/spass2fieldtrip.m @@ -26,7 +26,7 @@ % 'jeb012a02/jeb012a02.stm' % 'jeb012a02/jeb012a02.bhv' % -% Subsequently you can analyze the data in fieldtrip, or write the spike +% Subsequently you can analyze the data in FieldTrip, or write the spike % waveforms to a nex file for offline sorting using % ft_write_spike('jeb012a02_ch1.nex', spike, 'dataformat', 'plexon_nex', 'chanindx', 1) % ft_write_spike('jeb012a02_ch2.nex', spike, 'dataformat', 'plexon_nex', 'chanindx', 2) @@ -57,11 +57,11 @@ stmfile = fullfile(dirname, [dirname '.stm']); bhvfile = fullfile(dirname, [dirname '.bhv']); -if ~exist(anafile, 'file'), error(sprintf('the file "%s" does not exist', anafile)); end -if ~exist(swafile, 'file'), error(sprintf('the file "%s" does not exist', swafile)); end -if ~exist(spifile, 'file'), error(sprintf('the file "%s" does not exist', spifile)); end -if ~exist(stmfile, 'file'), error(sprintf('the file "%s" does not exist', stmfile)); end -if ~exist(bhvfile, 'file'), error(sprintf('the file "%s" does not exist', bhvfile)); end +if ~exist(anafile, 'file'), ft_error('the file "%s" does not exist', anafile); end +if ~exist(swafile, 'file'), ft_error('the file "%s" does not exist', swafile); end +if ~exist(spifile, 'file'), ft_error('the file "%s" does not exist', spifile); end +if ~exist(stmfile, 'file'), ft_error('the file "%s" does not exist', stmfile); end +if ~exist(bhvfile, 'file'), ft_error('the file "%s" does not exist', bhvfile); end % read the data fprintf('reading %s\n', anafile); ana = read_labview_dtlg(anafile, 'int16'); @@ -125,7 +125,7 @@ end end -% convert the spike timestamps and waveforms to a fieldtrip-compatible format +% convert the spike timestamps and waveforms to a FieldTrip-compatible format for i=1:nchans spike.waveform{i} = cell2mat(swa.data(i,:)); spike.timestamp{i} = cell2mat(spi.data(i,:)')'; diff --git a/external/fieldtrip/specest/ft_specest_hilbert.m b/external/fieldtrip/specest/ft_specest_hilbert.m index 1f750eb2..08a33f92 100644 --- a/external/fieldtrip/specest/ft_specest_hilbert.m +++ b/external/fieldtrip/specest/ft_specest_hilbert.m @@ -50,16 +50,16 @@ freqoi = ft_getopt(varargin, 'freqoi'); timeoi = ft_getopt(varargin, 'timeoi', 'all'); width = ft_getopt(varargin, 'width', 1); -filttype = ft_getopt(varargin, 'filttype'); if isempty(filttype), error('you need to specify filter type'), end -filtorder = ft_getopt(varargin, 'filtorder'); if isempty(filtorder), error('you need to specify filter order'), end -filtdir = ft_getopt(varargin, 'filtdir'); if isempty(filtdir), error('you need to specify filter direction'), end +filttype = ft_getopt(varargin, 'filttype'); if isempty(filttype), ft_error('you need to specify filter type'), end +filtorder = ft_getopt(varargin, 'filtorder'); if isempty(filtorder), ft_error('you need to specify filter order'), end +filtdir = ft_getopt(varargin, 'filtdir'); if isempty(filtdir), ft_error('you need to specify filter direction'), end pad = ft_getopt(varargin, 'pad'); padtype = ft_getopt(varargin, 'padtype', 'zero'); polyorder = ft_getopt(varargin, 'polyorder', 0); fbopt = ft_getopt(varargin, 'feedback'); verbose = ft_getopt(varargin, 'verbose', true); -if isempty(fbopt), +if isempty(fbopt) fbopt.i = 1; fbopt.n = 1; end @@ -68,8 +68,7 @@ [nchan,ndatsample] = size(dat); % This does not work on integer data -typ = class(dat); -if ~strcmp(typ, 'double') && ~strcmp(typ, 'single') +if ~isa(dat, 'double') && ~isa(dat, 'single') dat = cast(dat, 'double'); end @@ -84,7 +83,7 @@ % Zero padding if round(pad * fsample) < ndatsample - error('the padding that you specified is shorter than the data'); + ft_error('the padding that you specified is shorter than the data'); end if isempty(pad) % if no padding is specified padding is equal to current data length pad = dattime; @@ -94,7 +93,7 @@ % set a default sampling for the frequencies-of-interest -if isempty(freqoi), +if isempty(freqoi) freqoi = linspace(2*width, (fsample/3), 50); end % check for freqoi = 0 and remove it @@ -148,7 +147,7 @@ filtfreq(end+1,:) = tmpfreq; else invalidind = [invalidind ifreqoi]; - warning(sprintf('frequency %.2f Hz cannot be estimated with resolution %.2f Hz', freqoi(ifreqoi), width(ifreqoi))); + ft_warning(sprintf('frequency %.2f Hz cannot be estimated with resolution %.2f Hz', freqoi(ifreqoi), width(ifreqoi))); end end diff --git a/external/fieldtrip/specest/ft_specest_mtmconvol.m b/external/fieldtrip/specest/ft_specest_mtmconvol.m index 5135b9c1..30a19f8b 100644 --- a/external/fieldtrip/specest/ft_specest_mtmconvol.m +++ b/external/fieldtrip/specest/ft_specest_mtmconvol.m @@ -73,20 +73,19 @@ % throw errors for required input if isempty(tapsmofrq) && strcmp(taper, 'dpss') - error('you need to specify tapsmofrq when using dpss tapers') + ft_error('you need to specify tapsmofrq when using dpss tapers') end if isempty(timwin) - error('you need to specify timwin') + ft_error('you need to specify timwin') elseif (length(timwin) ~= length(freqoi) && ~strcmp(freqoi,'all')) - error('timwin should be of equal length as freqoi') + ft_error('timwin should be of equal length as freqoi') end % Set n's -[nchan,ndatsample] = size(dat); +[nchan, ndatsample] = size(dat); % This does not work on integer data -typ = class(dat); -if ~strcmp(typ, 'double') && ~strcmp(typ, 'single') +if ~isa(dat, 'double') && ~isa(dat, 'single') dat = cast(dat, 'double'); end @@ -101,7 +100,7 @@ % Zero padding if round(pad * fsample) < ndatsample - error('the padding that you specified is shorter than the data'); + ft_error('the padding that you specified is shorter than the data'); end if isempty(pad) % if no padding is specified padding is equal to current data length pad = dattime; @@ -199,7 +198,7 @@ % give error/warning about number of tapers if isempty(tap) - error('%.3f Hz: datalength to short for specified smoothing\ndatalength: %.3f s, smoothing: %.3f Hz, minimum smoothing: %.3f Hz',freqoi(ifreqoi), timwinsample(ifreqoi)/fsample,tapsmofrq(ifreqoi),fsample/timwinsample(ifreqoi)); + ft_error('%.3f Hz: datalength to short for specified smoothing\ndatalength: %.3f s, smoothing: %.3f Hz, minimum smoothing: %.3f Hz',freqoi(ifreqoi), timwinsample(ifreqoi)/fsample,tapsmofrq(ifreqoi),fsample/timwinsample(ifreqoi)); elseif size(tap,1) == 1 disp([num2str(freqoi(ifreqoi)) ' Hz: WARNING: using only one taper for specified smoothing']) end @@ -269,7 +268,7 @@ % else % line([ceil(tline) ceil(tline)],[-max(abs(wavelet)) max(abs(wavelet))],'color','g','linestyle','--'); % line([floor(tline) floor(tline)],[-max(abs(wavelet)) max(abs(wavelet))],'color','g','linestyle','--'); - % end; + % end % subplot(2,1,2); % plot(angle(wavelet),'color','g'); % if mod(tline,2)==0, diff --git a/external/fieldtrip/specest/ft_specest_mtmfft.m b/external/fieldtrip/specest/ft_specest_mtmfft.m index 457e0058..be0fdede 100644 --- a/external/fieldtrip/specest/ft_specest_mtmfft.m +++ b/external/fieldtrip/specest/ft_specest_mtmfft.m @@ -49,7 +49,7 @@ persistent previous_argin previous_tap % get the optional input arguments -taper = ft_getopt(varargin, 'taper'); if isempty(taper), error('You must specify a taper'); end +taper = ft_getopt(varargin, 'taper'); if isempty(taper), ft_error('You must specify a taper'); end pad = ft_getopt(varargin, 'pad'); padtype = ft_getopt(varargin, 'padtype', 'zero'); freqoi = ft_getopt(varargin, 'freqoi', 'all'); @@ -60,14 +60,14 @@ polyorder = ft_getopt(varargin, 'polyorder', 0); tapopt = ft_getopt(varargin, 'taperopt'); -if isempty(fbopt), +if isempty(fbopt) fbopt.i = 1; fbopt.n = 1; end % throw errors for required input -if isempty(tapsmofrq) && strcmp(taper, 'dpss') - error('you need to specify tapsmofrq when using dpss tapers') +if isempty(tapsmofrq) && (strcmp(taper, 'dpss') || strcmp(taper, 'sine')) + ft_error('you need to specify tapsmofrq when using dpss or sine tapers') end % this does not work on integer data @@ -77,8 +77,7 @@ [nchan,ndatsample] = size(dat); % This does not work on integer data -typ = class(dat); -if ~strcmp(typ, 'double') && ~strcmp(typ, 'single') +if ~isa(dat, 'double') && ~isa(dat, 'single') dat = cast(dat, 'double'); end @@ -93,7 +92,7 @@ % Zero padding if round(pad * fsample) < ndatsample - error('the padding that you specified is shorter than the data'); + ft_error('the padding that you specified is shorter than the data'); end if isempty(pad) % if no padding is specified padding is equal to current data length pad = dattime; @@ -115,8 +114,8 @@ end nfreqboi = length(freqboi); nfreqoi = length(freqoi); -if strcmp(taper, 'dpss') && numel(tapsmofrq)~=1 && (numel(tapsmofrq)~=nfreqoi) - error('tapsmofrq needs to contain a smoothing parameter for every frequency when requesting variable number of slepian tapers') +if (strcmp(taper, 'dpss') || strcmp(taper, 'sine')) && numel(tapsmofrq)~=1 && (numel(tapsmofrq)~=nfreqoi) + ft_error('tapsmofrq needs to contain a smoothing parameter for every frequency when requesting variable number of slepian tapers') end % throw a warning if input freqoi is different from output freqoi @@ -154,7 +153,7 @@ % give error/warning about number of tapers if isempty(tap) - error('datalength to short for specified smoothing\ndatalength: %.3f s, smoothing: %.3f Hz, minimum smoothing: %.3f Hz',ndatsample/fsample,tapsmofrq,fsample/ndatsample); + ft_error('datalength to short for specified smoothing\ndatalength: %.3f s, smoothing: %.3f Hz, minimum smoothing: %.3f Hz',ndatsample/fsample,tapsmofrq,fsample/ndatsample); elseif size(tap,1) == 1 ft_warning('using only one taper for specified smoothing'); end @@ -168,7 +167,7 @@ % give error/warning about number of tapers if isempty(currtap) - error('%.3f Hz: datalength to short for specified smoothing\ndatalength: %.3f s, smoothing: %.3f Hz, minimum smoothing: %.3f Hz',freqoi(ifreqoi), ndatsample/fsample,tapsmofrq(ifreqoi),fsample/ndatsample(ifreqoi)); + ft_error('%.3f Hz: datalength to short for specified smoothing\ndatalength: %.3f s, smoothing: %.3f Hz, minimum smoothing: %.3f Hz',freqoi(ifreqoi), ndatsample/fsample,tapsmofrq(ifreqoi),fsample/ndatsample(ifreqoi)); elseif size(currtap,1) == 1 disp([num2str(freqoi(ifreqoi)) ' Hz: WARNING: using only one taper for specified smoothing']) end @@ -177,8 +176,35 @@ end case 'sine' - tap = sine_taper(ndatsample, ndatsample*(tapsmofrq./fsample))'; - tap = tap(1:(end-1), :); % remove the last taper + if numel(tapsmofrq)==1 + % create a sequence of sine tapers, + tap = sine_taper(ndatsample, ndatsample*(tapsmofrq./fsample))'; + % remove the last taper + tap = tap(1:(end-1), :); + + % give error/warning about number of tapers + if isempty(tap) + ft_error('datalength to short for specified smoothing\ndatalength: %.3f s, smoothing: %.3f Hz, minimum smoothing: %.3f Hz',ndatsample/fsample,tapsmofrq,fsample/ndatsample); + elseif size(tap,1) == 1 + ft_warning('using only one taper for specified smoothing'); + end + elseif numel(tapsmofrq)>1 + tap = cell(1,nfreqoi); + for ifreqoi = 1:nfreqoi + % create a sequence of sine tapers + currtap = sine_taper(ndatsample, ndatsample .* (tapsmofrq(ifreqoi) ./ fsample))'; + % remove the last taper because the last slepian taper is always messy + currtap = currtap(1:(end-1), :); + + % give error/warning about number of tapers + if isempty(currtap) + ft_error('%.3f Hz: datalength to short for specified smoothing\ndatalength: %.3f s, smoothing: %.3f Hz, minimum smoothing: %.3f Hz',freqoi(ifreqoi), ndatsample/fsample,tapsmofrq(ifreqoi),fsample/ndatsample(ifreqoi)); + elseif size(currtap,1) == 1 + disp([num2str(freqoi(ifreqoi)) ' Hz: WARNING: using only one taper for specified smoothing']) + end + tap{ifreqoi} = currtap; + end + end case 'sine_old' % to provide compatibility with the tapers being scaled (which was default @@ -188,7 +214,7 @@ tap = tap(1:(end-1), :); % remove the last taper case 'alpha' - error('not yet implemented'); + ft_error('not yet implemented'); case 'hanning' tap = hanning(ndatsample)'; @@ -207,7 +233,7 @@ end % isequal currargin % set ntaper -if ~(strcmp(taper,'dpss') && numel(tapsmofrq)>1) % variable number of slepian tapers not requested +if ~((strcmp(taper,'dpss') || strcmp(taper,'sine')) && numel(tapsmofrq)>1) % variable number of slepian tapers not requested ntaper = repmat(size(tap,1),nfreqoi,1); else % variable number of slepian tapers requested ntaper = cellfun(@size,tap,repmat({1},[1 nfreqoi])); @@ -230,7 +256,7 @@ end % compute fft -if ~(strcmp(taper,'dpss') && numel(tapsmofrq)>1) % ariable number of slepian tapers not requested +if ~((strcmp(taper,'dpss') || strcmp(taper,'sine')) && numel(tapsmofrq)>1) % ariable number of slepian tapers not requested str = sprintf('nfft: %d samples, datalength: %d samples, %d tapers',endnsample,ndatsample,ntaper(1)); [st, cws] = dbstack; if length(st)>1 && strcmp(st(2).name, 'ft_freqanalysis') diff --git a/external/fieldtrip/specest/ft_specest_neuvar.m b/external/fieldtrip/specest/ft_specest_neuvar.m new file mode 100644 index 00000000..cf4e33ce --- /dev/null +++ b/external/fieldtrip/specest/ft_specest_neuvar.m @@ -0,0 +1,94 @@ +function [spectrum, freqoi] = ft_specest_neuvar(dat, time, varargin) + +% FT_SPECEST_NEUVAR computes a time-domain estimation of overall signal +% power, having compensated for the 1/f distribution of spectral content. +% +% Use as +% [spectrum,ntaper,freqoi] = ft_specest_neuvar(dat,time...) +% where +% dat = matrix of chan*sample +% time = vector, containing time in seconds for each sample +% neuvar = matrix of chan*neuvar +% +% Optional arguments should be specified in key-value pairs and can include +% order = number, the order of differentation for compensating for the 1/f (default: 1) +% pad = number, total length of data after zero padding (in seconds) +% padtype = string, indicating type of padding to be used (see ft_preproc_padding, default: 0) +% verbose = output progress to console (0 or 1, default 1) +% +% See also FT_FREQANALYSIS, FT_SPECEST_MTMFFT, FT_SPECEST_MTMCONVOL, FT_SPECEST_TFR, FT_SPECEST_HILBERT, FT_SPECEST_WAVELET + +% Copyright (C) 2016, Arjen Stolk +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + + +% get the optional input arguments +order = ft_getopt(varargin, 'order', 1); +pad = ft_getopt(varargin, 'pad'); +padtype = ft_getopt(varargin, 'padtype', 'zero'); +fbopt = ft_getopt(varargin, 'feedback'); +verbose = ft_getopt(varargin, 'verbose', true); + +if isempty(fbopt) + fbopt.i = 1; + fbopt.n = 1; +end + +% this does not work on integer data +dat = cast(dat, 'double'); + +% Set n's +[nchan,ndatsample] = size(dat); + +% This does not work on integer data +if ~isa(dat, 'double') && ~isa(dat, 'single') + dat = cast(dat, 'double'); +end + +% Determine fsample and set total time-length of data +fsample = 1./mean(diff(time)); +dattime = ndatsample / fsample; % total time in seconds of input data + +% Zero padding +if round(pad * fsample) < ndatsample + ft_error('the padding that you specified is shorter than the data'); +end +if isempty(pad) % if no padding is specified padding is equal to current data length + pad = dattime; +end +postpad = ceil((pad - dattime) * fsample); +endnsample = round(pad * fsample); % total number of samples of padded data +endtime = pad; % total time in seconds of padded data + +% Filter throught a differentiatior to compensate for the 1/f +dat = ft_preproc_derivative(dat, order); + +% Calculate overall power using variance +str = sprintf('neuronal variance: %d samples, datalength: %d samples',endnsample,ndatsample); +[st, cws] = dbstack; +if length(st)>1 && strcmp(st(2).name, 'ft_freqanalysis') + % specest_mtmfft has been called by ft_freqanalysis, meaning that ft_progress has been initialised + ft_progress(fbopt.i./fbopt.n, ['processing trial %d/%d ',str,'\n'], fbopt.i, fbopt.n); +elseif verbose + fprintf([str, '\n']); +end +spectrum = var(ft_preproc_padding(dat, padtype, 0, postpad), [], 2)'; % freq X chan +spectrum = sqrt(spectrum); % take square root since cfg.output = 'pow' assumes the output is amplitude and squares it +freqoi = 0; % assign to DC frequency diff --git a/external/fieldtrip/specest/ft_specest_tfr.m b/external/fieldtrip/specest/ft_specest_tfr.m index a265f5b6..53fe9373 100644 --- a/external/fieldtrip/specest/ft_specest_tfr.m +++ b/external/fieldtrip/specest/ft_specest_tfr.m @@ -53,7 +53,7 @@ fbopt = ft_getopt(varargin, 'feedback'); verbose = ft_getopt(varargin, 'verbose', true); -if isempty(fbopt), +if isempty(fbopt) fbopt.i = 1; fbopt.n = 1; end @@ -62,8 +62,7 @@ [nchan,ndatsample] = size(dat); % This does not work on integer data -typ = class(dat); -if ~strcmp(typ, 'double') && ~strcmp(typ, 'single') +if ~isa(dat, 'double') && ~isa(dat, 'single') dat = cast(dat, 'double'); end @@ -78,7 +77,7 @@ % Zero padding if round(pad * fsample) < ndatsample - error('the padding that you specified is shorter than the data'); + ft_error('the padding that you specified is shorter than the data'); end if isempty(pad) % if no padding is specified padding is equal to current data length pad = dattime; @@ -189,7 +188,7 @@ % else % line([ceil(tline) ceil(tline)],[-max(abs(wavelet)) max(abs(wavelet))],'color','g','linestyle','--'); % line([floor(tline) floor(tline)],[-max(abs(wavelet)) max(abs(wavelet))],'color','g','linestyle','--'); - % end; + % end % subplot(2,1,2); % plot(angle(wavelet),'color','g'); % if mod(tline,2)==0, diff --git a/external/fieldtrip/specest/ft_specest_wavelet.m b/external/fieldtrip/specest/ft_specest_wavelet.m index f1c2dae7..355b46e4 100644 --- a/external/fieldtrip/specest/ft_specest_wavelet.m +++ b/external/fieldtrip/specest/ft_specest_wavelet.m @@ -56,7 +56,7 @@ fbopt = ft_getopt(varargin, 'feedback'); verbose = ft_getopt(varargin, 'verbose', true); -if isempty(fbopt), +if isempty(fbopt) fbopt.i = 1; fbopt.n = 1; end @@ -65,8 +65,7 @@ [nchan,ndatsample] = size(dat); % This does not work on integer data -typ = class(dat); -if ~strcmp(typ, 'double') && ~strcmp(typ, 'single') +if ~isa(dat, 'double') && ~isa(dat, 'single') dat = cast(dat, 'double'); end @@ -81,7 +80,7 @@ % Zero padding if round(pad * fsample) < ndatsample - error('the padding that you specified is shorter than the data'); + ft_error('the padding that you specified is shorter than the data'); end if isempty(pad) % if no padding is specified padding is equal to current data length pad = dattime; @@ -191,7 +190,7 @@ % else % line([ceil(tline) ceil(tline)],[-max(abs(wavelet)) max(abs(wavelet))],'color','g','linestyle','--'); % line([floor(tline) floor(tline)],[-max(abs(wavelet)) max(abs(wavelet))],'color','g','linestyle','--'); - % end; + % end % subplot(2,1,2); % plot(angle(wavelet),'color','g'); % if mod(tline,2)==0, diff --git a/external/fieldtrip/specest/private/defaultId.m b/external/fieldtrip/specest/private/defaultId.m new file mode 100644 index 00000000..f4e1ee99 --- /dev/null +++ b/external/fieldtrip/specest/private/defaultId.m @@ -0,0 +1,57 @@ +function id = defaultId + +% DEFAULTID returns a string that can serve as warning or error identifier, +% for example 'FieldTip:ft_read_header:line345'. +% +% See also WARNING, ERROR, FT_NOTICE, FT_INFO, FT_DEBUG + +% Copyright (C) 2017, Robert Oostenveld +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +stack = dbstack('-completenames'); + +% remove the functions that pertain to the notification system itself +keep = true(size(stack)); +keep(strcmp({stack.name}, 'defaultId')) = false; % this function itself +keep(strcmp({stack.name}, 'ft_notification')) = false; % this one is doing the work underneath ft_error/ft_warning/ft_notice/etc. +keep(strcmp({stack.name}, 'ft_error')) = false; +keep(strcmp({stack.name}, 'ft_warning')) = false; +keep(strcmp({stack.name}, 'ft_notice')) = false; +keep(strcmp({stack.name}, 'ft_info')) = false; +keep(strcmp({stack.name}, 'ft_debug')) = false; +stack = stack(keep); + +% remove the non-FieldTrip functions from the path, these should not be part of the default message identifier +keep = true(size(stack)); +[v, p] = ft_version; +for i=1:numel(stack) + keep(i) = strncmp(p, stack(i).file, length(p)); +end +stack = stack(keep); + +if ~isempty(stack) + % it is called from within a function + stack = flipud(stack); + name = {stack.name}; + id = ['FieldTrip' sprintf(':%s', name{:}) ':line' num2str(stack(end).line)]; +else + % it is called from the command line + id = 'FieldTrip:commandline'; +end diff --git a/external/fieldtrip/specest/private/filter_with_correction.m b/external/fieldtrip/specest/private/filter_with_correction.m index 0ade7fd1..72638aa0 100644 --- a/external/fieldtrip/specest/private/filter_with_correction.m +++ b/external/fieldtrip/specest/private/filter_with_correction.m @@ -9,11 +9,14 @@ % B,A filter coefficients % dat data matrix (Nchans X Ntime) % dir optional filter direction, can be -% 'onepass' forward filter only -% 'onepass-reverse' reverse filter only, i.e. backward in time -% 'twopass' zero-phase forward and reverse filter (default) -% 'twopass-reverse' zero-phase reverse and forward filter -% 'twopass-average' average of the twopass and the twopass-reverse +% 'onepass' forward filter only +% 'onepass-reverse' reverse filter only, i.e. backward in time +% 'twopass' zero-phase forward and reverse filter (default) +% 'twopass-reverse' zero-phase reverse and forward filter +% 'twopass-average' average of the twopass and the twopass-reverse +% 'onepass-zerophase' zero-phase forward filter with delay compensation (default for firws, linear-phase symmetric FIR only) +% 'onepass-reverse-zerophase' zero-phase reverse filter with delay compensation +% 'onepass-minphase' minimum-phase converted forward filter (non-linear!, firws only) % % Note that a one- or two-pass filter has consequences for the % strength of the filter, i.e. a two-pass filter with the same filter @@ -40,7 +43,7 @@ % $Id$ % convert the data to double precision -% see http://bugzilla.fcdonders.nl/show_bug.cgi?id=2653 +% see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2653 inputclass = class(dat); B = double(B); A = double(A); @@ -48,7 +51,7 @@ poles = roots(A); if any(abs(poles) >= 1) - error('Calculated filter coefficients have poles on or outside the unit circle and will not be stable. Try a higher cutoff frequency or a different type/order of filter.'); + ft_error('Calculated filter coefficients have poles on or outside the unit circle and will not be stable. Try a higher cutoff frequency or a different type/order of filter.'); end dcGain = sum(B)/sum(A); @@ -78,10 +81,15 @@ filt = (filt1 + filt2)/2; case 'onepass-zerophase' filt = fir_filterdcpadded(B, A, dat', 0, usefftfilt)'; + case 'onepass-reverse-zerophase' + offset = dat(:,end); + dat = fliplr(dat) - repmat(offset,1,N); + filt = fir_filterdcpadded(B, A, dat', 0, usefftfilt)'; + filt = fliplr(filt) + repmat(dcGain*offset, 1, N); case 'onepass-minphase' filt = fir_filterdcpadded(B, A, dat', 1, usefftfilt)'; otherwise - error('unsupported filter direction "%s"', dir); + ft_error('unsupported filter direction "%s"', dir); end % cast it back into the type of the input data, which can e.g. be single or int32 diff --git a/external/fieldtrip/specest/private/fixname.m b/external/fieldtrip/specest/private/fixname.m index 96a345ec..76fd5951 100644 --- a/external/fieldtrip/specest/private/fixname.m +++ b/external/fieldtrip/specest/private/fixname.m @@ -1,19 +1,20 @@ -function str = fixname(str) +function str = fixname(str, version) % FIXNAME changes all inappropriate characters in a sting into '_' -% such that it can be used as a filename or as a structure field name. If -% the string begins with a numeric digit, an 'x' is prepended. +% so that it can be used as a filename or as a field name in a structure. +% If the string begins with a digit, an 'x' is prepended. % % Use as % str = fixname(str) % % MATLAB 2014a introduces the matlab.lang.makeValidName and -% matlab.lang.makeUniqueStrings functions for constructing unique MATLAB identifiers, -% but this particular implementation also works with older MATLAB versions. +% matlab.lang.makeUniqueStrings functions for constructing unique +% identifiers, but this particular implementation also works with +% older MATLAB versions. % % See also DEBLANK -% Copyright (C) 2012-2016, Robert Oostenveld +% Copyright (C) 2012-2017, Robert Oostenveld % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -33,19 +34,48 @@ % % $Id$ -str = lower(str); -str(regexp(str,'\W')) = '_'; - -while(str(1) == '_'), str = str(2:end); end; % remove all underscore at the begin of the string -while(str(end) == '_'), str = str(1:end-1); end; % remove all underscore at the end of the string - -if int8(str(1))<58 && int8(str(1))>47 - % the string begins with a digit, prepend an 'x' - str = ['x' str]; +if nargin<2 + version = 'default'; end -% truncate the string if it's too long: MATLAB maximizes the string length to 63 characters (and throws a warning when truncating) -if numel(str)>63 - str = str(1:63); - ft_warning(sprintf('%s exceeds MATLAB''s maximum name length of 63 characters and has been truncated to %s', str, str(1:63))); +switch version + case 'default' + if isempty(str) + str='x'; + end + str = lower(str); + str(regexp(str,'\W')) = '_'; + while(str(1) == '_'), str = str(2:end); end % remove all underscore at the begin of the string + while(str(end) == '_'), str = str(1:end-1); end % remove all underscore at the end of the string + if int8(str(1))<58 && int8(str(1))>47 + % the string begins with a digit, prepend an 'x' + str = ['x' str]; + end + % truncate the string if it's too long: MATLAB maximizes the string length to 63 characters (and throws a warning when truncating) + if numel(str)>63 + str = str(1:63); + warning('%s exceeds MATLAB''s maximum name length of 63 characters and has been truncated to %s', str, str(1:63)); + end + + case '2014a' + str = matlab.lang.makeValidName(str); + + case 'X_base64encode_X' + % this uses some code from Mathworks file exchange + ft_hastoolbox('fileexchange', 1); + % the following is an encoding that can be reverted + str = strtrim(base64encode(str)); + str(str=='=') = '_'; % replace the '=' sign with '_' + str = ['X' str 'X']; % start and end with an 'X' + + case 'X_base64decode_X' + % this uses some code from Mathworks file exchange + ft_hastoolbox('fileexchange', 1); + % revert the encoding + str = str(2:end-1); % it starts and ends with 'X' + str(str=='_') = '='; % the '=' sign has been replaced with '_' + str = char(base64decode(str)); + + otherwise + error('unsupported version "%s"', version); end diff --git a/external/fieldtrip/specest/private/ft_getopt.m b/external/fieldtrip/specest/private/ft_getopt.m index 21ed892a..0d433115 100644 --- a/external/fieldtrip/specest/private/ft_getopt.m +++ b/external/fieldtrip/specest/private/ft_getopt.m @@ -8,19 +8,19 @@ % where the input values are % s = structure or cell-array % key = string -% default = any valid MATLAB data type +% default = any valid MATLAB data type (optional, default = []) % emptymeaningful = boolean value (optional, default = 0) % -% If the key is present as field in the structure, or as key-value -% pair in the cell-array, the corresponding value will be returned. +% If the key is present as field in the structure, or as key-value pair in the +% cell-array, the corresponding value will be returned. % -% If the key is not present, ft_getopt will return an empty array. +% If the key is not present, ft_getopt will return the default, or an empty array +% when no default was specified. % -% If the key is present but has an empty value, then the emptymeaningful -% flag specifies whether the empty value or the default value should -% be returned. If emptymeaningful==true, then an empty array will be -% returned. If emptymeaningful==false, then the specified default will -% be returned. +% If the key is present but has an empty value, then the emptymeaningful flag +% specifies whether the empty value or the default value should be returned. +% If emptymeaningful==true, then the empty array will be returned. +% If emptymeaningful==false, then the specified default will be returned. % % See also FT_SETOPT, FT_CHECKOPT @@ -60,27 +60,27 @@ else val = opt.(key); end - + elseif isa(opt, 'cell') % get the key-value from the cell-array if mod(length(opt),2) error('optional input arguments should come in key-value pairs, i.e. there should be an even number'); end - + % the 1st, 3rd, etc. contain the keys, the 2nd, 4th, etc. contain the values keys = opt(1:2:end); vals = opt(2:2:end); - + % the following may be faster than cellfun(@ischar, keys) valid = false(size(keys)); for i=1:numel(keys) valid(i) = ischar(keys{i}); end - + if ~all(valid) error('optional input arguments should come in key-value pairs, the optional input argument %d is invalid (should be a string)', i); end - + hit = find(strcmpi(key, keys)); if isempty(hit) % the requested key was not found @@ -91,7 +91,7 @@ else error('multiple input arguments with the same name'); end - + elseif isempty(opt) % no options are specified, return default val = default; diff --git a/external/fieldtrip/specest/private/ft_notification.m b/external/fieldtrip/specest/private/ft_notification.m new file mode 100644 index 00000000..dc9b7369 --- /dev/null +++ b/external/fieldtrip/specest/private/ft_notification.m @@ -0,0 +1,482 @@ +function [varargout] = ft_notification(varargin) + +% FT_NOTIFICATION works mostly like the WARNING and ERROR commands in MATLAB and +% is called by FT_ERROR, FT_WARNING, FT_NOTICE, FT_INFO, FT_DEBUG. Note that you +% should not call this function directly. +% +% Some examples: +% ft_info on +% ft_info on msgId +% ft_info off +% ft_info off msgId +% ft_info once +% ft_info once msgId +% ft_info on backtrace +% ft_info off backtrace +% ft_info on verbose +% ft_info off verbose +% +% ft_info query % shows the status of all notifications +% ft_info last % shows the last notification +% ft_info clear % clears the status of all notifications +% ft_info timeout 10 % sets the timeout (for 'once') to 10 seconds +% +% See also DEFAULTID + +% Copyright (C) 2012-2017, Robert Oostenveld, J?rn M. Horschig +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +global ft_default + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% determine who is calling + +stack = dbstack('-completenames'); +% st(1) is this function +% st(2) is the calling function +switch stack(2).name + case 'ft_debug' + level = 'debug'; + case 'ft_info' + level = 'info'; + case 'ft_notice' + level = 'notice'; + case 'ft_warning' + level = 'warning'; + case 'ft_error' + level = 'error'; + otherwise + error('this function cannot be called from %s', stack(2).name); +end + +% remove this function itself and the ft_xxx calling function +stack = stack(3:end); + +% remove the non-FieldTrip functions from the path, these should not be part of the default message identifier +keep = true(size(stack)); +p = fileparts(which('ft_defaults')); +for i=1:numel(stack) + keep(i) = strncmp(p, stack(i).file, length(p)); +end +stack = stack(keep); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% handle the defaults + +if isfield(ft_default, 'notification') && isfield(ft_default.notification, level) + % this would be error, warning, notice, info, debug + s = ft_default.notification.(level); +else + s = []; +end + +% start with an empty state structure +if isempty(s) + s = struct('identifier', {}, 'state', {}, 'timestamp', {}); +end + +% set the default notification state +if ~ismember('all', {s.identifier}) + s = setstate(s, 'all', 'on'); +end + +% set the default backtrace state +defaultbacktrace = false; +if ~ismember('backtrace', {s.identifier}) + switch level + case {'debug' 'info' 'notice'} + s = setstate(s, 'backtrace', 'off'); + case 'warning' + defaultbacktrace = true; + t = warning('query', 'backtrace'); % get the default state + s = setstate(s, 'backtrace', t.state); + case 'error' + s = setstate(s, 'backtrace', 'on'); + end % switch +end + +% set the default verbose state +defaultverbose = false; +if ~ismember('verbose', {s.identifier}) + switch level + case 'warning' + defaultverbose = true; + t = warning('query', 'verbose');% get the default state + s = setstate(s, 'verbose', t.state); + otherwise + s = setstate(s, 'verbose', 'off'); + end +end + +% set the default timeout +if ~ismember('timeout', {s.identifier}) + s = setstate(s, 'timeout', 60); +end + +% set the last notification to empty +if ~ismember('last', {s.identifier}) + state.message = ''; + state.identifier = ''; + state.stack = struct('file', {}, 'name', {}, 'line', {}); + s = setstate(s, 'last', state); +end + +if strcmp(level, 'warning') + ws = warning; + % warnings should be on in general + warning on + % the backtrace is handled by this function + warning off backtrace + % the verbose message is handled by this function + warning off verbose +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% set the notification state according to the input + +if numel(varargin)>0 && (isstruct(varargin{1}) || isempty(varargin{1})) + ft_default.notification.(level) = varargin{1}; + return +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% act according to the first input argument + +if isempty(varargin) + varargin{1} = 'query'; +end + +switch varargin{1} + case 'on' + if numel(varargin)>1 + % switch a specific item on + msgId = varargin{2}; + s = setstate(s, msgId, 'on'); + if strcmp(msgId, 'backtrace') + defaultbacktrace = false; + end + if strcmp(msgId, 'verbose') + defaultverbose = false; + end + % return the message state of all + varargout{1} = getreturnstate(s, msgId); + else + % switch all on + s = setstate(s, 'all', 'on'); + % return the message state of all + varargout{1} = getreturnstate(s); + end + + case 'off' + if numel(varargin)>1 + % switch a specific item off + msgId = varargin{2}; + s = setstate(s, msgId, 'off'); + if strcmp(msgId, 'backtrace') + defaultbacktrace = false; + end + if strcmp(msgId, 'verbose') + defaultverbose = false; + end + % return the specific message state + varargout{1} = getreturnstate(s, msgId); + else + % switch all off + s = setstate(s, 'all', 'off'); + % return the message state of all + varargout{1} = getreturnstate(s); + end + + case 'once' + if numel(varargin)>1 + % switch a specific item to once + msgId = varargin{2}; + s = setstate(s, msgId, 'once'); + % return the specific message state + varargout{1} = getreturnstate(s, msgId); + else + % switch all to once + s = setstate(s, 'all', 'once'); + % return the message state of all + varargout{1} = getreturnstate(s); + end + + case 'timeout' + % set the timeout, this is used for 'once' + if ischar(varargin{2}) + s = setstate(s, 'timeout', str2double(varargin{2})); + else + s = setstate(s, 'timeout', varargin{2}); + end + + case {'last' '-last'} + % return the last notification + varargout{1} = getstate(s, 'last'); + + case {'clear' '-clear'} + % reset the notification system + s = []; + + case {'query' '-query'} + if numel(varargin)>1 + % select a specific item + msgId = varargin{2}; + if ~ismember(msgId, {s.identifier}) + error('Unknown setting or incorrect message identifier ''%s''.', msgId); + end + msgState = getstate(s, msgId); + if nargout + varargout{1} = getreturnstate(s, msgId); + elseif strcmp(msgId, 'verbose') + if istrue(msgState) + fprintf('%s output is verbose.\n', level); + else + fprintf('%s output is terse.\n', level); + end + elseif strcmp(msgId, 'backtrace') + if istrue(msgState) + fprintf('%s backtraces are enabled.\n', level); + else + fprintf('%s backtraces are disabled.\n', level); + end + else + fprintf('The state of %s ''%s'' is ''%s''\n', level, msgId, msgState); + end + else + % return all items + r = getreturnstate(s); + + if nargout + % return the state of all items + varargout{1} = r; + else + % show the state of all items that are different from the default + default = getstate(s, 'all'); + fprintf('The default %s state is ''%s''.', level, default); + r = r(~strcmp({r.state}, default)); + % don't show these + r(strcmp('verbose', {r.identifier})) = []; + r(strcmp('backtrace', {r.identifier})) = []; + if ~isempty(r) + fprintf(' Items not set to the default are\n\n'); + end + for i=1:numel(r) + fprintf(' %4s %s\n', r(i).state, r(i).identifier); + end + fprintf('\n'); + end + end + + otherwise + + if nargout + varargout{1} = getreturnstate(s); + end + + % first input might be msgId + if numel(varargin)>1 && ~isempty(regexp(varargin{1}, '^\w*:', 'once')) + msgId = varargin{1}; + varargin = varargin(2:end); % shift them all by one + else + msgId = defaultId; + end + + % get the state for this notification, it will default to the 'all' state + msgState = getstate(s, msgId); + + % errors are always to be printed + if strcmp(level, 'error') + msgState = 'on'; + end + + if strcmp(msgState, 'once') + timeout = getstate(s, 'timeout'); + since = elapsed(gettimestamp(s, msgId)); + if (since>timeout) + % the timeout has passed, update the timestamp and print the message + s = settimestamp(s, msgId, tic); + msgState = 'on'; + else + % the timeout has not yet passed, do not print the message + msgState = 'off'; + end + end + + % use an automatically generated default identifier + if isempty(msgId) + msgId = defaultId; + end + + % store the last notification + state.message = strtrim(sprintf(varargin{:})); % remove the trailing newline + state.identifier = msgId; + state.stack = stack; + s = setstate(s, 'last', state); + + if strcmp(msgState, 'on') + + if strcmp(level, 'error') + % update the global variable, we won't return here after the error + ft_default.notification.(level) = s; + % the remainder is fully handled by the ERROR function + if ~isempty(msgId) + error(msgId, varargin{:}); + else + error(varargin{:}); + end + + elseif strcmp(level, 'warning') + if ~isempty(msgId) + warning(msgId, varargin{:}); + else + warning(varargin{:}); + end + + else + % ensure there is a line end + if isempty(regexp(varargin{1}, '\\n$', 'once')) % note the double \\ + varargin{1} = [varargin{1} '\n']; + end + fprintf(varargin{:}); + + end % if level=error, warning or otherwise + + % decide whether the stack trace should be shown + if istrue(getstate(s, 'backtrace')) + for i=1:numel(stack) + % show the deepest and lowest-level function first + [p, f, x] = fileparts(stack(i).file); + if isequal(f, stack(i).name) + funname = stack(i).name; + else + funname = sprintf('%s>%s', f, stack(i).name); + end + filename = stack(i).file; + if isempty(fileparts(filename)) + % it requires the full path + filename = fullfile(pwd, filename); + end + if ft_platform_supports('html') + fprintf(' In %s at line %d\n', filename, stack(i).line, funname, stack(i).line); + else + fprintf(' In ''%s'' at line %d\n', filename, stack(i).line); + end + end + fprintf('\n'); + end + + % decide whether a verboe message should be shown + if istrue(getstate(s, 'verbose')) + if ~isempty(msgId) + fprintf('Type "ft_%s off %s" to suppress this message.\n', level, msgId) + else + fprintf('Type "ft_%s off" to suppress this message.\n', level) + end + end + + end % if msgState is on + +end % switch varargin{1} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% update the global variable +if defaultbacktrace && ~isempty(s) + % do not keep the default, it will be determined again on the next call + s = s(~strcmp({s.identifier}, 'backtrace')); +end +if defaultverbose && ~isempty(s) + % do not keep the default, it will be determined again on the next call + s = s(~strcmp({s.identifier}, 'verbose')); +end +ft_default.notification.(level) = s; + +if strcmp(level, 'warning') + % return to the original warning state + warning(ws); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTIONS +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +function r = getreturnstate(s, msgId) +if nargin<2 + r = s; + % don't return these + r(strcmp('timeout', {r.identifier})) = []; + r(strcmp('last', {r.identifier})) = []; + % don't return the timestamps + r = rmfield(r, 'timestamp'); +else + msgState = getstate(s, msgId); + r = struct('identifier', msgId, 'state', msgState); +end + +function state = getstate(s, msgId) +identifier = {s.identifier}; +sel = find(strcmp(identifier, msgId)); +if numel(sel)==1 + state = s(sel).state; + if isempty(state) + state = getstate(s, 'all'); + end +else + state = getstate(s, 'all'); +end + +function timestamp = gettimestamp(s, msgId) +identifier = {s.identifier}; +sel = find(strcmp(identifier, msgId)); +if numel(sel)==1 + timestamp = s(sel).timestamp; +else + timestamp = nan; +end + +function s = setstate(s, msgId, state) +if isempty(msgId), return; end % this happens from the command line +identifier = {s.identifier}; +sel = find(strcmp(identifier, msgId)); +if numel(sel)==1 + s(sel).state = state; +else + s(end+1).identifier = msgId; + s(end ).state = state; + s(end ).timestamp = nan; +end + +function s = settimestamp(s, msgId, timestamp) +if isempty(msgId), return; end % this happens from the command line +identifier = {s.identifier}; +sel = find(strcmp(identifier, msgId)); +if numel(sel)==1 + s(sel).timestamp = timestamp; +else + s(end+1).identifier = msgId; + s(end ).state = []; + s(end ).timestamp = timestamp; +end + +function t = elapsed(start) +if isempty(start) || isnan(start) + t = inf; +else + t = toc(start); +end diff --git a/external/fieldtrip/specest/private/ft_platform_supports.m b/external/fieldtrip/specest/private/ft_platform_supports.m new file mode 100644 index 00000000..c0676b62 --- /dev/null +++ b/external/fieldtrip/specest/private/ft_platform_supports.m @@ -0,0 +1,336 @@ +function tf = ft_platform_supports(what,varargin) + +% FT_PLATFORM_SUPPORTS returns a boolean indicating whether the current platform +% supports a specific capability +% +% Use as +% status = ft_platform_supports(what) +% or +% status = ft_platform_supports('matlabversion', min_version, max_version) +% +% The following values are allowed for the 'what' parameter, which means means that +% the specific feature explained on the right is supported: +% +% 'which-all' which(...,'all') +% 'exists-in-private-directory' exists(...) will look in the /private subdirectory to see if a file exists +% 'onCleanup' onCleanup(...) +% 'alim' alim(...) +% 'int32_logical_operations' bitand(a,b) with a, b of type int32 +% 'graphics_objects' graphics sysem is object-oriented +% 'libmx_c_interface' libmx is supported through mex in the C-language (recent MATLAB versions only support C++) +% 'images' all image processing functions in FieldTrip's external/images directory +% 'signal' all signal processing functions in FieldTrip's external/signal directory +% 'stats' all statistical functions in FieldTrip's external/stats directory +% 'program_invocation_name' program_invocation_name() (GNU Octave) +% 'singleCompThread' start MATLAB with -singleCompThread +% 'nosplash' start MATLAB with -nosplash +% 'nodisplay' start MATLAB with -nodisplay +% 'nojvm' start MATLAB with -nojvm +% 'no-gui' start GNU Octave with --no-gui +% 'RandStream.setGlobalStream' RandStream.setGlobalStream(...) +% 'RandStream.setDefaultStream' RandStream.setDefaultStream(...) +% 'rng' rng(...) +% 'rand-state' rand('state') +% 'urlread-timeout' urlread(..., 'Timeout', t) +% 'griddata-vector-input' griddata(...,...,...,a,b) with a and b vectors +% 'griddata-v4' griddata(...,...,...,...,...,'v4') with v4 interpolation support +% 'uimenu' uimenu(...) +% 'weboptions' weboptions(...) +% 'parula' parula(...) +% 'html' html rendering in desktop +% +% See also FT_VERSION, VERSION, VER, VERLESSTHAN + +if ~ischar(what) + error('first argument must be a string'); +end + +switch what + case 'matlabversion' + tf = is_matlab() && matlabversion(varargin{:}); + + case 'exists-in-private-directory' + tf = is_matlab(); + + case 'which-all' + tf = is_matlab(); + + case 'onCleanup' + tf = is_octave() || matlabversion(7.8, Inf); + + case 'alim' + tf = is_matlab(); + + case 'int32_logical_operations' + % earlier version of MATLAB don't support bitand (and similar) + % operations on int32 + tf = is_octave() || ~matlabversion(-Inf, '2012a'); + + case 'graphics_objects' + % introduced in MATLAB 2014b, graphics is handled through objects; + % previous versions use numeric handles + tf = is_matlab() && matlabversion('2014b', Inf); + + case 'libmx_c_interface' + % removed after 2013b + tf = is_matlab() && matlabversion(-Inf, '2013b'); + + case 'images' + root_dir = fileparts(which('ft_defaults')); + external_stats_dir = fullfile(root_dir, 'external', 'images'); + + tf = has_all_functions_in_dir(external_stats_dir, {}); + + case 'signal' + root_dir = fileparts(which('ft_defaults')); + external_stats_dir = fullfile(root_dir, 'external', 'signal'); + + tf = has_all_functions_in_dir(external_stats_dir, {}); + + case 'stats' + root_dir = fileparts(which('ft_defaults')); + external_stats_dir = fullfile(root_dir, 'external', 'stats'); + + % these files are only used by other functions in the external/stats directory + exclude_mfiles = { + 'common_size.m' + 'iscomplex.m' + }; + + tf = has_all_functions_in_dir(external_stats_dir, exclude_mfiles); + + case 'program_invocation_name' + % Octave supports program_invocation_name, which returns the path + % of the binary that was run to start Octave + tf = is_octave(); + + case 'singleCompThread' + tf = is_matlab() && matlabversion(7.8, Inf); + + case {'nosplash', 'nodisplay', 'nojvm'} + % Only on MATLAB + tf = is_matlab(); + + case 'no-gui' + % Only on Octave + tf = is_octave(); + + case 'RandStream.setDefaultStream' + tf = is_matlab() && matlabversion('2008b', '2011b'); + + case 'RandStream.setGlobalStream' + tf = is_matlab() && matlabversion('2012a', Inf); + + case 'randomized_PRNG_on_startup' + tf = is_octave() || ~matlabversion(-Inf, '7.3'); + + case 'rng' + % recent MATLAB versions + tf = is_matlab() && matlabversion('7.12', Inf); + + case 'rand-state' + % GNU Octave + tf = is_octave(); + + case 'urlread-timeout' + tf = is_matlab() && matlabversion('2012b', Inf); + + case 'griddata-vector-input' + tf = is_matlab(); + + case 'griddata-v4' + tf = is_matlab() && matlabversion('2009a', Inf); + + case 'uimenu' + tf = is_matlab(); + + case {'weboptions', 'webread', 'websave'} + tf = is_matlab() && matlabversion('2014b', Inf); + + case 'webwrite' + tf = is_matlab() && matlabversion('2015a', Inf); + + case 'boundary' + tf = is_matlab() && matlabversion('2014b', Inf); + + case 'parula' + tf = is_matlab() && matlabversion('2014b', Inf); + + case 'html' + tf = ~is_octave() && usejava('desktop') && desktop('-inuse'); + + otherwise + error('unsupported value for first argument: %s', what); + +end % switch + +end % function + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function tf = is_matlab() +tf = ~is_octave(); +end % function + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function tf = is_octave() +persistent cached_tf + +if isempty(cached_tf) + cached_tf = logical(exist('OCTAVE_VERSION', 'builtin')); +end + +tf = cached_tf; +end % function + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function tf = has_all_functions_in_dir(in_dir, exclude_mfiles) +% returns true if all functions in in_dir are already provided by the platform +m_files = dir(fullfile(in_dir,'*.m')); +n = numel(m_files); + +for k = 1:n + m_filename = m_files(k).name; + if isempty(which(m_filename)) && isempty(strmatch(m_filename,exclude_mfiles)) + tf = false; + return; + end +end + +tf = true; + +end % function + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function [inInterval] = matlabversion(min, max) + +% MATLABVERSION checks if the current MATLAB version is within the interval +% specified by min and max. +% +% Use as +% if matlabversion(7.0, 7.9) +% % do something +% end +% +% Both strings and numbers, as well as infinities, are supported, eg.: +% matlabversion(7.1, 7.9) % is version between 7.1 and 7.9? +% matlabversion(6, '7.10') % is version between 6 and 7.10? (note: '7.10', not 7.10) +% matlabversion(-Inf, 7.6) % is version <= 7.6? +% matlabversion('2009b') % exactly 2009b +% matlabversion('2008b', '2010a') % between two versions +% matlabversion('2008b', Inf) % from a version onwards +% etc. +% +% See also VERSION, VER, VERLESSTHAN + +% Copyright (C) 2006, Robert Oostenveld +% Copyright (C) 2010, Eelke Spaak +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +% the version does not change, making it persistent speeds up the subsequent calls +persistent curVer + +if nargin<2 + max = min; +end + +if isempty(curVer) + curVer = version(); +end + +if ((ischar(min) && isempty(str2num(min))) || (ischar(max) && isempty(str2num(max)))) + % perform comparison with respect to release string + + ind = strfind(curVer, '(R'); + [year, ab] = parseMatlabRelease(curVer((ind + 2):(numel(curVer) - 1))); + + [minY, minAb] = parseMatlabRelease(min); + [maxY, maxAb] = parseMatlabRelease(max); + + inInterval = orderedComparison(minY, minAb, maxY, maxAb, year, ab); + +else + % perform comparison with respect to version number + [major, minor] = parseMatlabVersion(curVer); + [minMajor, minMinor] = parseMatlabVersion(min); + [maxMajor, maxMinor] = parseMatlabVersion(max); + + inInterval = orderedComparison(minMajor, minMinor, maxMajor, maxMinor, major, minor); +end + +end % function + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function [year, ab] = parseMatlabRelease(str) +if (str == Inf) + year = Inf; ab = Inf; +elseif (str == -Inf) + year = -Inf; ab = -Inf; +else + year = str2num(str(1:4)); + ab = str(5); +end +end % function + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function [major, minor] = parseMatlabVersion(ver) +if (ver == Inf) + major = Inf; minor = Inf; +elseif (ver == -Inf) + major = -Inf; minor = -Inf; +elseif (isnumeric(ver)) + major = floor(ver); + minor = int8((ver - floor(ver)) * 10); +else % ver is string (e.g. '7.10'), parse accordingly + [major, rest] = strtok(ver, '.'); + major = str2num(major); + minor = str2num(strtok(rest, '.')); +end +end % function + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function inInterval = orderedComparison(lowerA, lowerB, upperA, upperB, testA, testB) +% checks if testA is in interval (lowerA,upperA); if at edges, checks if testB is in interval (lowerB,upperB). +if (testA < lowerA || testA > upperA) + inInterval = false; +else + inInterval = true; + if (testA == lowerA) + inInterval = inInterval && (testB >= lowerB); + end + + if (testA == upperA) + inInterval = inInterval && (testB <= upperB); + end +end +end % function diff --git a/external/fieldtrip/specest/private/ft_preproc_bandpassfilter.m b/external/fieldtrip/specest/private/ft_preproc_bandpassfilter.m index b9e4b6f3..a8ea8090 100644 --- a/external/fieldtrip/specest/private/ft_preproc_bandpassfilter.m +++ b/external/fieldtrip/specest/private/ft_preproc_bandpassfilter.m @@ -1,4 +1,4 @@ -function [filt] = ft_preproc_bandpassfilter(dat,Fs,Fbp,N,type,dir,instabilityfix,df,wintype,dev,plotfiltresp,usefftfilt) +function [filt, B, A] = ft_preproc_bandpassfilter(dat,Fs,Fbp,N,type,dir,instabilityfix,df,wintype,dev,plotfiltresp,usefftfilt) % FT_PREPROC_BANDPASSFILTER applies a band-pass filter to the data and thereby % removes the spectral components in the data except for the ones in the @@ -25,6 +25,7 @@ % 'twopass-reverse' zero-phase reverse and forward filter % 'twopass-average' average of the twopass and the twopass-reverse % 'onepass-zerophase' zero-phase forward filter with delay compensation (default for firws, linear-phase symmetric FIR only) +% 'onepass-reverse-zerophase' zero-phase reverse filter with delay compensation % 'onepass-minphase' minimum-phase converted forward filter (non-linear!, firws only) % instabilityfix optional method to deal with filter instabilities % 'no' only detect and give error (default) @@ -131,11 +132,15 @@ end % Filtering does not work on integer data -typ = class(dat); -if ~strcmp(typ, 'double') && ~strcmp(typ, 'single') +if ~isa(dat, 'double') && ~isa(dat, 'single') dat = cast(dat, 'double'); end +% preprocessing fails on channels that contain NaN +if any(isnan(dat(:))) + ft_warning('FieldTrip:dataContainsNaN', 'data contains NaN values'); +end + % Nyquist frequency Fn = Fs/2; @@ -151,12 +156,12 @@ % Input arguments if length(Fbp) ~= 2 - error('Two cutoff frequencies required.') + ft_error('Two cutoff frequencies required.') end % Filter order AND transition width set? if ~isempty(N) && ~isempty(df) - warning('firws:dfOverridesN', 'Filter order AND transition width set - transition width setting will override filter order.') + ft_warning('firws:dfOverridesN', 'Filter order AND transition width set - transition width setting will override filter order.') elseif isempty(N) && isempty(df) % Default transition width heuristic df = fir_df(Fbp, Fs); end @@ -166,14 +171,14 @@ isOrderLow = false; if ~isempty(df) if df > maxDf - error('Transition band too wide. Maximum transition width is %.2f Hz.', maxDf) + ft_error('Transition band too wide. Maximum transition width is %.2f Hz.', maxDf) end [N, dev] = firwsord(wintype, Fs, df, dev); else % Check filter order otherwise [df, dev] = invfirwsord(wintype, Fs, N, dev); if df > maxDf nOpt = firwsord(wintype, Fs, maxDf, dev); - warning('firws:filterOrderLow', 'Filter order too low. For better results a minimum filter order of %d is recommended. Effective cutoff frequency might deviate from requested cutoff frequency.', nOpt) + ft_warning('firws:filterOrderLow', 'Filter order too low. For better results a minimum filter order of %d is recommended. Effective cutoff frequency might deviate from requested cutoff frequency.', nOpt) isOrderLow = true; end end @@ -232,11 +237,12 @@ if N > floor( (size(dat,2) - 1) / 3) N=floor(size(dat,2)/3) - 1; end - [B, A] = fir1(N, [min(Fbp)/Fn max(Fbp)/Fn]); + B = fir1(N, [min(Fbp)/Fn max(Fbp)/Fn]); + A = 1; case 'firls' % from NUTMEG's implementation % Deprecated: see bug 2453 - warning('The filter type you requested is not recommended for neural signals, only proceed if you know what you are doing.') + ft_warning('The filter type you requested is not recommended for neural signals, only proceed if you know what you are doing.') if isempty(N) N = 3*fix(Fs / Fbp(1)); end @@ -275,7 +281,7 @@ return otherwise - error('unsupported filter type "%s"', type); + ft_error('unsupported filter type "%s"', type); end % demean the data before filtering @@ -289,20 +295,19 @@ case 'no' rethrow(lasterror); case 'reduce' - warning('backtrace', 'off') - warning('instability detected - reducing the %dth order filter to an %dth order filter', N, N-1); - warning('backtrace', 'on') + ft_warning('off','backtrace'); + ft_warning('instability detected - reducing the %dth order filter to an %dth order filter', N, N-1); + ft_warning('on','backtrace'); filt = ft_preproc_bandpassfilter(dat,Fs,Fbp,N-1,type,dir,instabilityfix); case 'split' N1 = ceil(N/2); N2 = floor(N/2); - warning('backtrace', 'off') - warning('instability detected - splitting the %dth order filter in a sequential %dth and a %dth order filter', N, N1, N2); - warning('backtrace', 'on') + ft_warning('off','backtrace'); + ft_warning('instability detected - splitting the %dth order filter in a sequential %dth and a %dth order filter', N, N1, N2); + ft_warning('on','backtrace'); filt = ft_preproc_bandpassfilter(dat ,Fs,Fbp,N1,type,dir,instabilityfix); filt = ft_preproc_bandpassfilter(filt,Fs,Fbp,N2,type,dir,instabilityfix); otherwise - error('incorrect specification of instabilityfix'); + ft_error('incorrect specification of instabilityfix'); end % switch end - diff --git a/external/fieldtrip/specest/private/ft_preproc_polyremoval.m b/external/fieldtrip/specest/private/ft_preproc_polyremoval.m index 6e1fb25c..b16bb60e 100644 --- a/external/fieldtrip/specest/private/ft_preproc_polyremoval.m +++ b/external/fieldtrip/specest/private/ft_preproc_polyremoval.m @@ -58,9 +58,37 @@ flag = 0; end -% this does not work on integer data +% This does not work on integer data typ = class(dat); -dat = cast(dat, 'double'); +if ~isa(dat, 'double') && ~isa(dat, 'single') + dat = cast(dat, 'double'); +end + +usesamples = false(1,size(dat,2)); +usesamples(begsample:endsample) = true; + +% preprocessing fails on channels that contain NaN +if any(isnan(dat(:))) + ft_warning('FieldTrip:dataContainsNaN', 'data contains NaN values'); + + datnans = isnan(dat); + + % if a nan occurs, it's for all time points + check1 = all(ismember(sum(datnans,1),[0 size(dat,1)])); + + % if a channel has nans, it's for all samples + check2 = all(ismember(sum(datnans,2),[0 size(dat,2)])); + + if ~(check1 || check2) + usesamples = repmat(usesamples, [size(dat,1) 1]); + usesamples = usesamples & ~isnan(dat); + elseif check1 + usesamples(sum(datnans,1)==size(dat,1)) = false; % switch the nan samples off, they are not to be used for the regression + end +else + check1 = true; + check2 = true; +end % construct a "time" axis nsamples = size(dat,2); @@ -75,10 +103,20 @@ x(i+1,:) = basis.^(i); end -% estimate the contribution of the basis functions -% beta = dat(:,begsample:endsample)/x(:,begsample:endsample); <-this leads to numerical issues, even in simple examples -invxcov = inv(x(:,begsample:endsample)*x(:,begsample:endsample)'); -beta = dat(:,begsample:endsample)*x(:,begsample:endsample)'*invxcov; +if ~(check1 || check2) + % loop across rows + beta = zeros(size(dat,1),size(x,1)); + for k = 1:size(dat,1) + invxcov = inv(x(:,usesamples(k,:))*x(:,usesamples(k,:))'); + beta(k,:) = dat(k,usesamples(k,:))*x(:,usesamples(k,:))'*invxcov; + end +else + + % estimate the contribution of the basis functions + % beta = dat(:,begsample:endsample)/x(:,begsample:endsample); <-this leads to numerical issues, even in simple examples + invxcov = inv(x(:,usesamples)*x(:,usesamples)'); + beta = dat(:,usesamples)*x(:,usesamples)'*invxcov; +end % remove the estimated basis functions dat = dat - beta*x; diff --git a/external/fieldtrip/specest/private/ft_warning.m b/external/fieldtrip/specest/private/ft_warning.m index 18b0ce00..58f3985e 100644 --- a/external/fieldtrip/specest/private/ft_warning.m +++ b/external/fieldtrip/specest/private/ft_warning.m @@ -1,39 +1,40 @@ -function [ws, warned] = ft_warning(varargin) +function varargout = ft_warning(varargin) -% FT_WARNING will throw a warning for every unique point in the -% stacktrace only, e.g. in a for-loop a warning is thrown only once. +% FT_WARNING prints a warning message on screen, depending on the verbosity +% settings of the calling high-level FieldTrip function. This function works +% similar to the standard WARNING function, but also features the "once" mode. % -% Use as one of the following -% ft_warning(string) -% ft_warning(id, string) -% Alternatively, you can use ft_warning using a timeout -% ft_warning(string, timeout) -% ft_warning(id, string, timeout) -% where timeout should be inf if you don't want to see the warning ever -% again. +% Use as +% ft_warning(...) +% with arguments similar to fprintf, or +% ft_warning(msgId, ...) +% with arguments similar to warning. % -% Use as ft_warning('-clear') to clear old warnings from the current -% stack +% You can switch of all warning messages using +% ft_warning off +% or for specific ones using +% ft_warning off msgId % -% It can be used instead of the MATLAB built-in function WARNING, thus as -% s = ft_warning(...) -% or as -% ft_warning(s) -% where s is a structure with fields 'identifier' and 'state', storing the -% state information. In other words, ft_warning accepts as an input the -% same structure it returns as an output. This returns or restores the -% states of warnings to their previous values. +% To switch them back on, you would use +% ft_warning on +% or for specific ones using +% ft_warning on msgId +% +% Warning messages are only printed once per timeout period using +% ft_warning timeout 60 +% ft_warning once +% or for specific ones using +% ft_warning once msgId % -% It can also be used as -% [s w] = ft_warning(...) -% where w is a boolean that indicates whether a warning as been thrown or not. +% You can see the most recent messages and identifier using +% ft_warning last % -% Please note that you can NOT use it like this -% ft_warning('the value is %d', 10) -% instead you should do -% ft_warning(sprintf('the value is %d', 10)) +% You can query the current on/off/once state for all messages using +% ft_warning query +% +% See also FT_ERROR, FT_WARNING, FT_NOTICE, FT_warning, FT_DEBUG, ERROR, WARNING -% Copyright (C) 2012-2016, Robert Oostenveld, J?rn M. Horschig +% Copyright (C) 2012-2017, Robert Oostenveld, J?rn M. Horschig % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -53,205 +54,12 @@ % % $Id$ -global ft_default -warned = false; -ws = []; - -stack = dbstack; -if any(strcmp({stack(2:end).file}, 'ft_warning.m')) - % don't call FT_WARNING recursively, see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=3068 - return; -end - -if nargin < 1 - error('You need to specify at least a warning message'); -end - -if isstruct(varargin{1}) - warning(varargin{1}); - return; -end - -if ~isfield(ft_default, 'warning') - ft_default.warning = []; -end -if ~isfield(ft_default.warning, 'stopwatch') - ft_default.warning.stopwatch = []; -end -if ~isfield(ft_default.warning, 'identifier') - ft_default.warning.identifier = []; -end -if ~isfield(ft_default.warning, 'ignore') - ft_default.warning.ignore = {}; -end - -% put the arguments we will pass to warning() in this cell array -warningArgs = {}; - -if nargin==3 - % calling syntax (id, msg, timeout) - - warningArgs = varargin(1:2); - msg = warningArgs{2}; - timeout = varargin{3}; - fname = [warningArgs{1} '_' warningArgs{2}]; - -elseif nargin==2 && isnumeric(varargin{2}) - % calling syntax (msg, timeout) - - warningArgs = varargin(1); - msg = warningArgs{1}; - timeout = varargin{2}; - fname = warningArgs{1}; - -elseif nargin==2 && isequal(varargin{1}, 'off') - - ft_default.warning.ignore = union(ft_default.warning.ignore, varargin{2}); - return - -elseif nargin==2 && isequal(varargin{1}, 'on') - - ft_default.warning.ignore = setdiff(ft_default.warning.ignore, varargin{2}); - return - -elseif nargin==2 && ~isnumeric(varargin{2}) - % calling syntax (id, msg) - - warningArgs = varargin(1:2); - msg = warningArgs{2}; - timeout = inf; - fname = [warningArgs{1} '_' warningArgs{2}]; - -elseif nargin==1 - % calling syntax (msg) - - warningArgs = varargin(1); - msg = warningArgs{1}; - timeout = inf; % default timeout in seconds - fname = [warningArgs{1}]; - -end - -if ismember(msg, ft_default.warning.ignore) - % do not show this warning - return; -end - -if isempty(timeout) - error('Timeout ill-specified'); -end - -if timeout ~= inf - fname = fixname(fname); % make a nice string that is allowed as fieldname in a structures - line = []; -else - % here, we create the fieldname functionA.functionB.functionC... - [tmpfname, ft_default.warning.identifier, line] = fieldnameFromStack(ft_default.warning.identifier); - if ~isempty(tmpfname), - fname = tmpfname; - clear tmpfname; - end -end - -if nargin==1 && ischar(varargin{1}) && strcmp('-clear', varargin{1}) - if strcmp(fname, '-clear') % reset all fields if called outside a function - ft_default.warning.identifier = []; - ft_default.warning.stopwatch = []; - else - if issubfield(ft_default.warning.identifier, fname) - ft_default.warning.identifier = rmsubfield(ft_default.warning.identifier, fname); - end - end - return; -end - -% and add the line number to make this unique for the last function -fname = horzcat(fname, line); - -if ~issubfield('ft_default.warning.stopwatch', fname) - ft_default.warning.stopwatch = setsubfield(ft_default.warning.stopwatch, fname, tic); -end - -now = toc(getsubfield(ft_default.warning.stopwatch, fname)); % measure time since first function call - -if ~issubfield(ft_default.warning.identifier, fname) || ... - (issubfield(ft_default.warning.identifier, fname) && now>getsubfield(ft_default.warning.identifier, [fname '.timeout'])) - - % create or reset field - ft_default.warning.identifier = setsubfield(ft_default.warning.identifier, fname, []); - - % warning never given before or timed out - ws = warning(warningArgs{:}); - ft_default.warning.identifier = setsubfield(ft_default.warning.identifier, [fname '.timeout'], now+timeout); - ft_default.warning.identifier = setsubfield(ft_default.warning.identifier, [fname '.ws'], msg); - warned = true; +if nargout + varargout{:} = ft_notification(varargin{:}); +elseif isequal(varargin, {'last'}) + % return an answer anyway + varargout{1} = ft_notification(varargin{:}); else - - % the warning has been issued before, but has not timed out yet - ws = getsubfield(ft_default.warning.identifier, [fname '.ws']); - -end - -end % function ft_warning - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% helper functions -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -function [fname, ft_previous_warnings, line] = fieldnameFromStack(ft_previous_warnings) -% stack(1) is this function, stack(2) is ft_warning -stack = dbstack('-completenames'); -if size(stack) < 3 - fname = []; - line = []; - return; -end -i0 = 3; -% ignore ft_preamble -while strfind(stack(i0).name, 'ft_preamble') - i0=i0+1; + ft_notification(varargin{:}); end -fname = horzcat(fixname(stack(end).name)); -if ~issubfield(ft_previous_warnings, fixname(stack(end).name)) - ft_previous_warnings.(fixname(stack(end).name)) = []; % iteratively build up structure fields -end - - -for i=numel(stack)-1:-1:(i0) - % skip postamble scripts - if strncmp(stack(i).name, 'ft_postamble', 12) - break; - end - - fname = horzcat(fname, '.', horzcat(fixname(stack(i).name))); % , stack(i).file - if ~issubfield(ft_previous_warnings, fname) % iteratively build up structure fields - setsubfield(ft_previous_warnings, fname, []); - end -end - -% line of last function call -line = ['.line', int2str(stack(i0).line)]; -end - -% function outcome = issubfield(strct, fname) -% substrindx = strfind(fname, '.'); -% if numel(substrindx) > 0 -% % separate the last fieldname from all former -% outcome = eval(['isfield(strct.' fname(1:substrindx(end)-1) ', ''' fname(substrindx(end)+1:end) ''')']); -% else -% % there is only one fieldname -% outcome = isfield(strct, fname); -% end -% end - -% function strct = rmsubfield(strct, fname) -% substrindx = strfind(fname, '.'); -% if numel(substrindx) > 0 -% % separate the last fieldname from all former -% strct = eval(['rmfield(strct.' fname(1:substrindx(end)-1) ', ''' fname(substrindx(end)+1:end) ''')']); -% else -% % there is only one fieldname -% strct = rmfield(strct, fname); -% end -% end diff --git a/external/fieldtrip/specest/private/istrue.m b/external/fieldtrip/specest/private/istrue.m new file mode 100644 index 00000000..742a0997 --- /dev/null +++ b/external/fieldtrip/specest/private/istrue.m @@ -0,0 +1,42 @@ +function y = istrue(x) + +% ISTRUE converts an input argument like "yes/no", "true/false" or "on/off" into a +% boolean. If the input is boolean, then it will remain like that. + +% Copyright (C) 2009-2012, Robert Oostenveld +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +true_list = {'yes' 'true' 'on' 'y' }; +false_list = {'no' 'false' 'off' 'n' 'none'}; + +if ischar(x) + % convert string to boolean value + if any(strcmpi(x, true_list)) + y = true; + elseif any(strcmpi(x, false_list)) + y = false; + else + error('cannot determine whether "%s" should be interpreted as true or false', x); + end +else + % convert numerical value to boolean + y = logical(x); +end + diff --git a/external/fieldtrip/specest/private/keyval.m b/external/fieldtrip/specest/private/keyval.m index b176ce8d..0043c72b 100644 --- a/external/fieldtrip/specest/private/keyval.m +++ b/external/fieldtrip/specest/private/keyval.m @@ -44,7 +44,7 @@ end if mod(length(varargin),2) - error('optional input arguments should come in key-value pairs, i.e. there should be an even number'); + ft_error('optional input arguments should come in key-value pairs, i.e. there should be an even number'); end % the 1st, 3rd, etc. contain the keys, the 2nd, 4th, etc. contain the values @@ -58,7 +58,7 @@ end if ~all(valid) - error('optional input arguments should come in key-value pairs, the optional input argument %d is invalid (should be a string)', i); + ft_error('optional input arguments should come in key-value pairs, the optional input argument %d is invalid (should be a string)', i); end hit = find(strcmpi(key, keys)); @@ -69,7 +69,7 @@ % the requested key was found val = vals{hit}; else - error('multiple input arguments with the same name'); + ft_error('multiple input arguments with the same name'); end if nargout>1 diff --git a/external/fieldtrip/specest/private/keyvalcheck.m b/external/fieldtrip/specest/private/keyvalcheck.m index 9f2cdaac..667287df 100644 --- a/external/fieldtrip/specest/private/keyvalcheck.m +++ b/external/fieldtrip/specest/private/keyvalcheck.m @@ -46,7 +46,7 @@ function keyvalcheck(arglist, varargin) vals = arglist(2:2:end); if numel(keys)~=numel(vals) - error('optional input arguments should come in key-value pairs, i.e. there should be an even number'); + ft_error('optional input arguments should come in key-value pairs, i.e. there should be an even number'); end keys = cellfun(@lower, keys, 'UniformOutput', false); @@ -56,7 +56,7 @@ function keyvalcheck(arglist, varargin) required = cellfun(@lower, required, 'UniformOutput', false); set = intersect(keys, required); if numel(set)~=numel(required) - error('the required input argument ''%s'' was not specified', set{:}); + ft_error('the required input argument ''%s'' was not specified', set{:}); end end @@ -65,7 +65,7 @@ function keyvalcheck(arglist, varargin) forbidden = cellfun(@lower, forbidden, 'UniformOutput', false); set = intersect(keys, forbidden); if numel(set)~=0 - error('the input argument ''%s'' is forbidden', set{:}); + ft_error('the input argument ''%s'' is forbidden', set{:}); end end @@ -74,7 +74,7 @@ function keyvalcheck(arglist, varargin) optional = cellfun(@lower, optional, 'UniformOutput', false); set = setdiff(keys, optional); if numel(set)>0 - error('the input argument ''%s'' is forbidden', set{:}); + ft_error('the input argument ''%s'' is forbidden', set{:}); end end diff --git a/external/fieldtrip/specest/private/sine_taper.m b/external/fieldtrip/specest/private/sine_taper.m index 563bbb5b..2a888f27 100644 --- a/external/fieldtrip/specest/private/sine_taper.m +++ b/external/fieldtrip/specest/private/sine_taper.m @@ -25,12 +25,12 @@ % $Id$ if nargin < 2 - error('usage: sine_taper(n, k)'); + ft_error('usage: sine_taper(n, k)'); end k = round(k * 2); if k <= 0 || k > n - error('sine_taper: k is %g, must be in (1:n)/2', k) + ft_error('sine_taper: k is %g, must be in (1:n)/2', k) end x = (1:k) .* (pi / (n + 1)); diff --git a/external/fieldtrip/specest/private/sine_taper_scaled.m b/external/fieldtrip/specest/private/sine_taper_scaled.m index f3b4d6bd..d58a3181 100644 --- a/external/fieldtrip/specest/private/sine_taper_scaled.m +++ b/external/fieldtrip/specest/private/sine_taper_scaled.m @@ -29,12 +29,12 @@ % $Id$ if nargin < 2 - error('usage: sine_taper_scaled(n, k)'); + ft_error('usage: sine_taper_scaled(n, k)'); end k = round(k * 2); if k <= 0 || k > n - error('sine_taper_scaled: k is %g, must be in (1:n)/2', k) + ft_error('sine_taper_scaled: k is %g, must be in (1:n)/2', k) end x = (1:k) .* (pi / (n + 1)); diff --git a/external/fieldtrip/spm2fieldtrip.m b/external/fieldtrip/spm2fieldtrip.m index 5f63d5ec..52529b7a 100644 --- a/external/fieldtrip/spm2fieldtrip.m +++ b/external/fieldtrip/spm2fieldtrip.m @@ -4,19 +4,19 @@ % % Use as % data = spm2fieldtrip(D) -% where D is the SPM8 meeg object which you can load in with SPM_EEG_LOAD +% where D is the SPM meeg object which you can load in with SPM_EEG_LOAD % and where data is a FieldTrip raw data structure as if it were returned % by FT_PREPROCESSING. % % See also FT_PREPROCESSING, SPM_EEG_LOAD -if ~ft_hastoolbox('SPM12') && ~ft_hastoolbox('SPM8') +if ~ft_hastoolbox('spm8up') % it should be version spm8 or higher, since spm99, spm2 and spm5 did not yet the "meeg" object - error('this requires the SPM toolbox on your MATLAB path'); + ft_error('this requires SPM8 or later to be on your MATLAB path'); end if ~isa(D, 'meeg') - error('this requires an SPM "meeg" object as input') + ft_error('this requires an SPM "meeg" object as input') end % this is how SPM8 represents it diff --git a/external/fieldtrip/src/det2x2.c b/external/fieldtrip/src/det2x2.c index d2f004e6..ca1ee8f7 100644 --- a/external/fieldtrip/src/det2x2.c +++ b/external/fieldtrip/src/det2x2.c @@ -1,5 +1,4 @@ #include -#include #include void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) diff --git a/external/fieldtrip/src/det2x2.m b/external/fieldtrip/src/det2x2.m index 82f9bdc4..260d5d1e 100644 --- a/external/fieldtrip/src/det2x2.m +++ b/external/fieldtrip/src/det2x2.m @@ -36,6 +36,6 @@ elseif numel(siz)==2, d = det(x); else - error('not implemented'); + ft_error('not implemented'); % write for loop for the higher dimensions, using normal inv end diff --git a/external/fieldtrip/src/det3x3.c b/external/fieldtrip/src/det3x3.c new file mode 100644 index 00000000..b9912dc0 --- /dev/null +++ b/external/fieldtrip/src/det3x3.c @@ -0,0 +1,94 @@ +#include +#include + +void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) +{ + /*declare variables*/ + const mwSize *dims; + mwSize *dimsout; + mwIndex indx; + int i, numdims; + int numelin; + mxClassID classid; + double *input1r, *input1i, *output1r, *output1i; + double a, b, c, d, e, f, g, h, j; + double ai, bi, ci, di, ei, fi, gi, hi ,ji; + + /*figure out the classid*/ + classid = mxGetClassID(prhs[0]); + + /*check inputs*/ + if (nrhs>1) + mexErrMsgTxt("Too many input arguments"); + + /*associate inputs*/ + input1r = mxGetData(prhs[0]); + input1i = mxGetImagData(prhs[0]); + + /*figure out dimension info and number of elements*/ + dims = mxGetDimensions(prhs[0]); + numdims = mxGetNumberOfDimensions(prhs[0]); + numelin = mxGetNumberOfElements(prhs[0]); + + dimsout = mxMalloc(numdims * sizeof(mwSize)); + for (i=0; i. +% +% $Id$ + +siz = size(x); +if all(siz(1:2)==3), + d = x(1,1,:,:).*x(2,2,:,:).*x(3,3,:,:) - ... + x(1,1,:,:).*x(2,3,:,:).*x(3,2,:,:) - ... + x(1,2,:,:).*x(2,1,:,:).*x(3,3,:,:) + ... + x(1,2,:,:).*x(2,3,:,:).*x(3,1,:,:) + ... + x(1,3,:,:).*x(2,1,:,:).*x(3,2,:,:) - ... + x(1,3,:,:).*x(2,2,:,:).*x(3,1,:,:); +else + ft_error('not implemented'); + % write for loop for the higher dimensions, using normal inv +end diff --git a/external/fieldtrip/src/ft_spike_sub_crossx.c b/external/fieldtrip/src/ft_spike_sub_crossx.c index 9821df26..a2c10ffe 100644 --- a/external/fieldtrip/src/ft_spike_sub_crossx.c +++ b/external/fieldtrip/src/ft_spike_sub_crossx.c @@ -15,7 +15,6 @@ #include "mex.h" #include -#include void mexFunction( int nOutputs, mxArray *pointerOutputs[], diff --git a/external/fieldtrip/src/geometry.c b/external/fieldtrip/src/geometry.c index f7a2cc05..7210b5c3 100644 --- a/external/fieldtrip/src/geometry.c +++ b/external/fieldtrip/src/geometry.c @@ -17,7 +17,6 @@ */ #include -#include "matrix.h" #include "geometry.h" /****************************************************************************/ diff --git a/external/fieldtrip/src/inv2x2.c b/external/fieldtrip/src/inv2x2.c index 754f3ee2..81003680 100644 --- a/external/fieldtrip/src/inv2x2.c +++ b/external/fieldtrip/src/inv2x2.c @@ -1,5 +1,4 @@ #include -#include #include void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) diff --git a/external/fieldtrip/src/inv2x2.m b/external/fieldtrip/src/inv2x2.m index f15d80a1..388940d7 100644 --- a/external/fieldtrip/src/inv2x2.m +++ b/external/fieldtrip/src/inv2x2.m @@ -32,11 +32,11 @@ adjx = [ det2x2(x([2 3],[2 3],:,:)) -det2x2(x([1 3],[2 3],:,:)) det2x2(x([1 2],[2 3],:,:)); ... -det2x2(x([2 3],[1 3],:,:)) det2x2(x([1 3],[1 3],:,:)) -det2x2(x([1 2],[1 3],:,:)); ... det2x2(x([2 3],[1 2],:,:)) -det2x2(x([1 3],[1 2],:,:)) det2x2(x([1 2],[1 2],:,:))]; - denom = det2x2(x); + denom = det3x3(x); d = adjx./denom([1 1 1],[1 1 1],:,:); elseif numel(siz)==2, d = inv(x); else - error('cannot compute slicewise inverse'); + ft_error('cannot compute slicewise inverse'); % write for loop for the higher dimensions, using normal inv end diff --git a/external/fieldtrip/src/inv3x3.c b/external/fieldtrip/src/inv3x3.c new file mode 100644 index 00000000..a80ada55 --- /dev/null +++ b/external/fieldtrip/src/inv3x3.c @@ -0,0 +1,146 @@ +#include +#include +#include + +void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) +{ + /*declare variables*/ + const mwSize *dims; + mwSize *dimsout; + mwIndex indx; + int i, j, k, numdims; + int numelin; + mxClassID classid; + double *input1r, *input1i, *output1r, *output1i; + double x[3][3], adjx[3][3]; + double xi[3][3], adjxi[3][3]; + double D,Di,Dabs; + + /*figure out the classid*/ + classid = mxGetClassID(prhs[0]); + + /*check inputs*/ + if (nrhs>1) + mexErrMsgTxt("Too many input arguments"); + + /*associate inputs*/ + input1r = mxGetData(prhs[0]); + input1i = mxGetImagData(prhs[0]); + + /*figure out dimension info and number of elements*/ + dims = mxGetDimensions(prhs[0]); + numdims = mxGetNumberOfDimensions(prhs[0]); + numelin = mxGetNumberOfElements(prhs[0]); + + dimsout = mxMalloc(numdims * sizeof(mwSize)); + for (i=0; i. +% +% $Id$ + +siz = size(x); +if all(siz(1:2)==3), + adjx = [ det2x2(x([2 3],[2 3],:,:)) -det2x2(x([1 3],[2 3],:,:)) det2x2(x([1 2],[2 3],:,:)); ... + -det2x2(x([2 3],[1 3],:,:)) det2x2(x([1 3],[1 3],:,:)) -det2x2(x([1 2],[1 3],:,:)); ... + det2x2(x([2 3],[1 2],:,:)) -det2x2(x([1 3],[1 2],:,:)) det2x2(x([1 2],[1 2],:,:))]; + denom = det3x3(x); + d = adjx./denom([1 1 1],[1 1 1],:,:); +else + ft_error('cannot compute slicewise inverse'); + % write for loop for the higher dimensions, using normal inv +end diff --git a/external/fieldtrip/src/lmoutr.c b/external/fieldtrip/src/lmoutr.c index 22ba3886..ee89b8a0 100644 --- a/external/fieldtrip/src/lmoutr.c +++ b/external/fieldtrip/src/lmoutr.c @@ -1,6 +1,5 @@ #include #include "mex.h" -#include "matrix.h" #include "geometry.h" void diff --git a/external/fieldtrip/src/lmoutr.m b/external/fieldtrip/src/lmoutr.m index 121b8301..cd7760e9 100644 --- a/external/fieldtrip/src/lmoutr.m +++ b/external/fieldtrip/src/lmoutr.m @@ -1,4 +1,4 @@ -function [varargout] = funname(varargin) +function [varargout] = lmoutr(varargin) % LMOUTR computes the la/mu parameters of a point projected to a triangle % diff --git a/external/fieldtrip/src/ltrisect.c b/external/fieldtrip/src/ltrisect.c index d85ef950..5600783e 100644 --- a/external/fieldtrip/src/ltrisect.c +++ b/external/fieldtrip/src/ltrisect.c @@ -1,6 +1,5 @@ #include #include "mex.h" -#include "matrix.h" #include "geometry.h" void diff --git a/external/fieldtrip/src/ltrisect.m b/external/fieldtrip/src/ltrisect.m index cf3c66bd..075d811a 100644 --- a/external/fieldtrip/src/ltrisect.m +++ b/external/fieldtrip/src/ltrisect.m @@ -1,4 +1,4 @@ -function [varargout] = funname(varargin) +function [varargout] = ltrisect(varargin) % LTRISECT intersects a line with a plane spanned by three vertices % diff --git a/external/fieldtrip/src/meg_leadfield1.c b/external/fieldtrip/src/meg_leadfield1.c index 41e7d44b..929ad5ed 100644 --- a/external/fieldtrip/src/meg_leadfield1.c +++ b/external/fieldtrip/src/meg_leadfield1.c @@ -1,7 +1,6 @@ #include #include #include "mex.h" -#include "matrix.h" void mexFunction (int nlhs, mxArray * plhs[], int nrhs, const mxArray * prhs[]) diff --git a/external/fieldtrip/src/meg_leadfield1.m b/external/fieldtrip/src/meg_leadfield1.m index 594c3c0a..ff2dc661 100644 --- a/external/fieldtrip/src/meg_leadfield1.m +++ b/external/fieldtrip/src/meg_leadfield1.m @@ -1,4 +1,4 @@ -function [varargout] = funname(varargin) +function [varargout] = meg_leadfield1(varargin) % MEG_LEADFIELD1 magnetic leadfield for a dipole in a homogenous sphere % diff --git a/external/fieldtrip/src/mtimes2x2.c b/external/fieldtrip/src/mtimes2x2.c index ba5b7e6c..d65263cf 100644 --- a/external/fieldtrip/src/mtimes2x2.c +++ b/external/fieldtrip/src/mtimes2x2.c @@ -1,5 +1,4 @@ #include -#include #include void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) diff --git a/external/fieldtrip/src/mtimes3x3.c b/external/fieldtrip/src/mtimes3x3.c new file mode 100644 index 00000000..177c6371 --- /dev/null +++ b/external/fieldtrip/src/mtimes3x3.c @@ -0,0 +1,170 @@ +#include +#include + +void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) +{ + /*declare variables*/ + const mwSize *dims; + mwIndex indx; + int i, numdims, indx1, indx2, indx3; + int numelin; + mxClassID classid; + double *input1r, *input1i, *input2r, *input2i, *output1r, *output1i; + double a[3][3], b[3][3]; + double ai[3][3], bi[3][3]; + + /*figure out the classid*/ + classid = mxGetClassID(prhs[0]); + + /*check inputs*/ + if (nrhs!=2) + mexErrMsgTxt("Wrong number of input arguments"); + + /*associate inputs*/ + input1r = mxGetData(prhs[0]); + input1i = mxGetImagData(prhs[0]); + + input2r = mxGetData(prhs[1]); + input2i = mxGetImagData(prhs[1]); + + /*figure out dimension info and number of elements*/ + dims = mxGetDimensions(prhs[0]); + numdims = mxGetNumberOfDimensions(prhs[0]); + numelin = mxGetNumberOfElements(prhs[0]); + + /*associate output*/ + if (input1i == NULL && input2i == NULL) + { + plhs[0] = mxCreateNumericArray(numdims, dims, classid, mxREAL); + output1r = mxGetData(plhs[0]); + } + else + { + plhs[0] = mxCreateNumericArray(numdims, dims, classid, mxCOMPLEX); + output1r = mxGetData(plhs[0]); + output1i = mxGetImagData(plhs[0]); + } + + /* do the computation*/ + if (input1i == NULL && input2i == NULL) + { + for (i=0; i. +% +% $Id$ + +z = complex(zeros(size(x))); +%xconj = conj(x); + +z(1,1,:,:) = x(1,1,:,:).*y(1,1,:,:) + x(1,2,:,:).*y(2,1,:,:) + x(1,3,:,:).*y(3,1,:,:); +z(1,2,:,:) = x(1,1,:,:).*y(1,2,:,:) + x(1,2,:,:).*y(2,2,:,:) + x(1,3,:,:).*y(3,2,:,:); +z(1,3,:,:) = x(1,1,:,:).*y(1,3,:,:) + x(1,2,:,:).*y(2,3,:,:) + x(1,3,:,:).*y(3,3,:,:); +z(2,1,:,:) = x(2,1,:,:).*y(1,1,:,:) + x(2,2,:,:).*y(2,1,:,:) + x(2,3,:,:).*y(3,1,:,:); +z(2,2,:,:) = x(2,1,:,:).*y(1,2,:,:) + x(2,2,:,:).*y(2,2,:,:) + x(2,3,:,:).*y(3,2,:,:); +z(2,3,:,:) = x(2,1,:,:).*y(1,3,:,:) + x(2,2,:,:).*y(2,3,:,:) + x(2,3,:,:).*y(3,3,:,:); +z(3,1,:,:) = x(3,1,:,:).*y(1,1,:,:) + x(3,2,:,:).*y(2,1,:,:) + x(3,3,:,:).*y(3,1,:,:); +z(3,2,:,:) = x(3,1,:,:).*y(1,2,:,:) + x(3,2,:,:).*y(2,2,:,:) + x(3,3,:,:).*y(3,2,:,:); +z(3,3,:,:) = x(3,1,:,:).*y(1,3,:,:) + x(3,2,:,:).*y(2,3,:,:) + x(3,3,:,:).*y(3,3,:,:); diff --git a/external/fieldtrip/src/mxDeserialize.m b/external/fieldtrip/src/mxDeserialize.m index 696f4ff8..d9b4843f 100644 --- a/external/fieldtrip/src/mxDeserialize.m +++ b/external/fieldtrip/src/mxDeserialize.m @@ -31,7 +31,7 @@ argout = mxDeserialize_c(argin); else % use the C++ implementation of the mex file - % see http://bugzilla.fcdonders.nl/show_bug.cgi?id=2452 + % see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2452 argout = mxDeserialize_cpp(argin); end diff --git a/external/fieldtrip/src/mxSerialize.m b/external/fieldtrip/src/mxSerialize.m index 78befccb..a2534051 100644 --- a/external/fieldtrip/src/mxSerialize.m +++ b/external/fieldtrip/src/mxSerialize.m @@ -31,7 +31,7 @@ argout = mxSerialize_c(argin); else % use the C++ implementation of the mex file - % see http://bugzilla.fcdonders.nl/show_bug.cgi?id=2452 + % see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2452 argout = mxSerialize_cpp(argin); end diff --git a/external/fieldtrip/src/nanaccum.h b/external/fieldtrip/src/nanaccum.h index 1b514ab6..709ad768 100644 --- a/external/fieldtrip/src/nanaccum.h +++ b/external/fieldtrip/src/nanaccum.h @@ -1,4 +1,3 @@ -#include #include #include #include diff --git a/external/fieldtrip/src/nanmean.c b/external/fieldtrip/src/nanmean.c index a36f9bd1..81152ecb 100644 --- a/external/fieldtrip/src/nanmean.c +++ b/external/fieldtrip/src/nanmean.c @@ -1,4 +1,3 @@ -#include #include #include #include diff --git a/external/fieldtrip/src/nannumel.c b/external/fieldtrip/src/nannumel.c deleted file mode 100644 index ab5bfe2e..00000000 --- a/external/fieldtrip/src/nannumel.c +++ /dev/null @@ -1,25 +0,0 @@ -#include "nanaccum.h" - -/* What is C a horrible language. To hoops we have to get through to make this - * work for different data types... Since overloading does not work, we - * generate type-specific functions: */ -#define fname(name, suffix) name ## _ ## suffix -#define nanstat_template(TYPE)\ -double fname(nanstat, TYPE)(int n, TYPE *x0, mwSize stride) \ -{\ - int i; int count = 0;\ - for (i = 0; i < n; ++i) {\ - if (!isnan(x0[i * stride]))\ - count += 1;\ - }\ - return count;\ -} - -nanstat_template(float); -nanstat_template(double); -nanstat_template(int8_T); nanstat_template(uint8_T); -nanstat_template(int16_T); nanstat_template(uint16_T); -nanstat_template(int32_T); nanstat_template(uint32_T); -nanstat_template(int64_T); nanstat_template(uint64_T); - -#include "nanaccum.c" /* takes care of generic nan-handling of arrays :D. */ diff --git a/external/fieldtrip/src/nanstd.c b/external/fieldtrip/src/nanstd.c index ec890a01..b7bd7a7e 100644 --- a/external/fieldtrip/src/nanstd.c +++ b/external/fieldtrip/src/nanstd.c @@ -1,4 +1,3 @@ -#include #include #include #include diff --git a/external/fieldtrip/src/nansum.c b/external/fieldtrip/src/nansum.c index d9149cc7..cf90625c 100644 --- a/external/fieldtrip/src/nansum.c +++ b/external/fieldtrip/src/nansum.c @@ -1,4 +1,3 @@ -#include #include #include #include diff --git a/external/fieldtrip/src/nanvar.c b/external/fieldtrip/src/nanvar.c index c07388fd..096f2282 100644 --- a/external/fieldtrip/src/nanvar.c +++ b/external/fieldtrip/src/nanvar.c @@ -1,4 +1,3 @@ -#include #include #include #include diff --git a/external/fieldtrip/src/platform.h b/external/fieldtrip/src/platform.h index 01531598..86bb7c76 100644 --- a/external/fieldtrip/src/platform.h +++ b/external/fieldtrip/src/platform.h @@ -1,78 +1,83 @@ +/* + * Copyright (C) 2008, Robert Oostenveld & Christian Hesse + * F.C. Donders Centre for Cognitive Neuroimaging, Radboud University Nijmegen, + * Kapittelweg 29, 6525 EN Nijmegen, The Netherlands + * + */ -/* prevent double include */ #ifndef PLATFORM_H #define PLATFORM_H -#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__) -/* linux, also other platforms (Hurd etc) that use GLIBC */ -#define PLATFORM_LINUX +#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__) + /* linux, also other platforms (Hurd etc) that use GLIBC */ + #define PLATFORM_LINUX #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) -/* BSD */ -#define PLATFORM_BSD + /* BSD */ + #define PLATFORM_BSD #elif defined(sun) || defined(__sun) -/* Solaris */ -#define PLATFORM_SUN + /* Sun Solaris */ + #define PLATFORM_SUN #elif defined(__sgi) -/* SGI Irix */ -#define PLATFORM_SGI + /* SGI Irix */ + #define PLATFORM_SGI #elif defined(__hpux) -/* hp unix */ -#define PLATFORM_HP + /* HP-UX */ + #define PLATFORM_HP #elif defined(__CYGWIN__) -/* cygwin is not win32 */ -#define PLATFORM_CYGWIN + /* cygwin is not windows */ + #define PLATFORM_CYGWIN #elif defined(_WIN64) || defined(__WIN64__) || defined(WIN64) -/* win64 */ -#define PLATFORM_WIN64 -#define PLATFORM_WINDOWS + /* win64 */ + #define PLATFORM_WIN64 + #define PLATFORM_WINDOWS #elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32) -/* win32 */ -#define PLATFORM_WIN32 -#define PLATFORM_WINDOWS + /* win32 */ + #define PLATFORM_WIN32 + #define PLATFORM_WINDOWS #elif defined(__BEOS__) -/* BeOS */ -#define PLATFORM_BEOS + /* BeOS */ + #define PLATFORM_BEOS #elif defined (__APPLE__) && defined (__MACH__) -/* MacOSX */ -#define PLATFORM_OSX + /* MacOSX */ + #define PLATFORM_OSX #elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) -/* MacOS classic */ -#define PLATFORM_MAC + /* MacOS classic */ + #define PLATFORM_MAC #elif defined(__IBMCPP__) || defined(_AIX) -/* IBM */ -#define PLATFORM_AIX + /* IBM */ + #define PLATFORM_AIX #elif defined(__amigaos__) -/* AmigaOS */ -#define PLATFORM_AMIGA + /* AmigaOS */ + #define PLATFORM_AMIGA #elif defined(__QNXNTO__) -/* QNX */ -#define PLATFORM_QNX + /* QNX */ + #define PLATFORM_QNX #elif defined(__VXWORKS__) -/* vxWorks */ -#define PLATFORM_VXWORKS + /* vxWorks */ + #define PLATFORM_VXWORKS #elif defined(unix) || defined(__unix) || defined(_XOPEN_SOURCE) || defined(_POSIX_SOURCE) -/* generic unix platform */ -#define PLATFORM_UNIX + /* generic UNIX platform */ + #define PLATFORM_UNIX #else -/* the platform cannot be determined at compile time */ -#error "Unknown platform - please report the platform details to http://fieldtrip.fcdonders.nl" + /* the platform cannot be determined at compile time */ + #error "Unknown platform - please report this to http://bugzilla.fieldtriptoolbox.org" + #endif #endif /* PLATFORM_H */ - diff --git a/external/fieldtrip/src/plgndr.c b/external/fieldtrip/src/plgndr.c index f7f5a53d..d476d0b1 100644 --- a/external/fieldtrip/src/plgndr.c +++ b/external/fieldtrip/src/plgndr.c @@ -25,7 +25,6 @@ #include #include "mex.h" -#include "matrix.h" double legendre_Pmm(double m, double x) { diff --git a/external/fieldtrip/src/plgndr.m b/external/fieldtrip/src/plgndr.m index 4796f6c8..8012d84a 100644 --- a/external/fieldtrip/src/plgndr.m +++ b/external/fieldtrip/src/plgndr.m @@ -1,4 +1,4 @@ -function [varargout] = funname(varargin) +function [varargout] = plgndr(varargin) % PLGNDR associated Legendre function % @@ -33,31 +33,30 @@ % compile the missing mex file on the fly % remember the original working directory pwdir = pwd; +pwdir_ressetter=onCleanup(@()cd(pwdir)); % determine the name and full path of this function funname = mfilename('fullpath'); mexsrc = [funname '.c']; [mexdir, mexname] = fileparts(funname); -try +mexfullpath=fullfile(mexdir,sprintf('%s.%s',mexname,mexext())); +disp(mexfullpath); +has_mex_func=@()exist(mexfullpath,'file'); + +if ~has_mex_func() % try to compile the mex file on the fly - warning('trying to compile MEX file from %s', mexsrc); + ft_warning('trying to compile MEX file from %s', mexsrc); cd(mexdir); mex(mexsrc); - cd(pwdir); - success = true; - -catch - % compilation failed - disp(lasterr); - error('could not locate MEX file for %s', mexname); - cd(pwdir); - success = false; -end -if success - % execute the mex file that was juist created - funname = mfilename; - funhandle = str2func(funname); - [varargout{1:nargout}] = funhandle(varargin{:}); + if ~has_mex_func() + ft_error('could not locate / compile MEX file for %s in %s', ... + mexname, mexfullpath); + end end + +% execute the mex file that was juist created +funname = mfilename; +funhandle = str2func(funname); +[varargout{1:nargout}] = funhandle(varargin{:}); diff --git a/external/fieldtrip/src/plinproj.c b/external/fieldtrip/src/plinproj.c index e6cc784b..0f2c6e49 100644 --- a/external/fieldtrip/src/plinproj.c +++ b/external/fieldtrip/src/plinproj.c @@ -1,6 +1,5 @@ #include #include "mex.h" -#include "matrix.h" #include "geometry.h" void diff --git a/external/fieldtrip/src/plinproj.m b/external/fieldtrip/src/plinproj.m index 67d1c448..015cf9b5 100644 --- a/external/fieldtrip/src/plinproj.m +++ b/external/fieldtrip/src/plinproj.m @@ -1,4 +1,4 @@ -function [varargout] = funname(varargin) +function [varargout] = plinproj(varargin) % PLINPROJ projects a point onto a line or linepiece % diff --git a/external/fieldtrip/src/ptriproj.c b/external/fieldtrip/src/ptriproj.c index cb1031e7..113d722b 100644 --- a/external/fieldtrip/src/ptriproj.c +++ b/external/fieldtrip/src/ptriproj.c @@ -1,6 +1,5 @@ #include #include "mex.h" -#include "matrix.h" #include "geometry.h" void diff --git a/external/fieldtrip/src/ptriproj.m b/external/fieldtrip/src/ptriproj.m index 49b78585..2e1acbe6 100644 --- a/external/fieldtrip/src/ptriproj.m +++ b/external/fieldtrip/src/ptriproj.m @@ -1,4 +1,4 @@ -function [varargout] = funname(varargin) +function [varargout] = ptriproj(varargin) % PTRIPROJ projects a point onto the plane going through a triangle % diff --git a/external/fieldtrip/src/read_16bit.c b/external/fieldtrip/src/read_16bit.c index 02a5f329..c9018c40 100644 --- a/external/fieldtrip/src/read_16bit.c +++ b/external/fieldtrip/src/read_16bit.c @@ -1,7 +1,8 @@ +#include #include #include #include "mex.h" -#include "matrix.h" +#include /* * Copyright (C) 2008, Robert Oostenveld, F.C. Donders Ccentre for Cognitive Neuroimaging diff --git a/external/fieldtrip/src/read_16bit.m b/external/fieldtrip/src/read_16bit.m index ce900ef9..5d28ea61 100644 --- a/external/fieldtrip/src/read_16bit.m +++ b/external/fieldtrip/src/read_16bit.m @@ -1,4 +1,4 @@ -function [varargout] = funname(varargin) +function [varargout] = read_16bit(varargin) % READ_16BIT read a stream of 16 bit values and converts them to doubles % This function is designed for EDF files and is implemented as mex diff --git a/external/fieldtrip/src/read_24bit.c b/external/fieldtrip/src/read_24bit.c index 9096b191..64e09103 100644 --- a/external/fieldtrip/src/read_24bit.c +++ b/external/fieldtrip/src/read_24bit.c @@ -28,10 +28,11 @@ #define _LARGEFILE_SOURCE +#include #include #include #include "mex.h" -#include "matrix.h" +#include #if defined(_WIN32) || defined(_WIN64) #define int32_t INT32_T diff --git a/external/fieldtrip/src/read_24bit.m b/external/fieldtrip/src/read_24bit.m index a7839aaf..e4bcc3e4 100644 --- a/external/fieldtrip/src/read_24bit.m +++ b/external/fieldtrip/src/read_24bit.m @@ -1,4 +1,4 @@ -function [varargout] = funname(varargin) +function [varargout] = read_24bit(varargin) % READ_24BIT read a stream of 24 bit values and converts them to doubles % This function is designed for Biosemi BDF files and is implemented as mex diff --git a/external/fieldtrip/src/read_ctf_shm.c b/external/fieldtrip/src/read_ctf_shm.c index 3fe3da77..30cda449 100644 --- a/external/fieldtrip/src/read_ctf_shm.c +++ b/external/fieldtrip/src/read_ctf_shm.c @@ -18,7 +18,7 @@ #include #include #include "mex.h" -#include "matrix.h" +#include #define ACQ_MSGQ_SIZE 600 #define ACQ_MSGQ_SHMKEY 0x39457f73 diff --git a/external/fieldtrip/src/read_ctf_shm.m b/external/fieldtrip/src/read_ctf_shm.m index eb1705f0..006e34b4 100644 --- a/external/fieldtrip/src/read_ctf_shm.m +++ b/external/fieldtrip/src/read_ctf_shm.m @@ -1,4 +1,4 @@ -function [varargout] = funname(varargin) +function [varargout] = read_ctf_shm(varargin) % READ_CTF_SHM reads metainformation or selected blocks of data from % shared memory. This function can be used for real-time processing of diff --git a/external/fieldtrip/src/rename.c b/external/fieldtrip/src/rename.c index 25713393..7b4e2706 100644 --- a/external/fieldtrip/src/rename.c +++ b/external/fieldtrip/src/rename.c @@ -8,7 +8,6 @@ #include #include "mex.h" -#include "matrix.h" void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { char *old, *new; diff --git a/external/fieldtrip/src/rfbevent.c b/external/fieldtrip/src/rfbevent.c index 7ef1ecaf..a6d6c4ec 100644 --- a/external/fieldtrip/src/rfbevent.c +++ b/external/fieldtrip/src/rfbevent.c @@ -69,7 +69,6 @@ #include "d3des.h" #include "mex.h" -#include "matrix.h" #define VNC_BASE 5900 #define CHALLENGESIZE 16 diff --git a/external/fieldtrip/src/rfbevent.m b/external/fieldtrip/src/rfbevent.m index e0e9744c..cf5b62ff 100644 --- a/external/fieldtrip/src/rfbevent.m +++ b/external/fieldtrip/src/rfbevent.m @@ -1,4 +1,4 @@ -function [varargout] = funname(varargin) +function [varargout] = rfbevent(varargin) % RFBEVENT sends a keyboard or mouse event to a VNC server % diff --git a/external/fieldtrip/src/routlm.c b/external/fieldtrip/src/routlm.c index b626284e..5f308bc5 100644 --- a/external/fieldtrip/src/routlm.c +++ b/external/fieldtrip/src/routlm.c @@ -1,6 +1,5 @@ #include #include "mex.h" -#include "matrix.h" #include "geometry.h" void diff --git a/external/fieldtrip/src/routlm.m b/external/fieldtrip/src/routlm.m index 4ce17d0b..6f8f2f6e 100644 --- a/external/fieldtrip/src/routlm.m +++ b/external/fieldtrip/src/routlm.m @@ -1,4 +1,4 @@ -function [varargout] = funname(varargin) +function [varargout] = routlm(varargin) % ROUTLM computes the projection of a point from its la/mu parameters % these equal the "Barycentric" coordinates diff --git a/external/fieldtrip/src/sandwich2x2.c b/external/fieldtrip/src/sandwich2x2.c index 4639d0c5..37065dff 100644 --- a/external/fieldtrip/src/sandwich2x2.c +++ b/external/fieldtrip/src/sandwich2x2.c @@ -1,5 +1,4 @@ #include -#include #include void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) diff --git a/external/fieldtrip/src/sandwich3x3.c b/external/fieldtrip/src/sandwich3x3.c new file mode 100644 index 00000000..6d10614a --- /dev/null +++ b/external/fieldtrip/src/sandwich3x3.c @@ -0,0 +1,204 @@ +#include +#include + +void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) +{ + /*declare variables*/ + const mwSize *dims; + mwIndex indx; + int i, numdims, indx1, indx2, indx3; + int numelin; + mxClassID classid; + double *input1r, *input1i, *input2r, *input2i, *output1r, *output1i; + double a[3][3], b[3][3], c[3][3]; + double ai[3][3], bi[3][3], ci[3][3]; + + /*figure out the classid*/ + classid = mxGetClassID(prhs[0]); + + /*check inputs*/ + if (nrhs!=2) + mexErrMsgTxt("Wrong number of input arguments"); + + /*associate inputs*/ + input1r = mxGetData(prhs[0]); + input1i = mxGetImagData(prhs[0]); + + input2r = mxGetData(prhs[1]); + input2i = mxGetImagData(prhs[1]); + + /*figure out dimension info and number of elements*/ + dims = mxGetDimensions(prhs[0]); + numdims = mxGetNumberOfDimensions(prhs[0]); + numelin = mxGetNumberOfElements(prhs[0]); + + /*associate output*/ + if (input1i == NULL && input2i == NULL) + { + plhs[0] = mxCreateNumericArray(numdims, dims, classid, mxREAL); + output1r = mxGetData(plhs[0]); + } + else + { + plhs[0] = mxCreateNumericArray(numdims, dims, classid, mxCOMPLEX); + output1r = mxGetData(plhs[0]); + output1i = mxGetImagData(plhs[0]); + } + + /* do the computation*/ + if (input1i == NULL && input2i == NULL) + { + for (i=0; i. +% +% $Id$ + +% FIXME build in check for hermitianity +z = complex(zeros(size(x))); +xconj = conj(x); +xabs2 = abs(x).^2; + +z(1,1,:,:) = xabs2(1,1,:,:).*y(1,1,:,:) + ... + xabs2(1,2,:,:).*y(2,2,:,:) + ... + xabs2(1,3,:,:).*y(3,3,:,:) + ... + 2.*real( x(1,2,:,:).*y(2,1,:,:).*xconj(1,1,:,:) ) + ... + 2.*real( x(1,3,:,:).*y(3,1,:,:).*xconj(1,1,:,:) ) + ... + 2.*real( x(1,3,:,:).*y(3,2,:,:).*xconj(1,2,:,:) ); + + %(x(1,2,:,:).*y(2,1,:,:) + x(1,3,:,:).*y(3,1,:,:)).*xconj(1,1,:,:) + ... + %(x(1,1,:,:).*y(1,2,:,:) + x(1,3,:,:).*y(3,2,:,:)).*xconj(1,2,:,:) + ... + %(x(1,1,:,:).*y(1,3,:,:) + x(1,2,:,:).*y(2,3,:,:)).*xconj(1,3,:,:); + +z(2,1,:,:) = (x(2,1,:,:).*y(1,1,:,:) + x(2,2,:,:).*y(2,1,:,:) + x(2,3,:,:).*y(3,1,:,:)).*xconj(1,1,:,:) + ... + (x(2,1,:,:).*y(1,2,:,:) + x(2,2,:,:).*y(2,2,:,:) + x(2,3,:,:).*y(3,2,:,:)).*xconj(1,2,:,:) + ... + (x(2,1,:,:).*y(1,3,:,:) + x(2,2,:,:).*y(2,3,:,:) + x(2,3,:,:).*y(3,3,:,:)).*xconj(1,3,:,:); + +z(3,1,:,:) = (x(3,1,:,:).*y(1,1,:,:) + x(3,2,:,:).*y(2,1,:,:) + x(3,3,:,:).*y(3,1,:,:)).*xconj(1,1,:,:) + ... + (x(3,1,:,:).*y(1,2,:,:) + x(3,2,:,:).*y(2,2,:,:) + x(3,3,:,:).*y(3,2,:,:)).*xconj(1,2,:,:) + ... + (x(3,1,:,:).*y(1,3,:,:) + x(3,2,:,:).*y(2,3,:,:) + x(3,3,:,:).*y(3,3,:,:)).*xconj(1,3,:,:); + +z(1,2,:,:) = conj(z(2,1,:,:)); + +z(2,2,:,:) = xabs2(2,1,:,:).*y(1,1,:,:) + ... + xabs2(2,2,:,:).*y(2,2,:,:) + ... + xabs2(2,3,:,:).*y(3,3,:,:) + ... + 2.*real( x(2,2,:,:).*y(2,1,:,:).*xconj(2,1,:,:) ) + ... + 2.*real( x(2,3,:,:).*y(3,1,:,:).*xconj(2,1,:,:) ) + ... + 2.*real( x(2,3,:,:).*y(3,2,:,:).*xconj(2,2,:,:) ); + + %(x(2,2,:,:).*y(2,1,:,:) + x(2,3,:,:).*y(3,1,:,:)).*xconj(2,1,:,:) + ... + %(x(2,1,:,:).*y(1,2,:,:) + x(2,3,:,:).*y(3,2,:,:)).*xconj(2,2,:,:) + ... + %(x(2,1,:,:).*y(1,3,:,:) + x(2,2,:,:).*y(2,3,:,:)).*xconj(2,3,:,:); + +z(3,2,:,:) = (x(3,1,:,:).*y(1,1,:,:) + x(3,2,:,:).*y(2,1,:,:) + x(3,3,:,:).*y(3,1,:,:)).*xconj(2,1,:,:) + ... + (x(3,1,:,:).*y(1,2,:,:) + x(3,2,:,:).*y(2,2,:,:) + x(3,3,:,:).*y(3,2,:,:)).*xconj(2,2,:,:) + ... + (x(3,1,:,:).*y(1,3,:,:) + x(3,2,:,:).*y(2,3,:,:) + x(3,3,:,:).*y(3,3,:,:)).*xconj(2,3,:,:); + +z(1,3,:,:) = conj(z(3,1,:,:)); + +z(2,3,:,:) = conj(z(3,2,:,:)); + +z(3,3,:,:) = xabs2(3,1,:,:).*y(1,1,:,:) + ... + xabs2(3,2,:,:).*y(2,2,:,:) + ... + xabs2(3,3,:,:).*y(3,3,:,:) + ... + 2.*real( x(3,2,:,:).*y(2,1,:,:).*xconj(3,1,:,:) ) + ... + 2.*real( x(3,3,:,:).*y(3,1,:,:).*xconj(3,1,:,:) ) + ... + 2.*real( x(3,3,:,:).*y(3,2,:,:).*xconj(3,2,:,:) ); + + %(x(3,2,:,:).*y(2,1,:,:) + x(3,3,:,:).*y(3,1,:,:)).*xconj(3,1,:,:) + ... + %(x(3,1,:,:).*y(1,2,:,:) + x(3,3,:,:).*y(3,2,:,:)).*xconj(3,2,:,:) + ... + %(x(3,1,:,:).*y(1,3,:,:) + x(3,2,:,:).*y(2,3,:,:)).*xconj(3,3,:,:); +% +%b1 b2 b7 a1 a2' a4' b1' b3' b5' +%b3 b4 b8 a2 a3 a5' b2' b4' b6' +%b5 b6 b9 a4 a5 a6 b7' b8' b9' +% +%b1*a1+b2*a2+b7*a4 b1*a2'+b2*a3+b7*a5 b1*a4'+b2*a5'+b7*a6 b1' b3' b5' +%b3*a1+b4*a2+b8*a4 b3*a2'+b4*a3+b8*a5 b3*a4'+b4*a5'+b8*a6 b2' b4' b6' +%b5*a1+b6*a2+b9*a4 b5*a2'+b6*a3+b9*a5 b5*a4'+b6*a5'+b9*a6 b7' b8' b9' +% +% + +%b1*a1*b1'+b2*a2*b1'+b1*a2'*b2'+b2*a3*b2' b1*a1*b3'+b2*a2*b3'+b1*a2'*b4'+b2*a3*b4' +%b3*a1*b1'+b4*a2*b1'+b3*a2'*b2'+b4*a3*b2' b3*a1*b3'+b4*a2*b3'+b3*a2'*b4'+b4*a3*b4' +% +%a1*abs(b1)^2 + a2*(b1'*b2) + a2'*(b1*b2') + a3*abs(b2)^2 a1*b1*b3' + a2*b2*b3' + a2'*b1*b4' + a3*b2*b4' +%a1*b1'*b3 + a2*b1'*b4 + a2'*b2'*b3 + a3*b2'*b4 a1*abs(b3)^2 + a2*(b3'*b4) + a2'*(b3*b4') + a3*abs(b4)^2 diff --git a/external/fieldtrip/src/solid_angle.c b/external/fieldtrip/src/solid_angle.c index cb379e08..1da4f259 100644 --- a/external/fieldtrip/src/solid_angle.c +++ b/external/fieldtrip/src/solid_angle.c @@ -1,6 +1,5 @@ #include #include "mex.h" -#include "matrix.h" #include "geometry.h" void diff --git a/external/fieldtrip/src/solid_angle.m b/external/fieldtrip/src/solid_angle.m index c984e803..47e65c67 100644 --- a/external/fieldtrip/src/solid_angle.m +++ b/external/fieldtrip/src/solid_angle.m @@ -1,4 +1,4 @@ -function [varargout] = funname(varargin) +function [varargout] = solid_angle(varargin) % SOLID_ANGLE of a planar triangle as seen from the origin % @@ -33,7 +33,6 @@ % You should have received a copy of the GNU General Public License % along with FieldTrip. If not, see . % -% $Id$ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % The first section contains the plain MATLAB implementation. The mex file @@ -79,7 +78,7 @@ % w = 2 * atan2 (nom, den); % return % else -% error('invalid input'); +% ft_error('invalid input'); % end % compile the missing mex file on the fly @@ -93,7 +92,7 @@ try % try to compile the mex file on the fly - warning('trying to compile MEX file from %s', mexsrc); + ft_warning('trying to compile MEX file from %s', mexsrc); cd(mexdir); if ispc @@ -111,7 +110,7 @@ catch % compilation failed disp(lasterr); - error('could not locate MEX file for %s', mexname); + ft_error('could not locate MEX file for %s', mexname); cd(pwdir); success = false; end diff --git a/external/fieldtrip/src/splint_gh.c b/external/fieldtrip/src/splint_gh.c index 57bb04b4..70b135ec 100644 --- a/external/fieldtrip/src/splint_gh.c +++ b/external/fieldtrip/src/splint_gh.c @@ -25,7 +25,6 @@ #include #include "mex.h" -#include "matrix.h" double legendre_Pmm(double m, double x) { diff --git a/external/fieldtrip/src/splint_gh.m b/external/fieldtrip/src/splint_gh.m index 7eac540f..bd71691d 100644 --- a/external/fieldtrip/src/splint_gh.m +++ b/external/fieldtrip/src/splint_gh.m @@ -1,4 +1,4 @@ -function [varargout] = funname(varargin) +function [varargout] = splint_gh(varargin) % SPLINT_GH implements equations (3) and (5b) of Perrin 1989 % for simultaneous computation of multiple values diff --git a/external/fieldtrip/src/write_ctf_shm.c b/external/fieldtrip/src/write_ctf_shm.c index 8c333254..d76a011a 100644 --- a/external/fieldtrip/src/write_ctf_shm.c +++ b/external/fieldtrip/src/write_ctf_shm.c @@ -14,7 +14,7 @@ #include #include #include "mex.h" -#include "matrix.h" +#include #define ACQ_MSGQ_SIZE 600 #define ACQ_MSGQ_SHMKEY 0x39457f73 diff --git a/external/fieldtrip/src/write_ctf_shm.m b/external/fieldtrip/src/write_ctf_shm.m index dcf6387d..8811c691 100644 --- a/external/fieldtrip/src/write_ctf_shm.m +++ b/external/fieldtrip/src/write_ctf_shm.m @@ -1,4 +1,4 @@ -function [varargout] = funname(varargin) +function [varargout] = write_ctf_shm(varargin) % WRITE_CTF_SHM writes metainformation and data as a packet to shared memory. % This function can be used for real-time processing of data while it is diff --git a/external/fieldtrip/statfun/ft_statfun_actvsblT.m b/external/fieldtrip/statfun/ft_statfun_actvsblT.m index 13c50f2e..61372287 100644 --- a/external/fieldtrip/statfun/ft_statfun_actvsblT.m +++ b/external/fieldtrip/statfun/ft_statfun_actvsblT.m @@ -1,10 +1,10 @@ function [s, cfg] = ft_statfun_actvsblT(cfg, dat, design) -% FT_STATFUN_ACTVSBLT calculates the activation-versus-baseline T-statistic -% on the biological data in dat (the dependent variable), using the information on -% the independent variable (ivar) in design. +% FT_STATFUN_ACTVSBLT calculates the activation-versus-baseline T-statistic +% on the biological data in dat (the dependent variable), using the information on +% the independent variable (ivar) in design. % -% Note: It does not make sense to use this test statistic when +% Note that it does not make sense to use this test statistic when % baseline-correction was performed by subtracting the time average of the % baseline period. Instead of this type of baseline-correction, one may % subtract the time average of the combined baseline and activation @@ -16,13 +16,14 @@ % [stat] = ft_sourcestatistics(cfg, source1, source2, ...) % with the following configuration option % cfg.statistic = 'ft_statfun_actvsblT' -% see FT_TIMELOCKSTATISTICS, FT_FREQSTATISTICS or FT_SOURCESTATISTICS for details. +% +% See FT_TIMELOCKSTATISTICS, FT_FREQSTATISTICS or FT_SOURCESTATISTICS for details. % % For low-level use, the external interface of this function has to be % [s,cfg] = ft_statfun_actvsblT(cfg, dat, design); % where % dat contains the biological data, Nsamples x Nreplications -% design contains the independent variable (ivar) and the unit-of-observation (uvar) +% design contains the independent variable (ivar) and the unit-of-observation (uvar) % factor, Nreplications x Nvar % % Configuration options @@ -41,11 +42,11 @@ % quantile (1-cfg.alpha) (with cfg.tail=1). % % Design specification -% cfg.ivar = row number of the design that contains the labels of the conditions that must be -% compared (default=1). The first condition, indicated by 1, corresponds to the +% cfg.ivar = row number of the design that contains the labels of the conditions that must be +% compared (default=1). The first condition, indicated by 1, corresponds to the % activation period and the second, indicated by 2, corresponds to the baseline period. % cfg.uvar = row number of design that contains the labels of the units-of-observation (subjects or trials) -% (default=2). The labels are assumed to be integers ranging from 1 to +% (default=2). The labels are assumed to be integers ranging from 1 to % the number of units-of-observation. % Copyright (C) 2006, Eric Maris @@ -69,16 +70,16 @@ % $Id$ % set defaults -if ~isfield(cfg, 'computestat'), cfg.computestat='yes'; end; -if ~isfield(cfg, 'computecritval'), cfg.computecritval='no'; end; -if ~isfield(cfg, 'computeprob'), cfg.computeprob='no'; end; -if ~isfield(cfg, 'alpha'), cfg.alpha=0.05; end; -if ~isfield(cfg, 'tail'), cfg.tail=1; end; +if ~isfield(cfg, 'computestat'), cfg.computestat='yes'; end +if ~isfield(cfg, 'computecritval'), cfg.computecritval='no'; end +if ~isfield(cfg, 'computeprob'), cfg.computeprob='no'; end +if ~isfield(cfg, 'alpha'), cfg.alpha=0.05; end +if ~isfield(cfg, 'tail'), cfg.tail=1; end % perform some checks on the configuration -if strcmp(cfg.computeprob,'yes') & strcmp(cfg.computestat,'no') - error('P-values can only be calculated if the test statistics are calculated.'); -end; +if strcmp(cfg.computeprob,'yes') && strcmp(cfg.computestat,'no') + ft_error('P-values can only be calculated if the test statistics are calculated.'); +end % calculate the number of time samples switch cfg.dimord @@ -87,52 +88,50 @@ nfreq = cfg.dim(2); ntime = cfg.dim(3); [nsmpls,nrepl] = size(dat); - nsmplsdivntime = floor(nsmpls/ntime); otherwise - error('Inappropriate dimord for the statistics function STATFUN_ACTVSBLT.'); -end; + ft_error('Inappropriate dimord for the statistics function FT_STATFUN_ACTVSBLT.'); +end sel1 = find(design(cfg.ivar,:)==1); sel2 = find(design(cfg.ivar,:)==2); n1 = length(sel1); n2 = length(sel2); if (n1+n2). +% +% $Id$ + +stack = dbstack('-completenames'); + +% remove the functions that pertain to the notification system itself +keep = true(size(stack)); +keep(strcmp({stack.name}, 'defaultId')) = false; % this function itself +keep(strcmp({stack.name}, 'ft_notification')) = false; % this one is doing the work underneath ft_error/ft_warning/ft_notice/etc. +keep(strcmp({stack.name}, 'ft_error')) = false; +keep(strcmp({stack.name}, 'ft_warning')) = false; +keep(strcmp({stack.name}, 'ft_notice')) = false; +keep(strcmp({stack.name}, 'ft_info')) = false; +keep(strcmp({stack.name}, 'ft_debug')) = false; +stack = stack(keep); + +% remove the non-FieldTrip functions from the path, these should not be part of the default message identifier +keep = true(size(stack)); +[v, p] = ft_version; +for i=1:numel(stack) + keep(i) = strncmp(p, stack(i).file, length(p)); +end +stack = stack(keep); + +if ~isempty(stack) + % it is called from within a function + stack = flipud(stack); + name = {stack.name}; + id = ['FieldTrip' sprintf(':%s', name{:}) ':line' num2str(stack(end).line)]; +else + % it is called from the command line + id = 'FieldTrip:commandline'; +end diff --git a/external/fieldtrip/statfun/private/fixname.m b/external/fieldtrip/statfun/private/fixname.m index 96a345ec..76fd5951 100644 --- a/external/fieldtrip/statfun/private/fixname.m +++ b/external/fieldtrip/statfun/private/fixname.m @@ -1,19 +1,20 @@ -function str = fixname(str) +function str = fixname(str, version) % FIXNAME changes all inappropriate characters in a sting into '_' -% such that it can be used as a filename or as a structure field name. If -% the string begins with a numeric digit, an 'x' is prepended. +% so that it can be used as a filename or as a field name in a structure. +% If the string begins with a digit, an 'x' is prepended. % % Use as % str = fixname(str) % % MATLAB 2014a introduces the matlab.lang.makeValidName and -% matlab.lang.makeUniqueStrings functions for constructing unique MATLAB identifiers, -% but this particular implementation also works with older MATLAB versions. +% matlab.lang.makeUniqueStrings functions for constructing unique +% identifiers, but this particular implementation also works with +% older MATLAB versions. % % See also DEBLANK -% Copyright (C) 2012-2016, Robert Oostenveld +% Copyright (C) 2012-2017, Robert Oostenveld % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -33,19 +34,48 @@ % % $Id$ -str = lower(str); -str(regexp(str,'\W')) = '_'; - -while(str(1) == '_'), str = str(2:end); end; % remove all underscore at the begin of the string -while(str(end) == '_'), str = str(1:end-1); end; % remove all underscore at the end of the string - -if int8(str(1))<58 && int8(str(1))>47 - % the string begins with a digit, prepend an 'x' - str = ['x' str]; +if nargin<2 + version = 'default'; end -% truncate the string if it's too long: MATLAB maximizes the string length to 63 characters (and throws a warning when truncating) -if numel(str)>63 - str = str(1:63); - ft_warning(sprintf('%s exceeds MATLAB''s maximum name length of 63 characters and has been truncated to %s', str, str(1:63))); +switch version + case 'default' + if isempty(str) + str='x'; + end + str = lower(str); + str(regexp(str,'\W')) = '_'; + while(str(1) == '_'), str = str(2:end); end % remove all underscore at the begin of the string + while(str(end) == '_'), str = str(1:end-1); end % remove all underscore at the end of the string + if int8(str(1))<58 && int8(str(1))>47 + % the string begins with a digit, prepend an 'x' + str = ['x' str]; + end + % truncate the string if it's too long: MATLAB maximizes the string length to 63 characters (and throws a warning when truncating) + if numel(str)>63 + str = str(1:63); + warning('%s exceeds MATLAB''s maximum name length of 63 characters and has been truncated to %s', str, str(1:63)); + end + + case '2014a' + str = matlab.lang.makeValidName(str); + + case 'X_base64encode_X' + % this uses some code from Mathworks file exchange + ft_hastoolbox('fileexchange', 1); + % the following is an encoding that can be reverted + str = strtrim(base64encode(str)); + str(str=='=') = '_'; % replace the '=' sign with '_' + str = ['X' str 'X']; % start and end with an 'X' + + case 'X_base64decode_X' + % this uses some code from Mathworks file exchange + ft_hastoolbox('fileexchange', 1); + % revert the encoding + str = str(2:end-1); % it starts and ends with 'X' + str(str=='_') = '='; % the '=' sign has been replaced with '_' + str = char(base64decode(str)); + + otherwise + error('unsupported version "%s"', version); end diff --git a/external/fieldtrip/statfun/private/ft_notification.m b/external/fieldtrip/statfun/private/ft_notification.m new file mode 100644 index 00000000..88466909 --- /dev/null +++ b/external/fieldtrip/statfun/private/ft_notification.m @@ -0,0 +1,490 @@ +function [varargout] = ft_notification(varargin) + +% FT_NOTIFICATION works mostly like the WARNING and ERROR commands in MATLAB and +% is called by FT_ERROR, FT_WARNING, FT_NOTICE, FT_INFO, FT_DEBUG. Note that you +% should not call this function directly. +% +% Some examples: +% ft_info on +% ft_info on msgId +% ft_info off +% ft_info off msgId +% ft_info once +% ft_info once msgId +% ft_info on backtrace +% ft_info off backtrace +% ft_info on verbose +% ft_info off verbose +% +% ft_info query % shows the status of all notifications +% ft_info last % shows the last notification +% ft_info clear % clears the status of all notifications +% ft_info timeout 10 % sets the timeout (for 'once') to 10 seconds + +% Copyright (C) 2012-2017, Robert Oostenveld, J?rn M. Horschig +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +global ft_default + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% determine who is calling + +stack = dbstack('-completenames'); +% st(1) is this function +% st(2) is the calling function +switch stack(2).name + case 'ft_debug' + level = 'debug'; + case 'ft_info' + level = 'info'; + case 'ft_notice' + level = 'notice'; + case 'ft_warning' + level = 'warning'; + case 'ft_error' + level = 'error'; + otherwise + error('this function cannot be called from %s', stack(2).name); +end + +% remove this function itself and the ft_xxx calling function +stack = stack(3:end); + +% remove the non-FieldTrip functions from the path, these should not be part of the default message identifier +keep = true(size(stack)); +[v, p] = ft_version; +for i=1:numel(stack) + keep(i) = strncmp(p, stack(i).file, length(p)); +end +stack = stack(keep); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% handle the defaults + +if isfield(ft_default, 'notification') && isfield(ft_default.notification, level) + % this would be error, warning, notice, info, debug + s = ft_default.notification.(level); +else + s = []; +end + +% start with an empty state structure +if isempty(s) + s = struct('identifier', {}, 'state', {}, 'timestamp', {}); +end + +% set the default notification state +if ~ismember('all', {s.identifier}) + s = setstate(s, 'all', 'on'); +end + +% set the default backtrace state +defaultbacktrace = false; +if ~ismember('backtrace', {s.identifier}) + switch level + case {'debug' 'info' 'notice'} + s = setstate(s, 'backtrace', 'off'); + case 'warning' + defaultbacktrace = true; + t = warning('query', 'backtrace'); % get the default state + s = setstate(s, 'backtrace', t.state); + case 'error' + s = setstate(s, 'backtrace', 'on'); + end % switch +end + +% set the default verbose state +defaultverbose = false; +if ~ismember('verbose', {s.identifier}) + switch level + case 'warning' + defaultverbose = true; + t = warning('query', 'verbose');% get the default state + s = setstate(s, 'verbose', t.state); + otherwise + s = setstate(s, 'verbose', 'off'); + end +end + +% set the default timeout +if ~ismember('timeout', {s.identifier}) + s = setstate(s, 'timeout', 60); +end + +% set the last notification to empty +if ~ismember('last', {s.identifier}) + state.message = ''; + state.identifier = ''; + state.stack = struct('file', {}, 'name', {}, 'line', {}); + s = setstate(s, 'last', state); +end + +if ~isempty(stack) + % it is called from within a function + name = fliplr({stack.name}); + defaultId = ['FieldTrip' sprintf(':%s', name{:}) ':line' num2str(stack(1).line)]; +else + % it is called from the command line + defaultId = ''; +end + +if strcmp(level, 'warning') + ws = warning; + % warnings should be on in general + warning on + % the backtrace is handled by this function + warning off backtrace + % the verbose message is handled by this function + warning off verbose +end + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% set the notification state according to the input + +if numel(varargin)>0 && (isstruct(varargin{1}) || isempty(varargin{1})) + ft_default.notification.(level) = varargin{1}; + return +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% act according to the first input argument + +if isempty(varargin) + varargin{1} = 'query'; +end + +switch varargin{1} + case 'on' + if numel(varargin)>1 + % switch a specific item on + msgId = varargin{2}; + s = setstate(s, msgId, 'on'); + if strcmp(msgId, 'backtrace') + defaultbacktrace = false; + end + if strcmp(msgId, 'verbose') + defaultverbose = false; + end + % return the message state of all + varargout{1} = getreturnstate(s, msgId); + else + % switch all on + s = setstate(s, 'all', 'on'); + % return the message state of all + varargout{1} = getreturnstate(s); + end + + case 'off' + if numel(varargin)>1 + % switch a specific item off + msgId = varargin{2}; + s = setstate(s, msgId, 'off'); + if strcmp(msgId, 'backtrace') + defaultbacktrace = false; + end + if strcmp(msgId, 'verbose') + defaultverbose = false; + end + % return the specific message state + varargout{1} = getreturnstate(s, msgId); + else + % switch all off + s = setstate(s, 'all', 'off'); + % return the message state of all + varargout{1} = getreturnstate(s); + end + + case 'once' + if numel(varargin)>1 + % switch a specific item to once + msgId = varargin{2}; + s = setstate(s, msgId, 'once'); + % return the specific message state + varargout{1} = getreturnstate(s, msgId); + else + % switch all to once + s = setstate(s, 'all', 'once'); + % return the message state of all + varargout{1} = getreturnstate(s); + end + + case 'timeout' + % set the timeout, this is used for 'once' + if ischar(varargin{2}) + s = setstate(s, 'timeout', str2double(varargin{2})); + else + s = setstate(s, 'timeout', varargin{2}); + end + + case {'last' '-last'} + % return the last notification + varargout{1} = getstate(s, 'last'); + + case {'clear' '-clear'} + % reset the notification system + s = []; + + case {'query' '-query'} + if numel(varargin)>1 + % select a specific item + msgId = varargin{2}; + if ~ismember(msgId, {s.identifier}) + error('Unknown setting or incorrect message identifier ''%s''.', msgId); + end + msgState = getstate(s, msgId); + if nargout + varargout{1} = getreturnstate(s, msgId); + elseif strcmp(msgId, 'verbose') + if istrue(msgState) + fprintf('%s output is verbose.\n', level); + else + fprintf('%s output is terse.\n', level); + end + elseif strcmp(msgId, 'backtrace') + if istrue(msgState) + fprintf('%s backtraces are enabled.\n', level); + else + fprintf('%s backtraces are disabled.\n', level); + end + else + fprintf('The state of %s ''%s'' is ''%s''\n', level, msgId, msgState); + end + else + % return all items + r = getreturnstate(s); + + if nargout + % return the state of all items + varargout{1} = r; + else + % show the state of all items that are different from the default + default = getstate(s, 'all'); + fprintf('The default %s state is ''%s''.', level, default); + r = r(~strcmp({r.state}, default)); + % don't show these + r(strcmp('verbose', {r.identifier})) = []; + r(strcmp('backtrace', {r.identifier})) = []; + if ~isempty(r) + fprintf(' Items not set to the default are\n\n'); + end + for i=1:numel(r) + fprintf(' %4s %s\n', r(i).state, r(i).identifier); + end + fprintf('\n'); + end + end + + otherwise + + if nargout + varargout{1} = getreturnstate(s); + end + + % first input might be msgId + if numel(varargin)>1 && ~isempty(regexp(varargin{1}, '^\w*:', 'once')) + msgId = varargin{1}; + varargin = varargin(2:end); % shift them all by one + else + msgId = defaultId; + end + + % get the state for this notification, it will default to the 'all' state + msgState = getstate(s, msgId); + + % errors are always to be printed + if strcmp(level, 'error') + msgState = 'on'; + end + + if strcmp(msgState, 'once') + timeout = getstate(s, 'timeout'); + since = elapsed(gettimestamp(s, msgId)); + if (since>timeout) + % the timeout has passed, update the timestamp and print the message + s = settimestamp(s, msgId, tic); + msgState = 'on'; + else + % the timeout has not yet passed, do not print the message + msgState = 'off'; + end + end + + % use an automatically generated default identifier + if isempty(msgId) + msgId = defaultId; + end + + % store the last notification + state.message = strtrim(sprintf(varargin{:})); % remove the trailing newline + state.identifier = msgId; + state.stack = stack; + s = setstate(s, 'last', state); + + if strcmp(msgState, 'on') + + if strcmp(level, 'error') + % update the global variable, we won't return here after the error + ft_default.notification.(level) = s; + % the remainder is fully handled by the ERROR function + if ~isempty(msgId) + error(msgId, varargin{:}); + else + error(varargin{:}); + end + + elseif strcmp(level, 'warning') + if ~isempty(msgId) + warning(msgId, varargin{:}); + else + warning(varargin{:}); + end + + else + % ensure there is a line end + if isempty(regexp(varargin{1}, '\\n$', 'once')) % note the double \\ + varargin{1} = [varargin{1} '\n']; + end + fprintf(varargin{:}); + + end % if level=error, warning or otherwise + + % decide whether the stack trace should be shown + if istrue(getstate(s, 'backtrace')) + for i=1:numel(stack) + % show the deepest and lowest-level function first + [p, f, x] = fileparts(stack(i).file); + if isequal(f, stack(i).name) + funname = stack(i).name; + else + funname = sprintf('%s>%s', f, stack(i).name); + end + filename = stack(i).file; + if isempty(fileparts(filename)) + % it requires the full path + filename = fullfile(pwd, filename); + end + if ft_platform_supports('html') + fprintf(' In %s at line %d\n', filename, stack(i).line, funname, stack(i).line); + else + fprintf(' In ''%s'' at line %d\n', filename, stack(i).line); + end + end + fprintf('\n'); + end + + % decide whether a verboe message should be shown + if istrue(getstate(s, 'verbose')) + if ~isempty(msgId) + fprintf('Type "ft_%s off %s" to suppress this message.\n', level, msgId) + else + fprintf('Type "ft_%s off" to suppress this message.\n', level) + end + end + + end % if msgState is on + +end % switch varargin{1} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% update the global variable +if defaultbacktrace && ~isempty(s) + % do not keep the default, it will be determined again on the next call + s = s(~strcmp({s.identifier}, 'backtrace')); +end +if defaultverbose && ~isempty(s) + % do not keep the default, it will be determined again on the next call + s = s(~strcmp({s.identifier}, 'verbose')); +end +ft_default.notification.(level) = s; + +if strcmp(level, 'warning') + % return to the original warning state + warning(ws); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTIONS +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +function r = getreturnstate(s, msgId) +if nargin<2 + r = s; + % don't return these + r(strcmp('timeout', {r.identifier})) = []; + r(strcmp('last', {r.identifier})) = []; + % don't return the timestamps + r = rmfield(r, 'timestamp'); +else + msgState = getstate(s, msgId); + r = struct('identifier', msgId, 'state', msgState); +end + +function state = getstate(s, msgId) +identifier = {s.identifier}; +sel = find(strcmp(identifier, msgId)); +if numel(sel)==1 + state = s(sel).state; + if isempty(state) + state = getstate(s, 'all'); + end +else + state = getstate(s, 'all'); +end + +function timestamp = gettimestamp(s, msgId) +identifier = {s.identifier}; +sel = find(strcmp(identifier, msgId)); +if numel(sel)==1 + timestamp = s(sel).timestamp; +else + timestamp = nan; +end + +function s = setstate(s, msgId, state) +if isempty(msgId), return; end % this happens from the command line +identifier = {s.identifier}; +sel = find(strcmp(identifier, msgId)); +if numel(sel)==1 + s(sel).state = state; +else + s(end+1).identifier = msgId; + s(end ).state = state; + s(end ).timestamp = nan; +end + +function s = settimestamp(s, msgId, timestamp) +if isempty(msgId), return; end % this happens from the command line +identifier = {s.identifier}; +sel = find(strcmp(identifier, msgId)); +if numel(sel)==1 + s(sel).timestamp = timestamp; +else + s(end+1).identifier = msgId; + s(end ).state = []; + s(end ).timestamp = timestamp; +end + +function t = elapsed(start) +if isempty(start) || isnan(start) + t = inf; +else + t = toc(start); +end diff --git a/external/fieldtrip/statfun/private/ft_warning.m b/external/fieldtrip/statfun/private/ft_warning.m index 18b0ce00..58f3985e 100644 --- a/external/fieldtrip/statfun/private/ft_warning.m +++ b/external/fieldtrip/statfun/private/ft_warning.m @@ -1,39 +1,40 @@ -function [ws, warned] = ft_warning(varargin) +function varargout = ft_warning(varargin) -% FT_WARNING will throw a warning for every unique point in the -% stacktrace only, e.g. in a for-loop a warning is thrown only once. +% FT_WARNING prints a warning message on screen, depending on the verbosity +% settings of the calling high-level FieldTrip function. This function works +% similar to the standard WARNING function, but also features the "once" mode. % -% Use as one of the following -% ft_warning(string) -% ft_warning(id, string) -% Alternatively, you can use ft_warning using a timeout -% ft_warning(string, timeout) -% ft_warning(id, string, timeout) -% where timeout should be inf if you don't want to see the warning ever -% again. +% Use as +% ft_warning(...) +% with arguments similar to fprintf, or +% ft_warning(msgId, ...) +% with arguments similar to warning. % -% Use as ft_warning('-clear') to clear old warnings from the current -% stack +% You can switch of all warning messages using +% ft_warning off +% or for specific ones using +% ft_warning off msgId % -% It can be used instead of the MATLAB built-in function WARNING, thus as -% s = ft_warning(...) -% or as -% ft_warning(s) -% where s is a structure with fields 'identifier' and 'state', storing the -% state information. In other words, ft_warning accepts as an input the -% same structure it returns as an output. This returns or restores the -% states of warnings to their previous values. +% To switch them back on, you would use +% ft_warning on +% or for specific ones using +% ft_warning on msgId +% +% Warning messages are only printed once per timeout period using +% ft_warning timeout 60 +% ft_warning once +% or for specific ones using +% ft_warning once msgId % -% It can also be used as -% [s w] = ft_warning(...) -% where w is a boolean that indicates whether a warning as been thrown or not. +% You can see the most recent messages and identifier using +% ft_warning last % -% Please note that you can NOT use it like this -% ft_warning('the value is %d', 10) -% instead you should do -% ft_warning(sprintf('the value is %d', 10)) +% You can query the current on/off/once state for all messages using +% ft_warning query +% +% See also FT_ERROR, FT_WARNING, FT_NOTICE, FT_warning, FT_DEBUG, ERROR, WARNING -% Copyright (C) 2012-2016, Robert Oostenveld, J?rn M. Horschig +% Copyright (C) 2012-2017, Robert Oostenveld, J?rn M. Horschig % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -53,205 +54,12 @@ % % $Id$ -global ft_default -warned = false; -ws = []; - -stack = dbstack; -if any(strcmp({stack(2:end).file}, 'ft_warning.m')) - % don't call FT_WARNING recursively, see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=3068 - return; -end - -if nargin < 1 - error('You need to specify at least a warning message'); -end - -if isstruct(varargin{1}) - warning(varargin{1}); - return; -end - -if ~isfield(ft_default, 'warning') - ft_default.warning = []; -end -if ~isfield(ft_default.warning, 'stopwatch') - ft_default.warning.stopwatch = []; -end -if ~isfield(ft_default.warning, 'identifier') - ft_default.warning.identifier = []; -end -if ~isfield(ft_default.warning, 'ignore') - ft_default.warning.ignore = {}; -end - -% put the arguments we will pass to warning() in this cell array -warningArgs = {}; - -if nargin==3 - % calling syntax (id, msg, timeout) - - warningArgs = varargin(1:2); - msg = warningArgs{2}; - timeout = varargin{3}; - fname = [warningArgs{1} '_' warningArgs{2}]; - -elseif nargin==2 && isnumeric(varargin{2}) - % calling syntax (msg, timeout) - - warningArgs = varargin(1); - msg = warningArgs{1}; - timeout = varargin{2}; - fname = warningArgs{1}; - -elseif nargin==2 && isequal(varargin{1}, 'off') - - ft_default.warning.ignore = union(ft_default.warning.ignore, varargin{2}); - return - -elseif nargin==2 && isequal(varargin{1}, 'on') - - ft_default.warning.ignore = setdiff(ft_default.warning.ignore, varargin{2}); - return - -elseif nargin==2 && ~isnumeric(varargin{2}) - % calling syntax (id, msg) - - warningArgs = varargin(1:2); - msg = warningArgs{2}; - timeout = inf; - fname = [warningArgs{1} '_' warningArgs{2}]; - -elseif nargin==1 - % calling syntax (msg) - - warningArgs = varargin(1); - msg = warningArgs{1}; - timeout = inf; % default timeout in seconds - fname = [warningArgs{1}]; - -end - -if ismember(msg, ft_default.warning.ignore) - % do not show this warning - return; -end - -if isempty(timeout) - error('Timeout ill-specified'); -end - -if timeout ~= inf - fname = fixname(fname); % make a nice string that is allowed as fieldname in a structures - line = []; -else - % here, we create the fieldname functionA.functionB.functionC... - [tmpfname, ft_default.warning.identifier, line] = fieldnameFromStack(ft_default.warning.identifier); - if ~isempty(tmpfname), - fname = tmpfname; - clear tmpfname; - end -end - -if nargin==1 && ischar(varargin{1}) && strcmp('-clear', varargin{1}) - if strcmp(fname, '-clear') % reset all fields if called outside a function - ft_default.warning.identifier = []; - ft_default.warning.stopwatch = []; - else - if issubfield(ft_default.warning.identifier, fname) - ft_default.warning.identifier = rmsubfield(ft_default.warning.identifier, fname); - end - end - return; -end - -% and add the line number to make this unique for the last function -fname = horzcat(fname, line); - -if ~issubfield('ft_default.warning.stopwatch', fname) - ft_default.warning.stopwatch = setsubfield(ft_default.warning.stopwatch, fname, tic); -end - -now = toc(getsubfield(ft_default.warning.stopwatch, fname)); % measure time since first function call - -if ~issubfield(ft_default.warning.identifier, fname) || ... - (issubfield(ft_default.warning.identifier, fname) && now>getsubfield(ft_default.warning.identifier, [fname '.timeout'])) - - % create or reset field - ft_default.warning.identifier = setsubfield(ft_default.warning.identifier, fname, []); - - % warning never given before or timed out - ws = warning(warningArgs{:}); - ft_default.warning.identifier = setsubfield(ft_default.warning.identifier, [fname '.timeout'], now+timeout); - ft_default.warning.identifier = setsubfield(ft_default.warning.identifier, [fname '.ws'], msg); - warned = true; +if nargout + varargout{:} = ft_notification(varargin{:}); +elseif isequal(varargin, {'last'}) + % return an answer anyway + varargout{1} = ft_notification(varargin{:}); else - - % the warning has been issued before, but has not timed out yet - ws = getsubfield(ft_default.warning.identifier, [fname '.ws']); - -end - -end % function ft_warning - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% helper functions -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -function [fname, ft_previous_warnings, line] = fieldnameFromStack(ft_previous_warnings) -% stack(1) is this function, stack(2) is ft_warning -stack = dbstack('-completenames'); -if size(stack) < 3 - fname = []; - line = []; - return; -end -i0 = 3; -% ignore ft_preamble -while strfind(stack(i0).name, 'ft_preamble') - i0=i0+1; + ft_notification(varargin{:}); end -fname = horzcat(fixname(stack(end).name)); -if ~issubfield(ft_previous_warnings, fixname(stack(end).name)) - ft_previous_warnings.(fixname(stack(end).name)) = []; % iteratively build up structure fields -end - - -for i=numel(stack)-1:-1:(i0) - % skip postamble scripts - if strncmp(stack(i).name, 'ft_postamble', 12) - break; - end - - fname = horzcat(fname, '.', horzcat(fixname(stack(i).name))); % , stack(i).file - if ~issubfield(ft_previous_warnings, fname) % iteratively build up structure fields - setsubfield(ft_previous_warnings, fname, []); - end -end - -% line of last function call -line = ['.line', int2str(stack(i0).line)]; -end - -% function outcome = issubfield(strct, fname) -% substrindx = strfind(fname, '.'); -% if numel(substrindx) > 0 -% % separate the last fieldname from all former -% outcome = eval(['isfield(strct.' fname(1:substrindx(end)-1) ', ''' fname(substrindx(end)+1:end) ''')']); -% else -% % there is only one fieldname -% outcome = isfield(strct, fname); -% end -% end - -% function strct = rmsubfield(strct, fname) -% substrindx = strfind(fname, '.'); -% if numel(substrindx) > 0 -% % separate the last fieldname from all former -% strct = eval(['rmfield(strct.' fname(1:substrindx(end)-1) ', ''' fname(substrindx(end)+1:end) ''')']); -% else -% % there is only one fieldname -% strct = rmfield(strct, fname); -% end -% end diff --git a/external/fieldtrip/statfun/private/istrue.m b/external/fieldtrip/statfun/private/istrue.m new file mode 100644 index 00000000..742a0997 --- /dev/null +++ b/external/fieldtrip/statfun/private/istrue.m @@ -0,0 +1,42 @@ +function y = istrue(x) + +% ISTRUE converts an input argument like "yes/no", "true/false" or "on/off" into a +% boolean. If the input is boolean, then it will remain like that. + +% Copyright (C) 2009-2012, Robert Oostenveld +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +true_list = {'yes' 'true' 'on' 'y' }; +false_list = {'no' 'false' 'off' 'n' 'none'}; + +if ischar(x) + % convert string to boolean value + if any(strcmpi(x, true_list)) + y = true; + elseif any(strcmpi(x, false_list)) + y = false; + else + error('cannot determine whether "%s" should be interpreted as true or false', x); + end +else + % convert numerical value to boolean + y = logical(x); +end + diff --git a/external/fieldtrip/trialfun/ft_trialfun_brainvision_segmented.m b/external/fieldtrip/trialfun/ft_trialfun_brainvision_segmented.m index 61ac8a36..6c4e843e 100644 --- a/external/fieldtrip/trialfun/ft_trialfun_brainvision_segmented.m +++ b/external/fieldtrip/trialfun/ft_trialfun_brainvision_segmented.m @@ -1,4 +1,5 @@ function [trl, event] = ft_trialfun_brainvision_segmented(cfg) + % FT_TRIALFUN_BRAINVISION_SEGMENTED creates trials for a Brain Vision Analyzer % dataset that was segmented in the BVA software. % @@ -9,21 +10,21 @@ % cfg = ft_definetrial(cfg); % data = ft_preprocessing(cfg); % -% Optionally, you can also specify: -% cfg.trigformat = 'S %d'; -% which will instruct this function to parse stimulus triggers according to -% the format you specified. The default is 'S %d'. cfg.trigformat always -% needs to contain exactly one %d code. Trigger values read in this way +% Optionally, you can specify: +% cfg.stimformat = 'S %d' +% +% The stimformat instruct this function to parse stimulus triggers according to +% the specific format. The default is 'S %d'. The cfg.stimformat always +% needs to contain exactly one %d code. The trigger values parsed in this way % will be stored in columns 4 and upwards of the output 'trl' matrix, and -% will end up in data.trialinfo if this matrix is subsequently passed to -% ft_preprocessing in order to read in data. +% after FT_PREPROCESSING will end up in data.trialinfo. % -% A dataset needs to consist of three files: a .eeg, .vhdr, and .vmrk file. -% cfg.dataset needs to refer to the .vhdr file. +% A BrainVision dataset consists of three files: an .eeg, .vhdr, and a .vmrk +% file. The option cfg.dataset should refer to the .vhdr file. % % See also FT_DEFINETRIAL, FT_PREPROCESSING -% Copyright (C) 20014, Robert Oostenveld, FCDC +% Copyright (C) 2014, Robert Oostenveld, DCCN % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -46,8 +47,11 @@ hdr = ft_read_header(cfg.dataset); event = ft_read_event(cfg.dataset); +% for backward compatibility +cfg = ft_checkconfig(cfg, 'renamed', {'trigformat', 'stimformat'}); + % set the defaults -cfg.trigformat = ft_getopt(cfg, 'trigformat', 'S %d'); +cfg.stimformat = ft_getopt(cfg, 'stimformat', 'S %d'); sel = find(strcmp({event.type}, 'New Segment')); ntrial = length(sel); @@ -56,7 +60,7 @@ sample = [event.sample]; if any(diff(sample)<0) % events should be ordered according to the sample in the file at which they occur - warning('reordering events based on their sample number'); + ft_warning('reordering events based on their sample number'); [sample, order] = sort(sample); event = event(order); end @@ -91,24 +95,35 @@ end % the endsample of each trial aligns with the beginsample of the next one -endsample(1:end-1) = begsample(2:end); +endsample(1:end-1) = begsample(2:end) - 1; % the last endsample corresponds to the end of the file endsample(end) = hdr.nSamples*hdr.nTrials; % add the stimulus events to the output, if possible numstim = cellfun(@length, stim); -if all(numstim==numstim(1)) - for i=1:length(stim) - for j=1:numstim(i) - stimvalue = sscanf(value{stim{i}(j)}, cfg.trigformat); - stimsample = sample(stim{i}(j)); - stimtime = (stimsample - begsample(i) + offset(i))/hdr.Fs; % relative to 'Time 0' - trialinfo(i,2*(j-1)+1) = stimvalue; - trialinfo(i,2*(j-1)+2) = stimtime; - end % j - end % i +if (numstim > 0) + if all(numstim==numstim(1)) + for i=1:length(stim) + for j=1:numstim(i) + if isempty(value{stim{i}(j)}) + ft_error('missing a stimulus type definition in the related *.vmrk file'); + end + stimvalue = sscanf(value{stim{i}(j)}, cfg.stimformat); + stimsample = sample(stim{i}(j)); + stimtime = (stimsample - begsample(i) + offset(i))/hdr.Fs; % relative to 'Time 0' + if isempty(stimvalue) + ft_error('the upper case letter of the stimulus value does not match with definition of "cfg.stimformat"'); + end + trialinfo(i,2*(j-1)+1) = stimvalue; + trialinfo(i,2*(j-1)+2) = stimtime; + end % j + end % i + else + ft_warning('the trials have a varying number of stimuli, not adding them to the "trl" matrix'); + trialinfo = []; + end else - warning('the trials have a varying number of stimuli, not adding them to the "trl" matrix'); + ft_warning('the trials have no stimuli, no "trialinfo" will be added to the "trl" matrix'); trialinfo = []; end diff --git a/external/fieldtrip/trialfun/ft_trialfun_edf.m b/external/fieldtrip/trialfun/ft_trialfun_edf.m index 207d7370..3466e47b 100644 --- a/external/fieldtrip/trialfun/ft_trialfun_edf.m +++ b/external/fieldtrip/trialfun/ft_trialfun_edf.m @@ -11,7 +11,7 @@ % See also FT_DEFINETRIAL, FT_PREPROCESSING if strcmp(mfilename,'ft_trialfun_edf') - warning('this trial function is only an example, please copy it and adapt it to your specific EDF situation - see http://www.fieldtriptoolbox.org/getting_started/edf'); + ft_warning('this trial function is only an example, please copy it and adapt it to your specific EDF situation - see http://www.fieldtriptoolbox.org/getting_started/edf'); end % read the header information diff --git a/external/fieldtrip/trialfun/ft_trialfun_example1.m b/external/fieldtrip/trialfun/ft_trialfun_example1.m index 6e075270..9cf19a81 100644 --- a/external/fieldtrip/trialfun/ft_trialfun_example1.m +++ b/external/fieldtrip/trialfun/ft_trialfun_example1.m @@ -4,6 +4,13 @@ % of type "trigger" and specifically for a trigger with value 7, followed % by a trigger with value 64. % +% You would use this function as follows +% cfg = []; +% cfg.dataset = string, containing filename or directory +% cfg.trialfun = 'ft_trialfun_example1'; +% cfg = definetrial(cfg); +% data = preprocessing(cfg); +% % You can use this example trial function as template for your own % conditial trial definitions. % @@ -14,7 +21,7 @@ chanindx = strmatch('EMGlft', hdr.label); if length(chanindx)>1 - error('only one EMG channel supported'); + ft_error('only one EMG channel supported'); end % read all data of the EMG channel, assume continuous file format @@ -23,10 +30,10 @@ emg = ft_read_data(cfg.datafile, 'begsample', begsample, 'endsample', endsample, 'chanindx', chanindx); % apply filtering, hilbert transformation and boxcar convolution (for smoothing) -emgflt = ft_preproc_highpassfilter(emg, hdr.Fs, 10); % highpassfilter (helper function from fieldtrip) +emgflt = ft_preproc_highpassfilter(emg, hdr.Fs, 10); % highpassfilter (helper function from fieldtrip/preproc) emghlb = abs(hilbert(emgflt')'); % hilbert transform emgcnv = conv2([1], ones(1,hdr.Fs), emghlb, 'same'); % smooth using convolution -emgstd = ft_preproc_standardize(emgcnv); % z-transform (helper function from fieldtrip) +emgstd = ft_preproc_standardize(emgcnv); % z-transform (helper function from fieldtrip/preproc) emgtrl = emgstd>0; % detect the muscle activity by thresholding emgtrl = diff(emgtrl, [], 2); diff --git a/external/fieldtrip/trialfun/ft_trialfun_example2.m b/external/fieldtrip/trialfun/ft_trialfun_example2.m index 9c0a75e0..ea737914 100644 --- a/external/fieldtrip/trialfun/ft_trialfun_example2.m +++ b/external/fieldtrip/trialfun/ft_trialfun_example2.m @@ -7,7 +7,7 @@ % You would use this function as follows % cfg = []; % cfg.dataset = string, containing filename or directory -% cfg.trialfun = 'trialfun_emgdetect'; +% cfg.trialfun = 'ft_trialfun_example2'; % cfg = definetrial(cfg); % data = preprocessing(cfg); % @@ -22,7 +22,7 @@ chanindx = strmatch('EMGlft', hdr.label); if length(chanindx)>1 - error('only one EMG channel supported'); + ft_error('only one EMG channel supported'); end % read all data of the EMG channel, assume continuous file format @@ -31,10 +31,10 @@ emg = ft_read_data(cfg.datafile, 'begsample', begsample, 'endsample', endsample, 'chanindx', chanindx); % apply filtering, hilbert transformation and boxcar convolution (for smoothing) -emgflt = ft_preproc_highpassfilter(emg, hdr.Fs, 10); % highpassfilter (helper function from fieldtrip) +emgflt = ft_preproc_highpassfilter(emg, hdr.Fs, 10); % highpassfilter (helper function from fieldtrip/preproc) emghlb = abs(hilbert(emgflt')'); % hilbert transform emgcnv = conv2([1], ones(1,hdr.Fs), emghlb, 'same'); % smooth using convolution -emgstd = ft_preproc_standardize(emgcnv); % z-transform (helper function from fieldtrip) +emgstd = ft_preproc_standardize(emgcnv); % z-transform (helper function from fieldtrip/preproc) emgtrl = emgstd>0; % detect the muscle activity by thresholding emgtrl = diff(emgtrl, [], 2); diff --git a/external/fieldtrip/trialfun/ft_trialfun_general.m b/external/fieldtrip/trialfun/ft_trialfun_general.m index 91de2c7f..655ab5bc 100644 --- a/external/fieldtrip/trialfun/ft_trialfun_general.m +++ b/external/fieldtrip/trialfun/ft_trialfun_general.m @@ -79,10 +79,10 @@ % read the events if isfield(cfg, 'event') - fprintf('using the events from the configuration structure\n'); + ft_info('using the events from the configuration structure\n'); event = cfg.event; else - fprintf('reading the events from ''%s''\n', cfg.headerfile); + ft_info('reading the events from ''%s''\n', cfg.headerfile); event = ft_read_event(cfg.headerfile, 'headerformat', cfg.headerformat, 'eventformat', cfg.eventformat, 'dataformat', cfg.dataformat); end @@ -112,11 +112,11 @@ trl = []; val = []; if isfield(cfg.trialdef, 'eventtype') - if strcmp(cfg.trialdef.eventtype, '?') + if isequal(cfg.trialdef.eventtype, '?') % no trials should be added, show event information using subfunction and exit show_event(event); return - elseif strcmp(cfg.trialdef.eventtype, 'gui') || (isfield(cfg.trialdef, 'eventvalue') && length(cfg.trialdef.eventvalue)==1 && strcmp(cfg.trialdef.eventvalue, 'gui')) + elseif isequal(cfg.trialdef.eventtype, 'gui') || (isfield(cfg.trialdef, 'eventvalue') && length(cfg.trialdef.eventvalue)==1 && strcmp(cfg.trialdef.eventvalue, 'gui')) cfg.trialdef = select_event(event, cfg.trialdef); usegui = 1; else @@ -162,12 +162,12 @@ % values are missing tries to ask the user for prestim/poststim answer = inputdlg({'Prestimulus latency (sec)','Poststimulus latency (sec)'}, 'Enter borders'); if isempty(answer) || any(cellfun('isempty', answer)) - error('The information in the data and cfg is insufficient to define trials.'); + ft_error('The information in the data and cfg is insufficient to define trials.'); else cfg.trialdef.prestim=str2double(answer{1}); cfg.trialdef.poststim=str2double(answer{2}); if isnan(cfg.trialdef.prestim) || isnan(cfg.trialdef.poststim) - error('Illegal input for trial borders'); + ft_error('Illegal input for trial borders'); end end end % if specification is not complete @@ -237,7 +237,7 @@ indx = select_channel_list(eventstrings, selected , 'Select events'); - trl=trl(indx, :); + trl = trl(indx, :); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -245,15 +245,15 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function show_event(event) if isempty(event) - fprintf('no events were found in the datafile\n'); + ft_info('no events were found in the datafile\n'); return end eventtype = unique({event.type}); Neventtype = length(eventtype); if Neventtype==0 - fprintf('no events were found in the datafile\n'); + ft_info('no events were found in the datafile\n'); else - fprintf('the following events were found in the datafile\n'); + ft_info('the following events were found in the datafile\n'); for i=1:Neventtype sel = find(strcmp(eventtype{i}, {event.type})); try @@ -263,9 +263,9 @@ function show_event(event) eventvalue = unique(cell2mat({event(sel).value})); % array with numeric values or empty eventvalue = num2str(eventvalue); % translate into a single string end - fprintf('event type: ''%s'' ', eventtype{i}); - fprintf('with event values: %s', eventvalue); - fprintf('\n'); + ft_info('event type: ''%s'' ', eventtype{i}); + ft_info('with event values: %s', eventvalue); + ft_info('\n'); end end @@ -274,7 +274,7 @@ function show_event(event) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function trialdef = select_event(event, trialdef) if isempty(event) - fprintf('no events were found in the datafile\n'); + ft_info('no events were found in the datafile\n'); return end if strcmp(trialdef.eventtype, 'gui') @@ -284,7 +284,7 @@ function show_event(event) end Neventtype = length(eventtype); if Neventtype==0 - fprintf('no events were found in the datafile\n'); + ft_info('no events were found in the datafile\n'); else % Two lists are built in parallel settings={}; % The list of actual values to be used later @@ -300,7 +300,7 @@ function show_event(event) else if ~isempty(find(strcmp('Inf', {event(sel).value}))) % It's a very unlikely scenario but ... - warning('Event value''Inf'' cannot be handled by GUI selection. Mistakes are possible.') + ft_warning('Event value''Inf'' cannot be handled by GUI selection. Mistakes are possible.') end [event(sel(emptyval)).value]=deal('Inf'); eventvalue = unique({event(sel).value}); @@ -324,7 +324,7 @@ function show_event(event) end end if isempty(strsettings) - fprintf('no events of the selected type were found in the datafile\n'); + ft_info('no events of the selected type were found in the datafile\n'); return end diff --git a/external/fieldtrip/trialfun/ft_trialfun_realtime.m b/external/fieldtrip/trialfun/ft_trialfun_realtime.m index aad01ad6..faeeb601 100644 --- a/external/fieldtrip/trialfun/ft_trialfun_realtime.m +++ b/external/fieldtrip/trialfun/ft_trialfun_realtime.m @@ -6,13 +6,12 @@ % % The configuration structure can contain the following specifications % cfg.minsample = the last sample number that was already considered (passed from rt_process) -% cfg.blocksize = in seconds. In case of events, offset is -% wrt the trigger. +% cfg.blocksize = in seconds. In case of events, offset is with respect to the trigger. % cfg.offset = the offset wrt the 0 point. In case of no events, offset is wrt % prevSample. E.g., [-0.9 1] will read 1 second blocks with % 0.9 second overlap % cfg.bufferdata = {'first' 'last'}. If 'last' then only the last block of -% interest is read. Otherwise, all well-defined blocks are read (default = 'first') +% interest is read. Otherwise, all well-defined blocks are read (default = 'first') % Copyright (C) 2009, Marcel van Gerven % diff --git a/external/fieldtrip/trialfun/ft_trialfun_trial.m b/external/fieldtrip/trialfun/ft_trialfun_trial.m index 21f5544f..339ad766 100644 --- a/external/fieldtrip/trialfun/ft_trialfun_trial.m +++ b/external/fieldtrip/trialfun/ft_trialfun_trial.m @@ -3,6 +3,13 @@ % FT_TRIALFUN_TRIAL creates a trial definition that corresponds to the % events that are returned by FT_READ_EVENT with type='trial' % +% You can use this function as follows +% cfg = []; +% cfg.dataset = string, containing filename or directory +% cfg.trialfun = 'ft_trialfun_trial'; +% cfg = definetrial(cfg); +% data = preprocessing(cfg); +% % See also FT_DEFINETRIAL, FT_PREPROCESSING % Copyright (C) 2012, Donders Centre for Cognitive Neuroimaging, Nijmegen, NL diff --git a/external/fieldtrip/trialfun/ft_trialfun_twoclass_classification.m b/external/fieldtrip/trialfun/ft_trialfun_twoclass_classification.m index 854b2fec..046cf5d2 100644 --- a/external/fieldtrip/trialfun/ft_trialfun_twoclass_classification.m +++ b/external/fieldtrip/trialfun/ft_trialfun_twoclass_classification.m @@ -9,12 +9,12 @@ % are marked as test items. % % This function can be used in conjunction with rt_classification and uses the options -% cfg.trialdef.numtrain = numberof training items, e.g. 20 +% cfg.trialdef.numtrain = number of training items, e.g. 20 % cfg.trialdef.eventvalue1 = trigger value for the 1st class % cfg.trialdef.eventvalue2 = trigger value for the 2nd class -% cfg.trialdef.eventtype = string, e.g. 'trigger' -% cfg.trialdef.prestim = latency in seconds, e.g. 0.3 -% cfg.trialdef.poststim = latency in seconds, e.g. 0.7 +% cfg.trialdef.eventtype = string, e.g. 'trigger' +% cfg.trialdef.prestim = latency in seconds, e.g. 0.3 +% cfg.trialdef.poststim = latency in seconds, e.g. 0.7 % Copyright (C) 2009, DCCN % diff --git a/external/fieldtrip/trialfun/private/defaultId.m b/external/fieldtrip/trialfun/private/defaultId.m new file mode 100644 index 00000000..f4e1ee99 --- /dev/null +++ b/external/fieldtrip/trialfun/private/defaultId.m @@ -0,0 +1,57 @@ +function id = defaultId + +% DEFAULTID returns a string that can serve as warning or error identifier, +% for example 'FieldTip:ft_read_header:line345'. +% +% See also WARNING, ERROR, FT_NOTICE, FT_INFO, FT_DEBUG + +% Copyright (C) 2017, Robert Oostenveld +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +stack = dbstack('-completenames'); + +% remove the functions that pertain to the notification system itself +keep = true(size(stack)); +keep(strcmp({stack.name}, 'defaultId')) = false; % this function itself +keep(strcmp({stack.name}, 'ft_notification')) = false; % this one is doing the work underneath ft_error/ft_warning/ft_notice/etc. +keep(strcmp({stack.name}, 'ft_error')) = false; +keep(strcmp({stack.name}, 'ft_warning')) = false; +keep(strcmp({stack.name}, 'ft_notice')) = false; +keep(strcmp({stack.name}, 'ft_info')) = false; +keep(strcmp({stack.name}, 'ft_debug')) = false; +stack = stack(keep); + +% remove the non-FieldTrip functions from the path, these should not be part of the default message identifier +keep = true(size(stack)); +[v, p] = ft_version; +for i=1:numel(stack) + keep(i) = strncmp(p, stack(i).file, length(p)); +end +stack = stack(keep); + +if ~isempty(stack) + % it is called from within a function + stack = flipud(stack); + name = {stack.name}; + id = ['FieldTrip' sprintf(':%s', name{:}) ':line' num2str(stack(end).line)]; +else + % it is called from the command line + id = 'FieldTrip:commandline'; +end diff --git a/external/fieldtrip/trialfun/private/select_channel_list.m b/external/fieldtrip/trialfun/private/select_channel_list.m index abc48ab9..721b6223 100644 --- a/external/fieldtrip/trialfun/private/select_channel_list.m +++ b/external/fieldtrip/trialfun/private/select_channel_list.m @@ -81,14 +81,14 @@ function label_redraw(h) % set the active element in the select listbox, based on the previous active element tmp = min(get(findobj(h, 'tag', 'lbsel'), 'value')); tmp = min(tmp, length(get(findobj(h, 'tag', 'lbsel'), 'string'))); -if isempty(tmp) | tmp==0 +if isempty(tmp) || tmp==0 tmp = 1; end set(findobj(h, 'tag', 'lbsel' ), 'value', tmp); % set the active element in the unselect listbox, based on the previous active element tmp = min(get(findobj(h, 'tag', 'lbunsel'), 'value')); tmp = min(tmp, length(get(findobj(h, 'tag', 'lbunsel'), 'string'))); -if isempty(tmp) | tmp==0 +if isempty(tmp) || tmp==0 tmp = 1; end set(findobj(h, 'tag', 'lbunsel' ), 'value', tmp); diff --git a/external/fieldtrip/utilities/appendstruct.m b/external/fieldtrip/utilities/appendstruct.m index a942ced9..4e1be25b 100644 --- a/external/fieldtrip/utilities/appendstruct.m +++ b/external/fieldtrip/utilities/appendstruct.m @@ -1,16 +1,16 @@ -function [s1] = appendstruct(s1, s2) +function s1 = appendstruct(varargin) % APPENDSTRUCT appends a structure to a structure or struct-array. % It also works if the initial structure is an empty structure or -% an empty double array. +% an empty double array. It also works if the input structures have +% different fields. % % Use as -% a = appendstruct(a, b) -% which appends b to a. +% ab = appendstruct(a, b) % % See also PRINTSTRUCT, COPYFIELDS, KEEPFIELDS, REMOVEFIELDS -% Copyright (C) 2015, Robert Oostenveld +% Copyright (C) 2015-2017, Robert Oostenveld % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -30,11 +30,39 @@ % % $Id$ +% narginchk(2,inf); + +if nargin>2 + % use recursion to append a whole list of structures + s1 = varargin{1}; + for i=2:nargin + s2 = varargin{i}; + s1 = appendstruct(s1, s2); + end + return +else + s1 = varargin{1}; + s2 = varargin{2}; +end + assert(isstruct(s1) || isempty(s1), 'input argument 1 should be empty or a structure'); assert(isstruct(s2), 'input argument 2 should be a structure'); if isempty(s1) s1 = s2; elseif isstruct(s1) - s1(end+1) = s2; + fn1 = fieldnames(s1); + fn2 = fieldnames(s2); + % find the fields that are missing in either one + missing1 = setdiff(union(fn1, fn2), fn1); + missing2 = setdiff(union(fn1, fn2), fn2); + % add the missing fields + for i=1:numel(missing1) + s1(1).(missing1{i}) = []; + end + for i=1:numel(missing2) + s2(1).(missing2{i}) = []; + end + % concatenate the second structure to the first + s1 = cat(1,s1(:), s2(:)); end diff --git a/external/fieldtrip/utilities/copyfields.m b/external/fieldtrip/utilities/copyfields.m index 63b939b5..3e8eea3b 100644 --- a/external/fieldtrip/utilities/copyfields.m +++ b/external/fieldtrip/utilities/copyfields.m @@ -43,7 +43,7 @@ if ischar(fields) fields = {fields}; elseif ~iscell(fields) - error('fields input argument must be a cell array of strings or a single string'); + ft_error('fields input argument must be a cell array of strings or a single string'); end fields = intersect(fieldnames(a), fields); diff --git a/external/fieldtrip/utilities/ft_channelcombination.m b/external/fieldtrip/utilities/ft_channelcombination.m index 4cd3f9b9..6b975acd 100644 --- a/external/fieldtrip/utilities/ft_channelcombination.m +++ b/external/fieldtrip/utilities/ft_channelcombination.m @@ -68,7 +68,7 @@ % it should have a selection of two channels or channelgroups in each row if size(channelcmb,1)==2 && size(channelcmb,2)~=2 - warning('transposing channelcombination matrix'); + ft_warning('transposing channelcombination matrix'); channelcmb = channelcmb'; end @@ -104,7 +104,7 @@ case 2 channelcmb = [channelcmb; channelcmb(:,[2 1])]; otherwise - error('unknown value for input argument ''dirflag'''); + ft_error('unknown value for input argument ''dirflag'''); end collect = channelcmb; @@ -167,7 +167,7 @@ indx = [i1 i2]; otherwise - error('unknown value for input argument ''dirflag'''); + ft_error('unknown value for input argument ''dirflag'''); end collect = [datachannel(indx(:,1)) datachannel(indx(:,2))]; diff --git a/external/fieldtrip/utilities/ft_channelselection.m b/external/fieldtrip/utilities/ft_channelselection.m index 19649c42..e1ffdf8e 100644 --- a/external/fieldtrip/utilities/ft_channelselection.m +++ b/external/fieldtrip/utilities/ft_channelselection.m @@ -5,15 +5,12 @@ % labels as they occur in the data. This channel selection procedure can be % used throughout FieldTrip. % -% Use as: -% channel = ft_channelselection(desired, datachannel) -% % You can specify a mixture of real channel labels and of special strings, % or index numbers that will be replaced by the corresponding channel % labels. Channels that are not present in the raw datafile are % automatically removed from the channel list. % -% E.g. the desired input element can be: +% E.g. the desired input specification can be: % 'all' is replaced by all channels in the datafile % 'gui' this will pop up a graphical user interface to select the channels % 'C*' is replaced by all channels that match the wildcard, e.g. C1, C2, C3, ... @@ -21,9 +18,9 @@ % 'M*1' is replaced by all channels that match the wildcard, e.g. MEG0111, MEG0131, MEG0131, ... % 'meg' is replaced by all MEG channels (works for CTF, 4D, Neuromag and Yokogawa) % 'megref' is replaced by all MEG reference channels (works for CTF and 4D) -% 'meggrad' is replaced by all MEG gradiometer channels (works for Yokogawa and Neuromag-306) -% 'megplanar' is replaced by all MEG planar gradiometer channels (works for Neuromag-306) -% 'megmag' is replaced by all MEG magnetometer channels (works for Yokogawa and Neuromag-306) +% 'meggrad' is replaced by all MEG gradiometer channels (works for Yokogawa and Neuromag306) +% 'megplanar' is replaced by all MEG planar gradiometer channels (works for Neuromag306) +% 'megmag' is replaced by all MEG magnetometer channels (works for Yokogawa and Neuromag306) % 'eeg' is replaced by all recognized EEG channels (this is system dependent) % 'eeg1020' is replaced by 'Fp1', 'Fpz', 'Fp2', 'F7', 'F3', ... % 'eog' is replaced by all recognized EOG channels @@ -84,23 +81,31 @@ senstype = ft_senstype(datachannel); end -if ~iscell(datachannel) - if ischar(datachannel) - datachannel = {datachannel}; - else - error('please specify the data channels as a cell-array'); - end +% this will be specified further down +datachantype = []; + +if iscell(datachannel) + % this is the expected input +elseif ischar(datachannel) + datachannel = {datachannel}; +elseif isstruct(datachannel) && isfield(datachannel, 'label') + % it looks like a header structure + hdr = datachannel; + datachannel = hdr.label; + datachantype = ft_chantype(hdr); +else + ft_error('please specify the data channels as a cell-array'); end if ~ischar(desired) && ~isnumeric(desired) && ~iscell(desired) - error('please specify the desired channels as a cell-array or a string'); + ft_error('please specify the desired channels as a cell-array or a string'); end % start with the list of desired channels, this will be pruned/expanded channel = desired; if length(datachannel)~=length(unique(datachannel)) - warning('discarding non-unique channel names'); + ft_warning('discarding non-unique channel names'); sel = false(size(datachannel)); for i=1:length(datachannel) sel(i) = sum(strcmp(datachannel, datachannel{i}))==1; @@ -113,11 +118,6 @@ return end -if ~iscell(datachannel) - % ensure that a single input argument like 'all' also works - datachannel = {datachannel}; -end - if isnumeric(channel) % remove channels tha fall outside the range channel = channel(channel>=1 & channel<=numel(datachannel)); @@ -172,15 +172,15 @@ findreg = []; for i=1:length(channel) if length(channel{i}) < 1 - continue; + continue; end - + if strcmp((channel{i}(1)), '-') % skip channels to be excluded continue; end - - rexp = sprintf('%s%s', regexptranslate('wildcard',channel{i}), '$'); + + rexp = sprintf('%s%s%s', '^', regexptranslate('wildcard',channel{i}), '$'); lreg = ~cellfun(@isempty, regexp(datachannel, rexp)); if any(lreg) labelreg = labelreg | lreg; @@ -202,7 +202,7 @@ labeleeg = []; switch senstype - + case {'yokogawa', 'yokogawa160', 'yokogawa160_planar', 'yokogawa64', 'yokogawa64_planar', 'yokogawa440', 'yokogawa440_planar'} % Yokogawa axial gradiometers channels start with AG, hardware planar gradiometer % channels start with PG, magnetometers start with M @@ -213,7 +213,7 @@ labelmeg = datachannel(megind); labelmegmag = datachannel(megmag); labelmeggrad = datachannel(megax | megpl); - + case {'ctf64'} labelml = datachannel(~cellfun(@isempty, regexp(datachannel, '^SL'))); % left MEG channels labelmr = datachannel(~cellfun(@isempty, regexp(datachannel, '^SR'))); % right MEG channels @@ -223,7 +223,7 @@ datachannel(strncmp('P' , datachannel, 1)); datachannel(strncmp('Q' , datachannel, 1)); datachannel(strncmp('R' , datachannel, length('G' )))]; - + case {'ctf', 'ctf275', 'ctf151', 'ctf275_planar', 'ctf151_planar'} % all CTF MEG channels start with "M" % all CTF reference channels start with B, G, P, Q or R @@ -235,7 +235,7 @@ datachannel(strncmp('Q' , datachannel, 1)); datachannel(strncmp('R' , datachannel, length('G' )))]; labeleeg = datachannel(strncmp('EEG', datachannel, length('EEG'))); - + % Not sure whether this should be here or outside the switch or % whether these specifications should be supported for systems % other than CTF. @@ -256,11 +256,11 @@ labelmzf = datachannel(strncmp('MZF', datachannel, length('MZF'))); labelmzo = datachannel(strncmp('MZO', datachannel, length('MZO'))); labelmzp = datachannel(strncmp('MZP', datachannel, length('MZP'))); - + case {'bti', 'bti248', 'bti248grad', 'bti148', 'bti248_planar', 'bti148_planar'} % all 4D-BTi MEG channels start with "A" % all 4D-BTi reference channels start with M or G - + labelmeg = datachannel(myregexp('^A[0-9]+$', datachannel)); labelmegref = [datachannel(myregexp('^M[CLR][xyz][aA]*$', datachannel)); datachannel(myregexp('^G[xyz][xyz]A$', datachannel)); datachannel(myregexp('^M[xyz][aA]*$', datachannel))]; labelmegrefa = datachannel(~cellfun(@isempty,strfind(datachannel, 'a'))); @@ -269,33 +269,41 @@ labelmegrefl = datachannel(strncmp('ML', datachannel, 2)); labelmegrefr = datachannel(strncmp('MR', datachannel, 2)); labelmegrefm = datachannel(myregexp('^M[xyz][aA]*$', datachannel)); - + case {'neuromag122' 'neuromag122alt', 'neuromag122_combined'} % all neuromag MEG channels start with MEG % all neuromag EEG channels start with EEG labelmeg = datachannel(strncmp('MEG', datachannel, length('MEG'))); labeleeg = datachannel(strncmp('EEG', datachannel, length('EEG'))); - + case {'neuromag306' 'neuromag306alt', 'neuromag306_combined'} % all neuromag MEG channels start with MEG % all neuromag EEG channels start with EEG - % all neuromag-306 gradiometers follow pattern MEG*2,MEG*3 - % all neuromag-306 magnetometers follow pattern MEG*1 + % all neuromag306 gradiometers follow pattern MEG*2,MEG*3 + % all neuromag306 magnetometers follow pattern MEG*1 labelmeg = datachannel(strncmp('MEG', datachannel, length('MEG'))); labeleeg = datachannel(strncmp('EEG', datachannel, length('EEG'))); - + labelmeggrad = labelmeg(~cellfun(@isempty, regexp(labelmeg, '^MEG.*[23]$'))); labelmegmag = labelmeg(~cellfun(@isempty, regexp(labelmeg, '^MEG.*1$'))); labelmegplanar = labelmeggrad; - + case {'ant128', 'biosemi64', 'biosemi128', 'biosemi256', 'egi32', 'egi64', 'egi128', 'egi256', 'eeg1020', 'eeg1010', 'eeg1005', 'ext1020'} - % use an external helper function to define the list with EEG channel names - labeleeg = ft_senslabel(ft_senstype(datachannel)); - - case {'itab153'} + if ~ft_senstype(datachannel, 'unknown') + % use an external helper function to define the list with EEG channel names + labeleeg = ft_senslabel(ft_senstype(datachannel)); + end + + case {'itab153' 'itab28' 'itab28_old'} % all itab MEG channels start with MAG labelmeg = datachannel(strncmp('MAG', datachannel, length('MAG'))); - + + otherwise + if ~isempty(datachantype) + labelmeg = datachannel(strncmp('meg', datachantype, 3)); + labeleeg = datachannel(strncmp('eeg', datachantype, 3)); + end + end % switch ft_senstype % figure out if there are bad channels or channel groups that should be excluded diff --git a/external/fieldtrip/utilities/ft_checkconfig.m b/external/fieldtrip/utilities/ft_checkconfig.m index c3abf412..fd4853f3 100644 --- a/external/fieldtrip/utilities/ft_checkconfig.m +++ b/external/fieldtrip/utilities/ft_checkconfig.m @@ -80,6 +80,13 @@ trackconfig = ft_getopt(varargin, 'trackconfig'); if ~isempty(trackconfig) && strcmp(trackconfig, 'on') + if ft_platform_supports('matlabversion', '2015a', inf) + % disable config tracking for the time being, due to a known bug (3187) + % ft_warning('disabling cfg tracking for the time being, due to a matlab version related issue'); + trackconfig = []; + cfg.trackconfig = 'off'; + end + % infer from the user configuration whether tracking should be enabled if isfield(cfg, 'trackconfig') && (strcmp(cfg.trackconfig, 'report') || strcmp(cfg.trackconfig, 'cleanup')) trackconfig = 'on'; % turn on configtracking if user requests report/cleanup @@ -115,9 +122,9 @@ if silent % don't mention it elseif loose - warning('use cfg.%s instead of cfg.%s', renamed{2}, renamed{1}); + ft_warning('use cfg.%s instead of cfg.%s', renamed{2}, renamed{1}); elseif pedantic - error('use cfg.%s instead of cfg.%s', renamed{2}, renamed{1}); + ft_error('use cfg.%s instead of cfg.%s', renamed{2}, renamed{1}); end end end @@ -131,9 +138,9 @@ if silent % don't mention it elseif loose - warning('use cfg.%s=''%s'' instead of cfg.%s=''%s''', renamedval{1}, renamedval{3}, renamedval{1}, renamedval{2}); + ft_warning('use cfg.%s=''%s'' instead of cfg.%s=''%s''', renamedval{1}, renamedval{3}, renamedval{1}, renamedval{2}); elseif pedantic - error('use cfg.%s=''%s'' instead of cfg.%s=''%s''', renamedval{1}, renamedval{3}, renamedval{1}, renamedval{2}); + ft_error('use cfg.%s=''%s'' instead of cfg.%s=''%s''', renamedval{1}, renamedval{3}, renamedval{1}, renamedval{2}); end end end @@ -145,7 +152,7 @@ fieldsused = fieldnames(cfg); [c, ia, ib] = setxor(required, fieldsused); if ~isempty(ia) - error('The field cfg.%s is required\n', required{ia}); + ft_error('The field cfg.%s is required\n', required{ia}); end end @@ -158,9 +165,9 @@ if silent % don't mention it elseif loose - warning('The option cfg.%s is deprecated, support is no longer guaranteed\n', deprecated{ismember(deprecated, fieldsused)}); + ft_warning('The option cfg.%s is deprecated, support is no longer guaranteed\n', deprecated{ismember(deprecated, fieldsused)}); elseif pedantic - error('The option cfg.%s is not longer supported\n', deprecated{ismember(deprecated, fieldsused)}); + ft_error('The option cfg.%s is not longer supported\n', deprecated{ismember(deprecated, fieldsused)}); end end end @@ -175,9 +182,9 @@ if silent % don't mention it elseif loose - warning('The field cfg.%s is unused, it will be removed from your configuration\n', unused{ismember(unused, fieldsused)}); + ft_warning('The field cfg.%s is unused, it will be removed from your configuration\n', unused{ismember(unused, fieldsused)}); elseif pedantic - error('The field cfg.%s is unused\n', unused{ismember(unused, fieldsused)}); + ft_error('The field cfg.%s is unused\n', unused{ismember(unused, fieldsused)}); end end end @@ -191,7 +198,7 @@ fieldsused = fieldnames(cfg); [c, i] = setdiff(fieldsused, allowed); if ~isempty(c) - error('The field cfg.%s is not allowed\n', c{1}); + ft_error('The field cfg.%s is not allowed\n', c{1}); end end @@ -205,9 +212,9 @@ if silent % don't mention it elseif loose - warning('The field cfg.%s is forbidden, it will be removed from your configuration\n', forbidden{ismember(forbidden, fieldsused)}); + ft_warning('The field cfg.%s is forbidden, it will be removed from your configuration\n', forbidden{ismember(forbidden, fieldsused)}); elseif pedantic - error('The field cfg.%s is forbidden\n', forbidden{ismember(forbidden, fieldsused)}); + ft_error('The field cfg.%s is forbidden\n', forbidden{ismember(forbidden, fieldsused)}); end end end @@ -222,27 +229,36 @@ s = [s allowedval{k} ', ']; end s = s(1:end-2); % strip last comma - error(s); + ft_error(s); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% backward compatibility for the gradiometer and electrode definition +% backward compatibility for gradiometer, electrode and optode definitions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% if isfield(cfg, 'grad') && ~isempty(cfg.grad) - cfg.grad = ft_datatype_sens(cfg.grad); + cfg.grad = ft_datatype_sens(struct(cfg.grad)); +end +if isfield(cfg, 'elec') && ~isempty(cfg.elec) + cfg.elec = ft_datatype_sens(struct(cfg.elec)); end -if isfield(cfg, 'elec')&& ~isempty(cfg.elec) - cfg.elec = ft_datatype_sens(cfg.elec); +if isfield(cfg, 'opto') && ~isempty(cfg.opto) + cfg.opto = ft_datatype_sens(struct(cfg.opto)); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% backward compatibility for old neighbourstructures +% backward compatibility for neighbour structures %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% if isfield(cfg, 'neighbours') && iscell(cfg.neighbours) - warning('cfg.neighbours is in the old format - converting it to a structure array'); cfg.neighbours = fixneighbours(cfg.neighbours); end +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% backward compatibility for montage +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +if isfield(cfg, 'montage') && isstruct(cfg.montage) + cfg.montage = fixoldorg(cfg.montage); +end + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % createsubcfg % @@ -255,7 +271,7 @@ if ~isempty(createsubcfg) for j=1:length(createsubcfg) subname = createsubcfg{j}; - + if isfield(cfg, subname) % get the options that are already specified in the substructure subcfg = cfg.(subname); @@ -263,7 +279,7 @@ % start with an empty substructure subcfg = []; end - + % add all other relevant options to the substructure switch subname case 'preproc' @@ -305,7 +321,7 @@ 'boxcar' 'absdiff' }; - + case 'grid' fieldname = { 'xgrid' @@ -321,7 +337,7 @@ 'dim' 'tight' }; - + case 'dics' fieldname = { 'feedback' @@ -339,7 +355,7 @@ 'realfilter' 'subspace' }; - + case 'eloreta' fieldname = { 'keepfilter' @@ -349,7 +365,7 @@ 'normalizeparam' 'reducerank' }; - + case 'sloreta' fieldname = { 'feedback' @@ -367,7 +383,7 @@ 'reducerank' 'subspace' }; - + case 'lcmv' fieldname = { 'feedback' @@ -385,7 +401,7 @@ 'reducerank' 'subspace' }; - + case 'pcc' fieldname = { 'feedback' @@ -401,13 +417,13 @@ 'realfilter' 'fixedori' }; - + case 'rv' fieldname = { 'feedback' 'lambda' }; - + case 'mne' fieldname = { 'feedback' @@ -431,13 +447,13 @@ 'connected_components' 'number_harmonics' }; - + case 'music' fieldname = { 'feedback' 'numcomponent' }; - + case 'sam' fieldname = { 'meansphereorigin' @@ -448,11 +464,11 @@ 'normalize' 'normalizeparam' }; - + case 'mvl' fieldname = {}; - - case {'npsf', 'granger' 'pdc' 'dtf'} + + case {'npsf', 'granger' 'pdc' 'dtf' 'gpdc' 'ddtf'} % non-parametric spectral factorization -> csd2transfer fieldname = { 'block' @@ -464,30 +480,30 @@ 'svd' 'init' 'checkconvergence' + 'stabilityfix' }; - + otherwise - error('unexpected name of the subfunction'); - fieldname = {}; - + ft_error('unexpected name of the subfunction'); + end % switch subname - + for i=1:length(fieldname) if ~isfield(subcfg, fieldname{i}) && isfield(cfg, fieldname{i}) - + if silent % don't mention it elseif loose - warning('The field cfg.%s is deprecated, please specify it as cfg.%s.%s instead of cfg.%s', fieldname{i}, subname, fieldname{i}); + ft_warning('The field cfg.%s is deprecated, pleae use cfg.%s.%s\n', fieldname{i}, subname, fieldname{i}); elseif pedantic - error('The field cfg.%s is not longer supported, use cfg.%s.%s instead\n', fieldname{i}, subname, fieldname{i}); + ft_error('The field cfg.%s is not longer supported, please use cfg.%s.%s\n', fieldname{i}, subname, fieldname{i}); end - + subcfg = setfield(subcfg, fieldname{i}, getfield(cfg, fieldname{i})); % set it in the subconfiguration cfg = rmfield(cfg, fieldname{i}); % remove it from the main configuration end end - + % copy the substructure back into the main configuration structure cfg = setfield(cfg, subname, subcfg); end @@ -518,7 +534,7 @@ % Converts cfg.dataset into cfg.headerfile and cfg.datafile if neccessary. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% if istrue(checkfilenames) - + % start with empty fields if they are not present if ~isfield(cfg, 'dataset') cfg.dataset = []; @@ -529,16 +545,16 @@ if ~isfield(cfg, 'headerfile') cfg.headerfile = []; end - + if ~isempty(cfg.dataset) % the dataset is an abstract concept and might relate to a file, a % constellation of fioles or a directory containing multiple files - + if isequal(cfg.dataset, 'gui') || isequal(cfg.dataset, 'uigetfile') % display a graphical file selection dialog [f, p] = uigetfile('*.*', 'Select a data file'); if isequal(f, 0) - error('User pressed cancel'); + ft_error('User pressed cancel'); else d = fullfile(p, f); end @@ -547,36 +563,36 @@ % display a graphical directory selection dialog d = uigetdir('*.*', 'Select a data directory'); if isequal(d, 0) - error('User pressed cancel'); + ft_error('User pressed cancel'); end cfg.dataset = d; end - + % ensure that the headerfile and datafile are defined, which are sometimes different than the name of the dataset % this requires correct autodetection of the format of the data set [cfg.dataset, cfg.headerfile, cfg.datafile] = dataset2files(cfg.dataset, []); - + elseif ~isempty(cfg.datafile) && isempty(cfg.headerfile); % assume that the datafile also contains the header information cfg.dataset = cfg.datafile; cfg.headerfile = cfg.datafile; - + elseif isempty(cfg.datafile) && ~isempty(cfg.headerfile); % assume that the headerfile also contains the data cfg.dataset = cfg.headerfile; cfg.datafile = cfg.headerfile; end - + % fill dataformat if unspecified, doing this only once saves time later if ~isfield(cfg,'dataformat') || isempty(cfg.dataformat) cfg.dataformat = ft_filetype(cfg.datafile); end - + % fill headerformat if unspecified, doing this only once saves time later if ~isfield(cfg,'headerformat') || isempty(cfg.headerformat) cfg.headerformat = ft_filetype(cfg.headerfile); end - + % remove empty fields, otherwise a subsequent check on required fields doesn't make any sense if isempty(cfg.dataset), cfg = rmfield(cfg, 'dataset'); end if isempty(cfg.headerfile), cfg = rmfield(cfg, 'headerfile'); end @@ -601,33 +617,33 @@ cfg = access(cfg, 'set', 'counter', access(cfg, 'get', 'counter')+1); % count the 'ONs' end end - + if strcmp(trackconfig, 'off') && isa(cfg, 'config') % turn OFF configuration tracking, optionally give report and/or cleanup cfg = access(cfg, 'set', 'counter', access(cfg, 'get', 'counter')-1); % count(down) the 'OFFs' - + if access(cfg, 'get', 'counter')==0 % only proceed when number of 'ONs' matches number of 'OFFs' - + if strcmp(cfg.trackconfig, 'report') || strcmp(cfg.trackconfig, 'cleanup') % gather information about the tracked results r = access(cfg, 'reference'); o = access(cfg, 'original'); - + % this uses a helper function to identify the fields that should be ignored key = fieldnames(cfg); key = key(:)'; skipsel = match_str(key, ignorefields('trackconfig')); key(skipsel) = []; - + used = zeros(size(key)); original = zeros(size(key)); - + for i=1:length(key) used(i) = (r.(key{i})>0); original(i) = (o.(key{i})>0); end - + if ~silent % give report on screen fprintf('\nThe following config fields were specified by YOU and were USED\n'); @@ -637,7 +653,7 @@ else fprintf(' \n'); end - + fprintf('\nThe following config fields were specified by YOU and were NOT USED\n'); sel = find(~used & original); if numel(sel) @@ -645,7 +661,7 @@ else fprintf(' \n'); end - + fprintf('\nThe following config fields were set to DEFAULTS and were USED\n'); sel = find(used & ~original); if numel(sel) @@ -653,7 +669,7 @@ else fprintf(' \n'); end - + fprintf('\nThe following config fields were set to DEFAULTS and were NOT USED\n'); sel = find(~used & ~original); if numel(sel) @@ -663,7 +679,7 @@ end end % report end % report/cleanup - + if strcmp(cfg.trackconfig, 'cleanup') % remove the unused options from the configuration unusedkey = key(~used); @@ -671,12 +687,12 @@ cfg = rmfield(cfg, unusedkey{i}); end end - + % convert the configuration back to a struct cfg = struct(cfg); end end % off - + catch disp(lasterr); end @@ -703,16 +719,16 @@ end % these fields should not be handled recursively -norecursion = {'event', 'headmodel', 'leadfield'}; +norecursion = {'event', 'headmodel', 'leadfield'}; fieldsorig = fieldnames(cfg); for i=1:numel(fieldsorig) for k=1:numel(cfg) % process each structure in a struct-array - + if any(strcmp(fieldsorig{i}, ignorefields('checksize'))) % keep this field, regardless of its size continue - + elseif iscell(cfg(k).(fieldsorig{i})) % run recursively on each struct element that is contained in the cell-array for j=1:numel(cfg(k).(fieldsorig{i})) @@ -720,11 +736,11 @@ cfg(k).(fieldsorig{i}){j} = checksizefun(cfg(k).(fieldsorig{i}){j}, max_size); end end - + elseif isstruct(cfg(k).(fieldsorig{i})) && ~any(strcmp(fieldsorig{i}, norecursion)) % run recursively on a struct field cfg(k).(fieldsorig{i}) = checksizefun(cfg(k).(fieldsorig{i}), max_size); - + else % determine the size of the field and remove it if too large temp = cfg(k).(fieldsorig{i}); @@ -733,7 +749,7 @@ cfg(k).(fieldsorig{i}) = 'empty - this was cleared by checkconfig'; end clear temp - + end end % for numel(cfg) end % for each of the fieldsorig @@ -744,6 +760,6 @@ function [newNeighbours] = fixneighbours(neighbours) newNeighbours = struct; for i=1:numel(neighbours) - if i==1, newNeighbours = neighbours{i}; end; + if i==1, newNeighbours = neighbours{i}; end newNeighbours(i) = neighbours{i}; end diff --git a/external/fieldtrip/utilities/ft_checkdata.m b/external/fieldtrip/utilities/ft_checkdata.m index ac130dee..d0ee2d49 100644 --- a/external/fieldtrip/utilities/ft_checkdata.m +++ b/external/fieldtrip/utilities/ft_checkdata.m @@ -1,25 +1,25 @@ function [data] = ft_checkdata(data, varargin) -% FT_CHECKDATA checks the input data of the main FieldTrip functions, e.g. whether -% the type of data strucure corresponds with the required data. If neccessary -% and possible, this function will adjust the data structure to the input -% requirements (e.g. change dimord, average over trials, convert inside from -% index into logical). +% FT_CHECKDATA checks the input data of the main FieldTrip functions, e.g. whether the +% type of data strucure corresponds with the required data. If neccessary and possible, +% this function will adjust the data structure to the input requirements (e.g. change +% dimord, average over trials, convert inside from index into logical). % -% If the input data does NOT correspond to the requirements, this function -% is supposed to give a elaborate warning message and if applicable point -% the user to external documentation (link to website). +% If the input data does NOT correspond to the requirements, this function will give a +% warning message and if applicable point the user to external documentation (link to +% website). % % Use as % [data] = ft_checkdata(data, ...) % % Optional input arguments should be specified as key-value pairs and can include % feedback = yes, no -% datatype = raw, freq, timelock, comp, spike, source, dip, volume, segmentation, parcellation +% datatype = raw, freq, timelock, comp, spike, source, mesh, dip, volume, segmentation, parcellation % dimord = any combination of time, freq, chan, refchan, rpt, subj, chancmb, rpttap, pos % senstype = ctf151, ctf275, ctf151_planar, ctf275_planar, neuromag122, neuromag306, bti148, bti248, bti248_planar, magnetometer, electrode % inside = logical, index % ismeg = yes, no +% iseeg = yes, no % isnirs = yes, no % hasunit = yes, no % hascoordsys = yes, no @@ -36,6 +36,8 @@ % For some options you can specify multiple values, e.g. % [data] = ft_checkdata(data, 'senstype', {'ctf151', 'ctf275'}), e.g. in megrealign % [data] = ft_checkdata(data, 'datatype', {'timelock', 'freq'}), e.g. in sourceanalysis +% +% See also FT_DATATYPE_XXX for each of the respective data types. % Copyright (C) 2007-2015, Robert Oostenveld % Copyright (C) 2010-2012, Martin Vinck @@ -66,6 +68,7 @@ % fixinside % fixprecision % fixvolume +% fixpos % data2raw % raw2data % grid2transform @@ -93,6 +96,7 @@ dimord = ft_getopt(varargin, 'dimord'); stype = ft_getopt(varargin, 'senstype'); % senstype is a function name which should not be masked ismeg = ft_getopt(varargin, 'ismeg'); +iseeg = ft_getopt(varargin, 'iseeg'); isnirs = ft_getopt(varargin, 'isnirs'); inside = ft_getopt(varargin, 'inside'); % can be 'logical' or 'index' hastrials = ft_getopt(varargin, 'hastrials'); @@ -112,12 +116,11 @@ % check whether people are using deprecated stuff depHastrialdef = ft_getopt(varargin, 'hastrialdef'); if (~isempty(depHastrialdef)) - ft_warning('ft_checkdata option ''hastrialdef'' is deprecated; use ''hassampleinfo'' instead'); + ft_warning('ft_checkdata option ''hastrialdef'' is deprecated; please use ''hassampleinfo'' instead'); hassampleinfo = depHastrialdef; end % determine the type of input data -% this can be raw, freq, timelock, comp, spike, source, volume, dip israw = ft_datatype(data, 'raw'); isfreq = ft_datatype(data, 'freq'); istimelock = ft_datatype(data, 'timelock'); @@ -134,46 +137,71 @@ ismesh = ft_datatype(data, 'mesh'); % FIXME use the istrue function on ismeg and hasxxx options -if ~isequal(feedback, 'no') +if ~isequal(feedback, 'no') % can be 'yes' or 'text' if iscomp % it can be comp and raw/timelock/freq at the same time, therefore this has to go first nchan = size(data.topo,1); ncomp = size(data.topo,2); - fprintf('the input is component data with %d components and %d original channels\n', ncomp, nchan); - end + ft_info('the input is component data with %d components and %d original channels\n', ncomp, nchan); + end % if iscomp + + if ismesh + % it can be comp and source at the same time, therefore this has to go first + data = fixpos(data); + npos = 0; + ntri = 0; + nhex = 0; + ntet = 0; + % the data can contain multiple surfaces + for i=1:numel(data) + npos = npos+size(data.pos,1); + if isfield(data, 'tri'), ntri = ntri+size(data.tri,1); end + if isfield(data, 'hex'), nhex = nhex+size(data.hex,1); end + if isfield(data, 'tet'), ntet = ntet+size(data.tet,1); end + end + if isfield(data,'tri') + ft_info('the input is mesh data with %d vertices and %d triangles\n', npos, ntri); + elseif isfield(data,'hex') + ft_info('the input is mesh data with %d vertices and %d hexahedrons\n', npos, nhex); + elseif isfield(data,'tet') + ft_info('the input is mesh data with %d vertices and %d tetrahedrons\n', npos, ntet); + else + ft_info('the input is mesh data with %d vertices', npos); + end + end % if ismesh if israw nchan = length(data.label); ntrial = length(data.trial); - fprintf('the input is raw data with %d channels and %d trials\n', nchan, ntrial); + ft_info('the input is raw data with %d channels and %d trials\n', nchan, ntrial); elseif istimelock nchan = length(data.label); ntime = length(data.time); - fprintf('the input is timelock data with %d channels and %d timebins\n', nchan, ntime); + ft_info('the input is timelock data with %d channels and %d timebins\n', nchan, ntime); elseif isfreq if isfield(data, 'label') nchan = length(data.label); nfreq = length(data.freq); if isfield(data, 'time'), ntime = num2str(length(data.time)); else ntime = 'no'; end - fprintf('the input is freq data with %d channels, %d frequencybins and %s timebins\n', nchan, nfreq, ntime); + ft_info('the input is freq data with %d channels, %d frequencybins and %s timebins\n', nchan, nfreq, ntime); elseif isfield(data, 'labelcmb') nchan = length(data.labelcmb); nfreq = length(data.freq); if isfield(data, 'time'), ntime = num2str(length(data.time)); else ntime = 'no'; end - fprintf('the input is freq data with %d channel combinations, %d frequencybins and %s timebins\n', nchan, nfreq, ntime); + ft_info('the input is freq data with %d channel combinations, %d frequencybins and %s timebins\n', nchan, nfreq, ntime); else - error('cannot infer freq dimensions'); + ft_error('cannot infer freq dimensions'); end elseif isspike nchan = length(data.label); - fprintf('the input is spike data with %d channels\n', nchan); + ft_info('the input is spike data with %d channels\n', nchan); elseif isvolume if issegmentation subtype = 'segmented volume'; else subtype = 'volume'; end - fprintf('the input is %s data with dimensions [%d %d %d]\n', subtype, data.dim(1), data.dim(2), data.dim(3)); + ft_info('the input is %s data with dimensions [%d %d %d]\n', subtype, data.dim(1), data.dim(2), data.dim(3)); clear subtype elseif issource data = fixpos(data); % ensure that positions are in pos, not in pnt @@ -184,43 +212,26 @@ subtype = 'source'; end if isfield(data, 'dim') - fprintf('the input is %s data with %d brainordinates on a [%d %d %d] grid\n', subtype, nsource, data.dim(1), data.dim(2), data.dim(3)); - elseif isfield(data, 'tri') - fprintf('the input is %s data with %d vertex positions and %d triangles\n', subtype, nsource, size(data.tri, 1)); + ft_info('the input is %s data with %d brainordinates on a [%d %d %d] grid\n', subtype, nsource, data.dim(1), data.dim(2), data.dim(3)); else - fprintf('the input is %s data with %d brainordinates\n', subtype, nsource); + ft_info('the input is %s data with %d brainordinates\n', subtype, nsource); end clear subtype elseif isdip - fprintf('the input is dipole data\n'); + ft_info('the input is dipole data\n'); elseif ismvar - fprintf('the input is mvar data\n'); + ft_info('the input is mvar data\n'); elseif isfreqmvar - fprintf('the input is freqmvar data\n'); + ft_info('the input is freqmvar data\n'); elseif ischan nchan = length(data.label); if isfield(data, 'brainordinate') - fprintf('the input is parcellated data with %d parcels\n', nchan); + ft_info('the input is parcellated data with %d parcels\n', nchan); else - fprintf('the input is chan data with %d channels\n', nchan); + ft_info('the input is chan data with %d channels\n', nchan); end - end -elseif ismesh - data = fixpos(data); - if numel(data)==1 - if isfield(data,'tri') - fprintf('the input is mesh data with %d vertices and %d triangles\n', size(data.pos,1), size(data.tri,1)); - elseif isfield(data,'hex') - fprintf('the input is mesh data with %d vertices and %d hexahedrons\n', size(data.pos,1), size(data.hex,1)); - elseif isfield(data,'tet') - fprintf('the input is mesh data with %d vertices and %d tetrahedrons\n', size(data.pos,1), size(data.tet,1)); - else - fprintf('the input is mesh data with %d vertices', size(data.pos,1)); - end - else - fprintf('the input is mesh data multiple surfaces\n'); - end -end % give feedback + end % if israw etc. +end % give feedback if issource && isvolume % it should be either one or the other: the choice here is to represent it as volume description since that is simpler to handle @@ -270,6 +281,8 @@ okflag = okflag + (isfreq & iscomp); case 'timelock+comp' okflag = okflag + (istimelock & iscomp); + case 'source+mesh' + okflag = okflag + (issource & ismesh); case 'raw' okflag = okflag + (israw & ~iscomp); case 'freq' @@ -333,15 +346,24 @@ issource = 1; okflag = 1; elseif isequal(dtype(iCell), {'volume'}) && (ischan || istimelock || isfreq) - data = parcellated2source(data); - data = ft_datatype_volume(data); - ischan = 0; + if isfield(data, 'brainordinate') + data = parcellated2source(data); + data = ft_datatype_volume(data); + else + ft_error('cannot convert channel-level data to volumetric representation'); + end + ischan = 0; istimelock = 0; isfreq = 0; isvolume = 1; okflag = 1; elseif isequal(dtype(iCell), {'source'}) && (ischan || istimelock || isfreq) - data = parcellated2source(data); - data = ft_datatype_source(data); - ischan = 0; + if isfield(data, 'brainordinate') + data = parcellated2source(data); + data = ft_datatype_source(data); + else + data = chan2source(data); + data = ft_datatype_source(data); + end % converting channel data + ischan = 0; istimelock = 0; isfreq = 0; issource = 1; okflag = 1; elseif isequal(dtype(iCell), {'volume'}) && issource @@ -357,6 +379,13 @@ iscomp = 1; israw = 1; okflag = 1; + elseif isequal(dtype(iCell), {'timelock+comp'}) && israw && iscomp + data = raw2timelock(data); + data = ft_datatype_timelock(data); + istimelock = 1; + iscomp = 1; + israw = 0; + okflag = 1; elseif isequal(dtype(iCell), {'raw'}) && issource data = source2raw(data); data = ft_datatype_raw(data, 'hassampleinfo', hassampleinfo); @@ -373,19 +402,19 @@ istimelock = 0; israw = 1; okflag = 1; - elseif isequal(dtype(iCell), {'comp'}) && israw + elseif isequal(dtype(iCell), {'comp'}) && israw && iscomp data = keepfields(data, {'label', 'topo', 'topolabel', 'unmixing', 'elec', 'grad', 'cfg'}); % these are the only relevant fields data = ft_datatype_comp(data); israw = 0; iscomp = 1; okflag = 1; - elseif isequal(dtype(iCell), {'comp'}) && istimelock + elseif isequal(dtype(iCell), {'comp'}) && istimelock && iscomp data = keepfields(data, {'label', 'topo', 'topolabel', 'unmixing', 'elec', 'grad', 'cfg'}); % these are the only relevant fields data = ft_datatype_comp(data); istimelock = 0; iscomp = 1; okflag = 1; - elseif isequal(dtype(iCell), {'comp'}) && isfreq + elseif isequal(dtype(iCell), {'comp'}) && isfreq && iscomp data = keepfields(data, {'label', 'topo', 'topolabel', 'unmixing', 'elec', 'grad', 'cfg'}); % these are the only relevant fields data = ft_datatype_comp(data); isfreq = 0; @@ -469,13 +498,18 @@ if ~okflag % construct an error message - if length(dtype)>1 - str = sprintf('%s, ', dtype{1:(end-2)}); - str = sprintf('%s%s or %s', str, dtype{end-1}, dtype{end}); + typestr = printor(dtype, true); + helpfun = cell(size(dtype)); + for i=1:numel(dtype) + helpfun{i} = sprintf('ft_datatype_%s', dtype{i}); + end + helpfun = helpfun(cellfun(@exist, helpfun)>0); + if ~isempty(helpfun) + helpstr = printor(helpfun); + ft_error('This function requires %s data as input, see %s.', typestr, helpstr); else - str = dtype{1}; + ft_error('This function requires %s data as input.', typestr); end - error('This function requires %s data as input.', str); end % if okflag end @@ -492,13 +526,7 @@ if ~okflag % construct an error message - if length(dimord)>1 - str = sprintf('%s, ', dimord{1:(end-2)}); - str = sprintf('%s%s or %s', str, dimord{end-1}, dimord{end}); - else - str = dimord{1}; - end - error('This function requires data with a dimord of %s.', str); + ft_error('This function requires data with a dimord of %s.', printor(dimord, true)); end % if okflag end @@ -516,17 +544,14 @@ else okflag = 0; end + else + % the data does not contain a sensor array + okflag = 0; end if ~okflag % construct an error message - if length(stype)>1 - str = sprintf('%s, ', stype{1:(end-2)}); - str = sprintf('%s%s or %s', str, stype{end-1}, stype{end}); - else - str = stype{1}; - end - error('This function requires %s data as input, but you are giving %s data.', str, ft_senstype(data)); + ft_error('This function requires data with an %s sensor array.', printor(stype, true)); end % if okflag end @@ -538,9 +563,23 @@ end if ~okflag && isequal(ismeg, 'yes') - error('This function requires MEG data with a ''grad'' field'); + ft_error('This function requires MEG data with a ''grad'' field'); elseif ~okflag && isequal(ismeg, 'no') - error('This function should not be given MEG data with a ''grad'' field'); + ft_error('This function should not be given MEG data with a ''grad'' field'); + end % if okflag +end + +if ~isempty(iseeg) + if isequal(iseeg, 'yes') + okflag = isfield(data, 'grad'); + elseif isequal(iseeg, 'no') + okflag = ~isfield(data, 'grad'); + end + + if ~okflag && isequal(iseeg, 'yes') + ft_error('This function requires EEG data with an ''elec'' field'); + elseif ~okflag && isequal(iseeg, 'no') + ft_error('This function should not be given EEG data with an ''elec'' field'); end % if okflag end @@ -552,15 +591,15 @@ end if ~okflag && isequal(isnirs, 'yes') - error('This function requires NIRS data with an ''opto'' field'); + ft_error('This function requires NIRS data with an ''opto'' field'); elseif ~okflag && isequal(isnirs, 'no') - error('This function should not be given NIRS data with an ''opto'' field'); + ft_error('This function should not be given NIRS data with an ''opto'' field'); end % if okflag end if ~isempty(inside) if strcmp(inside, 'index') - warning('the indexed representation of inside/outside source locations is deprecated'); + ft_warning('the indexed representation of inside/outside source locations is deprecated'); end % TODO absorb the fixinside function into this code data = fixinside(data, inside); @@ -568,13 +607,13 @@ if ~okflag % construct an error message - error('This function requires data with an ''inside'' field.'); + ft_error('This function requires data with an ''inside'' field.'); end % if okflag end if istrue(hasunit) && ~isfield(data, 'unit') % calling convert_units with only the input data adds the units without converting - data = ft_convert_units(data); + data = ft_determine_units(data); end % if hasunit if istrue(hascoordsys) && ~isfield(data, 'coordsys') @@ -582,16 +621,23 @@ end % if hascoordsys if isequal(hastrials, 'yes') - okflag = isfield(data, 'trial'); - if ~okflag && isfield(data, 'dimord') + hasrpt = isfield(data, 'trial'); + if ~hasrpt && isfield(data, 'dimord') % instead look in the dimord for rpt or subj - okflag = ~isempty(strfind(data.dimord, 'rpt')) || ... + hasrpt = ~isempty(strfind(data.dimord, 'rpt')) || ... ~isempty(strfind(data.dimord, 'rpttap')) || ... ~isempty(strfind(data.dimord, 'subj')); end - if ~okflag - error('This function requires data with a ''trial'' field'); - end % if okflag + if ~hasrpt + ft_error('This function requires data with a ''trial'' field'); + end % if hasrpt +elseif isequal(hastrials, 'no') && istimelock + if ~isfield(data, 'avg') && (isfield(data, 'trial') || isfield(data, 'individual')) + % average on the fly + tmpcfg = []; + tmpcfg.keeptrials = 'no'; + data = ft_timelockanalysis(tmpcfg, data); + end end if strcmp(hasdim, 'yes') && ~isfield(data, 'dim') @@ -601,13 +647,13 @@ end % if hasdim if strcmp(hascumtapcnt, 'yes') && ~isfield(data, 'cumtapcnt') - error('This function requires data with a ''cumtapcnt'' field'); + ft_error('This function requires data with a ''cumtapcnt'' field'); elseif strcmp(hascumtapcnt, 'no') && isfield(data, 'cumtapcnt') data = rmfield(data, 'cumtapcnt'); end % if hascumtapcnt if strcmp(hasdof, 'yes') && ~isfield(data, 'dof') - error('This function requires data with a ''dof'' field'); + ft_error('This function requires data with a ''dof'' field'); elseif strcmp(hasdof, 'no') && isfield(data, 'dof') data = rmfield(data, 'dof'); end % if hasdof @@ -620,7 +666,7 @@ elseif isfreqmvar data = fixcsd(data, cmbrepresentation, channelcmb); else - error('This function requires data with a covariance, coherence or cross-spectrum'); + ft_error('This function requires data with a covariance, coherence or cross-spectrum'); end end % cmbrepresentation @@ -645,16 +691,16 @@ current = 'sparse'; end else - error('Could not determine the current representation of the covariance matrix'); + ft_error('Could not determine the current representation of the covariance matrix'); end if isequal(current, desired) % nothing to do elseif strcmp(current, 'full') && strcmp(desired, 'sparse') % FIXME should be implemented - error('not yet implemented'); + ft_error('not yet implemented'); elseif strcmp(current, 'sparse') && strcmp(desired, 'full') % FIXME should be implemented - error('not yet implemented'); + ft_error('not yet implemented'); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -680,7 +726,7 @@ elseif isfield(data, 'labelcmb') current = 'sparse'; else - error('Could not determine the current representation of the %s matrix', param); + ft_error('Could not determine the current representation of the %s matrix', param); end % first go from univariate fourier to the required bivariate representation @@ -689,7 +735,7 @@ elseif strcmp(current, 'fourier') && strcmp(desired, 'sparsewithpow') dimtok = tokenize(data.dimord, '_'); - if ~isempty(strmatch('rpttap', dimtok)), + if ~isempty(strmatch('rpttap', dimtok)) nrpt = size(data.cumtapcnt,1); flag = 0; else @@ -713,7 +759,7 @@ powspctrm = powspctrm./ntap; else % different amount of tapers - powspctrm = zeros(nrpt,nchan,nfrq,ntim)+i.*zeros(nrpt,nchan,nfrq,ntim); + powspctrm = zeros(nrpt,nchan,nfrq,ntim) + zeros(nrpt,nchan,nfrq,ntim)*1i; sumtapcnt = [0;cumsum(data.cumtapcnt(:))]; for p = 1:nrpt indx = (sumtapcnt(p)+1):sumtapcnt(p+1); @@ -723,14 +769,14 @@ end %create cross-spectra - if ~isempty(channelcmb), + if ~isempty(channelcmb) ncmb = size(channelcmb,1); cmbindx = zeros(ncmb,2); labelcmb = cell(ncmb,2); for k = 1:ncmb ch1 = find(strcmp(data.label, channelcmb(k,1))); ch2 = find(strcmp(data.label, channelcmb(k,2))); - if ~isempty(ch1) && ~isempty(ch2), + if ~isempty(ch1) && ~isempty(ch2) cmbindx(k,:) = [ch1 ch2]; labelcmb(k,:) = data.label([ch1 ch2])'; end @@ -757,17 +803,17 @@ end data.powspctrm = powspctrm; data = rmfield(data, 'fourierspctrm'); - if ntim>1, + if ntim>1 data.dimord = 'chan_freq_time'; else data.dimord = 'chan_freq'; end - if nrpt>1, + if nrpt>1 data.dimord = ['rpt_',data.dimord]; end - if flag, + if flag siz = size(data.powspctrm); data.powspctrm = reshape(data.powspctrm, [siz(2:end) 1]); if isfield(data, 'crsspctrm') @@ -777,9 +823,9 @@ end elseif strcmp(current, 'fourier') && strcmp(desired, 'sparse') - if isempty(channelcmb), error('no channel combinations are specified'); end + if isempty(channelcmb), ft_error('no channel combinations are specified'); end dimtok = tokenize(data.dimord, '_'); - if ~isempty(strmatch('rpttap', dimtok)), + if ~isempty(strmatch('rpttap', dimtok)) nrpt = size(data.cumtapcnt,1); flag = 0; else @@ -795,7 +841,7 @@ for k = 1:ncmb ch1 = find(strcmp(data.label, channelcmb(k,1))); ch2 = find(strcmp(data.label, channelcmb(k,2))); - if ~isempty(ch1) && ~isempty(ch2), + if ~isempty(ch1) && ~isempty(ch2) cmbindx(k,:) = [ch1 ch2]; labelcmb(k,:) = data.label([ch1 ch2])'; end @@ -844,20 +890,22 @@ data.labelcmb = labelcmb; data = rmfield(data, 'fourierspctrm'); data = rmfield(data, 'label'); - if ntim>1, + if ntim>1 data.dimord = 'chancmb_freq_time'; else data.dimord = 'chancmb_freq'; end - if nrpt>1, + if nrpt>1 data.dimord = ['rpt_',data.dimord]; end - if flag, - % deal with the singleton 'rpt', i.e. remove it - siz = size(data.powspctrm); - data.powspctrm = reshape(data.powspctrm, [siz(2:end) 1]); + if flag + if isfield(data,'powspctrm') + % deal with the singleton 'rpt', i.e. remove it + siz = size(data.powspctrm); + data.powspctrm = reshape(data.powspctrm, [siz(2:end) 1]); + end if isfield(data,'crsspctrm') % this conditional statement is needed in case there's a single channel siz = size(data.crsspctrm); @@ -868,7 +916,7 @@ % this is how it is currently and the desired functionality of prepare_freq_matrices dimtok = tokenize(data.dimord, '_'); - if ~isempty(strmatch('rpttap', dimtok)), + if ~isempty(strmatch('rpttap', dimtok)) nrpt = size(data.cumtapcnt, 1); flag = 0; else @@ -878,7 +926,7 @@ if ~isempty(strmatch('rpttap',dimtok)), nrpt=size(data.cumtapcnt, 1); else nrpt = 1; end if ~isempty(strmatch('freq', dimtok)), nfrq=length(data.freq); else nfrq = 1; end if ~isempty(strmatch('time', dimtok)), ntim=length(data.time); else ntim = 1; end - if any(data.cumtapcnt(1,:) ~= data.cumtapcnt(1,1)), error('this only works when all frequencies have the same number of tapers'); end + if any(data.cumtapcnt(1,:) ~= data.cumtapcnt(1,1)), ft_error('this only works when all frequencies have the same number of tapers'); end nchan = length(data.label); crsspctrm = zeros(nrpt,nchan,nchan,nfrq,ntim); sumtapcnt = [0;cumsum(data.cumtapcnt(:,1))]; @@ -933,10 +981,10 @@ data.dimord = 'chan_chan_freq'; end - if isfield(data, 'trialinfo'), data = rmfield(data, 'trialinfo'); end; - if isfield(data, 'sampleinfo'), data = rmfield(data, 'sampleinfo'); end; - if isfield(data, 'cumsumcnt'), data = rmfield(data, 'cumsumcnt'); end; - if isfield(data, 'cumtapcnt'), data = rmfield(data, 'cumtapcnt'); end; + if isfield(data, 'trialinfo'), data = rmfield(data, 'trialinfo'); end + if isfield(data, 'sampleinfo'), data = rmfield(data, 'sampleinfo'); end + if isfield(data, 'cumsumcnt'), data = rmfield(data, 'cumsumcnt'); end + if isfield(data, 'cumtapcnt'), data = rmfield(data, 'cumtapcnt'); end end % convert to the requested bivariate representation @@ -948,10 +996,10 @@ (strcmp(current, 'sparse') && strcmp(desired, 'fourier')) || ... (strcmp(current, 'sparsewithpow') && strcmp(desired, 'fourier')) % this is not possible - error('converting the cross-spectrum into a Fourier representation is not possible'); + ft_error('converting the cross-spectrum into a Fourier representation is not possible'); elseif strcmp(current, 'full') && strcmp(desired, 'sparsewithpow') - error('not yet implemented'); + ft_error('not yet implemented'); elseif strcmp(current, 'sparse') && strcmp(desired, 'sparsewithpow') % convert back to crsspctrm/powspctrm representation: useful for plotting functions etc @@ -996,8 +1044,8 @@ % reshape all possible fields fn = fieldnames(data); for ii=1:numel(fn) - if numel(data.(fn{ii})) == nrpt*ncmb*nfrq*ntim; - if nrpt>1, + if numel(data.(fn{ii})) == nrpt*ncmb*nfrq*ntim + if nrpt>1 data.(fn{ii}) = reshape(data.(fn{ii}), nrpt, ncmb, nfrq, ntim); else data.(fn{ii}) = reshape(data.(fn{ii}), ncmb, nfrq, ntim); @@ -1009,19 +1057,19 @@ try data = rmfield(data, 'dof'); end % replace updated fields data.labelcmb = labelcmb; - if ntim>1, + if ntim>1 data.dimord = 'chancmb_freq_time'; else data.dimord = 'chancmb_freq'; end - if nrpt>1, + if nrpt>1 data.dimord = ['rpt_',data.dimord]; end elseif strcmp(current, 'sparsewithpow') && strcmp(desired, 'sparse') % this representation for sparse data contains autospectra as e.g. {'A' 'A'} in labelcmb - if isfield(data, 'crsspctrm'), + if isfield(data, 'crsspctrm') dimtok = tokenize(data.dimord, '_'); catdim = match_str(dimtok, {'chan' 'chancmb'}); data.crsspctrm = cat(catdim, data.powspctrm, data.crsspctrm); @@ -1060,7 +1108,7 @@ for k = 1:size(data.labelcmb,1) ch1 = find(strcmp(data.label, data.labelcmb(k,1))); ch2 = find(strcmp(data.label, data.labelcmb(k,2))); - if ~isempty(ch1) && ~isempty(ch2), + if ~isempty(ch1) && ~isempty(ch2) cmbindx(ch1,ch2) = k; end end @@ -1074,8 +1122,8 @@ fn = fieldnames(data); for ii=1:numel(fn) - if numel(data.(fn{ii})) == nrpt*ncmb*nfrq*ntim; - if nrpt==1, + if numel(data.(fn{ii})) == nrpt*ncmb*nfrq*ntim + if nrpt==1 data.(fn{ii}) = reshape(data.(fn{ii}), [nrpt ncmb nfrq ntim]); end @@ -1099,7 +1147,7 @@ end % for j % replace the data in the old representation with the new representation - if nrpt>1, + if nrpt>1 data.(fn{ii}) = tmpall; else data.(fn{ii}) = reshape(tmpall, [nchan nchan nfrq ntim]); @@ -1107,13 +1155,13 @@ end % if numel end % for ii - if ntim>1, + if ntim>1 data.dimord = 'chan_chan_freq_time'; else data.dimord = 'chan_chan_freq'; end - if nrpt>1, + if nrpt>1 data.dimord = ['rpt_',data.dimord]; end @@ -1134,7 +1182,7 @@ for k = 1:size(data.labelcmb,1) ch1 = find(strcmp(data.label, data.labelcmb(k,1))); ch2 = find(strcmp(data.label, data.labelcmb(k,2))); - if ~isempty(ch1) && ~isempty(ch2), + if ~isempty(ch1) && ~isempty(ch2) cmbindx(ch1,ch2) = k; end end @@ -1143,8 +1191,8 @@ fn = fieldnames(data); for ii=1:numel(fn) - if numel(data.(fn{ii})) == nrpt*ncmb*nfrq*ntim; - if nrpt==1, + if numel(data.(fn{ii})) == nrpt*ncmb*nfrq*ntim + if nrpt==1 data.(fn{ii}) = reshape(data.(fn{ii}), [nrpt ncmb nfrq ntim]); end @@ -1166,7 +1214,7 @@ end % for k % replace the data in the old representation with the new representation - if nrpt>1, + if nrpt>1 data.(fn{ii}) = tmpall; else data.(fn{ii}) = reshape(tmpall, [nchan nchan nfrq ntim]); @@ -1179,15 +1227,14 @@ try data = rmfield(data, 'labelcmb'); end try data = rmfield(data, 'dof'); end - if ntim>1, + if ntim>1 data.dimord = 'chan_chan_freq_time'; else data.dimord = 'chan_chan_freq'; end elseif strcmp(current, 'sparsewithpow') && any(strcmp(desired, {'full', 'fullfast'})) - % recursively call ft_checkdata, but ensure channel order to be the same - % as the original input. + % recursively call ft_checkdata, but ensure channel order to be the same as the original input. origlabelorder = data.label; % keep track of the original order of the channels data = ft_checkdata(data, 'cmbrepresentation', 'sparse'); data.label = origlabelorder; % this avoids the labels to be alphabetized in the next call @@ -1196,12 +1243,79 @@ end % convert from one to another bivariate representation +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% convert between datatypes +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function [source] = chan2source(data) +chanpos = zeros(0,3); +chanlab = cell(0,1); +posunit = []; +if isfield(data, 'elec') + chanpos = cat(1, chanpos, data.elec.chanpos); + chanlab = cat(1, chanlab, data.elec.label); + if isfield(data.elec, 'unit') + posunit = data.elec.unit; + end +end +if isfield(data, 'grad') + chanpos = cat(1, chanpos, data.grad.chanpos); + chanlab = cat(1, chanlab, data.grad.label); + if isfield(data.grad, 'unit') + posunit = data.grad.unit; + end +end +if isfield(data, 'opto') + chanpos = cat(1, chanpos, data.opto.chanpos); + chanlab = cat(1, chanlab, data.opto.label); + if isfield(data.opto, 'unit') + posunit = data.opto.unit; + end +end + +fn = fieldnames(data); +fn = setdiff(fn, {'label', 'time', 'freq', 'hdr', 'cfg', 'grad', 'elec', 'dimord', 'unit'}); % remove irrelevant fields +fn(~cellfun(@isempty, regexp(fn, 'dimord$'))) = []; % remove irrelevant (dimord) fields +sel = false(size(fn)); +for i=1:numel(fn) + try + sel(i) = ismember(getdimord(data, fn{i}), {'chan', 'chan_time', 'chan_freq', 'chan_freq_time', 'chan_chan'}); + end +end +parameter = fn(sel); + +% determine the channel indices for which the position is known +[datsel, possel] = match_str(data.label, chanlab); + +source = []; +source.pos = chanpos(possel, :); +if ~isempty(posunit) + source.unit = posunit; +end +for i=1:numel(parameter) + dat = data.(parameter{i}); + dimord = getdimord(data, parameter{i}); + dimtok = tokenize(dimord, '_'); + for dim=1:numel(dimtok) + if strcmp(dimtok{dim}, 'chan') + dat = dimindex(dat, dim, {datsel}); + dimtok{dim} = 'pos'; + end + end + dimord = sprintf('%s_', dimtok{:}); + dimord = dimord(1:end-1); % remove the last '_' + % copy the data to the source representation + source.(parameter{i}) = dat; + source.([parameter{i} 'dimord']) = dimord; +end +% copy the descriptive fields, these are necessary for visualising the data in ft_sourceplot +source = copyfields(data, source, {'time', 'freq'}); + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % convert between datatypes %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function [source] = parcellated2source(data) if ~isfield(data, 'brainordinate') - error('projecting parcellated data onto the full brain model geometry requires the specification of brainordinates'); + ft_error('projecting parcellated data onto the full brain model geometry requires the specification of brainordinates'); end % the main structure contains the functional data on the parcels % the brainordinate sub-structure contains the original geometrical model @@ -1230,7 +1344,7 @@ end parcelparam = fn(sel); if numel(parcelparam)~=1 - error('cannot determine which parcellation to use'); + ft_error('cannot determine which parcellation to use'); else parcelparam = parcelparam{1}(1:(end-5)); % minus the 'label' end @@ -1239,7 +1353,7 @@ source.(parameter{i}) = unparcellate(data, source, parameter{i}, parcelparam); end -% copy over fields (these are necessary for visualising the data in ft_sourceplot) +% copy the descriptive fields, these are necessary for visualising the data in ft_sourceplot source = copyfields(data, source, {'time', 'freq'}); @@ -1271,7 +1385,7 @@ %an ordered way which allows for the extraction of a transformation matrix %i.e. slice by slice try - if isfield(data, 'dim'), + if isfield(data, 'dim') data.dim = pos2dim(data.pos, data.dim); else data.dim = pos2dim(data); @@ -1280,7 +1394,7 @@ end end -if isfield(data, 'dim') && length(data.dim)>=3, +if isfield(data, 'dim') && length(data.dim)>=3 data.transform = pos2transform(data.pos, data.dim); end @@ -1301,7 +1415,7 @@ elseif isfield(freq, 'fourierspctrm') param = 'fourierspctrm'; else - error('not supported for this data representation'); + ft_error('not supported for this data representation'); end if strcmp(freq.dimord, 'rpt_chan_freq_time') || strcmp(freq.dimord, 'rpttap_chan_freq_time') @@ -1310,7 +1424,7 @@ dat = freq.(param); dat = reshape(dat, [1 size(dat)]); % add a singleton dimension else - error('not supported for dimord %s', freq.dimord); + ft_error('not supported for dimord %s', freq.dimord); end nrpt = size(dat,1); @@ -1330,7 +1444,7 @@ for i=1:nrpt data.time{i} = freq.time; data.trial{i} = reshape(dat(i,:,:,:), nchan*nfreq, ntime); - if any(isnan(data.trial{i}(1,:))), + if any(isnan(data.trial{i}(1,:))) tmp = data.trial{i}(1,:); begsmp = find(isfinite(tmp),1, 'first'); endsmp = find(isfinite(tmp),1, 'last' ); @@ -1339,31 +1453,32 @@ end end -if isfield(freq, 'trialinfo'), data.trialinfo = freq.trialinfo; end; +if isfield(freq, 'trialinfo'), data.trialinfo = freq.trialinfo; end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % convert between datatypes %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -function [data] = raw2timelock(data) +function [tlck] = raw2timelock(data) -nsmp = cellfun('size',data.time,2); data = ft_checkdata(data, 'hassampleinfo', 'yes'); ntrial = numel(data.trial); nchan = numel(data.label); + if ntrial==1 - data.time = data.time{1}; - data.avg = data.trial{1}; - data = rmfield(data, 'trial'); - data.dimord = 'chan_time'; -else + tlck.time = data.time{1}; + tlck.avg = data.trial{1}; + tlck.label = data.label; + tlck.dimord = 'chan_time'; + tlck = copyfields(data, tlck, {'grad', 'elec', 'opto', 'cfg', 'trialinfo', 'topo', 'unmixing', 'topolabel'}); - % code below tries to construct a general time-axis where samples of all trials can fall on - % find earliest beginning and latest ending - begtime = min(cellfun(@min,data.time)); - endtime = max(cellfun(@max,data.time)); +else + % the code below tries to construct a general time-axis where samples of all trials can fall on + % find the earliest beginning and latest ending + begtime = min(cellfun(@min, data.time)); + endtime = max(cellfun(@max, data.time)); % find 'common' sampling rate - fsample = 1./mean(cellfun(@mean,cellfun(@diff,data.time,'uniformoutput',false))); + fsample = 1./mean(cellfun(@mean, cellfun(@diff,data.time, 'uniformoutput', false))); % estimate number of samples nsmp = round((endtime-begtime)*fsample) + 1; % numerical round-off issues should be dealt with by this round, as they will/should never cause an extra sample to appear % construct general time-axis @@ -1380,20 +1495,12 @@ tmptrial(i,:,begsmp(i):endsmp(i)) = data.trial{i}; end - % update the sampleinfo - begpad = begsmp - min(begsmp); - endpad = max(endsmp) - endsmp; - if isfield(data, 'sampleinfo') - data.sampleinfo = data.sampleinfo + [-begpad(:) endpad(:)]; - end - % construct the output timelocked data - % data.avg = reshape(nanmean(tmptrial, 1), nchan, length(tmptime)); - % data.var = reshape(nanvar (tmptrial, [], 1), nchan, length(tmptime)) - % data.dof = reshape(sum(~isnan(tmptrial), 1), nchan, length(tmptime)); - data.trial = tmptrial; - data.time = time; - data.dimord = 'rpt_chan_time'; + tlck.trial = tmptrial; + tlck.time = time; + tlck.dimord = 'rpt_chan_time'; + tlck.label = data.label; + tlck = copyfields(data, tlck, {'grad', 'elec', 'opto', 'cfg', 'trialinfo', 'topo', 'unmixing', 'topolabel'}); end @@ -1401,47 +1508,61 @@ % convert between datatypes %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function [data] = timelock2raw(data) -switch data.dimord - case 'chan_time' - data.trial{1} = data.avg; - data.time = {data.time}; - data = rmfield(data, 'avg'); - case 'rpt_chan_time' - tmptrial = {}; - tmptime = {}; - ntrial = size(data.trial,1); - nchan = size(data.trial,2); - ntime = size(data.trial,3); - for i=1:ntrial - tmptrial{i} = reshape(data.trial(i,:,:), [nchan, ntime]); - tmptime{i} = data.time; - end - data = rmfield(data, 'trial'); - data.trial = tmptrial; - data.time = tmptime; - case 'subj_chan_time' - tmptrial = {}; - tmptime = {}; - ntrial = size(data.individual,1); - nchan = size(data.individual,2); - ntime = size(data.individual,3); - for i=1:ntrial - tmptrial{i} = reshape(data.individual(i,:,:), [nchan, ntime]); - tmptime{i} = data.time; - end - data = rmfield(data, 'individual'); - data.trial = tmptrial; - data.time = tmptime; - otherwise - error('unsupported dimord'); +fn = getdatfield(data); +if any(ismember(fn, {'trial', 'individual', 'avg'})) + % trial, individual and avg (in that order) should be preferred over all other data fields + % see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2965#c12 + fn = fn(ismember(fn, {'trial', 'individual', 'avg'})); end -% remove the unwanted fields -if isfield(data, 'avg'), data = rmfield(data, 'avg'); end -if isfield(data, 'var'), data = rmfield(data, 'var'); end -if isfield(data, 'cov'), data = rmfield(data, 'cov'); end -if isfield(data, 'dimord'), data = rmfield(data, 'dimord'); end -if isfield(data, 'numsamples'), data = rmfield(data, 'numsamples'); end -if isfield(data, 'dof'), data = rmfield(data, 'dof'); end +dimord = cell(size(fn)); +for i=1:numel(fn) + % determine the dimensions of each of the data fields + dimord{i} = getdimord(data, fn{i}); +end +% the fields trial, individual and avg (with their corresponding default dimord) are preferred +if sum(strcmp(dimord, 'rpt_chan_time'))==1 + fn = fn{strcmp(dimord, 'rpt_chan_time')}; + ft_info('constructing trials from "%s"\n', fn); + dimsiz = getdimsiz(data, fn); + ntrial = dimsiz(1); + nchan = dimsiz(2); + ntime = dimsiz(3); + tmptrial = {}; + tmptime = {}; + for j=1:ntrial + tmptrial{j} = reshape(data.(fn)(j,:,:), [nchan, ntime]); + tmptime{j} = data.time; + end + data = rmfield(data, fn); + data.trial = tmptrial; + data.time = tmptime; +elseif sum(strcmp(dimord, 'subj_chan_time'))==1 + fn = fn{strcmp(dimord, 'subj_chan_time')}; + ft_info('constructing trials from "%s"\n', fn); + dimsiz = getdimsiz(data, fn); + nsubj = dimsiz(1); + nchan = dimsiz(2); + ntime = dimsiz(3); + tmptrial = {}; + tmptime = {}; + for j=1:nsubj + tmptrial{j} = reshape(data.(fn)(j,:,:), [nchan, ntime]); + tmptime{j} = data.time; + end + data = rmfield(data, fn); + data.trial = tmptrial; + data.time = tmptime; +elseif sum(strcmp(dimord, 'chan_time'))==1 + fn = fn{strcmp(dimord, 'chan_time')}; + ft_info('constructing single trial from "%s"\n', fn); + data.time = {data.time}; + data.trial = {data.(fn)}; + data = rmfield(data, fn); +else + ft_error('unsupported data structure'); +end +% remove unwanted fields +data = removefields(data, {'avg', 'var', 'cov', 'dimord', 'numsamples' ,'dof'}); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % convert between datatypes @@ -1463,13 +1584,13 @@ % convert between datatypes %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function [spike] = raw2spike(data) -fprintf('converting raw data into spike data\n'); +ft_info('converting raw data into spike data\n'); nTrials = length(data.trial); [spikelabel] = detectspikechan(data); spikesel = match_str(data.label, spikelabel); nUnits = length(spikesel); if nUnits==0 - error('cannot convert raw data to spike format since the raw data structure does not contain spike channels'); + ft_error('cannot convert raw data to spike format since the raw data structure does not contain spike channels'); end trialTimes = zeros(nTrials,2); @@ -1506,7 +1627,7 @@ if nargin<2 || isempty(fsample) timeDiff = abs(diff(sort([spike.time{:}]))); fsample = 1/min(timeDiff(timeDiff>0)); - warning('Desired sampling rate for spike data not specified, automatically resampled to %f', fsample); + ft_warning('Desired sampling rate for spike data not specified, automatically resampled to %f', fsample); end % get some sizes @@ -1632,4 +1753,3 @@ % before adding these times, first remove the old ones spikeTimes(multiSpikes) = []; spikeTimes = sort([spikeTimes(:); addTimes(:)]); - diff --git a/external/fieldtrip/utilities/ft_checkopt.m b/external/fieldtrip/utilities/ft_checkopt.m index fd2c3c31..ba6bab98 100644 --- a/external/fieldtrip/utilities/ft_checkopt.m +++ b/external/fieldtrip/utilities/ft_checkopt.m @@ -103,7 +103,7 @@ case 'doublebivector' ok = isa(val,'double') && sum(size(val)>1)==1 && length(val)==2; case 'ascendingdoublebivector' - ok = isa(val,'double') && sum(size(val)>1)==1 && length(val)==2 && val(2)>val(1); + ok = isa(val,'double') && sum(size(val)>1)==1 && length(val)==2 && val(2)>val(1); case 'doublematrix' ok = isa(val, 'double') && sum(size(val)>1)>1; case 'numericscalar' diff --git a/external/fieldtrip/utilities/ft_compile_mex.m b/external/fieldtrip/utilities/ft_compile_mex.m index 12ead5c3..c726dffc 100644 --- a/external/fieldtrip/utilities/ft_compile_mex.m +++ b/external/fieldtrip/utilities/ft_compile_mex.m @@ -48,13 +48,13 @@ function ft_compile_mex(force) [ftver, ftpath] = ft_version; L = []; -L = add_mex_source(L,'fileio/@uint64','abs'); -L = add_mex_source(L,'fileio/@uint64','min'); -L = add_mex_source(L,'fileio/@uint64','max'); -L = add_mex_source(L,'fileio/@uint64','plus'); -L = add_mex_source(L,'fileio/@uint64','minus'); -L = add_mex_source(L,'fileio/@uint64','times'); -L = add_mex_source(L,'fileio/@uint64','rdivide'); +L = add_mex_source(L,'compat/matlablt2010b/@uint64','abs'); +L = add_mex_source(L,'compat/matlablt2010b/@uint64','min'); +L = add_mex_source(L,'compat/matlablt2010b/@uint64','max'); +L = add_mex_source(L,'compat/matlablt2010b/@uint64','plus'); +L = add_mex_source(L,'compat/matlablt2010b/@uint64','minus'); +L = add_mex_source(L,'compat/matlablt2010b/@uint64','times'); +L = add_mex_source(L,'compat/matlablt2010b/@uint64','rdivide'); L = add_mex_source(L,'@config/private','deepcopy'); L = add_mex_source(L,'@config/private','increment'); diff --git a/external/fieldtrip/utilities/ft_convert_coordsys.m b/external/fieldtrip/utilities/ft_convert_coordsys.m index b0d8bd87..2e58a11d 100644 --- a/external/fieldtrip/utilities/ft_convert_coordsys.m +++ b/external/fieldtrip/utilities/ft_convert_coordsys.m @@ -2,20 +2,20 @@ % FT_CONVERT_COORDSYS changes the coordinate system of the input object to % the specified coordinate system. The coordinate system of the input -% object is determined from the structure field object.coordsys, or need to -% be determined interactively by the user. +% object is determined from the structure field object.coordsys, or needs to +% be determined and specified interactively by the user. % % Use as % [object] = ft_convert_coordsys(object) % to only determine the coordinate system, or % [object] = ft_convert_coordsys(object, target) % [object] = ft_convert_coordsys(object, target, opt) -% [object] = ft_convert_coordsys(object, target, opt, template); +% [object] = ft_convert_coordsys(object, target, opt, template) % to determine and convert the coordinate system. % % The optional input argument opt determines the behavior when converting % to the spm coordinate system, and pertains to the functional behaviour of -% the private functions: align_ctf2spm and align_itab2spm. +% the private functions: align_ctf2acpc and align_neuromag2acpc. % % The following input objects are supported % anatomical mri, see FT_READ_MRI @@ -25,14 +25,15 @@ % (not yet) volume conductor definition % (not yet) dipole grid definition % -% Possible target coordinate systems are 'spm'. +% Possible input coordinate systems are 'ctf', 'bti', '4d', 'neuromag' and 'itab'. +% Possible target coordinate systems are 'acpc'. % % Note that the conversion will be an automatic one, which means that it % will be an approximate conversion, not taking into account differences in % individual anatomies/differences in conventions where to put the % fiducials. % -% See also FT_DETERMINE_COORDSYS, ALIGN_CTF2SPM, ALIGN_ITAB2SPM +% See also FT_DETERMINE_COORDSYS, ALIGN_CTF2ACPC, ALIGN_NEUROMAG2ACPC, ALIGN_FSAVERAGE2MNI % Copyright (C) 2005-2011, Robert Oostenveld & Jan-Mathijs Schoffelen % @@ -62,8 +63,14 @@ if ~isfield(obj, 'coordsys') || isempty(obj.coordsys) % the call to ft_determine_coordsys should have taken care of this, but % it is possible that the user aborted the coordinate system - % determination. See http://bugzilla.fcdonders.nl/show_bug.cgi?id=2526 - error('the coordinate system of the geometrical object is not specified'); + % determination. See http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2526 + ft_error('the coordinate system of the geometrical object is not specified'); +end + +if any(strcmp(target, {'spm', 'mni', 'tal'})) + % see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=3304 + ft_warning('Not applying any scaling, using ''acpc'' instead of ''%s''. See http://bit.ly/2sw7eC4', target); + target = 'acpc'; end % set default behavior to use an approximate alignment, followed by a call @@ -79,7 +86,7 @@ end if needtemplate && nargin<4 - error('you need to specify a template filename for the coregistration'); + ft_error('you need to specify a template filename for the coregistration'); end hastemplate = nargin>3; @@ -87,25 +94,26 @@ if nargin>1 && ~strcmpi(target, obj.coordsys) % convert to the desired coordinate system switch target - case {'spm' 'mni' 'tal'} + case 'acpc' switch obj.coordsys case {'ctf' 'bti' '4d'} fprintf('Converting the coordinate system from %s to %s\n', obj.coordsys, target); if hastemplate - obj = align_ctf2spm(obj, opt, template); + obj = align_ctf2acpc(obj, opt, template); else - obj = align_ctf2spm(obj, opt); + obj = align_ctf2acpc(obj, opt); end case {'itab' 'neuromag'} fprintf('Converting the coordinate system from %s to %s\n', obj.coordsys, target); if hastemplate - obj = align_ctf2spm(obj, opt, template); + obj = align_neuromag2acpc(obj, opt, template); else - obj = align_itab2spm(obj, opt); + obj = align_neuromag2acpc(obj, opt); end otherwise - end %switch obj.coordsys + end % switch obj.coordsys otherwise - error('conversion from %s to %s is not yet supported', obj.coordsys, target); - end %switch target + ft_error('conversion from %s to %s is not yet supported', obj.coordsys, target); + end % switch target end + diff --git a/external/fieldtrip/utilities/ft_convert_grad.m b/external/fieldtrip/utilities/ft_convert_grad.m deleted file mode 100644 index 29f73490..00000000 --- a/external/fieldtrip/utilities/ft_convert_grad.m +++ /dev/null @@ -1,11 +0,0 @@ -function [gradnew] = ft_convert_grad(grad, amplitude, distance, scaling) - -% FT_CONVERT_GRAD is deprecated, please use ft_datatype_sens - -% DEPRECATED by roboos on 1 July 2013 -% see http://bugzilla.fcdonders.nl/show_bug.cgi?id=963 for more details -% this function can be completely removed medio 2014 -warning('this function is deprecated, please use ft_datatype_sens'); - -% at the time of writing this code, this is only supported in the "upcoming" version, not the "latest/2011v2" -gradnew = ft_datatype_sens(grad, 'version', 'upcoming', 'amplitude', amplitude, 'distance', distance, 'scaling', scaling); diff --git a/external/fieldtrip/utilities/ft_datatype.m b/external/fieldtrip/utilities/ft_datatype.m index 56ea128f..fbcdeacb 100644 --- a/external/fieldtrip/utilities/ft_datatype.m +++ b/external/fieldtrip/utilities/ft_datatype.m @@ -39,7 +39,7 @@ % determine the type of input data israw = isfield(data, 'label') && isfield(data, 'time') && isa(data.time, 'cell') && isfield(data, 'trial') && isa(data.trial, 'cell') && ~isfield(data,'trialtime'); -isfreq = (isfield(data, 'label') || isfield(data, 'labelcmb')) && isfield(data, 'freq') && ~isfield(data,'trialtime') && ~isfield(data,'origtrial'); %&& (isfield(data, 'powspctrm') || isfield(data, 'crsspctrm') || isfield(data, 'cohspctrm') || isfield(data, 'fourierspctrm') || isfield(data, 'powcovspctrm')); +isfreq = ((isfield(data, 'label') && ~isfield(data, 'pos')) || isfield(data, 'labelcmb')) && isfield(data, 'freq') && ~isfield(data,'trialtime') && ~isfield(data,'origtrial'); %&& (isfield(data, 'powspctrm') || isfield(data, 'crsspctrm') || isfield(data, 'cohspctrm') || isfield(data, 'fourierspctrm') || isfield(data, 'powcovspctrm')); istimelock = isfield(data, 'label') && isfield(data, 'time') && ~isfield(data, 'freq') && ~isfield(data,'timestamp') && ~isfield(data,'trialtime') && ~(isfield(data, 'trial') && iscell(data.trial)) && ~isfield(data, 'pos'); %&& ((isfield(data, 'avg') && isnumeric(data.avg)) || (isfield(data, 'trial') && isnumeric(data.trial) || (isfield(data, 'cov') && isnumeric(data.cov)))); iscomp = isfield(data, 'label') && isfield(data, 'topo') || isfield(data, 'topolabel'); isvolume = isfield(data, 'transform') && isfield(data, 'dim') && ~isfield(data, 'pos'); @@ -51,8 +51,9 @@ ischan = check_chan(data); issegmentation = check_segmentation(data); isparcellation = check_parcellation(data); -ismontage = isfield(data, 'labelorg') && isfield(data, 'labelnew') && isfield(data, 'tra'); +ismontage = isfield(data, 'labelold') && isfield(data, 'labelnew') && isfield(data, 'tra'); isevent = isfield(data, 'type') && isfield(data, 'value') && isfield(data, 'sample') && isfield(data, 'offset') && isfield(data, 'duration'); +islayout = all(isfield(data, {'label', 'pos', 'width', 'height'})); % mask and outline are optional isheadmodel = false; % FIXME this is not yet implemented if issource && isstruct(data) && numel(data)>1 @@ -74,6 +75,7 @@ % check if it is a sensor array isgrad = isfield(data, 'label') && isfield(data, 'coilpos') && isfield(data, 'coilori'); iselec = isfield(data, 'label') && isfield(data, 'elecpos'); +isopto = isfield(data, 'label') && isfield(data, 'optopos'); if isspike type = 'spike'; @@ -82,7 +84,7 @@ elseif istimelock && iscomp type = 'timelock+comp'; elseif isfreq && iscomp - type = 'freq+comp'; + type = 'freq+comp'; elseif israw type = 'raw'; elseif iscomp @@ -105,23 +107,29 @@ type = 'volume'; elseif ismesh && isparcellation type = 'mesh+label'; -elseif ismesh - type = 'mesh'; elseif issource && isparcellation type = 'source+label'; +elseif issource && ismesh + type = 'source+mesh'; +elseif ismesh + type = 'mesh'; elseif issource type = 'source'; elseif ischan % this results from avgovertime/avgoverfreq after timelockstatistics or freqstatistics type = 'chan'; -elseif iselec - type = 'elec'; elseif isgrad type = 'grad'; +elseif iselec + type = 'elec'; +elseif isopto + type = 'opto'; elseif ismontage type = 'montage'; elseif isevent type = 'event'; +elseif islayout + type = 'layout'; else type = 'unknown'; end @@ -140,16 +148,16 @@ case 'volume' type = any(strcmp(type, {'volume', 'volume+label'})); case 'source' - type = any(strcmp(type, {'source', 'source+label', 'mesh', 'mesh+label'})); % a single mesh qualifies as source structure + type = any(strcmp(type, {'source', 'source+label', 'mesh', 'mesh+label', 'source+mesh'})); % a single mesh does qualify as source structure type = type && isstruct(data) && numel(data)==1; % an array of meshes does not qualify case 'mesh' - type = any(strcmp(type, {'mesh', 'mesh+label'})); + type = any(strcmp(type, {'mesh', 'mesh+label', 'source+mesh'})); case 'segmentation' - type = strcmp(type, 'volume+label'); + type = any(strcmp(type, {'segmentation', 'volume+label'})); case 'parcellation' - type = any(strcmp(type, {'source+label' 'mesh+label'})); + type = any(strcmp(type, {'parcellation', 'source+label' 'mesh+label'})); case 'sens' - type = any(strcmp(type, {'elec', 'grad'})); + type = any(strcmp(type, {'grad', 'elec', 'opto'})); otherwise type = strcmp(type, desired); end % switch diff --git a/external/fieldtrip/utilities/ft_datatype_comp.m b/external/fieldtrip/utilities/ft_datatype_comp.m index 164733a5..15466a69 100644 --- a/external/fieldtrip/utilities/ft_datatype_comp.m +++ b/external/fieldtrip/utilities/ft_datatype_comp.m @@ -11,12 +11,12 @@ % An example of a decomposed raw data structure with 100 components that resulted from % a 151-channel MEG recording is shown here: % -% unmixing: [100x151 double] the compoment unmixing matrix % topo: [151x100 double] the compoment topographies +% unmixing: [100x151 double] the compoment unmixing matrix % topolabel: {151x1 cell} the channel labels (e.g. 'MRC13') -% time: {1x10 cell} the timeaxis [1*Ntime double] per trial -% trial: {1x10 cell} the numeric data [151*Ntime double] per trial % label: {100x1 cell} the component labels (e.g. 'runica001') +% time: {1x10 cell} the time axis [1*Ntime double] per trial +% trial: {1x10 cell} the numeric data [151*Ntime double] per trial % grad: [1x1 struct] information about the sensor array (for EEG it is called elec) % cfg: [1x1 struct] the configuration used by the function that generated this data structure % @@ -33,7 +33,7 @@ % - cfg, all fields from FT_DATATYPE_RAW, FT_DATATYPE_TIMELOCK or FT_DATATYPE_FREQ % % Historical fields: -% - cfg, offset, fsample, grad, elec, label, sampleinfo, time, topo, topolabel, trial, unmixing, see bug2513 +% - offset, fsample % % Revision history: % (2014) The combination of comp with raw, timelock or freq has been defined explicitly. @@ -96,47 +96,37 @@ end end + if isfield(comp, 'unmixing') && ~isfield(comp, 'unmixingdimord') + comp.unmixingdimord = 'chan_topochan'; + end + + if isfield(comp, 'topo') && ~isfield(comp, 'topodimord') + comp.topodimord = 'topochan_chan'; + end + % convert it into a raw data structure and update it to the latest version if ft_datatype(comp, 'raw') - raw = comp; - raw = rmfield(raw, 'topo'); - raw = rmfield(raw, 'unmixing'); - raw = rmfield(raw, 'topolabel'); + raw = removefields(comp, {'topo', 'topodimord', 'unmixing', 'unmixingdimord', 'topolabel'}); raw = ft_datatype_raw(raw, 'version', rawversion, 'hassampleinfo', hassampleinfo, 'hastrialinfo', hastrialinfo); % add the component specific fields again - raw.unmixing = comp.unmixing; - raw.topo = comp.topo; - raw.topolabel = comp.topolabel; - comp = raw; + comp = copyfields(comp, raw, {'topo', 'topodimord', 'unmixing', 'unmixingdimord', 'topolabel'}); clear raw elseif ft_datatype(comp, 'timelock') - timelock = comp; - timelock = rmfield(timelock, 'topo'); - timelock = rmfield(timelock, 'unmixing'); - timelock = rmfield(timelock, 'topolabel'); + timelock = removefields(comp, {'topo', 'topodimord', 'unmixing', 'unmixingdimord', 'topolabel'}); timelock = ft_datatype_timelock(timelock, 'version', timelockversion); % add the component specific fields again - timelock.unmixing = comp.unmixing; - timelock.topo = comp.topo; - timelock.topolabel = comp.topolabel; - comp = timelock; + comp = copyfields(comp, timelock, {'topo', 'topodimord', 'unmixing', 'unmixingdimord', 'topolabel'}); clear timelock elseif ft_datatype(comp, 'freq') - freq = comp; - freq = rmfield(freq, 'topo'); - freq = rmfield(freq, 'unmixing'); - freq = rmfield(freq, 'topolabel'); + freq = removefields(comp, {'topo', 'topodimord', 'unmixing', 'unmixingdimord', 'topolabel'}); freq = ft_datatype_freq(freq, 'version', freqversion); % add the component specific fields again - freq.unmixing = comp.unmixing; - freq.topo = comp.topo; - freq.topolabel = comp.topolabel; - comp = freq; + comp = copyfields(comp, freq, {'topo', 'topodimord', 'unmixing', 'unmixingdimord', 'topolabel'}); clear freq end % raw, timelock or freq @@ -167,7 +157,7 @@ otherwise %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - error('unsupported version "%s" for comp datatype', version); + ft_error('unsupported version "%s" for comp datatype', version); end diff --git a/external/fieldtrip/utilities/ft_datatype_freq.m b/external/fieldtrip/utilities/ft_datatype_freq.m index 1ac38670..77321874 100644 --- a/external/fieldtrip/utilities/ft_datatype_freq.m +++ b/external/fieldtrip/utilities/ft_datatype_freq.m @@ -107,7 +107,7 @@ freq.time = freq.time'; end if ~isfield(freq, 'label') && ~isfield(freq, 'labelcmb') - warning('data structure is incorrect since it has no channel labels'); + ft_warning('data structure is incorrect since it has no channel labels'); end switch version @@ -128,12 +128,22 @@ freq.freq = freq.foi; freq = rmfield(freq, 'foi'); end - + if isfield(freq, 'toi') && ~isfield(freq, 'time') % this was still the case in early 2006 freq.time = freq.toi; freq = rmfield(freq, 'toi'); end + + if isfield(freq, 'cumtapcnt') && isvector(freq.cumtapcnt) + % ensure that it is a column vector + freq.cumtapcnt = freq.cumtapcnt(:); + end + + if isfield(freq, 'cumsumcnt') && isvector(freq.cumsumcnt) + % ensure that it is a column vector + freq.cumsumcnt = freq.cumsumcnt(:); + end case '2008' % there are no known conversions for backward or forward compatibility support @@ -149,5 +159,5 @@ otherwise %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - error('unsupported version "%s" for freq datatype', version); + ft_error('unsupported version "%s" for freq datatype', version); end diff --git a/external/fieldtrip/utilities/ft_datatype_headmodel.m b/external/fieldtrip/utilities/ft_datatype_headmodel.m index 8fe3ac83..4d332ed6 100644 --- a/external/fieldtrip/utilities/ft_datatype_headmodel.m +++ b/external/fieldtrip/utilities/ft_datatype_headmodel.m @@ -132,7 +132,7 @@ elseif isfield(headmodel, 'cond') && isfield(headmodel, 'c') && isequal(headmodel.cond, headmodel.c) headmodel = rmfield(headmodel, 'c'); elseif isfield(headmodel, 'cond') && isfield(headmodel, 'c') && ~isequal(headmodel.cond, headmodel.c) - error('inconsistent specification of conductive properties for %s model', headmodel.type); + ft_error('inconsistent specification of conductive properties for %s model', headmodel.type); end case '2012' @@ -165,9 +165,9 @@ elseif strcmp(headmodel.type, 'fdm_fns') headmodel.type = 'fns'; elseif strcmp(headmodel.type, 'bem') - error('not able to convert the original ''bem'' volume type, try using headmodel.type=''dipoli'''); + ft_error('not able to convert the original ''bem'' volume type, try using headmodel.type=''dipoli'''); elseif strcmp(headmodel.type, 'avo') - error('this format is not supported anymore'); + ft_error('this format is not supported anymore'); end end @@ -183,15 +183,13 @@ elseif isfield(headmodel, 'cond') && isfield(headmodel, 'c') && isequal(headmodel.cond, headmodel.c) headmodel = rmfield(headmodel, 'cond'); elseif isfield(headmodel, 'cond') && isfield(headmodel, 'c') && ~isequal(headmodel.cond, headmodel.c) - error('inconsistent specification of conductive properties for %s model', headmodel.type); + ft_error('inconsistent specification of conductive properties for %s model', headmodel.type); end end % ensure that the geometrical units are specified - if ~isfield(headmodel, 'unit') - headmodel = ft_convert_units(headmodel); - end + headmodel = ft_determine_units(headmodel); otherwise - error('converting to version "%s" is not supported', version); + ft_error('converting to version "%s" is not supported', version); end diff --git a/external/fieldtrip/utilities/ft_datatype_mvar.m b/external/fieldtrip/utilities/ft_datatype_mvar.m index 33b002d5..3ddef362 100644 --- a/external/fieldtrip/utilities/ft_datatype_mvar.m +++ b/external/fieldtrip/utilities/ft_datatype_mvar.m @@ -102,5 +102,5 @@ otherwise %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - error('unsupported version "%s" for mvar datatype', version); + ft_error('unsupported version "%s" for mvar datatype', version); end diff --git a/external/fieldtrip/utilities/ft_datatype_parcellation.m b/external/fieldtrip/utilities/ft_datatype_parcellation.m index 52f3c4d3..290de9b5 100644 --- a/external/fieldtrip/utilities/ft_datatype_parcellation.m +++ b/external/fieldtrip/utilities/ft_datatype_parcellation.m @@ -171,7 +171,7 @@ otherwise %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - error('unsupported version "%s" for parcellation datatype', parcelversion); + ft_error('unsupported version "%s" for parcellation datatype', parcelversion); end % the parcellation is a speciat type of volume structure, so ensure that it also fulfills the requirements for that diff --git a/external/fieldtrip/utilities/ft_datatype_raw.m b/external/fieldtrip/utilities/ft_datatype_raw.m index b32d60ac..98940c87 100644 --- a/external/fieldtrip/utilities/ft_datatype_raw.m +++ b/external/fieldtrip/utilities/ft_datatype_raw.m @@ -98,12 +98,12 @@ hassampleinfo = 'yes'; % if it's already there, consider keeping it numsmp = data.sampleinfo(:,2)-data.sampleinfo(:,1)+1; for i=1:length(data.trial) - if size(data.trial{i},2)~=numsmp(i); + if size(data.trial{i},2)~=numsmp(i) % it does not make sense, so don't keep it hassampleinfo = 'no'; % the actual removal will be done further down - warning('removing inconsistent sampleinfo'); - break; + ft_warning('removing inconsistent sampleinfo'); + break end end end @@ -116,7 +116,7 @@ if size(data.trialinfo,1)~=numel(data.trial) % it does not make sense, so don't keep it hastrialinfo = 'no'; - warning('removing inconsistent trialinfo'); + ft_warning('removing inconsistent trialinfo'); end end end @@ -156,7 +156,7 @@ end end if isnan(data.fsample) - warning('cannot determine sampling frequency'); + ft_warning('cannot determine sampling frequency'); end end @@ -252,13 +252,13 @@ otherwise %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - error('unsupported version "%s" for raw datatype', version); + ft_error('unsupported version "%s" for raw datatype', version); end % Numerical inaccuracies in the binary representations of floating point % values may accumulate. The following code corrects for small inaccuracies -% in the time axes of the trials. See http://bugzilla.fcdonders.nl/show_bug.cgi?id=1390 +% in the time axes of the trials. See http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=1390 data = fixtimeaxes(data); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/external/fieldtrip/utilities/ft_datatype_segmentation.m b/external/fieldtrip/utilities/ft_datatype_segmentation.m index 9ddbabef..126d5fe3 100644 --- a/external/fieldtrip/utilities/ft_datatype_segmentation.m +++ b/external/fieldtrip/utilities/ft_datatype_segmentation.m @@ -190,7 +190,7 @@ fn = fn(sel); if numel(fn)>1 - error('cannot construct a brain mask on the fly; this requires a single indexed representation'); + ft_error('cannot construct a brain mask on the fly; this requires a single indexed representation'); else seg = segmentation.(fn{1}); seglabel = segmentation.([fn{1} 'label']); @@ -199,7 +199,7 @@ smooth = 5; % ensure that the segmentation contains the brain mask, if not then construct it from gray+white+csf if length(intersect(seglabel, {'gray' 'white' 'csf'}))~=3 - error('cannot construct a brain mask on the fly; this requires gray, white and csf'); + ft_error('cannot construct a brain mask on the fly; this requires gray, white and csf'); end gray = seg==find(strcmp(seglabel, 'gray')); white = seg==find(strcmp(seglabel, 'white')); @@ -216,7 +216,7 @@ elseif all(probabilistic) if ~isfield(segmentation, 'brain') if ~all(isfield(segmentation, {'gray' 'white' 'csf'})) - error('cannot construct a brain mask on the fly; this requires gray, white and csf'); + ft_error('cannot construct a brain mask on the fly; this requires gray, white and csf'); end threshold = 0.5; smooth = 5; @@ -232,7 +232,7 @@ segmentation.brain = brain; end else - error('cannot construct a brain mask on the fly; this requires a uniquely indexed or a uniquely probabilitic representation'); + ft_error('cannot construct a brain mask on the fly; this requires a uniquely indexed or a uniquely probabilitic representation'); end end % if hasbrain @@ -246,7 +246,7 @@ otherwise %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - error('unsupported version "%s" for segmentation datatype', segversion); + ft_error('unsupported version "%s" for segmentation datatype', segversion); end % the segmentation is a speciat type of volume structure, so ensure that it also fulfills the requirements for that diff --git a/external/fieldtrip/utilities/ft_datatype_sens.m b/external/fieldtrip/utilities/ft_datatype_sens.m index 27597439..a3c1d2ec 100644 --- a/external/fieldtrip/utilities/ft_datatype_sens.m +++ b/external/fieldtrip/utilities/ft_datatype_sens.m @@ -129,11 +129,11 @@ scaling = ft_getopt(varargin, 'scaling'); % should be 'amplitude' or 'amplitude/distance', the default depends on the senstype if ~isempty(amplitude) && ~any(strcmp(amplitude, {'V' 'uV' 'T' 'mT' 'uT' 'nT' 'pT' 'fT'})) - error('unsupported unit of amplitude "%s"', amplitude); + ft_error('unsupported unit of amplitude "%s"', amplitude); end if ~isempty(distance) && ~any(strcmp(distance, {'m' 'dm' 'cm' 'mm'})) - error('unsupported unit of distance "%s"', distance); + ft_error('unsupported unit of distance "%s"', distance); end if strcmp(version, 'latest') @@ -157,31 +157,12 @@ % update it to the previous standard version sens = ft_datatype_sens(sens, 'version', '2011v2'); + % rename from org to old (reverse = false) + sens = fixoldorg(sens, false); + % ensure that all numbers are represented in double precision sens = ft_struct2double(sens); - % use "old/new" rather than "org/new" - if isfield(sens, 'labelorg') - sens.labelold = sens.labelorg; - sens = rmfield(sens, 'labelorg'); - end - if isfield(sens, 'chantypeorg') - sens.chantypeold = sens.chantypeorg; - sens = rmfield(sens, 'chantypeorg'); - end - if isfield(sens, 'chanuniteorg') - sens.chanunitold = sens.chanunitorg; - sens = rmfield(sens, 'chanunitorg'); - end - if isfield(sens, 'chanposorg') - sens.chanposold = sens.chanposorg; - sens = rmfield(sens, 'chanposorg'); - end - if isfield(sens, 'chanoriorg') - sens.chanoriold = sens.chanoriorg; - sens = rmfield(sens, 'chanoriorg'); - end - % in version 2011v2 this was optional, now it is required if ~isfield(sens, 'chantype') || all(strcmp(sens.chantype, 'unknown')) sens.chantype = ft_chantype(sens); @@ -213,7 +194,7 @@ sens.tra(i,:) = sens.tra(i,:) * ft_scalingfactor(sens.chanunit{i}, amplitude); sens.chanunit{i} = amplitude; else - error('unexpected channel unit "%s" in channel %d', sens.chanunit{i}, i); + ft_error('unexpected channel unit "%s" in channel %d', sens.chanunit{i}, i); end end else @@ -244,13 +225,13 @@ sel_mm = ~cellfun(@isempty, regexp(sens.chanunit, '/mm$')); if strcmp(sens.unit, 'm') && (any(sel_dm) || any(sel_cm) || any(sel_mm)) - error('inconsistent units in input gradiometer'); + ft_error('inconsistent units in input gradiometer'); elseif strcmp(sens.unit, 'dm') && (any(sel_m) || any(sel_cm) || any(sel_mm)) - error('inconsistent units in input gradiometer'); + ft_error('inconsistent units in input gradiometer'); elseif strcmp(sens.unit, 'cm') && (any(sel_m) || any(sel_dm) || any(sel_mm)) - error('inconsistent units in input gradiometer'); + ft_error('inconsistent units in input gradiometer'); elseif strcmp(sens.unit, 'mm') && (any(sel_m) || any(sel_dm) || any(sel_cm)) - error('inconsistent units in input gradiometer'); + ft_error('inconsistent units in input gradiometer'); end % the default should be amplitude/distance for neuromag and amplitude for all others @@ -258,7 +239,7 @@ if ft_senstype(sens, 'neuromag') scaling = 'amplitude/distance'; elseif ft_senstype(sens, 'yokogawa440') - warning('asuming that the default scaling should be amplitude rather than amplitude/distance'); + ft_warning('asuming that the default scaling should be amplitude rather than amplitude/distance'); scaling = 'amplitude'; else scaling = 'amplitude'; @@ -272,7 +253,7 @@ % this channel is expressed as amplitude per distance coil = find(abs(sens.tra(i,:))~=0); if length(coil)~=2 - error('unexpected number of coils contributing to channel %d', i); + ft_error('unexpected number of coils contributing to channel %d', i); end baseline = norm(sens.coilpos(coil(1),:) - sens.coilpos(coil(2),:)); sens.tra(i,:) = sens.tra(i,:)*baseline; % scale with the baseline distance @@ -281,7 +262,7 @@ % no conversion needed else % see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=3144 - ft_warning(sprintf('unexpected channel unit "%s" in channel %d', sens.chanunit{i}, i)); + ft_warning('unexpected channel unit "%s" in channel %d', sens.chanunit{i}, i); end % if end % for @@ -294,7 +275,7 @@ % this is a magnetometer channel, no conversion needed continue elseif length(coil)~=2 - error('unexpected number of coils (%d) contributing to channel %s (%d)', length(coil), sens.label{i}, i); + ft_error('unexpected number of coils (%d) contributing to channel %s (%d)', length(coil), sens.label{i}, i); end baseline = norm(sens.coilpos(coil(1),:) - sens.coilpos(coil(2),:)); sens.tra(i,:) = sens.tra(i,:)/baseline; % scale with the baseline distance @@ -303,7 +284,7 @@ % no conversion needed else % see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=3144 - ft_warning(sprintf('unexpected channel unit "%s" in channel %d', sens.chanunit{i}, i)); + ft_warning('unexpected channel unit "%s" in channel %d', sens.chanunit{i}, i); end % if end % for @@ -315,16 +296,19 @@ sel_cm = ~cellfun(@isempty, regexp(sens.chanunit, '/cm$')); sel_mm = ~cellfun(@isempty, regexp(sens.chanunit, '/mm$')); if any(sel_m | sel_dm | sel_cm | sel_mm) - error('scaling of amplitude/distance has not been considered yet for EEG'); + ft_error('scaling of amplitude/distance has not been considered yet for EEG'); end end % if iseeg or ismeg %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% case '2011v2' - + + % rename from old to org (reverse = true) + sens = fixoldorg(sens, true); + if ~isempty(amplitude) || ~isempty(distance) || ~isempty(scaling) - warning('amplitude, distance and scaling are not supported for version "%s"', version); + ft_warning('amplitude, distance and scaling are not supported for version "%s"', version); end % This speeds up subsequent calls to ft_senstype and channelposition. @@ -357,7 +341,7 @@ sens.chanpos(selsens,:) = chanpos(selpos,:); sens.chanori(selsens,:) = chanori(selpos,:); if length(selsens)~=length(sens.label) - warning('cannot determine the position and orientation for all channels'); + ft_warning('cannot determine the position and orientation for all channels'); end else % sensor description is something else, EEG/ECoG etc @@ -369,7 +353,7 @@ % insert the determined position/orientation on the appropriate rows sens.chanpos(selsens,:) = chanpos(selpos,:); if length(selsens)~=length(sens.label) - warning('cannot determine the position and orientation for all channels'); + ft_warning('cannot determine the position and orientation for all channels'); end end end @@ -384,7 +368,7 @@ if ~isfield(sens, 'unit') % this should be done prior to calling ft_chanunit, since ft_chanunit uses this for planar neuromag channels - sens = ft_convert_units(sens); + sens = ft_determine_units(sens); end if ~isfield(sens, 'chanunit') || all(strcmp(sens.chanunit, 'unknown')) @@ -397,7 +381,7 @@ if any(strcmp(sens.type, {'meg', 'eeg', 'magnetometer', 'electrode', 'unknown'})) % this is not sufficiently informative, so better remove it - % see also http://bugzilla.fcdonders.nl/show_bug.cgi?id=1806 + % see also http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=1806 sens = rmfield(sens, 'type'); end @@ -408,7 +392,7 @@ isfield(sens, 'tra') && isfield(sens, 'coilori') && size(sens.tra,2)~=size(sens.coilori,1) || ... isfield(sens, 'chanpos') && size(sens.chanpos,1)~=length(sens.label) || ... isfield(sens, 'chanori') && size(sens.chanori,1)~=length(sens.label) - error('inconsistent number of channels in sensor description'); + ft_error('inconsistent number of channels in sensor description'); end if ismeg @@ -465,7 +449,7 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% otherwise - error('converting to version %s is not supported', version); + ft_error('converting to version %s is not supported', version); end % switch diff --git a/external/fieldtrip/utilities/ft_datatype_source.m b/external/fieldtrip/utilities/ft_datatype_source.m index bc6f4c31..f1ac33ba 100644 --- a/external/fieldtrip/utilities/ft_datatype_source.m +++ b/external/fieldtrip/utilities/ft_datatype_source.m @@ -244,7 +244,7 @@ try source.(fn{i}) = reshape(source.(fn{i}), [prod(dimsiz(1:3)) dimsiz(4:end) 1]); catch - warning('could not reshape %s to the expected dimensions', fn{i}); + ft_warning('could not reshape %s to the expected dimensions', fn{i}); end end end @@ -332,7 +332,7 @@ otherwise %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - error('unsupported version "%s" for source datatype', version); + ft_error('unsupported version "%s" for source datatype', version); end function pos = grid2pos(xgrid, ygrid, zgrid) diff --git a/external/fieldtrip/utilities/ft_datatype_spike.m b/external/fieldtrip/utilities/ft_datatype_spike.m index eae78c48..2830560d 100644 --- a/external/fieldtrip/utilities/ft_datatype_spike.m +++ b/external/fieldtrip/utilities/ft_datatype_spike.m @@ -158,7 +158,7 @@ if isfield(spike,'origtrial') && isfield(spike,'origtime') % this was the old spiketriggered spectrum output - warning('The spike datatype format you are using is depreciated. Converting to newer spike format'); + ft_warning('The spike datatype format you are using is depreciated. Converting to newer spike format'); spike.trial = {spike.origtrial}; spike = rmfield(spike,'origtrial'); spike.time = {spike.origtime}; @@ -168,7 +168,7 @@ end if ~isfield(spike, 'trialtime') % determine from the data itself - warning('Reconstructing the field trialtime from spike.origtime and spike.origtrial. This is not the original representation'); + ft_warning('Reconstructing the field trialtime from spike.origtime and spike.origtrial. This is not the original representation'); tmax = nanmax(spike.trial{1}); tsmin = nanmin(spike.time{1}); tsmax = nanmax(spike.time{1}); @@ -181,7 +181,7 @@ try spike.label = spike.spikechannel; catch - {'unit1'}; %default + spike.label = {'unit1'}; %default end end spike.dimord = '{chan}_spike_lfpchan_freq'; @@ -206,7 +206,7 @@ nSpikes = length(spike.timestamp{iUnit}); % check what's the spike dimension from the timestamps spikedim = dim==nSpikes; if isempty(spikedim) - error('waveforms contains data but number of waveforms does not match number of spikes'); + ft_error('waveforms contains data but number of waveforms does not match number of spikes'); end if spikedim==1 spike.waveform{iUnit} = permute(spike.waveform{iUnit},[3 2 1]); @@ -221,10 +221,10 @@ leaddim = dim<6 & dim~=nSpikes; sampdim = dim>=6 & dim~=nSpikes; if isempty(spikedim) - error('waveforms contains data but number of waveforms does not match number of spikes'); + ft_error('waveforms contains data but number of waveforms does not match number of spikes'); end - if sum(leaddim)~=1 | sum(sampdim)~=1, continue,end % in this case we do not know what to do - if find(spikedim)~=3 & find(leaddim)~=1 & find(sampdim)~=2 + if sum(leaddim)~=1 || sum(sampdim)~=1, continue,end % in this case we do not know what to do + if find(spikedim)~=3 && find(leaddim)~=1 && find(sampdim)~=2 spike.waveform{iUnit} = permute(spike.waveform{iUnit}, [find(leaddim) find(sampdim) find(spikedim)]); end end @@ -270,7 +270,7 @@ otherwise %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - error('unsupported version "%s" for spike datatype', version); + ft_error('unsupported version "%s" for spike datatype', version); end diff --git a/external/fieldtrip/utilities/ft_datatype_timelock.m b/external/fieldtrip/utilities/ft_datatype_timelock.m index 0c443b19..a9a507e7 100644 --- a/external/fieldtrip/utilities/ft_datatype_timelock.m +++ b/external/fieldtrip/utilities/ft_datatype_timelock.m @@ -36,7 +36,10 @@ % % Revision history: % -% (2011v2/latest) The description of the sensors has changed, see FT_DATATYPE_SENS +% (2017/latest) The data structure cannot contain an average and simultaneously single +% trial information any more, i.e. avg/var/dof and trial/individual are mutually exclusive. +% +% (2011v2) The description of the sensors has changed, see FT_DATATYPE_SENS % for further information. % % (2011) The field 'fsample' was removed, as it was redundant. @@ -69,7 +72,7 @@ version = ft_getopt(varargin, 'version', 'latest'); if strcmp(version, 'latest') - version = '2011v2'; + version = '2017'; end if isempty(timelock) @@ -91,27 +94,55 @@ timelock.time = timelock.time'; end if ~isfield(timelock, 'label') - warning('data structure is incorrect since it has no channel labels'); + ft_warning('data structure is incorrect since it has no channel labels'); end switch version + case '2017' + timelock = ft_datatype_timelock(timelock, 'version', '2011v2'); + fn = fieldnames(timelock); + fn = setdiff(fn, ignorefields('appendtimelock')); + dimord = cell(size(fn)); + hasrpt = false(size(fn)); + for i=1:numel(fn) + dimord{i} = getdimord(timelock, fn{i}); + hasrpt(i) = ~isempty(strfind(dimord{i}, 'rpt')) || ~isempty(strfind(dimord{i}, 'subj')); + end + if any(hasrpt) && ~all(hasrpt) + ft_warning('timelock structure contains field with and without repetitions'); + str = sprintf('%s, ', fn{hasrpt}); + str = str(1:end-2); + ft_notice('selecting these fields that have repetitions: %s', str); + str = sprintf('%s, ', fn{~hasrpt}); + str = str(1:end-2); + ft_notice('removing these fields that do not have repetitions: %s', str); + timelock = removefields(timelock, fn(~hasrpt)); + if isfield(timelock, 'dimord') && ~ismember(timelock.dimord, dimord(hasrpt)) + % the dimord does not apply to any of the existing fields any more + timelock = rmfield(timelock, 'dimord'); + end + end + case '2011v2' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% if isfield(timelock, 'grad') % ensure that the gradiometer structure is up to date timelock.grad = ft_datatype_sens(timelock.grad); end - + if isfield(timelock, 'elec') % ensure that the electrode structure is up to date timelock.elec = ft_datatype_sens(timelock.elec); end - + + % these fields can be present in raw data, but not desired in timelock data + timelock = removefields(timelock, {'sampleinfo', 'fsample'}); + case '2003' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % there are no known conversions for backward or forward compatibility support - + otherwise %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - error('unsupported version "%s" for timelock datatype', version); + ft_error('unsupported version "%s" for timelock datatype', version); end diff --git a/external/fieldtrip/utilities/ft_datatype_volume.m b/external/fieldtrip/utilities/ft_datatype_volume.m index 2e7d5fab..eb99e9ff 100644 --- a/external/fieldtrip/utilities/ft_datatype_volume.m +++ b/external/fieldtrip/utilities/ft_datatype_volume.m @@ -133,7 +133,7 @@ try volume.(fn{i}) = reshape(volume.(fn{i}), volume.dim); catch - warning('could not reshape %s to the expected dimensions', fn{i}); + ft_warning('could not reshape "%s" to the expected dimensions', fn{i}); end end @@ -179,5 +179,5 @@ otherwise %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - error('unsupported version "%s" for volume datatype', version); + ft_error('unsupported version "%s" for volume datatype', version); end diff --git a/external/fieldtrip/utilities/ft_debug.m b/external/fieldtrip/utilities/ft_debug.m new file mode 100644 index 00000000..75367c74 --- /dev/null +++ b/external/fieldtrip/utilities/ft_debug.m @@ -0,0 +1,64 @@ +function varargout = ft_debug(varargin) + +% FT_DEBUG prints a debug message on screen, depending on the verbosity +% settings of the calling high-level FieldTrip function. +% +% Use as +% ft_debug(...) +% with arguments similar to fprintf, or +% ft_debug(msgId, ...) +% with arguments similar to warning. +% +% You can switch of all messages using +% ft_debug off +% or for specific ones using +% ft_debug off msgId +% +% To switch them back on, you would use +% ft_debug on +% or for specific ones using +% ft_debug on msgId +% +% Messages are only printed once per timeout period using +% ft_debug timeout 60 +% ft_debug once +% or for specific ones using +% ft_debug once msgId +% +% You can see the most recent messages and identifier using +% ft_debug last +% +% You can query the current on/off/once state for all messages using +% ft_debug query +% +% See also FT_ERROR, FT_WARNING, FT_NOTICE, FT_debug, FT_DEBUG, ERROR, WARNING + +% Copyright (C) 2017, Robert Oostenveld +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +if nargout + varargout{:} = ft_notification(varargin{:}); +elseif isequal(varargin, {'last'}) + % return an answer anyway + varargout{1} = ft_notification(varargin{:}); +else + ft_notification(varargin{:}); +end + diff --git a/external/fieldtrip/utilities/ft_determine_coordsys.m b/external/fieldtrip/utilities/ft_determine_coordsys.m index a3d243d4..7e97c2ac 100644 --- a/external/fieldtrip/utilities/ft_determine_coordsys.m +++ b/external/fieldtrip/utilities/ft_determine_coordsys.m @@ -16,6 +16,7 @@ % and can include % interactive = string, 'yes' or 'no' (default = 'yes') % axisscale = scaling factor for the reference axes and sphere (default = 1) +% clim = lower and upper anatomical MRI limits (default = [0 1]) % % This function wil pop up a figure that allows you to check whether the % alignment of the object relative to the coordinate system axes is correct @@ -25,7 +26,7 @@ % coordinate system, you should press the corresponding keyboard button. % % Recognized and supported coordinate systems include: ctf, 4d, bti, itab, -% neuromag, spm, mni, tal, als, ras, paxinos. +% neuromag, spm, mni, tal, acpc, als, ras, paxinos. % % See also FT_VOLUMEREALIGN, FT_VOLUMERESLICE @@ -51,10 +52,10 @@ dointeractive = ft_getopt(varargin, 'interactive', 'yes'); axisscale = ft_getopt(varargin, 'axisscale', 1); % this is used to scale the axmax and rbol +clim = ft_getopt(varargin, 'clim', [0 1]); % this is used to scale the orthoplot -data = ft_checkdata(data); +data = ft_checkdata(data, 'hasunit', 'yes'); dtype = ft_datatype(data); -data = ft_convert_units(data); % the high-level data structures are detected with ft_datatype, but there are % also some low-level data structures that need to be supproted here @@ -75,51 +76,12 @@ dtype = 'mesh'; end -% NOTE this section should be kept consistent with the shorter labels in FT_PLOT_AXES if isfield(data, 'coordsys') && ~isempty(data.coordsys) - label = cell(3,1); - if length(data.coordsys)==3 && length(intersect(data.coordsys, 'rlasif'))==3 - for i=1:3 - switch data.coordsys(i) - case 'l' - label{i} = 'the left'; - case 'r' - label{i} = 'the right'; - case 'i' - label{i} = 'inferior'; - case 's' - label{i} = 'superior'; - case 'a' - label{i} = 'anterior'; - case 'p' - label{i} = 'posterior'; - otherwise - error('incorrect letter in the coordsys'); - end % switch - end % for each of the three axes - elseif strcmpi(data.coordsys, 'itab') || strcmpi(data.coordsys, 'neuromag') || strcmpi(data.coordsys, 'tal') || strcmpi(data.coordsys, 'mni') || strcmpi(data.coordsys, 'spm') - label{1} = 'the right'; - label{2} = 'anterior'; - label{3} = 'superior'; - elseif strcmpi(data.coordsys, 'ctf') || strcmpi(data.coordsys, '4d') || strcmpi(data.coordsys, 'bti') - label{1} = 'anterior'; - label{2} = 'the left'; - label{3} = 'superior'; - elseif strcmpi(data.coordsys, 'paxinos') - label{1} = 'the right'; - label{2} = 'superior'; - label{3} = 'posterior'; - elseif strcmpi(data.coordsys, 'unknown') - label{1} = 'unknown'; - label{2} = 'unknown'; - label{3} = 'unknown'; - else - error('unsupported coordsys'); - end - - fprintf('The positive x-axis is pointing towards %s\n', label{1}); - fprintf('The positive y-axis is pointing towards %s\n', label{2}); - fprintf('The positive z-axis is pointing towards %s\n', label{3}); + % print the interpretation of the coordinate system + [labelx, labely, labelz] = coordsys2label(data.coordsys, 2, 0); + fprintf('The positive x-axis is pointing towards %s\n', labelx); + fprintf('The positive y-axis is pointing towards %s\n', labely); + fprintf('The positive z-axis is pointing towards %s\n', labelz); end % plot the geometrical object @@ -150,7 +112,7 @@ end if isempty(funparam) - error('don''t know which volumetric parameter to plot'); + ft_error('don''t know which volumetric parameter to plot'); end % the volumetric data needs to be interpolated onto three orthogonal planes @@ -159,12 +121,17 @@ diagonal_head = norm(range(corner_head)); diagonal_vox = norm(range(corner_vox)); resolution = diagonal_head/diagonal_vox; % this is in units of "data.unit" - + + % scale funparam between 0 and 1 + dmin = min(funparam(:)); + dmax = max(funparam(:)); + funparam = (funparam-dmin)./(dmax-dmin); + clear ft_plot_slice - ft_plot_ortho(funparam, 'transform', data.transform, 'unit', data.unit, 'resolution', resolution, 'style', 'intersect'); + ft_plot_ortho(funparam, 'transform', data.transform, 'unit', data.unit, 'resolution', resolution, 'style', 'intersect', 'clim', clim); axis vis3d view([110 36]); - + case 'source' if isfield(data, 'inside') && ~isfield(data, 'tri') % only plot the source locations that are inside the volume conduction model @@ -182,7 +149,7 @@ ft_plot_headshape(data); camlight; - case 'mesh' + case {'mesh', 'source+mesh'} ft_plot_mesh(data); camlight; @@ -214,7 +181,7 @@ % plot the 3-D axes, labels, and sphere at the origin ft_plot_axes(data, 'axisscale', axisscale); -if istrue(dointeractive), +if istrue(dointeractive) if ~isfield(data, 'coordsys') || isempty(data.coordsys) % default is yes @@ -247,9 +214,9 @@ end if origin=='a' && strcmp(orientation, 'ras') - coordsys = 'spm'; + coordsys = 'acpc'; % also used for spm, mni, tal elseif origin=='i' && strcmp(orientation, 'als') - coordsys = 'ctf'; + coordsys = 'ctf'; % also used for 4d, bti elseif origin=='i' && strcmp(orientation, 'ras') coordsys = 'neuromag'; % also used for itab else diff --git a/external/fieldtrip/utilities/ft_documentationindex.m b/external/fieldtrip/utilities/ft_documentationindex.m index 65622cbd..9cde770a 100644 --- a/external/fieldtrip/utilities/ft_documentationindex.m +++ b/external/fieldtrip/utilities/ft_documentationindex.m @@ -6,7 +6,7 @@ % http://www.fieldtriptoolboxorg/reference/index where the output of this % function can be found. % -% See FT_DOCUMENTATIONREFERENCE +% See also FT_DOCUMENTATIONREFERENCE % Copyright (C) 2008-2012, Robert Oostenveld % diff --git a/external/fieldtrip/utilities/ft_documentationreference.m b/external/fieldtrip/utilities/ft_documentationreference.m index e453a6b6..c20016d8 100644 --- a/external/fieldtrip/utilities/ft_documentationreference.m +++ b/external/fieldtrip/utilities/ft_documentationreference.m @@ -6,7 +6,7 @@ function ft_documentationreference(outdir) % http://www.fieldtriptoolbox.org/reference where the output of this function can % be found. % -% See FT_DOCUMENTATIONINDEX +% See also FT_DOCUMENTATIONINDEX % Copyright (C) 2008-2014, Robert Oostenveld % diff --git a/external/fieldtrip/utilities/ft_error.m b/external/fieldtrip/utilities/ft_error.m new file mode 100644 index 00000000..413b09f8 --- /dev/null +++ b/external/fieldtrip/utilities/ft_error.m @@ -0,0 +1,40 @@ +function varargout = ft_error(varargin) + +% FT_ERROR prints an error message on screen, just like the standard ERROR function. +% +% Use as +% ft_error(...) +% with arguments similar to fprintf, or +% ft_error(msgId, ...) +% with arguments similar to error. +% +% See also FT_ERROR, FT_WARNING, FT_NOTICE, FT_INFO, FT_DEBUG, ERROR, WARNING + +% Copyright (C) 2017, Robert Oostenveld +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +if nargout + varargout{:} = ft_notification(varargin{:}); +elseif isequal(varargin, {'last'}) + % return an answer anyway + varargout{1} = ft_notification(varargin{:}); +else + ft_notification(varargin{:}); +end diff --git a/external/fieldtrip/utilities/ft_fetch_data.m b/external/fieldtrip/utilities/ft_fetch_data.m index 595a38fb..a374bfdc 100644 --- a/external/fieldtrip/utilities/ft_fetch_data.m +++ b/external/fieldtrip/utilities/ft_fetch_data.m @@ -48,7 +48,7 @@ end if isempty(begsample) || isempty(endsample) - error('begsample and endsample must be specified'); + ft_error('begsample and endsample must be specified'); end if isempty(chanindx) @@ -59,14 +59,14 @@ if isfield(data, 'sampleinfo') trl = data.sampleinfo; else - error('data does not contain a consistent trial definition, fetching data is not possible'); + ft_error('data does not contain a consistent trial definition, fetching data is not possible'); end trlnum = length(data.trial); % start with the output data being all NaN dat = nan(numel(chanindx), endsample-begsample+1); -if trlnum>1, +if trlnum>1 % original implementation, used when the input data has multiple trials trllen = zeros(trlnum,1); @@ -76,15 +76,15 @@ % check whether data.trial is consistent with trl if size(trl,1)~=length(data.trial) - error('trial definition is not internally consistent') + ft_error('trial definition is not internally consistent') elseif any(trllen~=(trl(:,2)-trl(:,1)+1)) - error('trial definition is not internally consistent') + ft_error('trial definition is not internally consistent') end minchan = min(chanindx); maxchan = max(chanindx); if minchan<1 || maxchan>hdr.nChans - error('selected channels are not present in the data') + ft_error('selected channels are not present in the data') end % these are for bookkeeping @@ -127,7 +127,7 @@ % check if all samples are present and are not present twice or more if any(count>1) if ~allowoverlap - % error('some of the requested samples occur twice in the data'); + % ft_error('some of the requested samples occur twice in the data'); % this can be considered OK if the overlap has exactly identical values sel = find(count>1); % must be row vector for smplop=sel @@ -137,17 +137,17 @@ for i=2:length(seltrl) % compare all occurences to the first one if ~all(data.trial{seltrl(i)}(:,selsmp(i)) == data.trial{seltrl(1)}(:,selsmp(1))) - error('some of the requested samples occur twice in the data and have conflicting values'); + ft_error('some of the requested samples occur twice in the data and have conflicting values'); end end end else - warning('samples present in multiple trials, using only the last occurence of each sample') + ft_warning('samples present in multiple trials, using only the last occurence of each sample') end end % if any(count==0) - % warning('not all requested samples are present in the data, filling with NaNs'); + % ft_warning('not all requested samples are present in the data, filling with NaNs'); % end % construct the output data array @@ -167,7 +167,7 @@ utrl = unique(trialnum); utrl(~isfinite(utrl)) = 0; utrl(utrl==0) = []; - if length(utrl)==1, + if length(utrl)==1 ok = trialnum==utrl; smps = samplenum(ok); dat(:,ok) = data.trial{utrl}(chanindx,smps); @@ -185,14 +185,18 @@ % get the indices begindx = begsample - trl(1) + 1; endindx = endsample - trl(1) + 1; - + if endindx<=0 || begindx>size(data.trial{1},2) + % requested data samples outside the data present + return; + end + tmptrl = trl([1 2]) - [trl(1) trl(1)]+1; % ignore offset in case it's present datbegindx = max(1, trl(1)-begsample+1); datendindx = min(endsample-begsample+1, trl(2)-begsample+1); % if begsampletrl(2) - % warning('not all requested samples are present in the data, filling with NaNs'); + % ft_warning('not all requested samples are present in the data, filling with NaNs'); % end if begsample >= trl(1) && begsample <= trl(2) diff --git a/external/fieldtrip/utilities/ft_findcfg.m b/external/fieldtrip/utilities/ft_findcfg.m index ea39b132..7dfce3c2 100644 --- a/external/fieldtrip/utilities/ft_findcfg.m +++ b/external/fieldtrip/utilities/ft_findcfg.m @@ -48,11 +48,11 @@ status = 1; elseif issubfield(cfg, 'previous'); [val, status] = ft_findcfg(cfg.previous, var); - if status, break; end; + if status, break; end elseif iscell(cfg) for i=1:length(cfg) [val, status] = ft_findcfg(cfg{i}, var); - if status, break; end; + if status, break; end end else status = -1; diff --git a/external/fieldtrip/utilities/ft_getopt.m b/external/fieldtrip/utilities/ft_getopt.m index 21ed892a..0d433115 100644 --- a/external/fieldtrip/utilities/ft_getopt.m +++ b/external/fieldtrip/utilities/ft_getopt.m @@ -8,19 +8,19 @@ % where the input values are % s = structure or cell-array % key = string -% default = any valid MATLAB data type +% default = any valid MATLAB data type (optional, default = []) % emptymeaningful = boolean value (optional, default = 0) % -% If the key is present as field in the structure, or as key-value -% pair in the cell-array, the corresponding value will be returned. +% If the key is present as field in the structure, or as key-value pair in the +% cell-array, the corresponding value will be returned. % -% If the key is not present, ft_getopt will return an empty array. +% If the key is not present, ft_getopt will return the default, or an empty array +% when no default was specified. % -% If the key is present but has an empty value, then the emptymeaningful -% flag specifies whether the empty value or the default value should -% be returned. If emptymeaningful==true, then an empty array will be -% returned. If emptymeaningful==false, then the specified default will -% be returned. +% If the key is present but has an empty value, then the emptymeaningful flag +% specifies whether the empty value or the default value should be returned. +% If emptymeaningful==true, then the empty array will be returned. +% If emptymeaningful==false, then the specified default will be returned. % % See also FT_SETOPT, FT_CHECKOPT @@ -60,27 +60,27 @@ else val = opt.(key); end - + elseif isa(opt, 'cell') % get the key-value from the cell-array if mod(length(opt),2) error('optional input arguments should come in key-value pairs, i.e. there should be an even number'); end - + % the 1st, 3rd, etc. contain the keys, the 2nd, 4th, etc. contain the values keys = opt(1:2:end); vals = opt(2:2:end); - + % the following may be faster than cellfun(@ischar, keys) valid = false(size(keys)); for i=1:numel(keys) valid(i) = ischar(keys{i}); end - + if ~all(valid) error('optional input arguments should come in key-value pairs, the optional input argument %d is invalid (should be a string)', i); end - + hit = find(strcmpi(key, keys)); if isempty(hit) % the requested key was not found @@ -91,7 +91,7 @@ else error('multiple input arguments with the same name'); end - + elseif isempty(opt) % no options are specified, return default val = default; diff --git a/external/fieldtrip/utilities/ft_getopt.mexmaci64 b/external/fieldtrip/utilities/ft_getopt.mexmaci64 index 1e499c9421e1062ba1178bd37b44ea26728740c3..48fecb34b3878cd01301ebf956190ce9f9db8af2 100755 GIT binary patch literal 9680 zcmeHNU2Ggz6~62II6tOd2d6cn&}peFm;BizC~4BB-r7!g!A>3Qv=Ly&v+G&!(Al5N z&ZO(eiL5v-ow`P*DWyVHu+#@C1P>r2A_3K+w3vrLO?Zhah$=*rvD`|9LO?BKIp3W- z-q|rmec%brmG3?0JLlYU&zyVbdiKt|{{A~R>lurzVT^5{8l@_&V{D2j%Ezd-)iEZ^ zgFVLvxu~{52Y(Tmd@^#w)(f31n`+6d8V3DIn_QhiW1#@Aby>Gv%O?C#mW!s9EG~5vnU$5nrlk8d`2t*a!Xn zN%;Gg2+G64yw*1fW!cI-q2)$oEtk%7Tst4*jc(6=;Q+WMJ|XvrEUOtgZ75mQl?3Bk z5dPXl2Vks`)e6>$Lsgc$V}miDmA5`tp;#yI>%}U|IbAM}Ws`YbE||uu{ycYBu>QC( zpUuAEWm#ALo4=@VG$;B1`~4xlTYdg;opGwN+?zQ3`JV2CcTY&d$O}y11>6Kw;K#rI z?qY1B9SX_4?=}!^0TxA)7`s3nuH4DkK9V6n(8sCcZA6FfW~@N^&BXUp^%vNpZuJWT z{Dn_3_UV8O@Z(f5&K*m?xNY{K{lk;j=I^`O*|eL6<9h?!NH^xDO}wvnsib1K-EckV zi?O}ZX%rMQvrE^K+0xFDF`};KL)feS4lC_T+Sw#chQB&Kt?d%YPzaxgyg**W;SPKvW-vp+F?E5-C2iF)l* zWzxX<18R@6drY1N*gQSDwbu__thAOWluGMK-j4J3G;b$(dxp1X zdHW=9pW^M)ynTkZn1xC!=C{)NEN?OGmDcBZ`vPyV&MK`~yOq}S)Y6R4eBy7kzG4HF z*0+exW*}U=R;g4nc;s6AJ-EH#E`#d>_bYIChF*LH+(~dh1~&`td*FTmZVp@--1FcT zz&!)*O>k$x{TW;dTpdl;Vh-F^a3kQ_z*`#Vn`Lv|v3YIA;#;BE5b7qm58C7~*9g~WgyrqvwNmVKq)RdOi)DcN3 zN{S?Y&1mVWVtc@gq-G1|SXNbX^t&f*={{$Qq~}Mql%h*{15v1kmXb~=x}~yIK9|-; z8R>NT<&{i5UfiSY-aBUOmQzn8gIIb1fmkWCEns->0hZEL#gGE>1N_R;no%@GwACx5 zi=sevx>WAcGSt&pQ9<@|Z$mI%iFP}A6o>FyvhhiAY7%sj#7H&y)J5>}v zrM1U@|L!4*dJYe>RKR1QHqaAxv-^}C8HO=E*#7p|I=EZ@?Griq1r{kqBhiNX4YQuSdM}Ca=hP2I8Rdx1ryzPNvW0S|mU;}MuQ)nLpFfar))Ue>QZ=0~2q~rDQN_>{%I9O6 znRz7nRXVmqw>e?ZZ!H@@{BoqZlP1kbDMdAvEs)475sXZqbkrTPaw${G=h*hNMkj3Q zaZ5AQ5v8D=P>mwwbn-jbOb1I7c(*;*{3g98W$gW{4R~|CohrwWQQ>DyMBP&-->Y&6 z8cFMY$AQlWfG5P+72Y)y^!o94vwr+=K(7SwaTik;x10&!7X$eF0sKk;|2lyG5Ws&8 z;0TTE{*i*p<^aY)tzRz%@U{TPiND{zCxDN*csch&0gUe)@S+3X>};e;Z{_*707y5E z%5I^GIfzniqPm6ZN2%go$0Xn!5zaBm_)b840!{s#yu*x#5y;C@<-Xehi z`QCuWe^ad3tVpoRHbt764GOq+Ya)q%Q*vQ-J96=gjmQ;?Er@{Fd|VFOj?3{4hqLZh X!&z^W;lSHoI1u}a|88HgWi$3~)uY>q literal 9832 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 delta 33 mcmZp0X>eJ<$YTBPQ|M$CMjxgvZ#D-pCP{(?Ht&$~U! delta 32 lcmZqhXz-ZugT=2, get_spm_version()<95}; + %This is to avoid crashes when trying to add SPM to the path + fallback_toolbox = 'SPM8'; case 'SPM5' dependency = {'spm', get_spm_version()==5}; + case 'SPM5UP' % version 5 or later, but not SPM 9X + dependency = {'spm', get_spm_version()>=5, get_spm_version()<95}; + %This is to avoid crashes when trying to add SPM to the path + fallback_toolbox = 'SPM5'; case 'SPM8' dependency = {'spm', get_spm_version()==8}; case 'SPM8UP' % version 8 or later, but not SPM 9X dependency = {'spm', get_spm_version()>=8, get_spm_version()<95}; - %This is to avoid crashes when trying to add SPM to the path fallback_toolbox = 'SPM8'; case 'SPM12' dependency = {'spm', get_spm_version()==12}; + case 'SPM12UP' % version 12 or later, but not SPM 9X + dependency = {'spm', get_spm_version()>=12, get_spm_version()<95}; + %This is to avoid crashes when trying to add SPM to the path + fallback_toolbox = 'SPM12'; case 'MEG-PD' dependency = {'rawdata', 'channames'}; case 'MEG-CALC' @@ -205,8 +220,7 @@ case 'MRI' % other functions in the mri section dependency = {'avw_hdr_read', 'avw_img_read'}; case 'NEUROSHARE' - dependency = {'ns_OpenFile', 'ns_SetLibrary', ... - 'ns_GetAnalogData'}; + dependency = {'ns_OpenFile', 'ns_SetLibrary', 'ns_GetAnalogData'}; case 'ARTINIS' dependency = {'read_artinis_oxy3'}; case 'BESA' @@ -234,21 +248,21 @@ case '4D-VERSION' dependency = {'read4d', 'read4dhdr'}; case {'STATS', 'STATISTICS'} - dependency = has_license('statistics_toolbox'); % check the availability of a toolbox license + dependency = has_license('statistics_toolbox'); % also check the availability of a toolbox license case {'OPTIM', 'OPTIMIZATION'} - dependency = has_license('optimization_toolbox'); % check the availability of a toolbox license + dependency = has_license('optimization_toolbox'); % also check the availability of a toolbox license case {'SPLINES', 'CURVE_FITTING'} - dependency = has_license('curve_fitting_toolbox'); % check the availability of a toolbox license + dependency = has_license('curve_fitting_toolbox'); % also check the availability of a toolbox license case 'COMM' dependency = {has_license('communication_toolbox'), 'de2bi'}; % also check the availability of a toolbox license case 'SIGNAL' - dependency = {has_license('signal_toolbox'), 'window'}; % also check the availability of a toolbox license - case 'IMAGE' - dependency = has_license('image_toolbox'); % check the availability of a toolbox license + dependency = {has_license('signal_toolbox'), 'window'}; % also check the availability of a toolbox license + case 'IMAGES' + dependency = has_license('image_toolbox'); % also check the availability of a toolbox license case {'DCT', 'DISTCOMP'} - dependency = has_license('distrib_computing_toolbox'); % check the availability of a toolbox license + dependency = has_license('distrib_computing_toolbox'); % also check the availability of a toolbox license case 'COMPILER' - dependency = has_license('compiler'); % check the availability of a toolbox license + dependency = has_license('compiler'); % also check the availability of a toolbox license case 'FASTICA' dependency = 'fpica'; case 'BRAINSTORM' @@ -260,8 +274,7 @@ case 'BCI2000' dependency = {'load_bcidat'}; case 'NLXNETCOM' - dependency = {'MatlabNetComClient', 'NlxConnectToServer', ... - 'NlxGetNewCSCData'}; + dependency = {'MatlabNetComClient', 'NlxConnectToServer', 'NlxGetNewCSCData'}; case 'DIPOLI' dependency = {'dipoli.maci', 'file'}; case 'MNE' @@ -323,17 +336,17 @@ dependency = {'plx_adchan_gains', 'mexPlex'}; case '35625-INFORMATION-THEORY-TOOLBOX' dependency = {'conditionalEntropy', 'entropy', 'jointEntropy',... - 'mutualInformation' 'nmi' 'nvi' 'relativeEntropy'}; + 'mutualInformation' 'nmi' 'nvi' 'relativeEntropy'}; case '29046-MUTUAL-INFORMATION' dependency = {'MI', 'license.txt'}; case '14888-MUTUAL-INFORMATION-COMPUTATION' dependency = {'condentropy', 'demo_mi', 'estcondentropy.cpp',... - 'estjointentropy.cpp', 'estpa.cpp', ... - 'findjointstateab.cpp', 'makeosmex.m',... - 'mutualinfo.m', 'condmutualinfo.m',... - 'entropy.m', 'estentropy.cpp',... - 'estmutualinfo.cpp', 'estpab.cpp',... - 'jointentropy.m' 'mergemultivariables.m' }; + 'estjointentropy.cpp', 'estpa.cpp', ... + 'findjointstateab.cpp', 'makeosmex.m',... + 'mutualinfo.m', 'condmutualinfo.m',... + 'entropy.m', 'estentropy.cpp',... + 'estmutualinfo.cpp', 'estpab.cpp',... + 'jointentropy.m' 'mergemultivariables.m' }; case 'PLOT2SVG' dependency = {'plot2svg.m', 'simulink2svg.m'}; case 'BRAINSUITE' @@ -352,11 +365,16 @@ dependency = {'write_wobj' 'read_wobj'}; case 'NEURONE' dependency = {'readneurone' 'readneuronedata' 'readneuroneevents'}; - + case 'BREWERMAP' + dependency = {'brewermap' 'brewermap_view'}; + case 'GTEC' + dependency = {'ghdf5read' 'ghdf5fileimport'}; + case 'MARS' + dependency = {'spm_mars_mrf'}; + % the following are FieldTrip modules/toolboxes case 'FILEIO' - dependency = {'ft_read_header', 'ft_read_data', ... - 'ft_read_event', 'ft_read_sens'}; + dependency = {'ft_read_header', 'ft_read_data', 'ft_read_event', 'ft_read_sens'}; case 'FORWARD' dependency = {'ft_compute_leadfield', 'ft_prepare_vol_sens'}; case 'PLOTTING' @@ -369,33 +387,35 @@ dependency = {'ft_spiketriggeredaverage', 'ft_spiketriggeredspectrum'}; case 'FILEEXCHANGE' dependency = is_subdir_in_fieldtrip_path('/external/fileexchange'); + case 'CELLFUNCTION' + dependency = {'cellmean', 'cellvecadd', 'cellcat'}; case {'INVERSE', 'REALTIME', 'SPECEST', 'PREPROC', ... - 'COMPAT', 'STATFUN', 'TRIALFUN', 'UTILITIES/COMPAT', ... - 'FILEIO/COMPAT', 'PREPROC/COMPAT', 'FORWARD/COMPAT', ... - 'PLOTTING/COMPAT', 'TEMPLATE/LAYOUT', 'TEMPLATE/ANATOMY' ,... - 'TEMPLATE/HEADMODEL', 'TEMPLATE/ELECTRODE', ... - 'TEMPLATE/NEIGHBOURS', 'TEMPLATE/SOURCEMODEL'} + 'COMPAT', 'STATFUN', 'TRIALFUN', 'UTILITIES/COMPAT', ... + 'FILEIO/COMPAT', 'PREPROC/COMPAT', 'FORWARD/COMPAT', ... + 'PLOTTING/COMPAT', 'TEMPLATE/LAYOUT', 'TEMPLATE/ANATOMY' ,... + 'TEMPLATE/HEADMODEL', 'TEMPLATE/ELECTRODE', ... + 'TEMPLATE/NEIGHBOURS', 'TEMPLATE/SOURCEMODEL'} dependency = is_subdir_in_fieldtrip_path(toolbox); otherwise - if ~silent, warning('cannot determine whether the %s toolbox is present', toolbox); end + if ~silent, ft_warning('cannot determine whether the %s toolbox is present', toolbox); end dependency = false; end status = is_present(dependency); if ~status && ~isempty(fallback_toolbox) - % in case of SPM8UP + % in case of SPMxUP toolbox = fallback_toolbox; end % try to determine the path of the requested toolbox if autoadd>0 && ~status - + % for core FieldTrip modules prefix = fileparts(which('ft_defaults')); if ~status status = myaddpath(fullfile(prefix, lower(toolbox)), silent); end - + % for external FieldTrip modules prefix = fullfile(fileparts(which('ft_defaults')), 'external'); if ~status @@ -407,37 +427,37 @@ feval(licensefile); end end - + % for contributed FieldTrip extensions prefix = fullfile(fileparts(which('ft_defaults')), 'contrib'); if ~status status = myaddpath(fullfile(prefix, lower(toolbox)), silent); licensefile = [lower(toolbox) '_license']; if status && exist(licensefile, 'file') - % this will execute openmeeg_license and mne_license - % which display the license on screen for three seconds + % this will execute openmeeg_license, mne_license and artinis_license + % which display the license on screen for a few seconds feval(licensefile); end end - + % for linux computers in the Donders Centre for Cognitive Neuroimaging prefix = '/home/common/matlab'; if ~status && isdir(prefix) status = myaddpath(fullfile(prefix, lower(toolbox)), silent); end - + % for windows computers in the Donders Centre for Cognitive Neuroimaging prefix = 'h:\common\matlab'; if ~status && isdir(prefix) status = myaddpath(fullfile(prefix, lower(toolbox)), silent); end - + % use the MATLAB subdirectory in your homedirectory, this works on linux and mac prefix = fullfile(getenv('HOME'), 'matlab'); if ~status && isdir(prefix) status = myaddpath(fullfile(prefix, lower(toolbox)), silent); end - + if ~status % the toolbox is not on the path and cannot be added sel = find(strcmp(url(:,1), toolbox)); @@ -447,7 +467,7 @@ msg = sprintf('the %s toolbox is not installed', toolbox); end if autoadd==1 - error(msg); + ft_error(msg); elseif autoadd==2 ft_warning(msg); else @@ -458,30 +478,35 @@ % this function is called many times in FieldTrip and associated toolboxes % use efficient handling if the same toolbox has been investigated before -if status - previous.(fixname(toolbox)) = status; -end +% if status +% previous.(fixname(toolbox)) = status; +% end % remember the previous path, allows us to determine on the next call % whether the path has been modified outise of this function -previouspath = path; +% previouspath = path; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % helper function %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function status = myaddpath(toolbox, silent) if isdeployed - warning('cannot change path settings for %s in a compiled application', toolbox); + ft_warning('cannot change path settings for %s in a compiled application', toolbox); status = 1; elseif exist(toolbox, 'dir') - if ~silent, - ws = warning('backtrace', 'off'); - warning('adding %s toolbox to your MATLAB path', toolbox); - warning(ws); % return to the previous warning level + if ~silent + ft_warning('off','backtrace'); + ft_warning('adding %s toolbox to your MATLAB path', toolbox); + ft_warning('on','backtrace'); + end + if any(~cellfun(@isempty, regexp(toolbox, {'spm2', 'spm5', 'spm8', 'spm12'}))) + % SPM needs to be added with the subdirectories + addpath(genpath(toolbox)); + else + addpath(toolbox); end - addpath(toolbox); status = 1; -elseif (~isempty(regexp(toolbox, 'spm5$', 'once')) || ~isempty(regexp(toolbox, 'spm8$', 'once')) || ~isempty(regexp(toolbox, 'spm12$', 'once'))) && exist([toolbox 'b'], 'dir') +elseif (~isempty(regexp(toolbox, 'spm2$', 'once')) || ~isempty(regexp(toolbox, 'spm5$', 'once')) || ~isempty(regexp(toolbox, 'spm8$', 'once')) || ~isempty(regexp(toolbox, 'spm12$', 'once'))) && exist([toolbox 'b'], 'dir') status = myaddpath([toolbox 'b'], silent); else status = 0; @@ -511,9 +536,9 @@ m = lasterror; if strcmp(m.identifier, 'MATLAB:license:checkouterror') if nargin>1 - warning('the %s toolbox is available, but you don''t have a license for it', toolbox); + ft_warning('the %s toolbox is available, but you don''t have a license for it', toolbox); else - warning('the function ''%s'' is available, but you don''t have a license for it', funname); + ft_warning('the function ''%s'' is available, but you don''t have a license for it', funname); end status = false; elseif strcmp(m.identifier, 'MATLAB:UndefinedFunction') @@ -529,65 +554,65 @@ % helper function %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function status = is_subdir_in_fieldtrip_path(toolbox_name) - fttrunkpath = unixpath(fileparts(which('ft_defaults'))); - fttoolboxpath = fullfile(fttrunkpath, lower(toolbox_name)); +fttrunkpath = unixpath(fileparts(which('ft_defaults'))); +fttoolboxpath = fullfile(fttrunkpath, lower(toolbox_name)); - needle=[pathsep fttoolboxpath pathsep]; - haystack = [pathsep path() pathsep]; +needle=[pathsep fttoolboxpath pathsep]; +haystack = [pathsep path() pathsep]; - status = ~isempty(findstr(needle, haystack)); +status = ~isempty(findstr(needle, haystack)); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % helper function %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function status = has_mex(name) - full_name=[name '.' mexext]; - status = (exist(full_name, 'file')==3); +full_name=[name '.' mexext]; +status = (exist(full_name, 'file')==3); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % helper function %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function v = get_spm_version() - if ~is_present('spm') - v=NaN; - return - end +if ~is_present('spm') + v=NaN; + return +end - version_str = spm('ver'); - token = regexp(version_str,'(\d*)','tokens'); - v = str2num([token{:}{:}]); +version_str = spm('ver'); +token = regexp(version_str,'(\d*)','tokens'); +v = str2num([token{:}{:}]); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % helper function %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function status = has_license(toolbox_name) - status = license('checkout', toolbox_name)==1; +status = license('checkout', toolbox_name)==1; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % helper function %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function status = is_present(dependency) - if iscell(dependency) - % use recursion - status = all(cellfun(@is_present,dependency)); - elseif islogical(dependency) - % boolean - status = all(dependency); - elseif ischar(dependency) - % name of a function - status = is_function_present_in_search_path(dependency); - elseif isa(dependency, 'function_handle') - status = dependency(); - else - assert(false,'this should not happen'); - end +if iscell(dependency) + % use recursion + status = all(cellfun(@is_present,dependency)); +elseif islogical(dependency) + % boolean + status = all(dependency); +elseif ischar(dependency) + % name of a function + status = is_function_present_in_search_path(dependency); +elseif isa(dependency, 'function_handle') + status = dependency(); +else + assert(false,'this should not happen'); +end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % helper function %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function status = is_function_present_in_search_path(function_name) - w = which(function_name); +w = which(function_name); - % must be in path and not a variable - status = ~isempty(w) && ~isequal(w, 'variable'); +% must be in path and not a variable +status = ~isempty(w) && ~isequal(w, 'variable'); diff --git a/external/fieldtrip/utilities/ft_headcoordinates.m b/external/fieldtrip/utilities/ft_headcoordinates.m index 2c6cd04c..66751a8f 100644 --- a/external/fieldtrip/utilities/ft_headcoordinates.m +++ b/external/fieldtrip/utilities/ft_headcoordinates.m @@ -50,6 +50,7 @@ % according to FTG conventions: coordsys = 'ftg' % according to Talairach conventions: coordsys = 'tal' % according to SPM conventions: coordsys = 'spm' +% according to ACPC conventions: coordsys = 'acpc' % according to PAXINOS conventions: coordsys = 'paxinos' % If coordsys is not specified, it will default to 'ctf'. % @@ -59,7 +60,7 @@ % the Y-axis goes approximately towards lpa, orthogonal to X and in the plane spanned by the fiducials % the Z-axis goes approximately towards the vertex, orthogonal to X and Y % -% The TALAIRACH and SPM coordinate systems are defined as: +% The TALAIRACH, SPM and ACPC coordinate systems are defined as: % the origin corresponds with the anterior commissure % the Y-axis is along the line from the posterior commissure to the anterior commissure % the Z-axis is towards the vertex, in between the hemispheres @@ -88,7 +89,7 @@ % the y-axis points from dorsal to ventral, i.e. from inferior to superior % the z-axis passes through bregma and lambda and points from cranial to caudal, i.e. from anterior to posterior % -% See also FT_ELECTRODEREALIGN, FT_VOLUMEREALIGN, FT_INTERACTIVEREALIGN +% See also FT_ELECTRODEREALIGN, FT_VOLUMEREALIGN, FT_INTERACTIVEREALIGN, COORDSYS2LABEL % Copyright (C) 2003-2014 Robert Oostenveld % @@ -122,19 +123,19 @@ elseif nargin==5 % do nothing else - error('incorrect specification of input parameters'); + ft_error('incorrect specification of input parameters'); end if isnumeric(coordsys) % these are for backward compatibility, but should preferably not be used any more - if coordsys==0, + if coordsys==0 coordsys = 'ctf'; - elseif coordsys==1, + elseif coordsys==1 coordsys = 'asa'; - elseif coordsys==2, + elseif coordsys==2 coordsys = 'ftg'; else - error('if coordsys is numeric, it should assume one of the values 0/1/2'); + ft_error('if coordsys is numeric, it should assume one of the values 0/1/2'); end end @@ -154,7 +155,7 @@ % compute the origin and direction of the coordinate axes in MRI coordinates switch coordsys - case {'als_ctf' 'ctf' 'bti' '4d' 'yokogawa'} + case {'ctf' 'bti' '4d' 'yokogawa'} % rename the marker points for convenience nas = fid1; lpa = fid2; rpa = fid3; extrapoint = fid4; clear fid* origin = (lpa+rpa)/2; @@ -164,7 +165,7 @@ dirx = dirx/norm(dirx); diry = diry/norm(diry); dirz = dirz/norm(dirz); - case {'als_asa' 'asa'} + case {'asa'} % rename the marker points for convenience nas = fid1; lpa = fid2; rpa = fid3; extrapoint = fid4; clear fid* dirz = cross(nas-rpa, lpa-rpa); @@ -174,7 +175,7 @@ diry = diry/norm(diry); dirz = dirz/norm(dirz); origin = rpa + dot(nas-rpa,diry)*diry; - case {'ras_itab' 'itab' 'neuromag'} + case {'itab' 'neuromag'} % rename the fiducials nas = fid1; lpa = fid2; rpa = fid3; extrapoint = fid4; clear fid* dirz = cross(rpa-lpa,nas-lpa); @@ -195,7 +196,7 @@ dirx = dirx/norm(dirx); diry = diry/norm(diry); dirz = dirz/norm(dirz); - case {'ras_tal' 'tal' 'spm'} + case {'tal' 'spm' 'acpc'} % rename the marker points for convenience ac = fid1; pc = fid2; midsagittal = fid3; extrapoint = fid4; clear fid* origin = ac; @@ -217,27 +218,27 @@ diry = diry/norm(diry); dirz = dirz/norm(dirz); otherwise - error('unrecognized headcoordinate system "%s"', coordsys); + ft_error('unrecognized headcoordinate system "%s"', coordsys); end % use the extra point to validate that it is a right-handed coordinate system if ~isempty(extrapoint) dirq = extrapoint-origin; dirq = dirq/norm(dirq); - if any(strcmp(coordsys, {'als_ctf' 'ctf' 'bti' '4d' 'yokogawa' 'ras_itab' 'itab' 'neuromag'})) + if any(strcmp(coordsys, {'ctf' 'bti' '4d' 'yokogawa' 'itab' 'neuromag'})) phi = dirq(:)'*dirz(:); if sign(phi)<0 - warning('the input coordinate system seems left-handed, flipping z-axis to keep the transformation matrix consistent'); + ft_warning('the input coordinate system seems left-handed, flipping z-axis to keep the transformation matrix consistent'); dirz = -dirz; end - elseif any(strcmp(coordsys, {'ras_tal' 'tal' 'spm'})) + elseif any(strcmp(coordsys, {'tal' 'spm' 'acpc'})) phi = dirq(:)'*dirx(:); if sign(phi)<0 - warning('the input coordinate system seems left-handed, flipping x-axis to keep the transformation matrix consistent'); + ft_warning('the input coordinate system seems left-handed, flipping x-axis to keep the transformation matrix consistent'); dirx = -dirx; end else - warning('the extra input coordinate is not used with coordsys "%s"', coordsys); + ft_warning('the extra input coordinate is not used with coordsys "%s"', coordsys); end end diff --git a/external/fieldtrip/utilities/ft_info.m b/external/fieldtrip/utilities/ft_info.m new file mode 100644 index 00000000..72f2a06a --- /dev/null +++ b/external/fieldtrip/utilities/ft_info.m @@ -0,0 +1,64 @@ +function varargout = ft_info(varargin) + +% FT_INFO prints an info message on screen, depending on the verbosity +% settings of the calling high-level FieldTrip function. +% +% Use as +% ft_info(...) +% with arguments similar to fprintf, or +% ft_info(msgId, ...) +% with arguments similar to warning. +% +% You can switch of all messages using +% ft_info off +% or for specific ones using +% ft_info off msgId +% +% To switch them back on, you would use +% ft_info on +% or for specific ones using +% ft_info on msgId +% +% Messages are only printed once per timeout period using +% ft_info timeout 60 +% ft_info once +% or for specific ones using +% ft_info once msgId +% +% You can see the most recent messages and identifier using +% ft_info last +% +% You can query the current on/off/once state for all messages using +% ft_info query +% +% See also FT_ERROR, FT_WARNING, FT_NOTICE, FT_INFO, FT_DEBUG, ERROR, WARNING + +% Copyright (C) 2017, Robert Oostenveld +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +if nargout + varargout{:} = ft_notification(varargin{:}); +elseif isequal(varargin, {'last'}) + % return an answer anyway + varargout{1} = ft_notification(varargin{:}); +else + ft_notification(varargin{:}); +end + diff --git a/external/fieldtrip/utilities/ft_notice.m b/external/fieldtrip/utilities/ft_notice.m new file mode 100644 index 00000000..52561888 --- /dev/null +++ b/external/fieldtrip/utilities/ft_notice.m @@ -0,0 +1,64 @@ +function varargout = ft_notice(varargin) + +% FT_NOTICE prints a notice message on screen, depending on the verbosity +% settings of the calling high-level FieldTrip function. +% +% Use as +% ft_notice(...) +% with arguments similar to fprintf, or +% ft_notice(msgId, ...) +% with arguments similar to warning. +% +% You can switch of all messages using +% ft_notice off +% or for specific ones using +% ft_notice off msgId +% +% To switch them back on, you would use +% ft_notice on +% or for specific ones using +% ft_notice on msgId +% +% Messages are only printed once per timeout period using +% ft_notice timeout 60 +% ft_notice once +% or for specific ones using +% ft_notice once msgId +% +% You can see the most recent messages and identifier using +% ft_notice last +% +% You can query the current on/off/once state for all messages using +% ft_notice query +% +% See also FT_ERROR, FT_WARNING, FT_NOTICE, FT_DEBUG, ERROR, WARNING + +% Copyright (C) 2017, Robert Oostenveld +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +if nargout + varargout{:} = ft_notification(varargin{:}); +elseif isequal(varargin, {'last'}) + % return an answer anyway + varargout{1} = ft_notification(varargin{:}); +else + ft_notification(varargin{:}); +end + diff --git a/external/fieldtrip/utilities/ft_platform_supports.m b/external/fieldtrip/utilities/ft_platform_supports.m new file mode 100644 index 00000000..c0676b62 --- /dev/null +++ b/external/fieldtrip/utilities/ft_platform_supports.m @@ -0,0 +1,336 @@ +function tf = ft_platform_supports(what,varargin) + +% FT_PLATFORM_SUPPORTS returns a boolean indicating whether the current platform +% supports a specific capability +% +% Use as +% status = ft_platform_supports(what) +% or +% status = ft_platform_supports('matlabversion', min_version, max_version) +% +% The following values are allowed for the 'what' parameter, which means means that +% the specific feature explained on the right is supported: +% +% 'which-all' which(...,'all') +% 'exists-in-private-directory' exists(...) will look in the /private subdirectory to see if a file exists +% 'onCleanup' onCleanup(...) +% 'alim' alim(...) +% 'int32_logical_operations' bitand(a,b) with a, b of type int32 +% 'graphics_objects' graphics sysem is object-oriented +% 'libmx_c_interface' libmx is supported through mex in the C-language (recent MATLAB versions only support C++) +% 'images' all image processing functions in FieldTrip's external/images directory +% 'signal' all signal processing functions in FieldTrip's external/signal directory +% 'stats' all statistical functions in FieldTrip's external/stats directory +% 'program_invocation_name' program_invocation_name() (GNU Octave) +% 'singleCompThread' start MATLAB with -singleCompThread +% 'nosplash' start MATLAB with -nosplash +% 'nodisplay' start MATLAB with -nodisplay +% 'nojvm' start MATLAB with -nojvm +% 'no-gui' start GNU Octave with --no-gui +% 'RandStream.setGlobalStream' RandStream.setGlobalStream(...) +% 'RandStream.setDefaultStream' RandStream.setDefaultStream(...) +% 'rng' rng(...) +% 'rand-state' rand('state') +% 'urlread-timeout' urlread(..., 'Timeout', t) +% 'griddata-vector-input' griddata(...,...,...,a,b) with a and b vectors +% 'griddata-v4' griddata(...,...,...,...,...,'v4') with v4 interpolation support +% 'uimenu' uimenu(...) +% 'weboptions' weboptions(...) +% 'parula' parula(...) +% 'html' html rendering in desktop +% +% See also FT_VERSION, VERSION, VER, VERLESSTHAN + +if ~ischar(what) + error('first argument must be a string'); +end + +switch what + case 'matlabversion' + tf = is_matlab() && matlabversion(varargin{:}); + + case 'exists-in-private-directory' + tf = is_matlab(); + + case 'which-all' + tf = is_matlab(); + + case 'onCleanup' + tf = is_octave() || matlabversion(7.8, Inf); + + case 'alim' + tf = is_matlab(); + + case 'int32_logical_operations' + % earlier version of MATLAB don't support bitand (and similar) + % operations on int32 + tf = is_octave() || ~matlabversion(-Inf, '2012a'); + + case 'graphics_objects' + % introduced in MATLAB 2014b, graphics is handled through objects; + % previous versions use numeric handles + tf = is_matlab() && matlabversion('2014b', Inf); + + case 'libmx_c_interface' + % removed after 2013b + tf = is_matlab() && matlabversion(-Inf, '2013b'); + + case 'images' + root_dir = fileparts(which('ft_defaults')); + external_stats_dir = fullfile(root_dir, 'external', 'images'); + + tf = has_all_functions_in_dir(external_stats_dir, {}); + + case 'signal' + root_dir = fileparts(which('ft_defaults')); + external_stats_dir = fullfile(root_dir, 'external', 'signal'); + + tf = has_all_functions_in_dir(external_stats_dir, {}); + + case 'stats' + root_dir = fileparts(which('ft_defaults')); + external_stats_dir = fullfile(root_dir, 'external', 'stats'); + + % these files are only used by other functions in the external/stats directory + exclude_mfiles = { + 'common_size.m' + 'iscomplex.m' + }; + + tf = has_all_functions_in_dir(external_stats_dir, exclude_mfiles); + + case 'program_invocation_name' + % Octave supports program_invocation_name, which returns the path + % of the binary that was run to start Octave + tf = is_octave(); + + case 'singleCompThread' + tf = is_matlab() && matlabversion(7.8, Inf); + + case {'nosplash', 'nodisplay', 'nojvm'} + % Only on MATLAB + tf = is_matlab(); + + case 'no-gui' + % Only on Octave + tf = is_octave(); + + case 'RandStream.setDefaultStream' + tf = is_matlab() && matlabversion('2008b', '2011b'); + + case 'RandStream.setGlobalStream' + tf = is_matlab() && matlabversion('2012a', Inf); + + case 'randomized_PRNG_on_startup' + tf = is_octave() || ~matlabversion(-Inf, '7.3'); + + case 'rng' + % recent MATLAB versions + tf = is_matlab() && matlabversion('7.12', Inf); + + case 'rand-state' + % GNU Octave + tf = is_octave(); + + case 'urlread-timeout' + tf = is_matlab() && matlabversion('2012b', Inf); + + case 'griddata-vector-input' + tf = is_matlab(); + + case 'griddata-v4' + tf = is_matlab() && matlabversion('2009a', Inf); + + case 'uimenu' + tf = is_matlab(); + + case {'weboptions', 'webread', 'websave'} + tf = is_matlab() && matlabversion('2014b', Inf); + + case 'webwrite' + tf = is_matlab() && matlabversion('2015a', Inf); + + case 'boundary' + tf = is_matlab() && matlabversion('2014b', Inf); + + case 'parula' + tf = is_matlab() && matlabversion('2014b', Inf); + + case 'html' + tf = ~is_octave() && usejava('desktop') && desktop('-inuse'); + + otherwise + error('unsupported value for first argument: %s', what); + +end % switch + +end % function + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function tf = is_matlab() +tf = ~is_octave(); +end % function + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function tf = is_octave() +persistent cached_tf + +if isempty(cached_tf) + cached_tf = logical(exist('OCTAVE_VERSION', 'builtin')); +end + +tf = cached_tf; +end % function + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function tf = has_all_functions_in_dir(in_dir, exclude_mfiles) +% returns true if all functions in in_dir are already provided by the platform +m_files = dir(fullfile(in_dir,'*.m')); +n = numel(m_files); + +for k = 1:n + m_filename = m_files(k).name; + if isempty(which(m_filename)) && isempty(strmatch(m_filename,exclude_mfiles)) + tf = false; + return; + end +end + +tf = true; + +end % function + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function [inInterval] = matlabversion(min, max) + +% MATLABVERSION checks if the current MATLAB version is within the interval +% specified by min and max. +% +% Use as +% if matlabversion(7.0, 7.9) +% % do something +% end +% +% Both strings and numbers, as well as infinities, are supported, eg.: +% matlabversion(7.1, 7.9) % is version between 7.1 and 7.9? +% matlabversion(6, '7.10') % is version between 6 and 7.10? (note: '7.10', not 7.10) +% matlabversion(-Inf, 7.6) % is version <= 7.6? +% matlabversion('2009b') % exactly 2009b +% matlabversion('2008b', '2010a') % between two versions +% matlabversion('2008b', Inf) % from a version onwards +% etc. +% +% See also VERSION, VER, VERLESSTHAN + +% Copyright (C) 2006, Robert Oostenveld +% Copyright (C) 2010, Eelke Spaak +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +% the version does not change, making it persistent speeds up the subsequent calls +persistent curVer + +if nargin<2 + max = min; +end + +if isempty(curVer) + curVer = version(); +end + +if ((ischar(min) && isempty(str2num(min))) || (ischar(max) && isempty(str2num(max)))) + % perform comparison with respect to release string + + ind = strfind(curVer, '(R'); + [year, ab] = parseMatlabRelease(curVer((ind + 2):(numel(curVer) - 1))); + + [minY, minAb] = parseMatlabRelease(min); + [maxY, maxAb] = parseMatlabRelease(max); + + inInterval = orderedComparison(minY, minAb, maxY, maxAb, year, ab); + +else + % perform comparison with respect to version number + [major, minor] = parseMatlabVersion(curVer); + [minMajor, minMinor] = parseMatlabVersion(min); + [maxMajor, maxMinor] = parseMatlabVersion(max); + + inInterval = orderedComparison(minMajor, minMinor, maxMajor, maxMinor, major, minor); +end + +end % function + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function [year, ab] = parseMatlabRelease(str) +if (str == Inf) + year = Inf; ab = Inf; +elseif (str == -Inf) + year = -Inf; ab = -Inf; +else + year = str2num(str(1:4)); + ab = str(5); +end +end % function + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function [major, minor] = parseMatlabVersion(ver) +if (ver == Inf) + major = Inf; minor = Inf; +elseif (ver == -Inf) + major = -Inf; minor = -Inf; +elseif (isnumeric(ver)) + major = floor(ver); + minor = int8((ver - floor(ver)) * 10); +else % ver is string (e.g. '7.10'), parse accordingly + [major, rest] = strtok(ver, '.'); + major = str2num(major); + minor = str2num(strtok(rest, '.')); +end +end % function + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function inInterval = orderedComparison(lowerA, lowerB, upperA, upperB, testA, testB) +% checks if testA is in interval (lowerA,upperA); if at edges, checks if testB is in interval (lowerB,upperB). +if (testA < lowerA || testA > upperA) + inInterval = false; +else + inInterval = true; + if (testA == lowerA) + inInterval = inInterval && (testB >= lowerB); + end + + if (testA == upperA) + inInterval = inInterval && (testB <= upperB); + end +end +end % function diff --git a/external/fieldtrip/utilities/ft_postamble.m b/external/fieldtrip/utilities/ft_postamble.m index e0f6144e..41d89d43 100644 --- a/external/fieldtrip/utilities/ft_postamble.m +++ b/external/fieldtrip/utilities/ft_postamble.m @@ -51,10 +51,40 @@ function ft_postamble(cmd, varargin) % this is a trick to pass the input arguments into the ft_postamble_xxx script ft_default.postamble = varargin; -if exist(['ft_postamble_' cmd], 'file') - evalin('caller', ['ft_postamble_' cmd]); +full_cmd=['ft_postamble_' cmd]; +cmd_exists=false; + +if exist(full_cmd, 'file') + % Matlab can find commands in a private subdirectory; Octave cannot. + % If pwd is already the private directory, or if using Matlab then + % the command can be evaluated directly + cmd_exists = true; + +elseif ~ft_platform_supports('exists-in-private-directory') + % Octave does not find files by name in a private directory, so the full + % filename must be specified. + private_dir=fullfile(fileparts(which(mfilename)),'private'); + full_path=fullfile(private_dir,[full_cmd '.m']); + + cmd_exists=exist(full_path,'file'); + full_cmd_parts={'ft_tmp_orig_pwd=pwd();',... + 'ft_tmp_orig_pwd_cleaner='... + 'onCleanup(@()cd(ft_tmp_orig_pwd));',... + sprintf('cd(''%s'');',private_dir),... + [full_cmd ';'],... + 'clear ft_tmp_orig_pwd_cleaner;'}; + full_cmd=sprintf('%s',full_cmd_parts{:}); end +if ~cmd_exists + % XXX earlier versions would not do anything if ~cmd_exists, + % but fail silently (without raising an error or warning). + % Should that behavior be kept? + ft_error('Could not run %s - does not seem to exist', full_cmd); +end + +evalin('caller', full_cmd); + if isfield(ft_default, 'postamble') % the postamble field should not remain in the ft_default structure ft_default = rmfield(ft_default, 'postamble'); diff --git a/external/fieldtrip/utilities/ft_preamble.m b/external/fieldtrip/utilities/ft_preamble.m index 0bc80192..5b58c8c0 100644 --- a/external/fieldtrip/utilities/ft_preamble.m +++ b/external/fieldtrip/utilities/ft_preamble.m @@ -50,29 +50,40 @@ function ft_preamble(cmd, varargin) % this is a trick to pass the input arguments into the ft_preamble_xxx script ft_default.preamble = varargin; -if ft_platform_supports('exists-in-private-directory') - % Matlab can directly see the command, no trickery needed as in Octave. - if exist(['ft_preamble_' cmd], 'file') - evalin('caller', ['ft_preamble_' cmd]); - end -else - % Octave does not find files by name, so the full filename must be specified. - if exist(['private/ft_preamble_' cmd '.m'], 'file') +full_cmd=['ft_preamble_' cmd]; +cmd_exists=false; - % save the original working directory - orig_pwd=pwd(); +if exist(full_cmd, 'file') + % Matlab can find commands in a private subdirectory; Octave cannot. + % If pwd is already the private directory, or if using Matlab then + % the command can be evaluated directly + cmd_exists = true; - % ensure original working directory is restored when exiting this function - cleaner=onCleanup(@()cd(orig_pwd)); +elseif ~ft_platform_supports('exists-in-private-directory') + % Octave does not find files by name in a private directory, so the full + % filename must be specified. + private_dir=fullfile(fileparts(which(mfilename)),'private'); + full_path=fullfile(private_dir,[full_cmd '.m']); - % cd to private directory - cd([fileparts(which(mfilename)) '/private']); + cmd_exists=exist(full_path,'file'); + full_cmd_parts={'ft_tmp_orig_pwd=pwd();',... + 'ft_tmp_orig_pwd_cleaner='... + 'onCleanup(@()cd(ft_tmp_orig_pwd));',... + sprintf('cd(''%s'');',private_dir),... + [full_cmd ';'],... + 'clear ft_tmp_orig_pwd_cleaner;'}; + full_cmd=sprintf('%s',full_cmd_parts{:}); +end - % evaluate ft_preamble_* function - evalin('caller', ['ft_preamble_' cmd]); - end +if ~cmd_exists + % XXX earlier versions would not do anything if ~cmd_exists, + % but fail silently (without raising an error or warning). + % Should that behavior be kept? + ft_error('Could not run %s - does not seem to exist', full_cmd); end +evalin('caller', full_cmd); + if isfield(ft_default, 'preamble') % the preamble field should not remain in the ft_default structure ft_default = rmfield(ft_default, 'preamble'); diff --git a/external/fieldtrip/utilities/ft_progress.m b/external/fieldtrip/utilities/ft_progress.m index 559686aa..d7dce75e 100644 --- a/external/fieldtrip/utilities/ft_progress.m +++ b/external/fieldtrip/utilities/ft_progress.m @@ -27,6 +27,8 @@ function ft_progress(varargin) % pause(0.1); % end % ft_progress('close') +% +% See also WAITBAR % Copyright (C) 2004-2008, Robert Oostenveld % diff --git a/external/fieldtrip/utilities/ft_scalingfactor.m b/external/fieldtrip/utilities/ft_scalingfactor.m index 804871df..ad7a8512 100644 --- a/external/fieldtrip/utilities/ft_scalingfactor.m +++ b/external/fieldtrip/utilities/ft_scalingfactor.m @@ -87,7 +87,7 @@ end if ~isequal(class(old), class(new)) - error('the input arguments should be of the same class'); + ft_error('the input arguments should be of the same class'); end if iscell(old) @@ -178,7 +178,7 @@ eval(sprintf('oldunit = %s;', old)); eval(sprintf('newunit = %s;', new)); if ~isequal(oldunit, newunit) - error('cannot convert %s to %s', old, new); + ft_error('cannot convert %s to %s', old, new); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/external/fieldtrip/utilities/ft_selectdata.m b/external/fieldtrip/utilities/ft_selectdata.m index d37148b0..c00a60cb 100644 --- a/external/fieldtrip/utilities/ft_selectdata.m +++ b/external/fieldtrip/utilities/ft_selectdata.m @@ -24,14 +24,12 @@ % cfg.avgoverchancmb = string, can be 'yes' or 'no' (default = 'no') % % For data with a time dimension you can specify -% cfg.latency = scalar -> can be 'all', 'prestim', 'poststim' -% cfg.latency = [beg end] +% cfg.latency = scalar or string, can be 'all', 'prestim', 'poststim', or [beg end], specify time range in seconds % cfg.avgovertime = string, can be 'yes' or 'no' (default = 'no') % cfg.nanmean = string, can be 'yes' or 'no' (default = 'no') % % For data with a frequency dimension you can specify -% cfg.frequency = scalar -> can be 'all' -% cfg.frequency = [beg end] +% cfg.frequency = scalar or string, can be 'all', or [beg end], specify frequency range in Hz % cfg.avgoverfreq = string, can be 'yes' or 'no' (default = 'no') % cfg.nanmean = string, can be 'yes' or 'no' (default = 'no') % @@ -102,9 +100,12 @@ for i=2:length(varargin) % ensure that all subsequent inputs are of the same type ok = ft_datatype(varargin{i}, dtype); - if ~ok, error('input data should be of the same datatype'); end + if ~ok, ft_error('input data should be of the same datatype'); end end +% this only works with certain data types, it is not meant for descriptive fields such as elec, grad, opto, layout, etc. +assert(~ismember(dtype, {'elec', 'grad', 'opto', 'layout'}), 'invalid input data type "%s"', dtype); + % ensure that the user does not give invalid selection options cfg = ft_checkconfig(cfg, 'forbidden', {'foi', 'toi'}); @@ -128,12 +129,17 @@ varargin{i} = ft_checkdata(varargin{i}, 'datatype', 'source'); end dtype = 'source'; +else + % check that the data is according to the latest FieldTrip representation + for i=1:length(varargin) + varargin{i} = ft_checkdata(varargin{i}); + end end % this function only works for the upcoming (not yet standard) source representation without sub-structures % update the old-style beamformer source reconstruction to the upcoming representation if strcmp(dtype, 'source') - if isfield(varargin{1}, 'avg') + if isfield(varargin{1}, 'avg') && isstruct(varargin{1}.avg) restoreavg = fieldnames(varargin{1}.avg); else restoreavg = {}; @@ -153,7 +159,7 @@ cfg.trials = ft_getopt(cfg, 'trials', 'all', 1); if length(varargin)>1 && ~isequal(cfg.trials, 'all') - error('it is ambiguous to make a subselection of trials while at the same time concatenating multiple data structures') + ft_error('it is ambiguous to make a subselection of trials while at the same time concatenating multiple data structures') end cfg.frequency = ft_getopt(cfg, 'frequency', 'all', 1); @@ -171,7 +177,7 @@ datfield = setdiff(datfield, {'dim'}); % not used for selection, also not treated as data field xtrafield = {'cfg' 'hdr' 'fsample' 'fsampleorig' 'grad' 'elec' 'opto' 'transform' 'unit' 'topolabel'}; % these fields will not be touched in any way by the code datfield = setdiff(datfield, xtrafield); -orgdim1 = datfield(~cellfun(@isempty, regexp(datfield, 'label$'))); % xxxlabel +orgdim1 = datfield(~cellfun(@isempty, regexp(datfield, 'label$')) & cellfun(@isempty, regexp(datfield, '^csd'))); % xxxlabel, with the exception of csdlabel datfield = setdiff(datfield, orgdim1); datfield = datfield(:)'; orgdim1 = datfield(~cellfun(@isempty, regexp(datfield, 'dimord$'))); % xxxdimord @@ -211,12 +217,12 @@ dimtok = unique(dimtok); hasspike = any(ismember(dimtok, 'spike')); -haspos = any(ismember(dimtok, {'pos', '{pos}'})); -haschan = any(ismember(dimtok, {'chan', '{chan}'})); +haspos = any(ismember(dimtok, {'pos' '{pos}'})); +haschan = any(ismember(dimtok, {'chan' '{chan}'})); haschancmb = any(ismember(dimtok, 'chancmb')); hasfreq = any(ismember(dimtok, 'freq')); hastime = any(ismember(dimtok, 'time')); -hasrpt = any(ismember(dimtok, {'rpt', 'subj'})); +hasrpt = any(ismember(dimtok, {'rpt' 'subj' '{rpt}'})); hasrpttap = any(ismember(dimtok, 'rpttap')); if hasspike @@ -278,7 +284,7 @@ if ~keeprptdim, assert(avgoverrpt, 'removing a dimension is only possible when averaging'); end if strcmp(cfg.select, 'union') && (avgoverpos || avgoverchan || avgoverchancmb || avgoverfreq || avgovertime || avgoverrpt) - error('cfg.select ''union'' in combination with averaging across one of the dimensions is not possible'); + ft_error('cfg.select ''union'' in combination with averaging across one of the dimensions is not possible'); end % trim the selection to all inputs, rpt and rpttap are dealt with later @@ -293,14 +299,14 @@ keepfield = datfield; for i=1:numel(varargin) - + for j=1:numel(datfield) dimtok = tokenize(dimord{j}, '_'); - + % the rpt selection should only work with a single data argument % in case tapers were kept, selrpt~=selrpttap, otherwise selrpt==selrpttap [selrpt{i}, dum, rptdim{i}, selrpttap{i}] = getselection_rpt(cfg, varargin{i}, dimord{j}); - + % check for the presence of each dimension in each datafield fieldhasspike = ismember('spike', dimtok); fieldhaspos = ismember('pos', dimtok) || ismember('{pos}', dimtok); @@ -310,9 +316,9 @@ fieldhasfreq = ismember('freq', dimtok); fieldhasrpt = ismember('rpt', dimtok) | ismember('subj', dimtok) | ismember('{rpt}', dimtok); fieldhasrpttap = ismember('rpttap', dimtok); - + % cfg.latency is used to select individual spikes, not to select from a continuously sampled time axis - + if fieldhasspike, varargin{i} = makeselection(varargin{i}, datfield{j}, dimtok, find(strcmp(dimtok,'spike')), selspike{i}, false, 'intersect', average); end if fieldhaspos, varargin{i} = makeselection(varargin{i}, datfield{j}, dimtok, find(ismember(dimtok, {'pos', '{pos}'})), selpos{i}, avgoverpos, cfg.select, average); end if fieldhaschan, varargin{i} = makeselection(varargin{i}, datfield{j}, dimtok, find(ismember(dimtok,{'chan' '{chan}'})), selchan{i}, avgoverchan, cfg.select, average); end @@ -321,39 +327,39 @@ if fieldhasfreq, varargin{i} = makeselection(varargin{i}, datfield{j}, dimtok, find(strcmp(dimtok,'freq')), selfreq{i}, avgoverfreq, cfg.select, average); end if fieldhasrpt, varargin{i} = makeselection(varargin{i}, datfield{j}, dimtok, rptdim{i}, selrpt{i}, avgoverrpt, 'intersect', average); end if fieldhasrpttap, varargin{i} = makeselection(varargin{i}, datfield{j}, dimtok, rptdim{i}, selrpttap{i}, avgoverrpt, 'intersect', average); end - + % update the fields that should be kept in the structure as a whole % and update the dimord for this specific datfield keepdim = true(size(dimtok)); - + if avgoverchan && ~keepchandim keepdim(strcmp(dimtok, 'chan')) = false; keepfield = setdiff(keepfield, 'label'); else keepfield = [keepfield 'label']; end - + if avgoverchancmb && ~keepchancmbdim keepdim(strcmp(dimtok, 'chancmb')) = false; keepfield = setdiff(keepfield, 'labelcmb'); else keepfield = [keepfield 'labelcmb']; end - + if avgoverfreq && ~keepfreqdim keepdim(strcmp(dimtok, 'freq')) = false; keepfield = setdiff(keepfield, 'freq'); else keepfield = [keepfield 'freq']; end - + if avgovertime && ~keeptimedim keepdim(strcmp(dimtok, 'time')) = false; keepfield = setdiff(keepfield, 'time'); else keepfield = [keepfield 'time']; end - + if avgoverpos && ~keepposdim keepdim(strcmp(dimtok, 'pos')) = false; keepdim(strcmp(dimtok, '{pos}')) = false; @@ -364,21 +370,21 @@ else keepfield = [keepfield {'pos' '{pos}' 'dim'}]; end - + if avgoverrpt && ~keeprptdim keepdim(strcmp(dimtok, 'rpt')) = false; keepdim(strcmp(dimtok, 'rpttap')) = false; keepdim(strcmp(dimtok, 'subj')) = false; end - + varargin{i}.(datfield{j}) = squeezedim(varargin{i}.(datfield{j}), ~keepdim); - + end % for datfield - + % also update the fields that describe the dimensions, time/freq/pos have been dealt with as data if haschan, varargin{i} = makeselection_chan (varargin{i}, selchan{i}, avgoverchan); end % update the label field if haschancmb, varargin{i} = makeselection_chancmb(varargin{i}, selchancmb{i}, avgoverchancmb); end % update the labelcmb field - + end % for varargin if strcmp(cfg.select, 'union') @@ -412,7 +418,7 @@ % restore the original dimord fields in the data for i=1:length(orgdim1) dimtok = tokenize(orgdim2{i}, '_'); - + % using a setdiff may result in double occurrences of chan and pos to % disappear, so this causes problems as per bug 2962 % if ~keeprptdim, dimtok = setdiff(dimtok, {'rpt' 'rpttap' 'subj'}); end @@ -425,7 +431,7 @@ if ~keepchandim, dimtok = dimtok(~ismember(dimtok, {'chan'})); end if ~keepfreqdim, dimtok = dimtok(~ismember(dimtok, {'freq'})); end if ~keeptimedim, dimtok = dimtok(~ismember(dimtok, {'time'})); end - + dimord = sprintf('%s_', dimtok{:}); dimord = dimord(1:end-1); % remove the trailing _ for j=1:length(varargin) @@ -447,8 +453,8 @@ ft_postamble debug % this clears the onCleanup function used for debugging in case of an error ft_postamble trackconfig % this converts the config object back into a struct and can report on the unused fields ft_postamble provenance % this records the time and memory at the end of the function, prints them on screen and adds this information together with the function name and MATLAB version etc. to the output cfg -% ft_postamble previous varargin % this copies the datain.cfg structure into the cfg.previous field. You can also use it for multiple inputs, or for "varargin" -% ft_postamble history varargout % this adds the local cfg structure to the output data structure, i.e. dataout.cfg = cfg +ft_postamble previous varargin % this copies the datain.cfg structure into the cfg.previous field. You can also use it for multiple inputs, or for "varargin" +ft_postamble history varargout % this adds the local cfg structure to the output data structure, i.e. dataout.cfg = cfg % note that the cfg.previous thingy does not work with the postamble, % because the postamble puts the cfgs of all input arguments in the (first) @@ -517,7 +523,7 @@ data.(datfield){j} = cellmatselect(data.(datfield){j}, seldim-1, selindx{j}, numel(dimtok)==1); end end - + else % there is a single selection in a single vector if ~isempty(selindx) && all(isnan(selindx)) @@ -526,11 +532,11 @@ data.(datfield) = cellmatselect(data.(datfield), seldim, selindx, numel(dimtok)==1); end end - + if avgoverdim data.(datfield) = cellmatmean(data.(datfield), seldim, average); end - + case 'union' if ~isempty(selindx) && all(isnan(selindx)) % no selection needs to be made @@ -554,10 +560,10 @@ case 6 data.(datfield)(:,:,:,:,:,sel) = tmp(:,:,:,:,:,selindx(sel)); otherwise - error('unsupported dimension (%d) for making a selection for %s', seldim, datfield); + ft_error('unsupported dimension (%d) for making a selection for %s', seldim, datfield); end end - + if avgoverdim data.(datfield) = average(data.(datfield), seldim); end @@ -595,14 +601,14 @@ data.label = tmp; else % this should never happen - error('cannot figure out how to select channels'); + ft_error('cannot figure out how to select channels'); end end % function makeselection_chan %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function data = makeselection_chancmb(data, selchancmb, avgoverchancmb) if isempty(selchancmb) - error('no channel combinations were selected'); + ft_error('no channel combinations were selected'); elseif avgoverchancmb && all(isnan(selchancmb)) % naming the channel combinations becomes ambiguous, but should not % suggest that the mean was computed prior to combining @@ -638,7 +644,7 @@ data.labelcmb = tmp; else % this should never happen - error('cannot figure out how to select channelcombinations'); + ft_error('cannot figure out how to select channelcombinations'); end end % function makeselection_chancmb @@ -654,9 +660,18 @@ label = cell(1,0); for k = 1:ndata - selchannel = ft_channelselection(cfg.channel, varargin{k}.label); + if isfield(varargin{k}, 'grad') && isfield(varargin{k}.grad, 'type') + % this makes channel selection more robust + selchannel = ft_channelselection(cfg.channel, varargin{k}.label, varargin{k}.grad.type); + elseif isfield(varargin{k}, 'elec') && isfield(varargin{k}.elec, 'type') + % this makes channel selection more robust + selchannel = ft_channelselection(cfg.channel, varargin{k}.label, varargin{k}.elec.type); + else + selchannel = ft_channelselection(cfg.channel, varargin{k}.label); + end label = union(label, selchannel); end +label = label(:); % ensure column array % this call to match_str ensures that that labels are always in the % order of the first input argument see bug_2917, but also temporarily keep @@ -680,7 +695,7 @@ case 'union' % don't do a subselection otherwise - error('invalid value for cfg.select'); + ft_error('invalid value for cfg.select'); end % switch ok = false(size(indx,1),1); @@ -696,7 +711,7 @@ for k = 1:ndata % do a sanity check on double occurrences if numel(unique(indx(isfinite(indx(:,k)),k)))1 @@ -934,32 +949,32 @@ tbin = nearest(alltimevec, cfg.latency, true, false); % don't consider tolerance end cfg.latency = alltimevec(tbin); - + for k = 1:ndata timeindx{k} = indx(tbin, k); end - + elseif numel(cfg.latency)==2 % the [min max] range can be specifed with +inf or -inf, but should % at least partially overlap with the time axis of the input data mintime = min(alltimevec); maxtime = max(alltimevec); if all(cfg.latencymaxtime) - error('the selected time range falls outside the time axis in the data'); + ft_error('the selected time range falls outside the time axis in the data'); end tbeg = nearest(alltimevec, cfg.latency(1), false, false); tend = nearest(alltimevec, cfg.latency(2), false, false); cfg.latency = alltimevec([tbeg tend]); - + for k = 1:numel(alltimecell) timeindx{k} = indx(tbeg:tend, k); end - + elseif size(cfg.latency,2)==2 % this may be used for specification of the computation, not for data selection - + else - error('incorrect specification of cfg.latency'); + ft_error('incorrect specification of cfg.latency'); end for k = 1:numel(alltimecell) @@ -1001,7 +1016,7 @@ for k = 1:ndata % the nan return value specifies that no selection was specified freqindx{k} = nan; - + % update the axis along which the frequencies are defined freqaxis = union(freqaxis, round(varargin{k}.freq(:)/tol)*tol); end @@ -1020,7 +1035,7 @@ case 'union' % don't do a subselection otherwise - error('invalid value for cfg.select'); + ft_error('invalid value for cfg.select'); end if isfield(cfg, 'frequency') @@ -1040,10 +1055,10 @@ elseif strcmp(cfg.frequency, 'zeromax') cfg.frequency = [0 max(freqaxis)]; else - error('incorrect specification of cfg.frequency'); + ft_error('incorrect specification of cfg.frequency'); end end - + % deal with numeric selection if isempty(cfg.frequency) for k = 1:ndata @@ -1051,7 +1066,7 @@ % this signifies that all frequency bins are deselected and should be removed freqindx{k} = []; end - + elseif numel(cfg.frequency)==1 % this single value should be within the frequency axis of each input data structure if numel(freqaxis)>1 @@ -1060,32 +1075,32 @@ fbin = nearest(freqaxis, cfg.frequency, true, false); % don't consider tolerance end cfg.frequency = freqaxis(fbin); - + for k = 1:ndata freqindx{k} = indx(fbin,k); end - + elseif numel(cfg.frequency)==2 % the [min max] range can be specifed with +inf or -inf, but should % at least partially overlap with the freq axis of the input data minfreq = min(freqaxis); maxfreq = max(freqaxis); if all(cfg.frequencymaxfreq) - error('the selected range falls outside the frequency axis in the data'); + ft_error('the selected range falls outside the frequency axis in the data'); end fbeg = nearest(freqaxis, cfg.frequency(1), false, false); fend = nearest(freqaxis, cfg.frequency(2), false, false); cfg.frequency = freqaxis([fbeg fend]); - + for k = 1:ndata freqindx{k} = indx(fbeg:fend,k); end - + elseif size(cfg.frequency,2)==2 % this may be used for specification of the computation, not for data selection - + else - error('incorrect specification of cfg.frequency'); + ft_error('incorrect specification of cfg.frequency'); end end % if cfg.frequency @@ -1112,30 +1127,27 @@ if isequal(cfg.trials, 'all') rptindx = nan; % the nan return value specifies that no selection was specified rpttapindx = nan; % the nan return value specifies that no selection was specified - + elseif isempty(rptdim) + % FIXME should [] not mean that none of the trials is to be selected? rptindx = nan; % the nan return value specifies that no selection was specified rpttapindx = nan; % the nan return value specifies that no selection was specified - + else rptindx = ft_getopt(cfg, 'trials'); - + if islogical(rptindx) % convert from booleans to indices rptindx = find(rptindx); end - + rptindx = unique(sort(rptindx)); - + if strcmp(dimtok{rptdim}, 'rpttap') && isfield(data, 'cumtapcnt') % there are tapers in the data + % determine for each taper to which trial it belongs - - if numel(data.cumtapcnt)~=length(data.cumtapcnt) - error('FIXME this is not yet implemented for mtmconvol with keeptrials and varying number of tapers per frequency'); - end - - nrpt = length(data.cumtapcnt); + nrpt = size(data.cumtapcnt, 1); taper = zeros(nrpt, 1); sumtapcnt = cumsum([0; data.cumtapcnt(:)]); begtapcnt = sumtapcnt(1:end-1)+1; @@ -1144,7 +1156,7 @@ taper(begtapcnt(i):endtapcnt(i)) = i; end rpttapindx = find(ismember(taper, rptindx)); - + else % there are no tapers in the data rpttapindx = rptindx; @@ -1165,13 +1177,13 @@ for i=1:ndata if ~isequal(varargin{i}.pos, varargin{1}.pos) % FIXME it would be possible here to make a selection based on intersect or union - error('not yet implemented'); + ft_error('not yet implemented'); end end if strcmp(cfg.select, 'union') % FIXME it would be possible here to make a selection based on intersect or union - error('not yet implemented'); + ft_error('not yet implemented'); end for i=1:ndata @@ -1251,7 +1263,7 @@ case 6 x{i} = x{i}(:,:,:,:,selindx); otherwise - error('unsupported dimension (%d) for making a selection', seldim); + ft_error('unsupported dimension (%d) for making a selection', seldim); end % switch end % for end @@ -1276,7 +1288,7 @@ case 6 x = x(:,:,:,:,:,selindx); otherwise - error('unsupported dimension (%d) for making a selection', seldim); + ft_error('unsupported dimension (%d) for making a selection', seldim); end end end % function cellmatselect diff --git a/external/fieldtrip/utilities/ft_selectdata_new.m b/external/fieldtrip/utilities/ft_selectdata_new.m index da3d35e0..81205951 100644 --- a/external/fieldtrip/utilities/ft_selectdata_new.m +++ b/external/fieldtrip/utilities/ft_selectdata_new.m @@ -82,7 +82,7 @@ for i=2:length(varargin) % ensure that all subsequent inputs are of the same type ok = ft_datatype(varargin{i}, dtype); - if ~ok, error('input data should be of the same datatype'); end + if ~ok, ft_error('input data should be of the same datatype'); end end cfg = ft_checkconfig(cfg, 'renamed', {'selmode', 'select'}); @@ -108,11 +108,11 @@ end if length(varargin)>1 && isfield(cfg, 'trials') && ~isequal(cfg.trials, 'all') - error('it is ambiguous to make a subselection of trials while at the same time concatenating multiple data structures') + ft_error('it is ambiguous to make a subselection of trials while at the same time concatenating multiple data structures') end if strcmp(cfg.select, 'union') && any(strcmp(dtype, {'raw', 'comp', 'source'})) - error('cfg.select ''union'' is not yet supported for %s data', dtype); + ft_error('cfg.select ''union'' is not yet supported for %s data', dtype); end if ft_datatype(varargin{1}, 'raw') @@ -142,7 +142,7 @@ elseif ischar(cfg.parameter) && isfield(varargin{1}, 'dimord') dimord = varargin{1}.dimord; else - error('cannot determine which parameter to select from the data, please specify cfg.parameter'); + ft_error('cannot determine which parameter to select from the data, please specify cfg.parameter'); end dimtok = tokenize(dimord, '_'); @@ -192,13 +192,13 @@ dimfields{i} = 'implicit'; case 'comp' - error('FIXME'); + ft_error('FIXME'); case 'refchan' - error('FIXME'); + ft_error('FIXME'); case 'voxel' - error('FIXME'); + ft_error('FIXME'); otherwise % try to guess the size from the corresponding field @@ -230,7 +230,7 @@ end if any(strcmp(dimfields, 'implicit')) % it failed - error('could not determine the size of the implicit "%s" dimension', dimfields{strcmp(dimfields, 'implicit')}); + ft_error('could not determine the size of the implicit "%s" dimension', dimfields{strcmp(dimfields, 'implicit')}); end end @@ -287,7 +287,7 @@ keeptimedim = istrue(ft_getopt(cfg, 'keeptimedim', true)); if strcmp(cfg.select, 'union') && (avgoverpos || avgoverrpt || avgoverchan || avgoverfreq || avgovertime) - error('cfg.select ''union'' in combination with averaging across one of the dimensions is not implemented'); + ft_error('cfg.select ''union'' in combination with averaging across one of the dimensions is not implemented'); end if avgoverpos @@ -339,7 +339,7 @@ if hasrpt || hasrpttap, varargin{i} = makeselection_rpt (varargin{i}, selrpt{i}); end % avgoverrpt for the supporting fields is dealt with later % also deal with the supporting cumtapcnt field, because it has a frequency dimension when time dimension is present - % this is a temporary workaround, see http://bugzilla.fcdonders.nl/show_bug.cgi?id=2509 + % this is a temporary workaround, see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2509 if isfield(varargin{i}, 'cumtapcnt') && hastime varargin{i} = makeselection_cumtapcnt(varargin{i}, selfreq{i}, avgoverfreq); end @@ -459,7 +459,7 @@ end % also deal with the supporting cumtapcnt field, because it has a frequency dimension when time dimension is present - % this is a temporary workaround, see http://bugzilla.fcdonders.nl/show_bug.cgi?id=2509 + % this is a temporary workaround, see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2509 if hastime && isfield(varargin{i}, 'cumtapcnt') varargin{i} = makeselection_cumtapcnt(varargin{i}, selfreq{i}, avgoverfreq); end @@ -524,23 +524,23 @@ end % varargin case 'freqmvar' - error('FIXME'); + ft_error('FIXME'); case 'mvar' - error('FIXME'); + ft_error('FIXME'); case 'spike' - error('FIXME'); + ft_error('FIXME'); case 'volume' - error('FIXME'); + ft_error('FIXME'); case 'dip' - error('FIXME'); + ft_error('FIXME'); case 'chan' % this results from avgovertime/avgoverfreq after timelockstatistics or freqstatistics - error('FIXME'); + ft_error('FIXME'); otherwise % try to get the selection based on the field name @@ -689,7 +689,7 @@ case 6 data.(datfields{i})(:,:,:,:,:,sel) = tmp(:,:,:,:,:,selindx(sel)); otherwise - error('unsupported dimension (%d) for making a selection for %s', seldim, datfields{i}); + ft_error('unsupported dimension (%d) for making a selection for %s', seldim, datfields{i}); end end if avgoverdim @@ -783,7 +783,7 @@ function data = makeselection_cumtapcnt(data, selfreq, avgoverfreq) if ~isfield(data, 'time') - error('the subfunction makeselection_cumtapcnt should only be called when there is a time dimension in the data'); + ft_error('the subfunction makeselection_cumtapcnt should only be called when there is a time dimension in the data'); end if ~isfield(data, 'cumtapcnt') return; @@ -872,7 +872,7 @@ case 'union' % don't do a subselection otherwise - error('invalid value for cfg.select'); + ft_error('invalid value for cfg.select'); end % switch for k = 1:ndata @@ -904,7 +904,7 @@ cfg.channelcmb = ft_channelcombination(cfg.channelcmb, varargin{k}.labelcmb); end - error('selection of channelcmb is not yet implemented'); + ft_error('selection of channelcmb is not yet implemented'); else for k = 1:ndata @@ -951,7 +951,7 @@ case 'union' % don't do a subselection otherwise - error('invalid value for cfg.select'); + ft_error('invalid value for cfg.select'); end if isfield(cfg, 'latency') @@ -960,7 +960,7 @@ if strcmp(cfg.latency, 'all') cfg.latency = [min(timeaxis) max(timeaxis)]; else - error('incorrect specification of cfg.latency'); + ft_error('incorrect specification of cfg.latency'); end end % deal with numeric selection @@ -979,7 +979,7 @@ mintime = min(timeaxis); maxtime = max(timeaxis); if all(cfg.latencymaxtime) - error('the selected time range falls outside the time axis in the data'); + ft_error('the selected time range falls outside the time axis in the data'); end tbeg = nearest(timeaxis, cfg.latency(1), false, false); tend = nearest(timeaxis, cfg.latency(2), false, false); @@ -997,7 +997,7 @@ timeindx{k,1} = []; end else - error('incorrect specification of cfg.latency'); + ft_error('incorrect specification of cfg.latency'); end end % if cfg.latency @@ -1049,7 +1049,7 @@ case 'union' % don't do a subselection otherwise - error('invalid value for cfg.select'); + ft_error('invalid value for cfg.select'); end if isfield(cfg, 'frequency') @@ -1058,7 +1058,7 @@ if strcmp(cfg.frequency, 'all') cfg.frequency = [min(freqaxis) max(freqaxis)]; else - error('incorrect specification of cfg.frequency'); + ft_error('incorrect specification of cfg.frequency'); end end @@ -1078,7 +1078,7 @@ minfreq = min(freqaxis); maxfreq = max(freqaxis); if all(cfg.frequencymaxfreq) - error('the selected range falls outside the frequency axis in the data'); + ft_error('the selected range falls outside the frequency axis in the data'); end fbeg = nearest(freqaxis, cfg.frequency(1), false, false); fend = nearest(freqaxis, cfg.frequency(2), false, false); @@ -1096,7 +1096,7 @@ freqindx{k,1} = []; end else - error('incorrect specification of cfg.frequency'); + ft_error('incorrect specification of cfg.frequency'); end end % if cfg.frequency @@ -1107,7 +1107,7 @@ minfreq = min(freqaxis); maxfreq = max(freqaxis); if all(cfg.foilimmaxfreq) - error('the selected range falls outside the frequency axis in the data'); + ft_error('the selected range falls outside the frequency axis in the data'); end fbin = nan(1,2); fbin(1) = nearest(freqaxis, cfg.foilim(1), false, false); @@ -1119,7 +1119,7 @@ end else - error('incorrect specification of cfg.foilim'); + ft_error('incorrect specification of cfg.foilim'); end end % cfg.foilim @@ -1194,9 +1194,9 @@ end if ~isempty(rptindx) && rptindx(1)<1 - error('cannot select rpt/subj/rpttap smaller than 1'); + ft_error('cannot select rpt/subj/rpttap smaller than 1'); elseif ~isempty(rptindx) && rptindx(end)>rptsiz - error('cannot select rpt/subj/rpttap larger than the number of repetitions in the data'); + ft_error('cannot select rpt/subj/rpttap larger than the number of repetitions in the data'); end % commented out because of rpttap dilemma... @@ -1226,7 +1226,7 @@ for i=2:ndata if ~isequal(varargin{i}.pos, varargin{1}.pos) % FIXME it would be possible here to make a selection based on intersect or union - error('source positions are different'); + ft_error('source positions are different'); end end % for for i=1:ndata @@ -1302,7 +1302,7 @@ case 6 x{i} = x{i}(:,:,:,:,selindx); otherwise - error('unsupported dimension (%d) for making a selection', seldim); + ft_error('unsupported dimension (%d) for making a selection', seldim); end % switch end % for end @@ -1321,7 +1321,7 @@ case 6 x = x(:,:,:,:,:,selindx); otherwise - error('unsupported dimension (%d) for making a selection', seldim); + ft_error('unsupported dimension (%d) for making a selection', seldim); end end end % function cellmatselect diff --git a/external/fieldtrip/utilities/ft_selectdata_old.m b/external/fieldtrip/utilities/ft_selectdata_old.m index c521d730..0d94a3fb 100644 --- a/external/fieldtrip/utilities/ft_selectdata_old.m +++ b/external/fieldtrip/utilities/ft_selectdata_old.m @@ -86,12 +86,12 @@ end if ~all(strcmp(dtype{1},dtype)) - error('the data type is not consistent for all inputs'); + ft_error('the data type is not consistent for all inputs'); end % check consistency of input data if ~all(strcmp(dimord{1},dimord)) - error('the dimord is not consistent for all inputs'); + ft_error('the dimord is not consistent for all inputs'); end israw = strcmp(dtype{1},'raw') || strcmp(dtype{1},'comp'); % comp can be treated as raw @@ -128,17 +128,17 @@ dojack = istrue(dojack); if dojack && avgoverrpt, - error('it is not possible to do both a jackknife and to average across replicates'); + ft_error('it is not possible to do both a jackknife and to average across replicates'); end if length(data)>1 && selectrpt, - error('multiple data structures as input is not supported in combination with subselection of trials'); + ft_error('multiple data structures as input is not supported in combination with subselection of trials'); end % a quick check to ensure the user does not use this function in cases % where it is known to contain a bug %if selectrpt && (isempty(selrpt) || ~any(selrpt)) -% error('ft_selectdata_old does not work when selecting 0 trials; please use ft_selectdata_new instead (use a cfg input, instead of key-value pairs, to ft_selectdata)'); +% ft_error('ft_selectdata_old does not work when selecting 0 trials; please use ft_selectdata_new instead (use a cfg input, instead of key-value pairs, to ft_selectdata)'); %end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -168,7 +168,7 @@ %end if issource || isvolume if numel(param)>1, - error('ft_selectdata for source inputs works only for one parameter at a time'); + ft_error('ft_selectdata for source inputs works only for one parameter at a time'); end dimord(:) = {data{1}.([param{1},'dimord'])}; end @@ -195,8 +195,8 @@ % dimtok is 'rpt' or 'rpttap' dimdat2 = size(data{m}.(param{1}),1); end - try, dimmat(k,m) = all(dimdat(:)==dimdat2(:)); catch end; - try, dimmat(k,m) = all(cellfun(@isequal,dimdat,dimdat2)); catch end; + try, dimmat(k,m) = all(dimdat(:)==dimdat2(:)); catch end + try, dimmat(k,m) = all(cellfun(@isequal,dimdat,dimdat2)); catch end end end catdim = find(sum(dimmat,2)1, - error('ambiguous dimensions for concatenation'); + ft_error('ambiguous dimensions for concatenation'); elseif isempty(catdim) && isempty(intersect(dimtok, {'rpt', 'rpttap', 'subj'})) % treat as individual observations: prepend a first dimension 'rpt' % (so this part should be able to cover the functionality of ...grandaverage) @@ -223,7 +223,7 @@ elseif ~isempty(strfind(dimtok{catdim},'pos')) dimtok{catdim} = 'pos'; elseif isempty(catdim) - error('don''t know how to concatenate the data'); + ft_error('don''t know how to concatenate the data'); end % concatenate the data @@ -250,7 +250,7 @@ % this is for source data with the positions in a cell-array npos = numel(tmp{1}); if catdim==0, - error('not implemented yet'); + ft_error('not implemented yet'); elseif catdim==1, datacat.(param{k}) = cat(1, tmp{:}); else @@ -310,7 +310,7 @@ fprintf('%d voxels are inside the brain of all subjects\n', nallinside); fprintf('%d voxels are inside the brain of some, but not all subjects\n', nsomeinside); fprintf('%d voxels are outside the brain of all subjects\n', nalloutside); - warning('marking only voxels inside the brain of all subjects as ''inside'''); + ft_warning('marking only voxels inside the brain of all subjects as ''inside'''); if isboolean data{1}.inside = inside; @@ -445,7 +445,7 @@ end elseif length(data)>1 && israw - error('concatenation of several raw data-structures is done by ''ft_appenddata'''); + ft_error('concatenation of several raw data-structures is done by ''ft_appenddata'''); else % nothing to do data = data{1}; @@ -461,7 +461,7 @@ if islogical(selrpt), selrpt = find(selrpt); elseif isempty(selrpt), - warning('you request all repetitions to be thrown away'); + ft_warning('you request all repetitions to be thrown away'); end if ~issource @@ -498,7 +498,7 @@ if islogical(selrpt), selrpt = find(selrpt); elseif isempty(selrpt), - warning('you request all repetitions to be thrown away'); + ft_warning('you request all repetitions to be thrown away'); end end @@ -519,7 +519,7 @@ end if selectfoi, - if numel(selfoi)==1, selfoi(2) = selfoi; end; + if numel(selfoi)==1, selfoi(2) = selfoi; end if numel(selfoi)==2, % treat selfoi as lower limit and upper limit selfoi = nearest(data.freq, selfoi(1)):nearest(data.freq, selfoi(2)); @@ -535,7 +535,7 @@ end if selecttoi && ~israw, - if length(seltoi)==1, seltoi(2) = seltoi; end; + if length(seltoi)==1, seltoi(2) = seltoi; end if numel(seltoi)==2, % treat seltoi as lower limit and upper limit toitmp=nearest(data.time,[seltoi(1) seltoi(2)]); @@ -553,7 +553,7 @@ end if selectroi, - error('not yet implemented'); + ft_error('not yet implemented'); end if israw, @@ -571,7 +571,7 @@ elseif isfreq, % if isfield(data, 'labelcmb') && isfield(data, 'label') && (selectchan || avgoverchan) - % error('selection of or averaging across channels in the presence of both label and labelcmb is not possible'); + % ft_error('selection of or averaging across channels in the presence of both label and labelcmb is not possible'); % end tmpdata = []; if isfield(data, 'labelcmb'), @@ -586,7 +586,7 @@ if selectchan && isfield(data, 'label') selcmb = find(sum(ismember(tmpdata.label, data.label(selchan)),2)==2); elseif selectchan - error('this is not yet implemented'); + ft_error('this is not yet implemented'); end % make the subselection @@ -630,7 +630,7 @@ if selectfoi, data = seloverdim(data, 'freq', selfoi, fb); end if selecttoi, data = seloverdim(data, 'time', seltoi, fb); end if isfield(data,'trial') && isfield(data,'avg') %&& size(data.trial,3)~=size(data.avg,2) - warning('Warning: .avg, .var, .dof and .cov not updated.'); + ft_warning('Warning: .avg, .var, .dof and .cov not updated.'); if isfield(data, 'avg'), data = rmfield(data, 'avg'); end if isfield(data, 'cov'), data = rmfield(data, 'cov'); end if isfield(data, 'dof'), data = rmfield(data, 'dof'); end @@ -652,7 +652,7 @@ if avgoverfreq, data = avgoverdim(data, 'freq'); end elseif isvolume, - error('this is not yet implemented'); + ft_error('this is not yet implemented'); elseif isfreqmvar, % make the subselection if selectrpt, data = seloverdim(data, 'rpt', selrpt, fb); end diff --git a/external/fieldtrip/utilities/ft_source2full.m b/external/fieldtrip/utilities/ft_source2full.m index 2ede3983..48084a86 100644 --- a/external/fieldtrip/utilities/ft_source2full.m +++ b/external/fieldtrip/utilities/ft_source2full.m @@ -36,12 +36,12 @@ if ~isfield(source, 'inside') || ... ~isfield(source, 'outside') || ... ~isfield(source, 'dim') - error('one of the required fields is missing in the source structure'); + ft_error('one of the required fields is missing in the source structure'); end if ~isfield(source, 'pos') && (~isfield(source, 'xgrid') || ~isfield(source, 'ygrid') || ... ~isfield(source, 'zgrid')) - error('the input data needs at least a ''pos'' field, or ''x/y/zgrid'''); + ft_error('the input data needs at least a ''pos'' field, or ''x/y/zgrid'''); end if isfield(source, 'xgrid'), @@ -56,7 +56,7 @@ else %FIXME this assumes that the voxel data are ordered as if in a regularly spaced 3D grid, %but with only the inside voxels present - warning('assuming the voxel data to be ordered as if in a regularly spaced 3D grid'); + ft_warning('assuming the voxel data to be ordered as if in a regularly spaced 3D grid'); xgrid = 1:source.dim(1); ygrid = 1:source.dim(2); zgrid = 1:source.dim(3); @@ -140,7 +140,7 @@ stype = 'old'; end -if strcmp(stype, 'old'), +if strcmp(stype, 'old') % original code % first do the non-trial fields source.dim = [1 length(inside) 1]; %to fool parameterselection @@ -153,10 +153,10 @@ for j = 1:length(param) dat = getsubfield(source, param{j}); - if islogical(dat), + if islogical(dat) tmp = false(1,Nfull); tmp(inside) = dat; - elseif iscell(dat), + elseif iscell(dat) tmp = cell(1,Nfull); tmp(inside) = dat; %tmp(outside) = nan; @@ -168,17 +168,17 @@ end % then do the trial fields - if isfield(source, 'trial' ), + if isfield(source, 'trial' ) for j = 1:length(source.trial) tmpsource = source.trial(j); tmpsource.dim = source.dim; % to fool parameterselection tmpparam = parameterselection('all', tmpsource); for k = 1:length(tmpparam) dat = getsubfield(tmpsource, tmpparam{k}); - if strcmp(class(dat), 'logical'), - tmp = logical(zeros(1,Nfull)); + if islogical(dat) + tmp = false(1,Nfull); tmp(inside) = dat; - elseif strcmp(class(dat), 'cell'), + elseif iscell(dat) tmp = cell(1,Nfull); tmp(inside) = dat; %tmp(outside) = nan; @@ -191,17 +191,17 @@ tmpsource = rmfield(tmpsource, 'dim'); source.trial(j) = tmpsource; end - elseif isfield(source, 'trialA'), + elseif isfield(source, 'trialA') for j = 1:length(source.trialA) tmpsource = source.trialA(j); tmpsource.dim = source.dim; % to fool parameterselection tmpparam = parameterselection('all', tmpsource); for k = 1:length(tmpparam) dat = getsubfield(tmpsource, tmpparam{k}); - if strcmp(class(dat), 'logical'), - tmp = logical(zeros(1,Nfull)); + if islogical(dat) + tmp = false(1,Nfull); tmp(inside) = dat; - elseif strcmp(class(dat), 'cell'), + elseif iscell(dat) tmp = cell(1,Nfull); tmp(inside) = dat; %tmp(outside) = nan; @@ -214,17 +214,17 @@ tmpsource = rmfield(tmpsource, 'dim'); source.trialA(j) = tmpsource; end - elseif isfield(source, 'trialB'), + elseif isfield(source, 'trialB') for j = 1:length(source.trialB) tmpsource = source.trialB(j); tmpsource.dim = source.dim; % to fool parameterselection tmpparam = parameterselection('all', tmpsource); for k = 1:length(tmpparam) dat = getsubfield(tmpsource, tmpparam{k}); - if strcmp(class(dat), 'logical'), - tmp = logical(zeros(1,Nfull)); + if islogical(dat) + tmp = false(1,Nfull); tmp(inside) = dat; - elseif strcmp(class(dat), 'cell'), + elseif iscell(dat) tmp = cell(1,Nfull); tmp(inside) = dat; %tmp(outside) = nan; @@ -261,37 +261,37 @@ % new style conversion fn = fieldnames(source); for i=1:numel(fn) - if any(size(source.(fn{i}))==Nsparse), - if iscell(source.(fn{i})), + if any(size(source.(fn{i}))==Nsparse) + if iscell(source.(fn{i})) indx = find(size(source.(fn{i}))==Nsparse); - if all(indx==1), + if all(indx==1) tmp = cell(Nfull,1); tmp(inside,1) = source.(fn{i}); source.(fn{i}) = tmp; - elseif all(indx==2), + elseif all(indx==2) tmp = cell(1,Nfull); tmp(1,inside) = source.(fn{i}); source.(fn{i}) = tmp; else - warning('sparse to full conversion failed for field %s\n', fn{i}); + ft_warning('sparse to full conversion failed for field %s\n', fn{i}); end else indx = find(size(source.(fn{i}))==Nsparse); - if all(indx==1), + if all(indx==1) tmpsiz = [size(source.(fn{i})) 1]; tmp = nan([Nfull tmpsiz(2:end)]); tmp(inside,:,:,:,:) = source.(fn{i}); - elseif all(indx==2), + elseif all(indx==2) tmpsiz = [size(source.(fn{i})) 1]; tmp = nan([tmpsiz(1) Nfull tmpsiz(3:end)]); tmp(:,inside,:,:,:) = source.(fn{i}); - elseif all(indx==[1 2]), + elseif all(indx==[1 2]) % bivariate matrix tmpsiz = [size(source.(fn{i})) 1]; tmp = nan([Nfull Nfull tmpsiz(3:end)]); tmp(inside,inside,:,:,:) = source.(fn{i}); else - warning('sparse to full conversion failed for field %s\n', fn{i}); + ft_warning('sparse to full conversion failed for field %s\n', fn{i}); end end % nothing to do diff --git a/external/fieldtrip/utilities/ft_source2grid.m b/external/fieldtrip/utilities/ft_source2grid.m index c751b964..6c06554d 100644 --- a/external/fieldtrip/utilities/ft_source2grid.m +++ b/external/fieldtrip/utilities/ft_source2grid.m @@ -44,7 +44,7 @@ elseif issubfield(source, 'avg.filter') grid.filter = source.avg.filter; elseif issubfield(source, 'trial.filter') - error('single trial filters are not supported here'); + ft_error('single trial filters are not supported here'); end if issubfield(source, 'leadfield') diff --git a/external/fieldtrip/utilities/ft_source2sparse.m b/external/fieldtrip/utilities/ft_source2sparse.m index 0a82bb7e..94ef4610 100644 --- a/external/fieldtrip/utilities/ft_source2sparse.m +++ b/external/fieldtrip/utilities/ft_source2sparse.m @@ -35,14 +35,14 @@ ft_defaults if ~isfield(source, 'inside') - warning('no gridpoints defined inside the brain'); + ft_warning('no gridpoints defined inside the brain'); source.inside = []; elseif all(islogical(source.inside)) source = fixinside(source, 'index'); % in contrast to the new convention, this function still relies on an indexed inside end if ~isfield(source, 'outside') - warning('no gridpoints defined outside the brain'); + ft_warning('no gridpoints defined outside the brain'); source.outside = []; end @@ -135,7 +135,7 @@ elseif tmpsel==2, source.(fnames{k}) = source.(fnames{k})(:,inside,:,:,:); else - warning('not subselecting voxels, because location of pos-dimension is unexpected'); + ft_warning('not subselecting voxels, because location of pos-dimension is unexpected'); end end end diff --git a/external/fieldtrip/utilities/ft_struct2double.m b/external/fieldtrip/utilities/ft_struct2double.m index b485e2e1..9c82bfc9 100644 --- a/external/fieldtrip/utilities/ft_struct2double.m +++ b/external/fieldtrip/utilities/ft_struct2double.m @@ -50,7 +50,7 @@ function [a] = convert(a, depth, maxdepth) if depth>maxdepth - error('recursive depth exceeded'); + ft_error('recursive depth exceeded'); end switch class(a) diff --git a/external/fieldtrip/utilities/ft_struct2single.m b/external/fieldtrip/utilities/ft_struct2single.m index a4424e71..069bffcb 100644 --- a/external/fieldtrip/utilities/ft_struct2single.m +++ b/external/fieldtrip/utilities/ft_struct2single.m @@ -50,7 +50,7 @@ function [a] = convert(a, depth, maxdepth) if depth>maxdepth - error('recursive depth exceeded'); + ft_error('recursive depth exceeded'); end switch class(a) diff --git a/external/fieldtrip/utilities/ft_test.m b/external/fieldtrip/utilities/ft_test.m new file mode 100644 index 00000000..b9acfcb9 --- /dev/null +++ b/external/fieldtrip/utilities/ft_test.m @@ -0,0 +1,111 @@ +function ft_test(varargin) + +% FT_TEST performs selected FieldTrip test scripts or reports on previous test +% results from the dashboard. +% +% Use as +% ft_test run ... +% ft_test moxunit_run ... +% ft_test report ... +% ft_test compare ... +% +% ========= Running tests ========= +% +% To execute a test and submit the results to the database, you would do +% ft_test run +% to run all test functions, or +% ft_test run test_bug46 +% to run a selected test. +% +% Test functions should not require any input arguments. Any output arguments will +% not be considered. +% +% Additional optional arguments are specified as key-value pairs and can include +% dependency = string +% upload = string, upload test results to the dashboard, can be 'yes' or 'no' (default = 'yes') +% dccnpath = string, allow files to be read from the DCCN path, can be 'yes' or 'no' (default is automatic) +% assertclean = string, test whether FT version is clean, can be 'yes' or 'no' (default = 'yes') +% maxmem = number (in bytes) or string such as 10GB +% maxwalltime = number (in seconds) or string such as HH:MM:SS +% +% ========= Running MOxUnit tests ========= +% +% To execute tests using MOxUNit, you would do +% ft_test moxunit_run +% +% This feature is currently experimental, but should support the same +% options as ft_test run (see above), and in addition: +% xmloutput = string, filename for JUnit-like XML file with test +% results (used for shippable CI). +% exclude_if_prefix_equals_failed = string, if set to false (or 'no') +% then tests are also run if their filename starts +% with 'failed'. If set to true (or 'yes'), which is +% the default, then filenames starting with 'failed' +% are skipped. +% +% ========= Reporting on tests ========= +% +% To print a table with the results on screen, you would do +% ft_test report +% to show all, or for a specific one +% ft_test report test_bug46 +% +% Additional query arguments are specified as key-value pairs and can include +% matlabversion = string, for example 2016b +% fieldtripversion = string +% branch = string +% arch = string, can be glnxa64, maci64. win32 or win64 +% hostname = string +% user = string +% +% ========= Comparing tests ========= +% +% To print a table comparing different test results, you would do +% ft_test compare matlabversion 2015b 2016b +% ft_test compare fieldtripversion ea3c2b9 314d186 +% ft_test compare arch glnxa64 win32 +% +% Additional query arguments are specified as key-value pairs and can include +% matlabversion = string, for example 2016b +% fieldtripversion = string +% branch = string +% arch = string, can be glnxa64, maci64. win32 or win64 +% hostname = string +% user = string +% +% See also FT_VERSION + +% Copyright (C) 2016-2017, Robert oostenveld +% +% This file is part of FieldTrip, see http://www.ru.nl/donders/fieldtrip +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +switch (varargin{1}) + case 'run' + ft_test_run(varargin{:}); + case 'moxunit_run' + ft_test_moxunit_run(varargin{:}); + case 'report' + ft_test_report(varargin{:}); + case 'compare' + ft_test_compare(varargin{:}); + otherwise + ft_error('unsupported command "%s"', varargin{1}) +end % switch + + diff --git a/external/fieldtrip/utilities/ft_test_result.m b/external/fieldtrip/utilities/ft_test_result.m deleted file mode 100644 index 244f0684..00000000 --- a/external/fieldtrip/utilities/ft_test_result.m +++ /dev/null @@ -1,197 +0,0 @@ -function results = ft_test_result(varargin) - -% FT_TEST_RESULT checks the status of selected test scripts on the FieldTrip dashboard -% -% To get all dashboard results as a structure array, you would do -% result = ft_test_result -% -% To print a table with the results on screen, you would do -% ft_test_result comparerevision ea3c2b9 314d186 -% ft_test_result comparematlab 2015b 2016b -% ft_test_result comparemexext mexw32 mexw64 -% ft_test_result compareos osx windows -% -% Additional query arguments are specified as key-value pairs and can include -% matlabversion = string -% fieldtripversion = string -% hostname = string -% user = string -% branch = string -% result = string -% -% See also FT_TEST_RUN, FT_VERSION - -% Copyright (C) 2016, Robert oostenveld -% -% This file is part of FieldTrip, see http://www.ru.nl/donders/fieldtrip -% for the documentation and details. -% -% FieldTrip is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. -% -% FieldTrip is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with FieldTrip. If not, see . -% -% $Id$ - -% set the default -command = 'query'; - -if nargin>0 - if isequal(varargin{1}, 'compare') || isequal(varargin{1}, 'comparerevision') - % comparerevision rev1 rev2 - command = 'comparerevision'; - arg1 = varargin{2}; - arg2 = varargin{3}; - varargin = varargin(4:end); - elseif isequal(varargin{1}, 'matlab') || isequal(varargin{1}, 'comparematlab') - % comparematlab ver1 ver2 - command = 'comparematlab'; - arg1 = varargin{2}; - arg2 = varargin{3}; - varargin = varargin(4:end); - end -end - -% construct the query string -query = '?'; - -% the 'distict' parameter is mutually exclusive with all others -queryparam = {'matlabversion', 'fieldtripversion', 'hostname', 'user', 'functionname', 'result', 'branch', 'distinct'}; -for i=1:numel(queryparam) - val = ft_getopt(varargin, queryparam{i}); - if ~isempty(val) - query = [query sprintf('%s=%s&', queryparam{i}, val)]; - end -end - -options = weboptions('ContentType','json'); % this returns the results as MATLAB structure - -switch command - case 'query' - results = webread(['http://dashboard.fieldtriptoolbox.org/api/' query], options); - - case 'comparerevision' - dashboard1 = webread(['http://dashboard.fieldtriptoolbox.org/api/' query sprintf('&fieldtripversion=%s', arg1)], options); - dashboard2 = webread(['http://dashboard.fieldtriptoolbox.org/api/' query sprintf('&fieldtripversion=%s', arg2)], options); - assert(~isempty(dashboard1), 'no tests were returned for the first revision'); - assert(~isempty(dashboard2), 'no tests were returned for the second revision'); - functionname1 = {dashboard1.functionname}; - functionname2 = {dashboard2.functionname}; - functionname = unique(cat(2, functionname1, functionname2)); - n = max(cellfun(@length, functionname)); - line = cell(size(functionname)); - order = nan(size(functionname)); - for i=1:numel(functionname) - sel1 = find(strcmp(functionname1, functionname{i})); - sel2 = find(strcmp(functionname2, functionname{i})); - res1 = getresult(dashboard1, sel1); - res2 = getresult(dashboard2, sel2); - line{i} = sprintf('%s : %s in %s, %s in %s\n', padto(functionname{i}, n), res1, arg1, res2, arg2); - - % determine the order - if strcmp(res1, 'passed') && strcmp(res2, 'passed') - order(i) = 1; - elseif strcmp(res1, 'failed') && strcmp(res2, 'failed') - order(i) = 2; - elseif strcmp(res1, 'missing') && strcmp(res2, 'passed') - order(i) = 3; - elseif strcmp(res1, 'passed') && strcmp(res2, 'missing') - order(i) = 4; - elseif strcmp(res1, 'missing') && strcmp(res2, 'failed') - order(i) = 5; - elseif strcmp(res1, 'failed') && strcmp(res2, 'missing') - order(i) = 6; - elseif strcmp(res1, 'failed') && strcmp(res2, 'passed') - order(i) = 7; - elseif strcmp(res1, 'passed') && strcmp(res2, 'failed') - order(i) = 8; - else - order(i) = 9; - end - end % for each functionname - - [order, index] = sort(order); - line = line(index); - for i=1:length(line) - fprintf(line{i}); - end - - case 'comparematlab' - dashboard1 = webread(['http://dashboard.fieldtriptoolbox.org/api/' query sprintf('&matlabversion=%s', arg1)], options); - dashboard2 = webread(['http://dashboard.fieldtriptoolbox.org/api/' query sprintf('&matlabversion=%s', arg2)], options); - assert(~isempty(dashboard1), 'no tests were returned for the first matab version'); - assert(~isempty(dashboard2), 'no tests were returned for the second matab version'); - functionname1 = {dashboard1.functionname}; - functionname2 = {dashboard2.functionname}; - functionname = unique(cat(2, functionname1, functionname2)); - n = max(cellfun(@length, functionname)); - line = cell(size(functionname)); - order = nan(size(functionname)); - for i=1:numel(functionname) - sel1 = find(strcmp(functionname1, functionname{i})); - sel2 = find(strcmp(functionname2, functionname{i})); - res1 = getresult(dashboard1, sel1); - res2 = getresult(dashboard2, sel2); - line{i} = sprintf('%s : %s in %s, %s in %s\n', padto(functionname{i}, n), res1, arg1, res2, arg2); - - % determine the order - if strcmp(res1, 'passed') && strcmp(res2, 'passed') - order(i) = 1; - elseif strcmp(res1, 'failed') && strcmp(res2, 'failed') - order(i) = 2; - elseif strcmp(res1, 'missing') && strcmp(res2, 'passed') - order(i) = 3; - elseif strcmp(res1, 'passed') && strcmp(res2, 'missing') - order(i) = 4; - elseif strcmp(res1, 'missing') && strcmp(res2, 'failed') - order(i) = 5; - elseif strcmp(res1, 'failed') && strcmp(res2, 'missing') - order(i) = 6; - elseif strcmp(res1, 'failed') && strcmp(res2, 'passed') - order(i) = 7; - elseif strcmp(res1, 'passed') && strcmp(res2, 'failed') - order(i) = 8; - else - order(i) = 9; - end - end % for each functionname - - [order, index] = sort(order); - line = line(index); - for i=1:length(line) - fprintf(line{i}); - end - - otherwise - error('unsupported command "%s"', command); -end % switch command - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% SUBFUNCTION -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -function str = padto(str, n) -if n>length(str) - str = [str repmat(' ', [1 n-length(str)])]; -end - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% SUBFUNCTION -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -function str = getresult(dashboard, sel) -if isempty(sel) - str = 'missing'; -elseif all(istrue([dashboard(sel).result])) - str = 'passed'; -elseif all(~istrue([dashboard(sel).result])) - str = 'failed'; -else - str = 'ambiguous'; -end diff --git a/external/fieldtrip/utilities/ft_trackusage.m b/external/fieldtrip/utilities/ft_trackusage.m index 15171bb6..159aea90 100644 --- a/external/fieldtrip/utilities/ft_trackusage.m +++ b/external/fieldtrip/utilities/ft_trackusage.m @@ -48,126 +48,126 @@ function ft_trackusage(event, varargin) % % $Id$ -global ft_default -persistent initialized - -if isempty(initialized) - initialized = false; -end - -if nargin<1 - % there is nothing to track - return -end - -%% Since the functionality is still in beta testing, only enable the tracking for some developpers -knownuser = false; -knownuser = knownuser || (strcmp(getusername, 'roboos') && (~isempty(regexp(gethostname, '^dccn', 'once')) || ~isempty(regexp(gethostname, '^mac011', 'once')))); -%knownuser = knownuser || (strcmp(getusername, 'jansch') && (~isempty(regexp(gethostname, '^dccn', 'once')) || ~isempty(regexp(gethostname, '^fcdc', 'once')))); -knownuser = knownuser || (strcmp(getusername, 'jimher') && (~isempty(regexp(gethostname, '^dccn', 'once')) || ~isempty(regexp(gethostname, '^fcdc', 'once')))); -%knownuser = knownuser || (strcmp(getusername, 'nielam') && (~isempty(regexp(gethostname, '^dccn', 'once')) || ~isempty(regexp(gethostname, '^fcdc', 'once')))); -knownuser = knownuser || (strcmp(getusername, 'tzvpop') && (~isempty(regexp(gethostname, '^dccn', 'once')) || ~isempty(regexp(gethostname, '^fcdc', 'once')))); -knownuser = knownuser || (strcmp(getusername, 'lucamb') && (~isempty(regexp(gethostname, '^dccn', 'once')) || ~isempty(regexp(gethostname, '^fcdc', 'once')))); -knownuser = knownuser || (strcmp(getusername, 'elivzan') && (~isempty(regexp(gethostname, '^dccn', 'once')) || ~isempty(regexp(gethostname, '^fcdc', 'once')))); -if ~knownuser - return -end - -if ~strcmp(mfilename, 'ft_trackusage') - % this function should not be used outside of the FieldTrip toolbox without updating the token (see below) - return -end - -if ~ft_platform_supports('rng') - % this function should not (yet) be used on Octave - return -end - -%% The first part pertains to keeping the tracking settings consistent over multiple MATLAB sessions - -% This functionality overlaps in part with what normally would be done using -% ft_defaults, but is replicated here to make the tracking independent from the path -% settings in ft_defaults. - -% locate the file that contains the persistent FieldTrip preferences -fieldtripprefs = fullfile(prefdir, 'fieldtripprefs.mat'); - -if ~isfield(ft_default, 'trackusage') - % read options from the preferences file - if exist(fieldtripprefs, 'file') - prefs = load(fieldtripprefs); % the file contains multiple fields - ft_default = mergeconfig(ft_default, prefs); +try + + global ft_default + persistent initialized + + if isempty(initialized) + initialized = false; end -end - -if ~isfield(ft_default, 'trackusage') - % the default is to allow tracking - % create a salt for one-way encryption of identifying information - rng('shuffle'); - trackusage = dec2hex(intmax('uint32')*rand(1)); % create a secret salt, this is never shared - warning('enabling online tracking of FieldTrip usage, see http://www.fieldtriptoolbox.org/faq/tracking'); - if exist(fieldtripprefs, 'file') - % update the existing preferences file - save(fieldtripprefs, 'trackusage', '-append'); + + if nargin<1 + % there is nothing to track + return end - % keep it in the global variable - ft_default.trackusage = trackusage; - clear trackusage -end - -if ~exist(fieldtripprefs, 'file') - % save it to a new preferences file - trackusage = ft_default.trackusage; - save(fieldtripprefs, 'trackusage'); - clear trackusage -end - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% The second part pertains to the actual tracking - -if isequal(ft_default.trackusage, false) || isequal(ft_default.trackusage, 'no') || isequal(ft_default.trackusage, 'off') - return -end - -% this are the default properties to track -properties.token = '1187d9a6959c39d0e733d6273d1658a5'; % this is specific for the FieldTrip project -properties.user = ft_hash(sprintf('%s%s', ft_default.trackusage, getusername)); % hash it with a secret salt -properties.host = ft_hash(sprintf('%s%s', ft_default.trackusage, gethostname)); % hash it with a secret salt -properties.matlab = version('-release'); -properties.fieldtrip = ft_version; -properties.computer = lower(computer); -properties.distinct_id = properties.user; % this links the event to the profile - -% add the custom properties, these come in key-value pairs -for i=1:2:numel(varargin) - properties.(varargin{i}) = varargin{i+1}; -end - -% construct the HTTP request for Mixpanel, see https://mixpanel.com/help/reference/http -event_json = sprintf('{"event": "%s", "properties": {%s}}', event, ft_struct2json(properties)); -event_base64 = base64encode(event_json); -event_http = sprintf('http://api.mixpanel.com/track/?data=%s', event_base64); - - -[output, status] = ft_urlread(event_http); -if ~status - disp(output); - warning('could not send tracker information for "%s"', event); -end - -if ~initialized - % this only gets send once - user_json = sprintf('{"$token": "%s", "$distinct_id": "%s", "$ip": "%s", "$set": {} }', properties.token, properties.user, getaddress()); - user_base64 = base64encode(user_json); - user_http = sprintf('http://api.mixpanel.com/engage/?data=%s', user_base64); - - [output, status] = ft_urlread(user_http); + + %% only enable the tracking for people at the DCCN + knownuser = false; + knownuser = knownuser || ~isempty(regexp(lower(gethostname), '^mac011', 'once')); + knownuser = knownuser || ~isempty(regexp(lower(gethostname), '^mbp', 'once')); + knownuser = knownuser || ~isempty(regexp(lower(gethostname), '^dccn', 'once')); + knownuser = knownuser || ~isempty(regexp(lower(gethostname), '^fcdc', 'once')); + + if ~knownuser + return + end + + if ~strcmp(mfilename, 'ft_trackusage') + % this function should not be used outside of the FieldTrip toolbox without updating the token (see below) + return + end + + if ~ft_platform_supports('rng') + % this function should not (yet) be used on Octave + return + end + + %% The first part pertains to keeping the tracking settings consistent over multiple MATLAB sessions + + % This functionality overlaps in part with what normally would be done using + % ft_defaults, but is replicated here to make the tracking independent from the path + % settings in ft_defaults. + + % locate the file that contains the persistent FieldTrip preferences + fieldtripprefs = fullfile(prefdir, 'fieldtripprefs.mat'); + + if ~isfield(ft_default, 'trackusage') + % read options from the preferences file + if exist(fieldtripprefs, 'file') + prefs = load(fieldtripprefs); % the file contains multiple fields + ft_default = mergeconfig(ft_default, prefs); + end + end + + if ~isfield(ft_default, 'trackusage') + % the default is to allow tracking + % create a salt for one-way encryption of identifying information + rng('shuffle'); + trackusage = dec2hex(intmax('uint32')*rand(1)); % create a secret salt, this is never shared + ft_warning('enabling online tracking of FieldTrip usage, see http://www.fieldtriptoolbox.org/faq/tracking'); + if exist(fieldtripprefs, 'file') + % update the existing preferences file + save(fieldtripprefs, 'trackusage', '-append'); + end + % keep it in the global variable + ft_default.trackusage = trackusage; + clear trackusage + end + + if ~exist(fieldtripprefs, 'file') + % save it to a new preferences file + trackusage = ft_default.trackusage; + save(fieldtripprefs, 'trackusage'); + clear trackusage + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% The second part pertains to the actual tracking + + if isequal(ft_default.trackusage, false) || isequal(ft_default.trackusage, 'no') || isequal(ft_default.trackusage, 'off') + return + end + + % these are the default properties to track + properties.token = '1187d9a6959c39d0e733d6273d1658a5'; % this is specific for the FieldTrip project + properties.user = ft_hash(sprintf('%s%s', ft_default.trackusage, getusername)); % hash it with a secret salt + properties.host = ft_hash(sprintf('%s%s', ft_default.trackusage, gethostname)); % hash it with a secret salt + properties.matlab = version('-release'); + properties.fieldtrip = ft_version; + properties.computer = lower(computer); + properties.distinct_id = properties.user; % this links the event to the profile + + % user information only gets send once at startup + if ~initialized + % construct the HTTP request for Mixpanel, see https://mixpanel.com/help/reference/http + user_json = sprintf('{"$token": "%s", "$distinct_id": "%s", "$ip": "%s", "$set": { "Computer": "%s", "Matlab": "%s" } }', properties.token, properties.user, getaddress(), properties.computer, properties.matlab); + user_base64 = base64encode(user_json); + user_http = sprintf('http://api.mixpanel.com/engage/?data=%s', user_base64); + + [output, status] = ft_urlread(user_http); + + initialized = true; + end % if initialized + + % add the properties for the particular event, these come in key-value pairs + for i=1:2:numel(varargin) + properties.(varargin{i}) = varargin{i+1}; + end + + % construct the HTTP request for Mixpanel, see https://mixpanel.com/help/reference/http + event_json = sprintf('{"event": "%s", "properties": {%s}}', event, ft_struct2json(properties)); + event_base64 = base64encode(event_json); + event_http = sprintf('http://api.mixpanel.com/track/?data=%s', event_base64); + + [output, status] = ft_urlread(event_http); if ~status disp(output); - warning('could not send tracker information for "%s"', event); + ft_warning('could not send tracker information for "%s"', event); + return end - - initialized = true; -end % if initialized - - + +catch + % there are multiple reasons why this might fail, e.g. because Java is not available + % see https://github.com/fieldtrip/fieldtrip/issues/539 +end diff --git a/external/fieldtrip/utilities/ft_transform_geometry.m b/external/fieldtrip/utilities/ft_transform_geometry.m index 38763192..3ee45a28 100644 --- a/external/fieldtrip/utilities/ft_transform_geometry.m +++ b/external/fieldtrip/utilities/ft_transform_geometry.m @@ -1,21 +1,24 @@ function [output] = ft_transform_geometry(transform, input) -% FT_TRANSFORM_GEOMETRY applies a homogeneous coordinate transformation to -% a structure with geometric information, for example a volume conduction model -% for the head, gradiometer of electrode structure containing EEG or MEG -% sensor positions and MEG coil orientations, a head shape or a source model. +% FT_TRANSFORM_GEOMETRY applies a homogeneous coordinate transformation to a +% structure with geometric information, for example a volume conduction model for the +% head, gradiometer of electrode structure containing EEG or MEG sensor positions and +% MEG coil orientations, a head shape or a source model. % -% The units in which the transformation matrix is expressed are assumed to -% be the same units as the units in which the geometric object is -% expressed. Depending on the input object, the homogeneous transformation -% matrix should be limited to a rigid-body translation plus rotation -% (MEG-gradiometer array), or to a rigid-body translation plus rotation -% plus a global rescaling (volume conductor geometry). +% The units in which the transformation matrix is expressed are assumed to be the +% same units as the units in which the geometric object is expressed. Depending on +% the input object, the homogeneous transformation matrix should be limited to a +% rigid-body translation plus rotation (MEG-gradiometer array), or to a rigid-body +% translation plus rotation plus a global rescaling (volume conductor geometry). % % Use as % output = ft_transform_geometry(transform, input) +% where transform should be a 4x4 homogenous transformation matrix and the input data +% structure can be any of the FieldTrip data structures that describes geometrical +% data. % -% See also FT_WARP_APPLY, FT_HEADCOORDINATES +% See also FT_WARP_APPLY, FT_HEADCOORDINATES, FT_TRANSFORM_SENS, FT_TRANSFORM_HEADSHAPE, +% FT_TRANSFORM_VOL % Copyright (C) 2011, Jan-Mathijs Schoffelen % @@ -45,14 +48,13 @@ rotation(1:3,1:3) = transform(1:3,1:3); if any(abs(transform(4,:)-[0 0 0 1])>100*eps) - error('invalid transformation matrix'); + ft_error('invalid transformation matrix'); end if ~allowscaling % allow for some numerical imprecision - if abs(det(rotation)-1)>1e-6%100*eps - %if abs(det(rotation)-1)>100*eps % allow for some numerical imprecision - error('only a rigid body transformation without rescaling is allowed'); + if (abs(det(rotation))-1)>1e-6 + ft_error('only a rigid body transformation without rescaling is allowed'); end end @@ -61,33 +63,33 @@ % FIXME insert check for nonuniform scaling, should give an error end -tfields = {'pos' 'pnt' 'o' 'coilpos' 'chanpos' 'chanposold' 'chanposorg' 'elecpos', 'nas', 'lpa', 'rpa', 'zpoint'}; % apply rotation plus translation -rfields = {'ori' 'nrm' 'coilori' 'chanori' 'chanoriold' 'chanoriorg'}; % only apply rotation +tfields = {'pos' 'pnt' 'o' 'coilpos' 'elecpos' 'optopos' 'chanpos' 'chanposold' 'nas' 'lpa' 'rpa' 'zpoint'}; % apply rotation plus translation +rfields = {'ori' 'nrm' 'coilori' 'elecori' 'optoori' 'chanori' 'chanoriold' }; % only apply rotation mfields = {'transform'}; % plain matrix multiplication recfields = {'fid' 'bnd' 'orig'}; % recurse into these fields % the field 'r' is not included here, because it applies to a volume % conductor model, and scaling is not allowed, so r will not change. -fnames = fieldnames(input); +fnames = fieldnames(input); for k = 1:numel(fnames) - if ~isempty(input.(fnames{k})) - if any(strcmp(fnames{k}, tfields)) - input.(fnames{k}) = apply(transform, input.(fnames{k})); - elseif any(strcmp(fnames{k}, rfields)) - input.(fnames{k}) = apply(rotation, input.(fnames{k})); - elseif any(strcmp(fnames{k}, mfields)) - input.(fnames{k}) = transform*input.(fnames{k}); - elseif any(strcmp(fnames{k}, recfields)) - for j = 1:numel(input.(fnames{k})) - input.(fnames{k})(j) = ft_transform_geometry(transform, input.(fnames{k})(j)); - end - else - % do nothing - end + if ~isempty(input.(fnames{k})) + if any(strcmp(fnames{k}, tfields)) + input.(fnames{k}) = apply(transform, input.(fnames{k})); + elseif any(strcmp(fnames{k}, rfields)) + input.(fnames{k}) = apply(rotation, input.(fnames{k})); + elseif any(strcmp(fnames{k}, mfields)) + input.(fnames{k}) = transform*input.(fnames{k}); + elseif any(strcmp(fnames{k}, recfields)) + for j = 1:numel(input.(fnames{k})) + input.(fnames{k})(j) = ft_transform_geometry(transform, input.(fnames{k})(j)); + end + else + % do nothing end + end end output = input; -return; + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % SUBFUNCTION that applies the homogeneous transformation diff --git a/external/fieldtrip/utilities/ft_version.m b/external/fieldtrip/utilities/ft_version.m index d88d4bac..bad35e60 100644 --- a/external/fieldtrip/utilities/ft_version.m +++ b/external/fieldtrip/utilities/ft_version.m @@ -3,10 +3,16 @@ % FT_VERSION returns the version and installation directory of FieldTrip % % FieldTrip is not released with version numbers as "2.0", "2.1", etc. Instead, we -% have a Subversion (SVN) development version and a daily FTP release version. +% share our development version on http://github.com/fieldtrip. You can use git or +% subversion (svn) to make a local version of the repository. Furthermore, we release +% daily version as zip-file on our FTP server. % -% The SVN development version is labeled with the revision number like "rXXXXX", -% where XXXX is the revision number. +% If you access the development version using git, it is labeled with the hash of the +% latest commit like "128c693". You can access the specific version "XXXXXX" at +% https://github.com/fieldtrip/fieldtrip/commit/XXXXXX. +% +% If you access the development version using svn, it is labeled with the revision +% number like "rXXXXX", where XXXX is the revision number. % % The daily FTP release version is packaged as a zip file and its version is % indicated with "YYMMDD" (year, month, day). @@ -17,7 +23,12 @@ % [ftver, ftpath] = ft_version % to get the version and the installation root directory. % -% See also VERSION, VER +% When using git for version control, you can also get additional information with +% ft_version revision +% ft_version branch +% ft_version clean +% +% See also FT_PLATFORM_SUPPORTS, VERSION, VER, VERLESSTHAN % Copyright (C) 2012-2016, Eelke Spaak % @@ -51,13 +62,13 @@ ftpath = ftpath(1:end-10); % strip away '/utilities' where this function is located if isempty(issvn) - % are we dealing with an SVN working copy of fieldtrip? + % are we dealing with an SVN working copy of FieldTrip? issvn = isdir(fullfile(ftpath, '.svn')); end if isempty(isgit) - % are we dealing with an GIT working copy of fieldtrip? - isgit = isdir(fullfile(ftpath, '.git')); + % are we dealing with an GIT working copy of FieldTrip? + isgit = exist(fullfile(ftpath, '.git'), 'file'); end if ispc @@ -76,7 +87,7 @@ if status > 0 if ~ispc % the command line tools will probably not be available on windows - warning('you seem to have an SVN development copy of FieldTrip, yet ''svn info'' does not work as expected'); + ft_warning('you seem to have an SVN development copy of FieldTrip, yet ''svn info'' does not work as expected'); end ftver = 'unknown'; else @@ -91,7 +102,7 @@ if status>0 if ~ispc % the command line tools will probably not be available on windows - warning('you seem to have an GIT development copy of FieldTrip, yet ''git'' does not work as expected'); + ft_warning('you seem to have an GIT development copy of FieldTrip, yet ''git'' does not work as expected'); end ftver = 'unknown'; @@ -114,7 +125,7 @@ ftver = 'yes'; end otherwise - error('unsupported command "%s"'); + ft_error('unsupported command "%s"'); end cd(olddir); @@ -133,8 +144,11 @@ else % get it from the Contents.m file in the FieldTrip release a = ver(ftpath); - ftver = a.Version; - + if isempty(a) + ftver = 'unknown'; + else + ftver = a.Version; + end end % if issvn, isgit or otherwise if nargout==0 diff --git a/external/fieldtrip/utilities/ft_warning.m b/external/fieldtrip/utilities/ft_warning.m index 18b0ce00..58f3985e 100644 --- a/external/fieldtrip/utilities/ft_warning.m +++ b/external/fieldtrip/utilities/ft_warning.m @@ -1,39 +1,40 @@ -function [ws, warned] = ft_warning(varargin) +function varargout = ft_warning(varargin) -% FT_WARNING will throw a warning for every unique point in the -% stacktrace only, e.g. in a for-loop a warning is thrown only once. +% FT_WARNING prints a warning message on screen, depending on the verbosity +% settings of the calling high-level FieldTrip function. This function works +% similar to the standard WARNING function, but also features the "once" mode. % -% Use as one of the following -% ft_warning(string) -% ft_warning(id, string) -% Alternatively, you can use ft_warning using a timeout -% ft_warning(string, timeout) -% ft_warning(id, string, timeout) -% where timeout should be inf if you don't want to see the warning ever -% again. +% Use as +% ft_warning(...) +% with arguments similar to fprintf, or +% ft_warning(msgId, ...) +% with arguments similar to warning. % -% Use as ft_warning('-clear') to clear old warnings from the current -% stack +% You can switch of all warning messages using +% ft_warning off +% or for specific ones using +% ft_warning off msgId % -% It can be used instead of the MATLAB built-in function WARNING, thus as -% s = ft_warning(...) -% or as -% ft_warning(s) -% where s is a structure with fields 'identifier' and 'state', storing the -% state information. In other words, ft_warning accepts as an input the -% same structure it returns as an output. This returns or restores the -% states of warnings to their previous values. +% To switch them back on, you would use +% ft_warning on +% or for specific ones using +% ft_warning on msgId +% +% Warning messages are only printed once per timeout period using +% ft_warning timeout 60 +% ft_warning once +% or for specific ones using +% ft_warning once msgId % -% It can also be used as -% [s w] = ft_warning(...) -% where w is a boolean that indicates whether a warning as been thrown or not. +% You can see the most recent messages and identifier using +% ft_warning last % -% Please note that you can NOT use it like this -% ft_warning('the value is %d', 10) -% instead you should do -% ft_warning(sprintf('the value is %d', 10)) +% You can query the current on/off/once state for all messages using +% ft_warning query +% +% See also FT_ERROR, FT_WARNING, FT_NOTICE, FT_warning, FT_DEBUG, ERROR, WARNING -% Copyright (C) 2012-2016, Robert Oostenveld, J?rn M. Horschig +% Copyright (C) 2012-2017, Robert Oostenveld, J?rn M. Horschig % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -53,205 +54,12 @@ % % $Id$ -global ft_default -warned = false; -ws = []; - -stack = dbstack; -if any(strcmp({stack(2:end).file}, 'ft_warning.m')) - % don't call FT_WARNING recursively, see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=3068 - return; -end - -if nargin < 1 - error('You need to specify at least a warning message'); -end - -if isstruct(varargin{1}) - warning(varargin{1}); - return; -end - -if ~isfield(ft_default, 'warning') - ft_default.warning = []; -end -if ~isfield(ft_default.warning, 'stopwatch') - ft_default.warning.stopwatch = []; -end -if ~isfield(ft_default.warning, 'identifier') - ft_default.warning.identifier = []; -end -if ~isfield(ft_default.warning, 'ignore') - ft_default.warning.ignore = {}; -end - -% put the arguments we will pass to warning() in this cell array -warningArgs = {}; - -if nargin==3 - % calling syntax (id, msg, timeout) - - warningArgs = varargin(1:2); - msg = warningArgs{2}; - timeout = varargin{3}; - fname = [warningArgs{1} '_' warningArgs{2}]; - -elseif nargin==2 && isnumeric(varargin{2}) - % calling syntax (msg, timeout) - - warningArgs = varargin(1); - msg = warningArgs{1}; - timeout = varargin{2}; - fname = warningArgs{1}; - -elseif nargin==2 && isequal(varargin{1}, 'off') - - ft_default.warning.ignore = union(ft_default.warning.ignore, varargin{2}); - return - -elseif nargin==2 && isequal(varargin{1}, 'on') - - ft_default.warning.ignore = setdiff(ft_default.warning.ignore, varargin{2}); - return - -elseif nargin==2 && ~isnumeric(varargin{2}) - % calling syntax (id, msg) - - warningArgs = varargin(1:2); - msg = warningArgs{2}; - timeout = inf; - fname = [warningArgs{1} '_' warningArgs{2}]; - -elseif nargin==1 - % calling syntax (msg) - - warningArgs = varargin(1); - msg = warningArgs{1}; - timeout = inf; % default timeout in seconds - fname = [warningArgs{1}]; - -end - -if ismember(msg, ft_default.warning.ignore) - % do not show this warning - return; -end - -if isempty(timeout) - error('Timeout ill-specified'); -end - -if timeout ~= inf - fname = fixname(fname); % make a nice string that is allowed as fieldname in a structures - line = []; -else - % here, we create the fieldname functionA.functionB.functionC... - [tmpfname, ft_default.warning.identifier, line] = fieldnameFromStack(ft_default.warning.identifier); - if ~isempty(tmpfname), - fname = tmpfname; - clear tmpfname; - end -end - -if nargin==1 && ischar(varargin{1}) && strcmp('-clear', varargin{1}) - if strcmp(fname, '-clear') % reset all fields if called outside a function - ft_default.warning.identifier = []; - ft_default.warning.stopwatch = []; - else - if issubfield(ft_default.warning.identifier, fname) - ft_default.warning.identifier = rmsubfield(ft_default.warning.identifier, fname); - end - end - return; -end - -% and add the line number to make this unique for the last function -fname = horzcat(fname, line); - -if ~issubfield('ft_default.warning.stopwatch', fname) - ft_default.warning.stopwatch = setsubfield(ft_default.warning.stopwatch, fname, tic); -end - -now = toc(getsubfield(ft_default.warning.stopwatch, fname)); % measure time since first function call - -if ~issubfield(ft_default.warning.identifier, fname) || ... - (issubfield(ft_default.warning.identifier, fname) && now>getsubfield(ft_default.warning.identifier, [fname '.timeout'])) - - % create or reset field - ft_default.warning.identifier = setsubfield(ft_default.warning.identifier, fname, []); - - % warning never given before or timed out - ws = warning(warningArgs{:}); - ft_default.warning.identifier = setsubfield(ft_default.warning.identifier, [fname '.timeout'], now+timeout); - ft_default.warning.identifier = setsubfield(ft_default.warning.identifier, [fname '.ws'], msg); - warned = true; +if nargout + varargout{:} = ft_notification(varargin{:}); +elseif isequal(varargin, {'last'}) + % return an answer anyway + varargout{1} = ft_notification(varargin{:}); else - - % the warning has been issued before, but has not timed out yet - ws = getsubfield(ft_default.warning.identifier, [fname '.ws']); - -end - -end % function ft_warning - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% helper functions -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -function [fname, ft_previous_warnings, line] = fieldnameFromStack(ft_previous_warnings) -% stack(1) is this function, stack(2) is ft_warning -stack = dbstack('-completenames'); -if size(stack) < 3 - fname = []; - line = []; - return; -end -i0 = 3; -% ignore ft_preamble -while strfind(stack(i0).name, 'ft_preamble') - i0=i0+1; + ft_notification(varargin{:}); end -fname = horzcat(fixname(stack(end).name)); -if ~issubfield(ft_previous_warnings, fixname(stack(end).name)) - ft_previous_warnings.(fixname(stack(end).name)) = []; % iteratively build up structure fields -end - - -for i=numel(stack)-1:-1:(i0) - % skip postamble scripts - if strncmp(stack(i).name, 'ft_postamble', 12) - break; - end - - fname = horzcat(fname, '.', horzcat(fixname(stack(i).name))); % , stack(i).file - if ~issubfield(ft_previous_warnings, fname) % iteratively build up structure fields - setsubfield(ft_previous_warnings, fname, []); - end -end - -% line of last function call -line = ['.line', int2str(stack(i0).line)]; -end - -% function outcome = issubfield(strct, fname) -% substrindx = strfind(fname, '.'); -% if numel(substrindx) > 0 -% % separate the last fieldname from all former -% outcome = eval(['isfield(strct.' fname(1:substrindx(end)-1) ', ''' fname(substrindx(end)+1:end) ''')']); -% else -% % there is only one fieldname -% outcome = isfield(strct, fname); -% end -% end - -% function strct = rmsubfield(strct, fname) -% substrindx = strfind(fname, '.'); -% if numel(substrindx) > 0 -% % separate the last fieldname from all former -% strct = eval(['rmfield(strct.' fname(1:substrindx(end)-1) ', ''' fname(substrindx(end)+1:end) ''')']); -% else -% % there is only one fieldname -% strct = rmfield(strct, fname); -% end -% end diff --git a/external/fieldtrip/utilities/ft_warp_apply.m b/external/fieldtrip/utilities/ft_warp_apply.m index 980e1b88..fa7fa903 100644 --- a/external/fieldtrip/utilities/ft_warp_apply.m +++ b/external/fieldtrip/utilities/ft_warp_apply.m @@ -102,19 +102,19 @@ s = size(M); if s(1)~=3 - error('invalid size of nonlinear transformation matrix'); + ft_error('invalid size of nonlinear transformation matrix'); elseif strcmp(method, 'nonlin0') && s(2)~=1 - error('invalid size of nonlinear transformation matrix'); + ft_error('invalid size of nonlinear transformation matrix'); elseif strcmp(method, 'nonlin1') && s(2)~=4 - error('invalid size of nonlinear transformation matrix'); + ft_error('invalid size of nonlinear transformation matrix'); elseif strcmp(method, 'nonlin2') && s(2)~=10 - error('invalid size of nonlinear transformation matrix'); + ft_error('invalid size of nonlinear transformation matrix'); elseif strcmp(method, 'nonlin3') && s(2)~=20 - error('invalid size of nonlinear transformation matrix'); + ft_error('invalid size of nonlinear transformation matrix'); elseif strcmp(method, 'nonlin4') && s(2)~=35 - error('invalid size of nonlinear transformation matrix'); + ft_error('invalid size of nonlinear transformation matrix'); elseif strcmp(method, 'nonlin5') && s(2)~=56 - error('invalid size of nonlinear transformation matrix'); + ft_error('invalid size of nonlinear transformation matrix'); end if s(2)==1 @@ -143,7 +143,7 @@ yy = M(2,1) + M(2,2)*x + M(2,3)*y + M(2,4)*z + M(2,5)*x.*x + M(2,6)*x.*y + M(2,7)*x.*z + M(2,8)*y.*y + M(2,9)*y.*z + M(2,10)*z.*z + M(2,11)*x.*x.*x + M(2,12)*x.*x.*y + M(2,13)*x.*x.*z + M(2,14)*x.*y.*y + M(2,15)*x.*y.*z + M(2,16)*x.*z.*z + M(2,17)*y.*y.*y + M(2,18)*y.*y.*z + M(2,19)*y.*z.*z + M(2,20)*z.*z.*z + M(2,21)*x.*x.*x.*x + M(2,22)*x.*x.*x.*y + M(2,23)*x.*x.*x.*z + M(2,24)*x.*x.*y.*y + M(2,25)*x.*x.*y.*z + M(2,26)*x.*x.*z.*z + M(2,27)*x.*y.*y.*y + M(2,28)*x.*y.*y.*z + M(2,29)*x.*y.*z.*z + M(2,30)*x.*z.*z.*z + M(2,31)*y.*y.*y.*y + M(2,32)*y.*y.*y.*z + M(2,33)*y.*y.*z.*z + M(2,34)*y.*z.*z.*z + M(2,35)*z.*z.*z.*z + M(2,36)*x.*x.*x.*x.*x + M(2,37)*x.*x.*x.*x.*y + M(2,38)*x.*x.*x.*x.*z + M(2,39)*x.*x.*x.*y.*y + M(2,40)*x.*x.*x.*y.*z + M(2,41)*x.*x.*x.*z.*z + M(2,42)*x.*x.*y.*y.*y + M(2,43)*x.*x.*y.*y.*z + M(2,44)*x.*x.*y.*z.*z + M(2,45)*x.*x.*z.*z.*z + M(2,46)*x.*y.*y.*y.*y + M(2,47)*x.*y.*y.*y.*z + M(2,48)*x.*y.*y.*z.*z + M(2,49)*x.*y.*z.*z.*z + M(2,50)*x.*z.*z.*z.*z + M(2,51)*y.*y.*y.*y.*y + M(2,52)*y.*y.*y.*y.*z + M(2,53)*y.*y.*y.*z.*z + M(2,54)*y.*y.*z.*z.*z + M(2,55)*y.*z.*z.*z.*z + M(2,56)*z.*z.*z.*z.*z; zz = M(3,1) + M(3,2)*x + M(3,3)*y + M(3,4)*z + M(3,5)*x.*x + M(3,6)*x.*y + M(3,7)*x.*z + M(3,8)*y.*y + M(3,9)*y.*z + M(3,10)*z.*z + M(3,11)*x.*x.*x + M(3,12)*x.*x.*y + M(3,13)*x.*x.*z + M(3,14)*x.*y.*y + M(3,15)*x.*y.*z + M(3,16)*x.*z.*z + M(3,17)*y.*y.*y + M(3,18)*y.*y.*z + M(3,19)*y.*z.*z + M(3,20)*z.*z.*z + M(3,21)*x.*x.*x.*x + M(3,22)*x.*x.*x.*y + M(3,23)*x.*x.*x.*z + M(3,24)*x.*x.*y.*y + M(3,25)*x.*x.*y.*z + M(3,26)*x.*x.*z.*z + M(3,27)*x.*y.*y.*y + M(3,28)*x.*y.*y.*z + M(3,29)*x.*y.*z.*z + M(3,30)*x.*z.*z.*z + M(3,31)*y.*y.*y.*y + M(3,32)*y.*y.*y.*z + M(3,33)*y.*y.*z.*z + M(3,34)*y.*z.*z.*z + M(3,35)*z.*z.*z.*z + M(3,36)*x.*x.*x.*x.*x + M(3,37)*x.*x.*x.*x.*y + M(3,38)*x.*x.*x.*x.*z + M(3,39)*x.*x.*x.*y.*y + M(3,40)*x.*x.*x.*y.*z + M(3,41)*x.*x.*x.*z.*z + M(3,42)*x.*x.*y.*y.*y + M(3,43)*x.*x.*y.*y.*z + M(3,44)*x.*x.*y.*z.*z + M(3,45)*x.*x.*z.*z.*z + M(3,46)*x.*y.*y.*y.*y + M(3,47)*x.*y.*y.*y.*z + M(3,48)*x.*y.*y.*z.*z + M(3,49)*x.*y.*z.*z.*z + M(3,50)*x.*z.*z.*z.*z + M(3,51)*y.*y.*y.*y.*y + M(3,52)*y.*y.*y.*y.*z + M(3,53)*y.*y.*y.*z.*z + M(3,54)*y.*y.*z.*z.*z + M(3,55)*y.*z.*z.*z.*z + M(3,56)*z.*z.*z.*z.*z; else - error('invalid size of nonlinear transformation matrix'); + ft_error('invalid size of nonlinear transformation matrix'); end warped = [xx yy zz]; @@ -188,7 +188,7 @@ %error('individual2sn is not yet implemented'); warped = individual2sn(M, input); else - error('unrecognized transformation method'); + ft_error('unrecognized transformation method'); end if ~input3d diff --git a/external/fieldtrip/utilities/ft_warp_dykstra2012.m b/external/fieldtrip/utilities/ft_warp_dykstra2012.m deleted file mode 100644 index a0d91c59..00000000 --- a/external/fieldtrip/utilities/ft_warp_dykstra2012.m +++ /dev/null @@ -1,158 +0,0 @@ -function [coord_snapped] = ft_warp_dykstra2012(coord, surf, feedback) - -% FT_WARP_DYKSTRA2012 projects the ECoG grid / strip onto a cortex hull -% while minimizing the distance from original positions and the -% deformation of the grid. To align ECoG electrodes to the pial surface, -% you first need to compute the cortex hull with FT_PREPARE_MESH. -% FT_WARP_DYKSTRA2012 uses algorithm described in Dykstra et al. (2012, -% Neuroimage) in which electrodes are projected onto pial surface while -% minimizing the displacement of the electrodes from original location -% and maintaining the grid shape. It relies on the optimization toolbox. -% -% See also FT_ELECTRODEREALIGN, FT_PREPARE_MESH - -% Copyright (C) 2012-2016, Gio Piantoni, Andrew Dykstra -% -% This program is free software; you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation; either version 2 of the License, or -% (at your option) any later version. -% -% This program is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with this program; if not, write to the Free Software -% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org -% for the documentation and details. -% -% FieldTrip is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. -% -% FieldTrip is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with FieldTrip. If not, see . -% -% $Id$ - -% determine whether the MATLAB Optimization toolbox is available and can be used -ft_hastoolbox('optim', 1); - -disp('Please cite: Dykstra et al. 2012 Neuroimage PMID: 22155045') - -% get starting coordinates -coord0 = coord; - -% compute pairs of neighbors -pairs = knn_pairs(coord, 4); - -% anonymous function handles -efun = @(coord_snapped) energy_electrodesnap(coord_snapped, coord, pairs); -cfun = @(coord_snapped) dist_to_surface(coord_snapped, surf); - -% options -options = optimset('Algorithm','active-set',... - 'MaxIter', 50,... - 'MaxFunEvals', Inf,... - 'UseParallel', 'always',... - 'GradObj', 'off',... - 'TypicalX', coord(:),... - 'DiffMaxChange', 2,... - 'DiffMinChange', 0.3,... - 'TolFun', 0.3,... - 'TolCon', 0.01 * size(coord0, 1),... - 'TolX', 0.5,... - 'Diagnostics', 'off',... - 'RelLineSrchBnd',1); - -if strcmp(feedback, 'yes') - options = optimset(options, 'Display', 'iter'); -else - options = optimset(options, 'Display', 'final'); -end - -% run minimization -coord_snapped = fmincon(efun, coord0, [], [], [], [], [], [], cfun, options); - -end - -function [energy, denergy] = energy_electrodesnap(coord, coord_orig, pairs) -% ENERGY_ELECTRODESNAP compute energy to be minimized, based on deformation -% and distance of the electrodes from original distance - -energy_eshift = sum((coord - coord_orig).^2, 2); -energy_deform = deformation_energy(coord, coord_orig, pairs); -energy = mean(energy_eshift) + mean(energy_deform.^2); - -denergy=[]; - -end - -function energy = deformation_energy(coord, coord_orig, pairs) -% DEFORMATION_ENERGY measure energy due to grid deformation - -dist = sqrt(sum((coord(pairs(:, 1), :) - coord(pairs(:, 2), :)) .^ 2, 2)); -dist_orig = sqrt(sum((coord_orig(pairs(:, 1), :) - coord_orig(pairs(:, 2), :)) .^ 2, 2)); - -energy = (dist - dist_orig) .^2; -end - -function [c, dist] = dist_to_surface(coord, surf) -% DIST_TO_SURFACE Compute distance to surface, this is the fastest way to run -% it, although running the loops in other directions might be more intuitive. - -c = []; - -dist = zeros(size(coord, 1), 1); -for i0 = 1:size(coord, 1) - dist_one_elec = zeros(size(surf.pos, 1), 1); - for i1 = 1:size(surf.pos, 2) - dist_one_elec = dist_one_elec + (surf.pos(:, i1) - coord(i0, i1)) .^ 2; - end - dist(i0) = min(dist_one_elec); -end -dist = sqrt(dist); - -end - -function pairs = knn_pairs(coord, k) -% KNN_PAIRS compute pairs of neighbors of the grid - -knn_ind = knn_search(coord, coord, k); -pairs = cat(3, knn_ind, repmat([1:size(coord,1)]',1,k)); -pairs = permute(pairs,[3 1 2]); -pairs = sort(reshape(pairs,2,[]),1)'; -pairs = unique(pairs,'rows'); - -end - -function idx = knn_search(Q, R, K) -%KNN_SEARCH perform search using k-Nearest Neighbors algorithm - -[N, M] = size(Q); -L = size(R, 1); -idx = zeros(N, K); -D = idx; - -for k = 1:N - d = zeros(L, 1); - for t = 1:M - d = d + (R(:, t) - Q(k, t)) .^ 2; - end - d(k) = inf; - [s, t] = sort(d); - idx(k, :) = t(1:K); - D(k, :)= s(1:K); -end - -end diff --git a/external/fieldtrip/utilities/ft_warp_optim.m b/external/fieldtrip/utilities/ft_warp_optim.m index d8c38aaa..916e892a 100644 --- a/external/fieldtrip/utilities/ft_warp_optim.m +++ b/external/fieldtrip/utilities/ft_warp_optim.m @@ -71,8 +71,8 @@ pos1 = input; pos2 = target; -% The ft_warp_error function might be located in the private subdirectory fo -% fieldtrip, i.e. only available to functions in the FieldTrip toolbox. +% The ft_warp_error function might be located in the private subdirectory of +% FieldTrip, i.e. only available to functions in the FieldTrip toolbox. % The following line ensures that the function can also be found by the % feval that is executed by the optimalization toolbox. errorfun = str2func('ft_warp_error'); @@ -97,13 +97,13 @@ options = optimset(options, 'Display', 'off'); options = optimset(options, 'MaxIter', 4500); else - warning('unknown optimization function "%s", using default parameters', func2str(optimfun)); + ft_warning('unknown optimization function "%s", using default parameters', func2str(optimfun)); end if fb; fprintf('distance = %f\n', errorfun([0 0 0 0 0 0], pos1, pos2, 'rigidbody')); end if isempty(method) - error('incorrect warping method specified'); + ft_error('incorrect warping method specified'); end % the warp is done in steps, starting simple and progressively getting more complex @@ -119,7 +119,7 @@ })); if isempty(level) - error('incorrect warping method specified'); + ft_error('incorrect warping method specified'); end if level>=1 diff --git a/external/fieldtrip/utilities/hasyokogawa.m b/external/fieldtrip/utilities/hasyokogawa.m index b98d91bb..cf309aab 100644 --- a/external/fieldtrip/utilities/hasyokogawa.m +++ b/external/fieldtrip/utilities/hasyokogawa.m @@ -74,7 +74,7 @@ elseif [0 2 2 5] == [rev_ADbitInfoM rev_ChannelInfoM rev_AmpGainM rev_MatchingInfoM] version='16bitBeta6'; else - warning('The version of the installed Yokogawa toolbox cannot be determined.'); + ft_warning('The version of the installed Yokogawa toolbox cannot be determined.'); end catch m = lasterror; diff --git a/external/fieldtrip/utilities/istrue.m b/external/fieldtrip/utilities/istrue.m index 79631e32..742a0997 100644 --- a/external/fieldtrip/utilities/istrue.m +++ b/external/fieldtrip/utilities/istrue.m @@ -1,7 +1,7 @@ function y = istrue(x) -% ISTRUE ensures that a true/false input argument like "yes", "true" -% or "on" is converted into a boolean +% ISTRUE converts an input argument like "yes/no", "true/false" or "on/off" into a +% boolean. If the input is boolean, then it will remain like that. % Copyright (C) 2009-2012, Robert Oostenveld % diff --git a/external/fieldtrip/utilities/keepfields.m b/external/fieldtrip/utilities/keepfields.m index 1b360a91..0f9402cb 100644 --- a/external/fieldtrip/utilities/keepfields.m +++ b/external/fieldtrip/utilities/keepfields.m @@ -35,7 +35,7 @@ if ischar(fields) fields = {fields}; elseif ~iscell(fields) - error('fields input argument must be a cell array of strings or a single string'); + ft_error('fields input argument must be a cell array of strings or a single string'); end fields = setdiff(fieldnames(s), fields); diff --git a/external/fieldtrip/utilities/keyval.m b/external/fieldtrip/utilities/keyval.m index b176ce8d..0043c72b 100644 --- a/external/fieldtrip/utilities/keyval.m +++ b/external/fieldtrip/utilities/keyval.m @@ -44,7 +44,7 @@ end if mod(length(varargin),2) - error('optional input arguments should come in key-value pairs, i.e. there should be an even number'); + ft_error('optional input arguments should come in key-value pairs, i.e. there should be an even number'); end % the 1st, 3rd, etc. contain the keys, the 2nd, 4th, etc. contain the values @@ -58,7 +58,7 @@ end if ~all(valid) - error('optional input arguments should come in key-value pairs, the optional input argument %d is invalid (should be a string)', i); + ft_error('optional input arguments should come in key-value pairs, the optional input argument %d is invalid (should be a string)', i); end hit = find(strcmpi(key, keys)); @@ -69,7 +69,7 @@ % the requested key was found val = vals{hit}; else - error('multiple input arguments with the same name'); + ft_error('multiple input arguments with the same name'); end if nargout>1 diff --git a/external/fieldtrip/utilities/keyvalcheck.m b/external/fieldtrip/utilities/keyvalcheck.m index 9f2cdaac..667287df 100644 --- a/external/fieldtrip/utilities/keyvalcheck.m +++ b/external/fieldtrip/utilities/keyvalcheck.m @@ -46,7 +46,7 @@ function keyvalcheck(arglist, varargin) vals = arglist(2:2:end); if numel(keys)~=numel(vals) - error('optional input arguments should come in key-value pairs, i.e. there should be an even number'); + ft_error('optional input arguments should come in key-value pairs, i.e. there should be an even number'); end keys = cellfun(@lower, keys, 'UniformOutput', false); @@ -56,7 +56,7 @@ function keyvalcheck(arglist, varargin) required = cellfun(@lower, required, 'UniformOutput', false); set = intersect(keys, required); if numel(set)~=numel(required) - error('the required input argument ''%s'' was not specified', set{:}); + ft_error('the required input argument ''%s'' was not specified', set{:}); end end @@ -65,7 +65,7 @@ function keyvalcheck(arglist, varargin) forbidden = cellfun(@lower, forbidden, 'UniformOutput', false); set = intersect(keys, forbidden); if numel(set)~=0 - error('the input argument ''%s'' is forbidden', set{:}); + ft_error('the input argument ''%s'' is forbidden', set{:}); end end @@ -74,7 +74,7 @@ function keyvalcheck(arglist, varargin) optional = cellfun(@lower, optional, 'UniformOutput', false); set = setdiff(keys, optional); if numel(set)>0 - error('the input argument ''%s'' is forbidden', set{:}); + ft_error('the input argument ''%s'' is forbidden', set{:}); end end diff --git a/external/fieldtrip/utilities/match_str.m b/external/fieldtrip/utilities/match_str.m index 440a3818..39eced66 100644 --- a/external/fieldtrip/utilities/match_str.m +++ b/external/fieldtrip/utilities/match_str.m @@ -1,10 +1,11 @@ function [sel1, sel2] = match_str(a, b, fullout) -% MATCH_STR looks for matching labels in two listst of strings +% MATCH_STR looks for matching labels in two lists of strings % and returns the indices into both the 1st and 2nd list of the matches. % They will be ordered according to the first input argument. % -% [sel1, sel2] = match_str(strlist1, strlist2) +% Use as +% [sel1, sel2] = match_str(strlist1, strlist2) % % The strings can be stored as a char matrix or as an vertical array of % cells, the matching is done for each row. @@ -69,7 +70,7 @@ % According to the original implementation empty numeric elements are % allowed, but are not returned as match. This is different to empty string % elements, which are returned as match. -% See also http://bugzilla.fcdonders.nl/show_bug.cgi?id=1808 +% See also http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=1808 empty_a = cellfun(@isnumeric, a) & cellfun(@isempty, a); empty_b = cellfun(@isnumeric, b) & cellfun(@isempty, b); % the following allows the unique function to operate normally diff --git a/external/fieldtrip/utilities/match_val.m b/external/fieldtrip/utilities/match_val.m new file mode 100644 index 00000000..33048f96 --- /dev/null +++ b/external/fieldtrip/utilities/match_val.m @@ -0,0 +1,35 @@ +function [IA, IB] = match_val(A, B) + +% MATCH_VAL looks for matching values in two arrays of values +% and returns the indices into both the 1st and 2nd list of the matches. +% They will be ordered according to the first input argument. +% +% Use as +% [sel1, sel2] = match_str(vallist1, vallist2) +% +% See also MATCH_STR + +% Copyright (C) 2017, Robert Oostenveld +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +A = A(:); +B = B(:); + +[C,IA,IB] = intersect(A, B, 'rows', 'stable'); diff --git a/external/fieldtrip/utilities/memtic.m b/external/fieldtrip/utilities/memtic.m index d073f441..6a471871 100644 --- a/external/fieldtrip/utilities/memtic.m +++ b/external/fieldtrip/utilities/memtic.m @@ -77,7 +77,7 @@ output = nan; end otherwise - error('invalid input argument #1'); + ft_error('invalid input argument #1'); end % switch return end % if mex file does not exist @@ -88,7 +88,7 @@ switch action case 'tic' if nargin>1 - error('the counter cannot be specified as imput argument'); + ft_error('the counter cannot be specified as imput argument'); end counter = length(state)+1; @@ -105,7 +105,7 @@ % take the latest counter = length(state); elseif counter<1 || counter>numel(state) - error('invalid counter'); + ft_error('invalid counter'); end if counter==0 @@ -121,6 +121,6 @@ end otherwise - error('invalid input argument #1'); + ft_error('invalid input argument #1'); end % switch diff --git a/external/fieldtrip/utilities/nearest.m b/external/fieldtrip/utilities/nearest.m index bd23814f..6e8c18d6 100644 --- a/external/fieldtrip/utilities/nearest.m +++ b/external/fieldtrip/utilities/nearest.m @@ -53,11 +53,11 @@ if numel(val)==2 % interpret this as a range specification like [minval maxval] - % see also http://bugzilla.fcdonders.nl/show_bug.cgi?id=1431 + % see also http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=1431 intervaltol = eps; sel = find(array>=val(1) & array<=val(2)); if isempty(sel) - error('The limits you selected are outside the range available in the data'); + ft_error('The limits you selected are outside the range available in the data'); end indx = sel([1 end]); if indx(1)>1 && abs(array(indx(1)-1)-val(1))<=intervaltol @@ -91,22 +91,22 @@ if ~toleranceflag if valmaxarray if numel(array)==1 - warning('the selected value %g should be within the range of the array from %g to %g', val, minarray, maxarray); + ft_warning('the selected value %g should be within the range of the array from %g to %g', val, minarray, maxarray); else - error('the selected value %g should be within the range of the array from %g to %g', val, minarray, maxarray); + ft_error('the selected value %g should be within the range of the array from %g to %g', val, minarray, maxarray); end end else if ~isequal(array, sort(array)) - error('the input array should be sorted from small to large'); + ft_error('the input array should be sorted from small to large'); end if numel(array)<2 - error('the input array must have multiple elements to compute the tolerance'); + ft_error('the input array must have multiple elements to compute the tolerance'); end mintolerance = (array(2)-array(1))/2; maxtolerance = (array(end)-array(end-1))/2; if val<(minarray-mintolerance) || val>(maxarray+maxtolerance) - error('the value %g should be within the range of the array from %g to %g with a tolerance of %g and %g on both sides', val, minarray, maxarray, mintolerance, maxtolerance); + ft_error('the value %g should be within the range of the array from %g to %g with a tolerance of %g and %g on both sides', val, minarray, maxarray, mintolerance, maxtolerance); end end % toleragceflag end % insideflag @@ -130,7 +130,7 @@ else % implements a threshold to correct for errors due to numerical precision - % see http://bugzilla.fcdonders.nl/show_bug.cgi?id=498 and http://bugzilla.fcdonders.nl/show_bug.cgi?id=1943 + % see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=498 and http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=1943 % if maxarray==minarray % precision = 1; % else @@ -140,7 +140,7 @@ % % return the first occurence of the nearest number % [dum, indx] = min(round((abs(array(:) - val)./precision)).*precision); - % use find instead, see http://bugzilla.fcdonders.nl/show_bug.cgi?id=1943 + % use find instead, see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=1943 wassorted = true; if ~issorted(array) wassorted = false; @@ -165,7 +165,7 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function mbreal(a) if ~isreal(a) - error('Argument to mbreal must be real'); + ft_error('Argument to mbreal must be real'); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -173,7 +173,7 @@ function mbreal(a) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function mbscalar(a) if ~all(size(a)==1) - error('Argument to mbscalar must be scalar'); + ft_error('Argument to mbscalar must be scalar'); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -181,5 +181,5 @@ function mbscalar(a) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function mbvector(a) if ndims(a) > 2 || (size(a, 1) > 1 && size(a, 2) > 1) - error('Argument to mbvector must be a vector'); + ft_error('Argument to mbvector must be a vector'); end diff --git a/external/fieldtrip/utilities/printstruct.m b/external/fieldtrip/utilities/printstruct.m index 740067f0..23460b71 100644 --- a/external/fieldtrip/utilities/printstruct.m +++ b/external/fieldtrip/utilities/printstruct.m @@ -97,7 +97,7 @@ case 'function_handle' line = printstr([name '.' fn{i}], func2str(fv)); otherwise - error('unsupported'); + ft_error('unsupported'); end if numel(line)>1 && line(end)==10 && line(end-1)==10 % do not repeat the end-of-line @@ -117,7 +117,7 @@ case 'cell' str = printcell(name, val); otherwise - error('unsupported'); + ft_error('unsupported'); end end @@ -174,7 +174,7 @@ end str = strrep(str, ';', [';' 10]); else - warning('multidimensional arrays are not supported'); + ft_warning('multidimensional arrays are not supported'); str = '''FIXME: printing multidimensional arrays is not supported'''; end @@ -201,6 +201,6 @@ str = [str ')']; otherwise - warning('cannot print unknown object at this level'); + ft_warning('cannot print unknown object at this level'); str = '''FIXME: printing unknown objects is not supported'''; end diff --git a/external/fieldtrip/utilities/private/align_ctf2acpc.m b/external/fieldtrip/utilities/private/align_ctf2acpc.m new file mode 100644 index 00000000..745a23ca --- /dev/null +++ b/external/fieldtrip/utilities/private/align_ctf2acpc.m @@ -0,0 +1,191 @@ +function [mri] = align_ctf2acpc(mri, opt, template) + +% ALIGN_CTF2ACPC performs an approximate rigid body alignment of the anatomical +% volume from CTF towards ACPC coordinates. Only the homogeneous transformation +% matrix is modified and the coordsys-field is updated. +% +% Use as +% mri = align_ctf2acpc(mri) +% mri = align_ctf2acpc(mri, opt) +% mri = align_ctf2acpc(mri, opt, template) +% where the first argument is a FieldTrip MRI-structure, and the second optional +% argument specifies how the registration is to be done: +% opt = 0: only an approximate coregistration +% opt = 1: an approximate coregistration, followed by spm_affreg +% opt = 2 (default): an approximate coregistration, followed by spm_normalise +% +% When opt = 1 or 2, an optional template filename can be specified, which denotes +% the filename of the target volume. This option is required when running in deployed +% mode. + +if nargin<2 + opt = 2; +end + +%-------------------------------------------------------------------------- +% do a first round of approximate coregistration using the predefined voxel +% locations of the fiducials and landmarks in the template T1 image from +% SPM + +acpcvox2acpchead = [ + 2 0 0 -92 + 0 2 0 -128 + 0 0 2 -74 + 0 0 0 1 + ]; + +% these are the voxel indices of some points in the SPM canonical T1 +acpcvox_Ac = [46 64 37 1]'; % the anterior commissure +acpcvox_Ori = [46 48 10 1]'; % approximately between the ears in T1.mnc +acpcvox_Nas = [46 106 13 1]'; % approximately the nasion in T1.mnc +acpcvox_Lpa_canal = [ 5 48 10 1]'; % Left ear canal +acpcvox_Rpa_canal = [87 48 10 1]'; % Right ear canal + +acpchead_Ac = acpcvox2acpchead * acpcvox_Ac ; +acpchead_Ori = acpcvox2acpchead * acpcvox_Ori ; +acpchead_Nas = acpcvox2acpchead * acpcvox_Nas ; +acpchead_Lpa_canal = acpcvox2acpchead * acpcvox_Lpa_canal ; +acpchead_Rpa_canal = acpcvox2acpchead * acpcvox_Rpa_canal ; + +ctfvox2ctfhead = mri.transform; +acpchead2ctfhead = ft_headcoordinates(acpchead_Nas(1:3), acpchead_Lpa_canal(1:3), acpchead_Rpa_canal(1:3), 'ctf'); + +%ctfvox2acpchead = inv(acpchead2ctfhead) * ctfvox2ctfhead; +ctfvox2acpchead = acpchead2ctfhead \ ctfvox2ctfhead; + +% change the transformation matrix, such that it returns approximate SPM head coordinates +mri.transform = ctfvox2acpchead; +mri.vox2headOrig = ctfvox2ctfhead; +mri.vox2head = ctfvox2acpchead; +mri.head2headOrig = acpchead2ctfhead; +mri.coordsys = 'acpc'; + +%-------------------------------------------------------------------------- +% Do a second round of affine registration (rigid body) to get improved +% alignment with ACPC coordinate system. this is needed because there may be +% different conventions defining LPA and RPA. The affine registration may +% fail however, e.g. if the initial alignment is not close enough. In that +% case SPM will throw an error + +if opt==1 + % use spm_affreg + + switch lower(spm('ver')) + case 'spm2' + if isdeployed + if nargin<3, ft_error('you need to specify a template filename when in deployed mode and using opt==1'); end + else + template = fullfile(spm('Dir'),'templates','T1.mnc'); + end + + case 'spm8' + if isdeployed + if nargin<3, ft_error('you need to specify a template filename when in deployed mode and using opt==1'); end + else + template = fullfile(spm('Dir'),'templates','T1.nii'); + end + + case 'spm12' + if isdeployed + if nargin<3, ft_error('you need to specify a template filename when in deployed mode and using opt==1'); end + else + template = fullfile(spm('Dir'),'toolbox','OldNorm','T1.nii'); + if ~exist('spm_affreg', 'file') + addpath(fullfile(spm('Dir'),'toolbox','OldNorm')); + end + end + fprintf('using ''OldNorm'' affine registration\n'); + + otherwise + ft_error('unsupported SPM version'); + end + mri2 = ft_read_mri(template); + + tname1 = [tempname, '.img']; + tname2 = [tempname, '.img']; + V1 = ft_write_mri(tname1, mri.anatomy, 'transform', mri.transform, 'spmversion', spm('ver'), 'dataformat', 'nifti_spm'); + V2 = ft_write_mri(tname2, mri2.anatomy, 'transform', mri2.transform, 'spmversion', spm('ver'), 'dataformat', 'nifti_spm'); + + % the below, using just spm_affreg does not work robustly enough in some cases + flags.regtype = 'rigid'; + [M, scale] = spm_affreg(V1,V2,flags); + + % some juggling around with the transformation matrices + ctfvox2acpchead2 = M \ V1.mat; + acpchead2ctfhead2 = ctfvox2ctfhead / ctfvox2acpchead2; + + % update the transformation matrix + mri.transform = ctfvox2acpchead2; + + % this one is unchanged + mri.vox2headOrig = ctfvox2ctfhead; + + % these are new + mri.vox2head = ctfvox2acpchead2; + mri.head2headOrig = acpchead2ctfhead2; + + % delete the temporary files + delete(tname1); delete(strrep(tname1, 'img', 'hdr')); + delete(tname2); delete(strrep(tname2, 'img', 'hdr')); + +elseif opt==2 + % use spm_normalise + + switch lower(spm('ver')) + case 'spm2' + if isdeployed + if nargin<3, ft_error('you need to specify a template filename when in deployed mode and using opt==2'); end + else + template = fullfile(spm('Dir'),'templates','T1.mnc'); + end + + case 'spm8' + if isdeployed + if nargin<3, ft_error('you need to specify a template filename when in deployed mode and using opt==2'); end + else + template = fullfile(spm('Dir'),'templates','T1.nii'); + end + + case 'spm12' + % this uses the 'OldNorm' functionality, so the path needs to be + % added, can only be done if non-deployed. + if isdeployed + if nargin<3, ft_error('you need to specify a template filename when in deployed mode and using opt==2'); end + else + template = fullfile(spm('Dir'),'toolbox','OldNorm','T1.nii'); + if ~exist('spm_normalise', 'file') + addpath(fullfile(spm('Dir'),'toolbox','OldNorm')); + end + end + fprintf('using ''OldNorm'' normalisation\n'); + + otherwise + ft_error('unsupported SPM version'); + end + mri2 = ft_read_mri(template); + + tname1 = [tempname, '.img']; + tname2 = [tempname, '.img']; + V1 = ft_write_mri(tname1, mri.anatomy, 'transform', mri.transform, 'spmversion', spm('ver'), 'dataformat', 'nifti_spm'); + V2 = ft_write_mri(tname2, mri2.anatomy, 'transform', mri2.transform, 'spmversion', spm('ver'), 'dataformat', 'nifti_spm'); + + flags.nits = 0; %set number of non-linear iterations to zero + flags.regtype = 'rigid'; + params = spm_normalise(V2,V1,[],[],[],flags); + acpchead2ctfhead2 = acpchead2ctfhead*V1.mat*params.Affine/V2.mat; + ctfvox2acpchead2 = acpchead2ctfhead2\ctfvox2ctfhead; + + % update the transformation matrix + mri.transform = ctfvox2acpchead2; + + % this one is unchanged + mri.vox2headOrig = ctfvox2ctfhead; + + % these are new + mri.vox2head = ctfvox2acpchead2; + mri.head2headOrig = acpchead2ctfhead2; + + % delete the temporary files + delete(tname1); delete(strrep(tname1, 'img', 'hdr')); + delete(tname2); delete(strrep(tname2, 'img', 'hdr')); +end diff --git a/external/fieldtrip/utilities/private/align_ctf2spm.m b/external/fieldtrip/utilities/private/align_ctf2spm.m deleted file mode 100644 index 308e185d..00000000 --- a/external/fieldtrip/utilities/private/align_ctf2spm.m +++ /dev/null @@ -1,167 +0,0 @@ -function [mri] = align_ctf2spm(mri, opt, template) - -% ALIGN_CTF2SPM performs an approximate alignment of the anatomical volume -% from CTF towards SPM coordinates. Only the homogeneous transformation matrix -% is modified and the coordsys-field is updated. -% -% Use as -% mri = align_ctf2spm(mri) -% mri = align_ctf2spm(mri, opt) -% mri = align_ctf2spm(mri, opt, template) -% -% Where mri is a FieldTrip MRI-structure, and opt an optional argument -% specifying how the registration is done. -% opt = 0: only an approximate coregistration -% opt = 1: an approximate coregistration, followed by spm_affreg -% opt = 2 (default): an approximate coregistration, followed by spm_normalise -% -% When opt = 1 or 2, an optional template filename can be specified, which -% denotes the filename of the target volume. this option is required when -% running in deployed mode - -if nargin<2 - opt = 2; -end - -%-------------------------------------------------------------------------- -% do a first round of approximate coregistration using the predefined voxel -% locations of the fiducials and landmarks in the template T1 image from -% SPM - -spmvox2spmhead = [ - 2 0 0 -92 - 0 2 0 -128 - 0 0 2 -74 - 0 0 0 1 -]; - -% these are the voxel indices of some points in the SPM canonical T1 -spmvox_Ac = [46 64 37 1]'; % the anterior commissure -spmvox_Ori = [46 48 10 1]'; % approximately between the ears in T1.mnc -spmvox_Nas = [46 106 13 1]'; % approximately the nasion in T1.mnc -spmvox_Lpa_canal = [ 5 48 10 1]'; % Left ear canal -spmvox_Rpa_canal = [87 48 10 1]'; % Right ear canal - -spmhead_Ac = spmvox2spmhead * spmvox_Ac ; -spmhead_Ori = spmvox2spmhead * spmvox_Ori ; -spmhead_Nas = spmvox2spmhead * spmvox_Nas ; -spmhead_Lpa_canal = spmvox2spmhead * spmvox_Lpa_canal ; -spmhead_Rpa_canal = spmvox2spmhead * spmvox_Rpa_canal ; - -ctfvox2ctfhead = mri.transform; -spmhead2ctfhead = ft_headcoordinates(spmhead_Nas(1:3), spmhead_Lpa_canal(1:3), spmhead_Rpa_canal(1:3), 'ctf'); - -%ctfvox2spmhead = inv(spmhead2ctfhead) * ctfvox2ctfhead; -ctfvox2spmhead = spmhead2ctfhead \ ctfvox2ctfhead; - -% change the transformation matrix, such that it returns approximate SPM head coordinates -mri.transform = ctfvox2spmhead; -mri.vox2headOrig = ctfvox2ctfhead; -mri.vox2head = ctfvox2spmhead; -mri.head2headOrig = spmhead2ctfhead; -mri.coordsys = 'spm'; - -% Do a second round of affine registration (rigid body) to get improved -% alignment with spm coordinate system. this is needed because there may be -% different conventions defining LPA and RPA. The affine registration may -% fail however, e.g. if the initial alignment is not close enough. In that -% case SPM will throw an error - -if opt==1 - % use spm_affreg - ft_hastoolbox('spm8', 1); - - switch spm('ver') - case 'SPM8' - if isdeployed - if nargin<3, error('you need to specify a template filename when in deployed mode and using opt==2'); end - else - template = fullfile(spm('Dir'),'templates','T1.nii'); - end - case 'SPM2' - if isdeployed - if nargin<3, error('you need to specify a template filename when in deployed mode and using opt==2'); end - else - template = fullfile(spm('Dir'),'templates','T1.mnc'); - end - otherwise - error('unsupported spm-version'); - end - mri2 = ft_read_mri(template); - - tname1 = [tempname, '.img']; - tname2 = [tempname, '.img']; - V1 = ft_write_mri(tname1, mri.anatomy, 'transform', mri.transform, 'spmversion', spm('ver'), 'dataformat', 'nifti_spm'); - V2 = ft_write_mri(tname2, mri2.anatomy, 'transform', mri2.transform, 'spmversion', spm('ver'), 'dataformat', 'nifti_spm'); - - % the below, using just spm_affreg does not work robustly enough in some - % cases - flags.regtype = 'rigid'; - [M, scale] = spm_affreg(V1,V2,flags); - - % some juggling around with the transformation matrices - ctfvox2spmhead2 = M \ V1.mat; - spmhead2ctfhead2 = ctfvox2ctfhead / ctfvox2spmhead2; - - % update the transformation matrix - mri.transform = ctfvox2spmhead2; - - % this one is unchanged - mri.vox2headOrig = ctfvox2ctfhead; - - % these are new - mri.vox2head = ctfvox2spmhead2; - mri.head2headOrig = spmhead2ctfhead2; - - % delete the temporary files - delete(tname1); delete(strrep(tname1, 'img', 'hdr')); - delete(tname2); delete(strrep(tname2, 'img', 'hdr')); - -elseif opt==2 - % use spm_normalise - ft_hastoolbox('spm8', 1); - - switch spm('ver') - case 'SPM8' - if isdeployed - if nargin<3, error('you need to specify a template filename when in deployed mode and using opt==2'); end - else - template = fullfile(spm('Dir'),'templates','T1.nii'); - end - case 'SPM2' - if isdeployed - if nargin<3, error('you need to specify a template filename when in deployed mode and using opt==2'); end - else - template = fullfile(spm('Dir'),'templates','T1.mnc'); - end - otherwise - error('unsupported spm-version'); - end - mri2 = ft_read_mri(template); - - tname1 = [tempname, '.img']; - tname2 = [tempname, '.img']; - V1 = ft_write_mri(tname1, mri.anatomy, 'transform', mri.transform, 'spmversion', spm('ver'), 'dataformat', 'nifti_spm'); - V2 = ft_write_mri(tname2, mri2.anatomy, 'transform', mri2.transform, 'spmversion', spm('ver'), 'dataformat', 'nifti_spm'); - - flags.nits = 0; %set number of non-linear iterations to zero - flags.regtype = 'rigid'; - params = spm_normalise(V2,V1,[],[],[],flags); - spmhead2ctfhead2 = spmhead2ctfhead*V1.mat*params.Affine/V2.mat; - ctfvox2spmhead2 = spmhead2ctfhead2\ctfvox2ctfhead; - - % update the transformation matrix - mri.transform = ctfvox2spmhead2; - - % this one is unchanged - mri.vox2headOrig = ctfvox2ctfhead; - - % these are new - mri.vox2head = ctfvox2spmhead2; - mri.head2headOrig = spmhead2ctfhead2; - - % delete the temporary files - delete(tname1); delete(strrep(tname1, 'img', 'hdr')); - delete(tname2); delete(strrep(tname2, 'img', 'hdr')); -end - diff --git a/external/fieldtrip/utilities/private/align_fsaverage2mni.m b/external/fieldtrip/utilities/private/align_fsaverage2mni.m new file mode 100644 index 00000000..5f847b83 --- /dev/null +++ b/external/fieldtrip/utilities/private/align_fsaverage2mni.m @@ -0,0 +1,24 @@ +function [mri] = align_fsaverage2mni(mri) + +% ALIGN_FSAVERAGE2MNI performs an affine alignment of the anatomical volume from +% FSAVERAGE towards MNI coordinates. Only the homogeneous transformation matrix is +% modified and the coordsys-field is updated. +% +% Use as +% mri = align_fsaverage2mni(mri) +% where the first input argument is a FieldTrip MRI-structure. +% +% with fsaverage we mean MNI305 +% with mni we mean MNI152, i.e. the template used in SPM +% +% See http://freesurfer.net/fswiki/CoordinateSystems + +fsaverage2mni = [ + 0.9975 -0.0073 0.0176 -0.0429 + 0.0146 1.0009 -0.0024 1.5496 + -0.0130 -0.0093 0.9971 1.1840 + ]; + +assert(strcmp(mri.coordsys, 'fsaverage'), 'incorrect input coordinate system ''%s''', mri.coordsys); +mri.transform = fsaverage2mni * mri.transform; +mri.coordsys = 'mni'; diff --git a/external/fieldtrip/utilities/private/align_itab2spm.m b/external/fieldtrip/utilities/private/align_itab2spm.m deleted file mode 100644 index 91389cf2..00000000 --- a/external/fieldtrip/utilities/private/align_itab2spm.m +++ /dev/null @@ -1,142 +0,0 @@ -function [mri] = align_itab2spm(mri, opt) - -% ALIGN_ITAB2SPM performs an approximate alignment of the anatomical volume -% from ITAB towards SPM coordinates. Only the homogenous transformation matrix -% is modified and the coordsys-field is updated. -% -% Use as -% mri = align_itab2spm(mri) -% mri = align_itab2spm(mri, opt) -% -% Where mri is a FieldTrip MRI-structure, and opt an optional argument -% specifying how the registration is done. -% opt = 0: only an approximate coregistration -% opt = 1: an approximate coregistration, followed by spm_affreg -% opt = 2: (default): an approximate coregistration, followed by spm_normalise - -if nargin<2 - opt = 2; -end - -%-------------------------------------------------------------------------- -% do a first round of approximate coregistration using the predefined voxel -% locations of the fiducials and landmarks in the template T1 image from -% SPM - -spmvox2spmhead = [ - 2 0 0 -92 - 0 2 0 -128 - 0 0 2 -74 - 0 0 0 1 -]; - -% these are the voxel indices of some points in the SPM canonical T1 -spmvox_Ac = [46 64 37 1]'; % the anterior commissure -spmvox_Ori = [46 48 10 1]'; % approximately between the ears in T1.mnc -spmvox_Nas = [46 106 13 1]'; % approximately the nasion in T1.mnc -spmvox_Lpa_canal = [ 5 48 10 1]'; % Left ear canal -spmvox_Rpa_canal = [87 48 10 1]'; % Right ear canal - -spmhead_Ac = spmvox2spmhead * spmvox_Ac ; -spmhead_Ori = spmvox2spmhead * spmvox_Ori ; -spmhead_Nas = spmvox2spmhead * spmvox_Nas ; -spmhead_Lpa_canal = spmvox2spmhead * spmvox_Lpa_canal ; -spmhead_Rpa_canal = spmvox2spmhead * spmvox_Rpa_canal ; - -itabvox2itabhead = mri.transform; -spmhead2itabhead = ft_headcoordinates(spmhead_Nas(1:3), spmhead_Lpa_canal(1:3), spmhead_Rpa_canal(1:3), 'itab'); - -%itabvox2spmhead = inv(spmhead2itabhead) * itabvox2itabhead; -itabvox2spmhead = spmhead2itabhead \ itabvox2itabhead; - -% change the transformation matrix, such that it returns approximate SPM head coordinates -mri.transform = itabvox2spmhead; -mri.vox2headOrig = itabvox2itabhead; -mri.vox2head = itabvox2spmhead; -mri.head2headOrig = spmhead2itabhead; -mri.coordsys = 'spm'; - -% Do a second round of affine registration (rigid body) to get improved -% alignment with spm coordinate system. this is needed because there may be -% different conventions defining LPA and RPA. The affine registration may -% fail however, e.g. if the initial alignment is not close enough. In that -% case SPM will throw an error -if opt==1 - % use spm_affreg - - switch spm('ver') - case 'SPM8' - template = fullfile(spm('Dir'),'templates','T1.nii'); - case 'SPM2' - template = fullfile(spm('Dir'),'templates','T1.mnc'); - otherwise - error('unsupported spm-version'); - end - mri2 = ft_read_mri(template); - - tname1 = [tempname, '.img']; - tname2 = [tempname, '.img']; - V1 = ft_write_mri(tname1, mri.anatomy, 'transform', mri.transform, 'spmversion', spm('ver')); - V2 = ft_write_mri(tname2, mri2.anatomy, 'transform', mri2.transform, 'spmversion', spm('ver')); - - % the below, using just spm_affreg does not work robustly enough in some - % cases - flags.regtype = 'rigid'; - [M, scale] = spm_affreg(V1,V2,flags); - - % some juggling around with the transformation matrices - itabvox2spmhead2 = M \ V1.mat; - spmhead2itabhead2 = itabvox2itabhead / itabvox2spmhead2; - - % update the transformation matrix - mri.transform = itabvox2spmhead2; - - % this one is unchanged - mri.vox2headOrig = itabvox2itabhead; - - % these are new - mri.vox2head = itabvox2spmhead2; - mri.head2headOrig = spmhead2itabhead2; - - % delete the temporary files - delete(tname1); delete(strrep(tname1, 'img', 'hdr')); - delete(tname2); delete(strrep(tname2, 'img', 'hdr')); - -elseif opt==2 - % use spm_normalise - - switch spm('ver') - case 'SPM8' - template = fullfile(spm('Dir'),'templates','T1.nii'); - case 'SPM2' - template = fullfile(spm('Dir'),'templates','T1.mnc'); - otherwise - error('unsupported spm-version'); - end - mri2 = ft_read_mri(template); - - tname1 = [tempname, '.img']; - tname2 = [tempname, '.img']; - V1 = ft_write_mri(tname1, mri.anatomy, 'transform', mri.transform, 'spmversion', spm('ver'), 'dataformat', 'nifti_spm'); - V2 = ft_write_mri(tname2, mri2.anatomy, 'transform', mri2.transform, 'spmversion', spm('ver'), 'dataformat', 'nifti_spm'); - - flags.nits = 0; %set number of non-linear iterations to zero - flags.regtype = 'rigid'; - params = spm_normalise(V2,V1,[],[],[],flags); - spmhead2itabhead2 = spmhead2itabhead*V1.mat*params.Affine/V2.mat; - itabvox2spmhead2 = spmhead2itabhead2\itabvox2itabhead; - - % update the transformation matrix - mri.transform = itabvox2spmhead2; - - % this one is unchanged - mri.vox2headOrig = itabvox2itabhead; - - % these are new - mri.vox2head = itabvox2spmhead2; - mri.head2headOrig = spmhead2itabhead2; - - % delete the temporary files - delete(tname1); delete(strrep(tname1, 'img', 'hdr')); - delete(tname2); delete(strrep(tname2, 'img', 'hdr')); -end diff --git a/external/fieldtrip/utilities/private/align_neuromag2acpc.m b/external/fieldtrip/utilities/private/align_neuromag2acpc.m new file mode 100644 index 00000000..fd14d1c0 --- /dev/null +++ b/external/fieldtrip/utilities/private/align_neuromag2acpc.m @@ -0,0 +1,191 @@ +function [mri] = align_neuromag2acpc(mri, opt, template) + +% ALIGN_NEUROMAG2ACPC performs an approximate alignment of the anatomical +% volume from NEUROMAG towards ACPC coordinates. Only the homogenous transformation +% matrix is modified and the coordsys-field is updated. +% +% Use as +% mri = align_neuromag2acpc(mri) +% mri = align_neuromag2acpc(mri, opt) +% mri = align_neuromag2acpc(mri, opt, template) +% where the first input argument is a FieldTrip MRI-structure, and the second optional +% argument specifies how the registration is to be done: +% opt = 0: only an approximate coregistration +% opt = 1: an approximate coregistration, followed by spm_affreg +% opt = 2 (default): an approximate coregistration, followed by spm_normalise +% +% When opt = 1 or 2, an optional template filename can be specified, which denotes +% the filename of the target volume. This option is required when running in deployed +% mode. + +if nargin<2 + opt = 2; +end + +%-------------------------------------------------------------------------- +% do a first round of approximate coregistration using the predefined voxel +% locations of the fiducials and landmarks in the template T1 image from +% SPM + +acpcvox2acpchead = [ + 2 0 0 -92 + 0 2 0 -128 + 0 0 2 -74 + 0 0 0 1 + ]; + +% these are the voxel indices of some points in the SPM canonical T1 +acpcvox_Ac = [46 64 37 1]'; % the anterior commissure +acpcvox_Ori = [46 48 10 1]'; % approximately between the ears in T1.mnc +acpcvox_Nas = [46 106 13 1]'; % approximately the nasion in T1.mnc +acpcvox_Lpa_canal = [ 5 48 10 1]'; % Left ear canal +acpcvox_Rpa_canal = [87 48 10 1]'; % Right ear canal + +acpchead_Ac = acpcvox2acpchead * acpcvox_Ac ; +acpchead_Ori = acpcvox2acpchead * acpcvox_Ori ; +acpchead_Nas = acpcvox2acpchead * acpcvox_Nas ; +acpchead_Lpa_canal = acpcvox2acpchead * acpcvox_Lpa_canal ; +acpchead_Rpa_canal = acpcvox2acpchead * acpcvox_Rpa_canal ; + +neuromagvox2neuromaghead = mri.transform; +acpchead2neuromaghead = ft_headcoordinates(acpchead_Nas(1:3), acpchead_Lpa_canal(1:3), acpchead_Rpa_canal(1:3), 'neuromag'); + +%neuromagvox2acpchead = inv(acpchead2neuromaghead) * neuromagvox2neuromaghead; +neuromagvox2acpchead = acpchead2neuromaghead \ neuromagvox2neuromaghead; + +% change the transformation matrix, such that it returns approximate SPM head coordinates +mri.transform = neuromagvox2acpchead; +mri.vox2headOrig = neuromagvox2neuromaghead; +mri.vox2head = neuromagvox2acpchead; +mri.head2headOrig = acpchead2neuromaghead; +mri.coordsys = 'acpc'; + +%-------------------------------------------------------------------------- +% Do a second round of affine registration (rigid body) to get improved +% alignment with ACPC coordinate system. this is needed because there may be +% different conventions defining LPA and RPA. The affine registration may +% fail however, e.g. if the initial alignment is not close enough. In that +% case SPM will throw an error + +if opt==1 + % use spm_affreg + + switch lower(spm('ver')) + case 'spm2' + if isdeployed + if nargin<3, ft_error('you need to specify a template filename when in deployed mode and using opt==1'); end + else + template = fullfile(spm('Dir'),'templates','T1.mnc'); + end + + case 'spm8' + if isdeployed + if nargin<3, ft_error('you need to specify a template filename when in deployed mode and using opt==1'); end + else + template = fullfile(spm('Dir'),'templates','T1.nii'); + end + + case 'spm12' + if isdeployed + if nargin<3, ft_error('you need to specify a template filename when in deployed mode and using opt==1'); end + else + template = fullfile(spm('Dir'),'toolbox','OldNorm','T1.nii'); + if ~exist('spm_affreg', 'file') + addpath(fullfile(spm('Dir'),'toolbox','OldNorm')); + end + end + fprintf('using ''OldNorm'' affine registration\n'); + + otherwise + ft_error('unsupported SPM version'); + end + mri2 = ft_read_mri(template); + + tname1 = [tempname, '.img']; + tname2 = [tempname, '.img']; + V1 = ft_write_mri(tname1, mri.anatomy, 'transform', mri.transform, 'spmversion', spm('ver'), 'dataformat', 'nifti_spm'); + V2 = ft_write_mri(tname2, mri2.anatomy, 'transform', mri2.transform, 'spmversion', spm('ver'), 'dataformat', 'nifti_spm'); + + % the below, using just spm_affreg does not work robustly enough in some cases + flags.regtype = 'rigid'; + [M, scale] = spm_affreg(V1,V2,flags); + + % some juggling around with the transformation matrices + neuromagvox2acpchead2 = M \ V1.mat; + acpchead2neuromaghead2 = neuromagvox2neuromaghead / neuromagvox2acpchead2; + + % update the transformation matrix + mri.transform = neuromagvox2acpchead2; + + % this one is unchanged + mri.vox2headOrig = neuromagvox2neuromaghead; + + % these are new + mri.vox2head = neuromagvox2acpchead2; + mri.head2headOrig = acpchead2neuromaghead2; + + % delete the temporary files + delete(tname1); delete(strrep(tname1, 'img', 'hdr')); + delete(tname2); delete(strrep(tname2, 'img', 'hdr')); + +elseif opt==2 + % use spm_normalise + + switch lower(spm('ver')) + case 'spm2' + if isdeployed + if nargin<3, ft_error('you need to specify a template filename when in deployed mode and using opt==2'); end + else + template = fullfile(spm('Dir'),'templates','T1.mnc'); + end + + case 'spm8' + if isdeployed + if nargin<3, ft_error('you need to specify a template filename when in deployed mode and using opt==2'); end + else + template = fullfile(spm('Dir'),'templates','T1.nii'); + end + + case 'spm12' + % this uses the 'OldNorm' functionality, so the path needs to be + % added, can only be done if non-deployed. + if isdeployed + if nargin<3, ft_error('you need to specify a template filename when in deployed mode and using opt==2'); end + else + template = fullfile(spm('Dir'),'toolbox','OldNorm','T1.nii'); + if ~exist('spm_normalise', 'file') + addpath(fullfile(spm('Dir'),'toolbox','OldNorm')); + end + end + fprintf('using ''OldNorm'' normalisation\n'); + + otherwise + ft_error('unsupported SPM version'); + end + mri2 = ft_read_mri(template); + + tname1 = [tempname, '.img']; + tname2 = [tempname, '.img']; + V1 = ft_write_mri(tname1, mri.anatomy, 'transform', mri.transform, 'spmversion', spm('ver'), 'dataformat', 'nifti_spm'); + V2 = ft_write_mri(tname2, mri2.anatomy, 'transform', mri2.transform, 'spmversion', spm('ver'), 'dataformat', 'nifti_spm'); + + flags.nits = 0; %set number of non-linear iterations to zero + flags.regtype = 'rigid'; + params = spm_normalise(V2,V1,[],[],[],flags); + acpchead2neuromaghead2 = acpchead2neuromaghead*V1.mat*params.Affine/V2.mat; + neuromagvox2acpchead2 = acpchead2neuromaghead2\neuromagvox2neuromaghead; + + % update the transformation matrix + mri.transform = neuromagvox2acpchead2; + + % this one is unchanged + mri.vox2headOrig = neuromagvox2neuromaghead; + + % these are new + mri.vox2head = neuromagvox2acpchead2; + mri.head2headOrig = acpchead2neuromaghead2; + + % delete the temporary files + delete(tname1); delete(strrep(tname1, 'img', 'hdr')); + delete(tname2); delete(strrep(tname2, 'img', 'hdr')); +end diff --git a/external/fieldtrip/utilities/private/avgoverdim.m b/external/fieldtrip/utilities/private/avgoverdim.m index 31d25edf..7cd6f365 100644 --- a/external/fieldtrip/utilities/private/avgoverdim.m +++ b/external/fieldtrip/utilities/private/avgoverdim.m @@ -35,9 +35,9 @@ end if sum(~cellfun('isempty', avgdimnum))<1 - error('the "%s" dimension is not present in the data', avgdim) + ft_error('the "%s" dimension is not present in the data', avgdim) elseif any(cellfun(@numel, avgdimnum)>1) - error('cannot average over multiple dimensions at the same time') + ft_error('cannot average over multiple dimensions at the same time') end [reduceddim, fntmp] = dimlength(data); @@ -79,7 +79,7 @@ end else % not yet implemented - error('averaging across cells is not yet possible'); + ft_error('averaging across cells is not yet possible'); end if ~iscelltmp, @@ -107,7 +107,7 @@ case 'rpttap' for i=1:length(param) if fb, fprintf('removing dimension %s from %s\n', avgdim, param{i}); end - warning('this is only allowed for cross-spectra and power-spectra'); + ft_warning('this is only allowed for cross-spectra and power-spectra'); tmp = data.(param{i}); tmp = reshape(tmp, [reduceddim{i}(2:end) 1]); data.(param{i}) = tmp; @@ -130,7 +130,7 @@ data.time = mean(data.time); dimord = data.dimord; otherwise - error('unknown dimension "%s"', avgdim); + ft_error('unknown dimension "%s"', avgdim); end if isfield(data, 'dim'), diff --git a/external/fieldtrip/utilities/private/base64encode.m b/external/fieldtrip/utilities/private/base64encode.m index a9b8b07f..308b2087 100644 --- a/external/fieldtrip/utilities/private/base64encode.m +++ b/external/fieldtrip/utilities/private/base64encode.m @@ -44,28 +44,22 @@ % URL: http://home.online.no/~pjacklam % check number of input arguments - try - % this is available from MATLAB 2011b onwards - narginchk(1, 2); - catch - % this is available in older versions - error(nargchk(1, 2, nargin)); - end + narginchk(1, 2); % make sure we have the EOL value if nargin < 2 eol = ''; %sprintf('\n'); else if sum(size(eol) > 1) > 1 - error('EOL must be a vector.'); + ft_error('EOL must be a vector.'); end if any(eol(:) > 255) - error('EOL can not contain values larger than 255.'); + ft_error('EOL can not contain values larger than 255.'); end end if sum(size(x) > 1) > 1 - error('STR must be a vector.'); + ft_error('STR must be a vector.'); end x = uint8(x); diff --git a/external/fieldtrip/utilities/private/channelposition.m b/external/fieldtrip/utilities/private/channelposition.m index 25f8db11..1eecb56a 100644 --- a/external/fieldtrip/utilities/private/channelposition.m +++ b/external/fieldtrip/utilities/private/channelposition.m @@ -110,7 +110,7 @@ dist(selrest,sum(~isinf(dist(selmode,:)))>0) = inf; numcoils = sum(isfinite(dist),2); if niter>500 - error('Failed to extract the positions of the channels. This is most likely due to the balancing matrix being rank deficient. Please replace data.grad with the original grad-structure obtained after reading the header.'); + ft_error('Failed to extract the positions of the channels. This is most likely due to the balancing matrix being rank deficient. Please replace data.grad with the original grad-structure obtained after reading the header.'); end end else @@ -332,5 +332,5 @@ % do a sanity check on the number of positions nchan = numel(sens.label); if length(lab)~=nchan || size(pnt,1)~=nchan || size(ori,1)~=nchan - warning('the positions were not determined for all channels'); + ft_warning('the positions were not determined for all channels'); end diff --git a/external/fieldtrip/utilities/private/convert_segmentationstyle.m b/external/fieldtrip/utilities/private/convert_segmentationstyle.m index 5e543742..c99e01e7 100644 --- a/external/fieldtrip/utilities/private/convert_segmentationstyle.m +++ b/external/fieldtrip/utilities/private/convert_segmentationstyle.m @@ -17,7 +17,7 @@ for i=1:length(fn) tmp = segmentation.(fn{i})>threshold; if any(seg(tmp(:))) - error('overlapping tissue probability maps cannot be converted to an indexed representation'); + ft_error('overlapping tissue probability maps cannot be converted to an indexed representation'); % FIXME in principle it is possible to represent two tissue types at one voxel else seg(tmp) = i; @@ -46,5 +46,5 @@ end % for i otherwise - error('unsupported style "%s"', style); + ft_error('unsupported style "%s"', style); end diff --git a/external/fieldtrip/utilities/private/coordsys2label.m b/external/fieldtrip/utilities/private/coordsys2label.m new file mode 100644 index 00000000..de55e2ed --- /dev/null +++ b/external/fieldtrip/utilities/private/coordsys2label.m @@ -0,0 +1,169 @@ +function [labelx, labely, labelz] = coordsys2label(coordsys, format, both) + +% COORDSYS2LABEL returns the labels for the three axes, given the symbolic +% string representation of the coordinate system. +% +% Use as +% [labelx, labely, labelz] = coordsys2label(coordsys, format, both) +% +% The scalar argument 'format' results in return values like these +% 1) 'right' +% 2) 'the right' +% 3) '+X (right)' +% +% The boolean argument 'both' results in return values like these +% 0) 'right' i.e. only the direction that it is pointing to +% 1) {'left' 'right'} i.e. both the directions that it is pointing from and to +% +% See also FT_DETERMINE_COORDSYS, FT_PLOT_AXES, FT_HEADCOORDINATES, SETVIEWPOINT + +% Copyright (C) 2017, Robert Oostenveld +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + + +% FIXME this function could also rerturn a label for the origin +% see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=3304 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +if ~isempty(coordsys) && ~strcmp(coordsys, 'unknown') + + % the coordsys consists of three letters for the direction of the positive axes + % or of a string that relates to external software, an atlas or a template + if length(coordsys)==3 && length(intersect(coordsys, 'rlasif'))==3 + axis = 'XYZ'; + label = cell(1,3); + for i=1:3 + switch coordsys(i) + case 'l' + label{i} = {['-' axis(i) ' (right)'], ['+' axis(i) ' (left)']}; + case 'r' + label{i} = {['-' axis(i) ' (left)'], ['+' axis(i) ' (right)']}; + case 'i' + label{i} = {['-' axis(i) ' (superior)'], ['+' axis(i) ' (inferior)']}; + case 's' + label{i} = {['-' axis(i) ' (inferior)'], ['+' axis(i) ' (superior)']}; + case 'a' + label{i} = {['-' axis(i) ' (posterior)'], ['+' axis(i) ' (anterior)']}; + case 'p' + label{i} = {['-' axis(i) ' (anterior)'], ['+' axis(i) ' (posterior)']}; + otherwise + ft_error('incorrect letter in the coordsys'); + end % switch + end % for each of the three axes + + labelx = label{1}; + labely = label{2}; + labelz = label{3}; + + else + switch lower(coordsys) + case {'ras' 'itab' 'neuromag' 'acpc' 'spm' 'mni' 'tal'} + labelx = {'-X (left)' '+X (right)' }; + labely = {'-Y (posterior)' '+Y (anterior)'}; + labelz = {'-Z (inferior)' '+Z (superior)'}; + case {'als' 'ctf' '4d' 'bti'} + labelx = {'-X (posterior)' '+X (anterior)'}; + labely = {'-Y (right)' '+Y (left)'}; + labelz = {'-Z (inferior)' '+Z (superior)'}; + case {'rsp' 'paxinos'} + labelx = {'-X (left)' '+X (right)'}; + labely = {'-Y (inferior)' '+Y (superior)'}; + labelz = {'-Z (anterior)' '+Z (posterior)'}; + case {'lps'} + labelx = {'-X (right)' '+X (left)'}; + labely = {'-Y (anterior)' '+Y (posterior)'}; + labelz = {'-Z (inferior)' '+Z (superior)'}; + otherwise + % the coordinate system is unknown + ft_warning('unknown coordsys ''%s''', coordsys); + labelx = {'-X (unknown)' '+X (unknown)'}; + labely = {'-Y (unknown)' '+Y (unknown)'}; + labelz = {'-Z (unknown)' '+Z (unknown)'}; + end + + end % if it matches with 'rlasif' + +else + % the coordinate system is not specified + labelx = {'-X (unknown)' '+X (unknown)'}; + labely = {'-Y (unknown)' '+Y (unknown)'}; + labelz = {'-Z (unknown)' '+Z (unknown)'}; +end + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +switch format + case 1 + % remove the -, +, X, Y, Z , (, ) and space + labelx{1} = trim(labelx{1}); + labelx{2} = trim(labelx{2}); + labely{1} = trim(labely{1}); + labely{2} = trim(labely{2}); + labelz{1} = trim(labelz{1}); + labelz{2} = trim(labelz{2}); + + case 2 + % remove the -, +, X, Y, Z , (, ) and space + labelx{1} = trim(labelx{1}); + labelx{2} = trim(labelx{2}); + labely{1} = trim(labely{1}); + labely{2} = trim(labely{2}); + labelz{1} = trim(labelz{1}); + labelz{2} = trim(labelz{2}); + % insert 'the' for left and right + if any(strcmp(labelx{1}, {'left', 'right'})), labelx{1} = ['the ' labelx{1}]; end + if any(strcmp(labelx{2}, {'left', 'right'})), labelx{2} = ['the ' labelx{2}]; end + if any(strcmp(labely{1}, {'left', 'right'})), labely{1} = ['the ' labely{1}]; end + if any(strcmp(labely{2}, {'left', 'right'})), labely{2} = ['the ' labely{2}]; end + if any(strcmp(labelz{1}, {'left', 'right'})), labelz{1} = ['the ' labelz{1}]; end + if any(strcmp(labelz{2}, {'left', 'right'})), labelz{2} = ['the ' labelz{2}]; end + + case 3 + % keep it as it is + + otherwise + ft_error('unsupported option') +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +switch both + case false + % only keep the direction that is it pointing towards + labelx = labelx{2}; + labely = labely{2}; + labelz = labelz{2}; + case true + % keep it as it is + otherwise + ft_error('unsupported option') +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function str = trim(str) +str(str=='+') = []; +str(str=='-') = []; +str(str=='(') = []; +str(str==')') = []; +str(str=='X') = []; +str(str=='Y') = []; +str(str=='Z') = []; +str(str==' ') = []; diff --git a/external/fieldtrip/utilities/private/dataset2files.m b/external/fieldtrip/utilities/private/dataset2files.m index 65fb4ab7..fae0883f 100644 --- a/external/fieldtrip/utilities/private/dataset2files.m +++ b/external/fieldtrip/utilities/private/dataset2files.m @@ -106,7 +106,7 @@ elseif exist(fullfile(path, [file '.dat']), 'file') datafile = fullfile(path, [file '.dat']); else - error('cannot determine the data file that corresponds to %s', filename); + ft_error('cannot determine the data file that corresponds to %s', filename); end case 'brainvision_eeg' [path, file, ext] = fileparts(filename); diff --git a/external/fieldtrip/utilities/private/defaultId.m b/external/fieldtrip/utilities/private/defaultId.m new file mode 100644 index 00000000..f4e1ee99 --- /dev/null +++ b/external/fieldtrip/utilities/private/defaultId.m @@ -0,0 +1,57 @@ +function id = defaultId + +% DEFAULTID returns a string that can serve as warning or error identifier, +% for example 'FieldTip:ft_read_header:line345'. +% +% See also WARNING, ERROR, FT_NOTICE, FT_INFO, FT_DEBUG + +% Copyright (C) 2017, Robert Oostenveld +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +stack = dbstack('-completenames'); + +% remove the functions that pertain to the notification system itself +keep = true(size(stack)); +keep(strcmp({stack.name}, 'defaultId')) = false; % this function itself +keep(strcmp({stack.name}, 'ft_notification')) = false; % this one is doing the work underneath ft_error/ft_warning/ft_notice/etc. +keep(strcmp({stack.name}, 'ft_error')) = false; +keep(strcmp({stack.name}, 'ft_warning')) = false; +keep(strcmp({stack.name}, 'ft_notice')) = false; +keep(strcmp({stack.name}, 'ft_info')) = false; +keep(strcmp({stack.name}, 'ft_debug')) = false; +stack = stack(keep); + +% remove the non-FieldTrip functions from the path, these should not be part of the default message identifier +keep = true(size(stack)); +[v, p] = ft_version; +for i=1:numel(stack) + keep(i) = strncmp(p, stack(i).file, length(p)); +end +stack = stack(keep); + +if ~isempty(stack) + % it is called from within a function + stack = flipud(stack); + name = {stack.name}; + id = ['FieldTrip' sprintf(':%s', name{:}) ':line' num2str(stack(end).line)]; +else + % it is called from the command line + id = 'FieldTrip:commandline'; +end diff --git a/external/fieldtrip/utilities/private/dimindex.m b/external/fieldtrip/utilities/private/dimindex.m new file mode 100644 index 00000000..c3ebda52 --- /dev/null +++ b/external/fieldtrip/utilities/private/dimindex.m @@ -0,0 +1,70 @@ +function M = dimindex(A,dim,idx) + +% DIMINDEX makes a selection from a multi-dimensional array where the dimension is +% selected by a scalar, not by the place between the brackets. +% +% Use as +% M = dimindex(A,dim,idx) +% +% The purpose of the function is shown by the following example: +% +% A(:,:,:,23,:,:,...) is the same as dimindex(A,4,23) +% A(2,4,3) is the same as dimindex(A,[1,2,3],[2,4,3]) +% A(4,:,[5:10]) is the same as dimindex(A,[1,3],{4,[5:10]}) +% +% See also the function DIMASSIGN + +% Copyright (C) 2005, Geerten Kramer +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +if (~iscell(idx)) + if (~any(size(dim)==1) || ~any(size(idx)==1) || ndims(dim)>2 || ndims(idx)>2 || length(dim)~=length(idx)) + ft_error('dim and idx must be both scalars or both vectors of the same size'); + end + dummi = []; + for i=1:length(idx) + dummi{i} = idx(i); + end + idx = dummi; + clear dummi; +end +if (~any(size(dim)==1) || ~any(size(idx)==1) || ndims(dim)>2 || ndims(idx)>2 || length(dim)~=length(idx)) + ft_error('dim and idx must be both scalars or both must have the same length'); +end + + +if (length(dim)>ndims(A)||any(dim>ndims(A))) + ft_error('dim, or one of its contents are larger than the number of dimentions in A'); +end +if (~isequal(unique(dim),sort(dim))) + ft_error('dim must be unique, every dimention can be addressed only once'); +end + +N = ndims(A); +for i=1:N + ref = find(dim==i); + if (isempty(ref)) + C{i} = ':'; + else + C{i} = idx{ref}; + end +end +M = A(C{:}); + diff --git a/external/fieldtrip/utilities/private/dimlength.m b/external/fieldtrip/utilities/private/dimlength.m index 4f207f3c..f318db55 100644 --- a/external/fieldtrip/utilities/private/dimlength.m +++ b/external/fieldtrip/utilities/private/dimlength.m @@ -122,7 +122,7 @@ if isfield(data, 'individual'), n = [n size(data.individual, 1)]; end if isfield(data, 'stat'), n = [n size(data.stat, 1)]; end if ~all(n==n(1)) - error('inconsistent number of repetitions for dim "%s"', seldim); + ft_error('inconsistent number of repetitions for dim "%s"', seldim); end n = n(1); @@ -156,7 +156,7 @@ if isfield(data, 'trial'), n = [n size(data.trial, 1)]; end if isfield(data, 'fourierspctrm'), n = [n size(data.fourierspctrm, 1)]; end if ~all(n==n(1)) - error('inconsistent number of repetitions for dim "%s"', seldim); + ft_error('inconsistent number of repetitions for dim "%s"', seldim); end n = n(1); @@ -175,7 +175,7 @@ if isfield(data, 'powspctrm'), n = [n size(data.powspctrm, 1)]; end if isfield(data, 'trial'), n = [n size(data.trial, 1)]; end - if ~all(n==n(1)), error('inconsistent number of repetitions for dim "%s"', seldim); end + if ~all(n==n(1)), ft_error('inconsistent number of repetitions for dim "%s"', seldim); end n = n(1); case 'chan' @@ -225,7 +225,7 @@ end otherwise - error('unsupported dim "%s"', seldim); + ft_error('unsupported dim "%s"', seldim); end end % if nargin diff --git a/external/fieldtrip/utilities/private/fixdimord.m b/external/fieldtrip/utilities/private/fixdimord.m index 3786e1a8..b2b05928 100644 --- a/external/fieldtrip/utilities/private/fixdimord.m +++ b/external/fieldtrip/utilities/private/fixdimord.m @@ -50,7 +50,7 @@ % % if any(ft_datatype(data, {'source', 'volume'})) && isfield(data, 'dimord') && ~keepsourcedimord % % the old source data representation does not have a dimord, whereas the new source data representation does have a dimord -% warning(sprintf('removing dimord "%s" from source representation data', data.dimord)); +% ft_warning(sprintf('removing dimord "%s" from source representation data', data.dimord)); % data = rmfield(data, 'dimord'); % return % else @@ -68,24 +68,17 @@ elseif ft_datatype(data, 'volume') % it is volume data, which does not have a dimord -> this is ok return + elseif ft_datatype(data, 'source') || ft_datatype(data, 'parcellation') + % it is old-style source data -> this is ok + return else + % find the XXXdimord fields fn = fieldnames(data); sel = true(size(fn)); for i=1:length(fn) sel(i) = ~isempty(strfind(fn{i}, 'dimord')); end df = fn(sel); - - if isempty(df) - if ft_datatype(data, 'source') || ft_datatype(data, 'parcellation') - % it is old-style source data -> this is ok - % ft_checkdata will convert it to new-style - return - else - error('the data does not contain a dimord, but it also does not resemble raw or component data'); - end - end - % use this function recursively on the XXXdimord fields for i=1:length(df) data.dimord = data.(df{i}); @@ -96,7 +89,7 @@ % after the recursive call it should be ok return end -end +end % if no dimord if strcmp(data.dimord, 'voxel') % this means that it is position @@ -155,12 +148,12 @@ case {'{pos}' '{pos}_rpt' '{pos}_rpttap'} % this is for source data on a 3-d grid, a cortical sheet, or unstructured positions % the data itself is represented in a cell-array, e.g. source.mom or source.leadfield - + case {'{pos_pos}'} % this is for bivariate source data on a 3-d grid, a cortical sheet, or unstructured positions otherwise - error(sprintf('unexpected dimord "%s"', data.dimord)); + ft_error('unexpected dimord "%s"', data.dimord); end % switch dimtok end % for length dimtok @@ -217,4 +210,3 @@ for i=2:length(dimtok) data.dimord = [data.dimord '_' dimtok{i}]; end - diff --git a/external/fieldtrip/utilities/private/fixdipole.m b/external/fieldtrip/utilities/private/fixdipole.m index 2d691a78..14d94b56 100644 --- a/external/fieldtrip/utilities/private/fixdipole.m +++ b/external/fieldtrip/utilities/private/fixdipole.m @@ -29,15 +29,15 @@ % the input representation is Nx3, which is what we want elseif m==3 % it is possible to translate it into a Nx3 unambiguously - warning('input dipole positions should be specified as Nx3 matrix'); + ft_warning('input dipole positions should be specified as Nx3 matrix'); dip.pos = dip.pos'; elseif m==1 % it is possible to translate it into a Nx3 unambiguously - warning('input dipole positions should be specified as Nx3 matrix'); + ft_warning('input dipole positions should be specified as Nx3 matrix'); dip.pos = reshape(dip.pos, 3, n/3)'; else % it is not clear how to convert to a Nx3 matrix - error('input dipole positions should be specified as Nx3 matrix'); + ft_error('input dipole positions should be specified as Nx3 matrix'); end if isfield(dip, 'mom') diff --git a/external/fieldtrip/utilities/private/fixname.m b/external/fieldtrip/utilities/private/fixname.m index 96a345ec..76fd5951 100644 --- a/external/fieldtrip/utilities/private/fixname.m +++ b/external/fieldtrip/utilities/private/fixname.m @@ -1,19 +1,20 @@ -function str = fixname(str) +function str = fixname(str, version) % FIXNAME changes all inappropriate characters in a sting into '_' -% such that it can be used as a filename or as a structure field name. If -% the string begins with a numeric digit, an 'x' is prepended. +% so that it can be used as a filename or as a field name in a structure. +% If the string begins with a digit, an 'x' is prepended. % % Use as % str = fixname(str) % % MATLAB 2014a introduces the matlab.lang.makeValidName and -% matlab.lang.makeUniqueStrings functions for constructing unique MATLAB identifiers, -% but this particular implementation also works with older MATLAB versions. +% matlab.lang.makeUniqueStrings functions for constructing unique +% identifiers, but this particular implementation also works with +% older MATLAB versions. % % See also DEBLANK -% Copyright (C) 2012-2016, Robert Oostenveld +% Copyright (C) 2012-2017, Robert Oostenveld % % This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. @@ -33,19 +34,48 @@ % % $Id$ -str = lower(str); -str(regexp(str,'\W')) = '_'; - -while(str(1) == '_'), str = str(2:end); end; % remove all underscore at the begin of the string -while(str(end) == '_'), str = str(1:end-1); end; % remove all underscore at the end of the string - -if int8(str(1))<58 && int8(str(1))>47 - % the string begins with a digit, prepend an 'x' - str = ['x' str]; +if nargin<2 + version = 'default'; end -% truncate the string if it's too long: MATLAB maximizes the string length to 63 characters (and throws a warning when truncating) -if numel(str)>63 - str = str(1:63); - ft_warning(sprintf('%s exceeds MATLAB''s maximum name length of 63 characters and has been truncated to %s', str, str(1:63))); +switch version + case 'default' + if isempty(str) + str='x'; + end + str = lower(str); + str(regexp(str,'\W')) = '_'; + while(str(1) == '_'), str = str(2:end); end % remove all underscore at the begin of the string + while(str(end) == '_'), str = str(1:end-1); end % remove all underscore at the end of the string + if int8(str(1))<58 && int8(str(1))>47 + % the string begins with a digit, prepend an 'x' + str = ['x' str]; + end + % truncate the string if it's too long: MATLAB maximizes the string length to 63 characters (and throws a warning when truncating) + if numel(str)>63 + str = str(1:63); + warning('%s exceeds MATLAB''s maximum name length of 63 characters and has been truncated to %s', str, str(1:63)); + end + + case '2014a' + str = matlab.lang.makeValidName(str); + + case 'X_base64encode_X' + % this uses some code from Mathworks file exchange + ft_hastoolbox('fileexchange', 1); + % the following is an encoding that can be reverted + str = strtrim(base64encode(str)); + str(str=='=') = '_'; % replace the '=' sign with '_' + str = ['X' str 'X']; % start and end with an 'X' + + case 'X_base64decode_X' + % this uses some code from Mathworks file exchange + ft_hastoolbox('fileexchange', 1); + % revert the encoding + str = str(2:end-1); % it starts and ends with 'X' + str(str=='_') = '='; % the '=' sign has been replaced with '_' + str = char(base64decode(str)); + + otherwise + error('unsupported version "%s"', version); end diff --git a/external/fieldtrip/utilities/private/fixoldorg.m b/external/fieldtrip/utilities/private/fixoldorg.m new file mode 100644 index 00000000..93174b7a --- /dev/null +++ b/external/fieldtrip/utilities/private/fixoldorg.m @@ -0,0 +1,36 @@ +function input = fixoldorg(input, revert) + +% FIXOLDORG use "old/new" instead of "org/new" + +if nargin<2 + revert = false; +end + +if ~(isstruct(input) && numel(input)==1) + % this does not look like a montage or a sensor description + return +end + +if ~revert + from = {'labelorg', 'chantypeorg', 'chanunitorg', 'chanposorg', 'chanoriorg'}; + to = {'labelold', 'chantypeold', 'chanunitold', 'chanposold', 'chanoriold'}; +else + to = {'labelorg', 'chantypeorg', 'chanunitorg', 'chanposorg', 'chanoriorg'}; + from = {'labelold', 'chantypeold', 'chanunitold', 'chanposold', 'chanoriold'}; +end + +% replace the fields +for i=1:numel(from) + if isfield(input, from{i}) + input.(to{i}) = input.(from{i}); + input = rmfield(input, from{i}); + end +end + +% use recursion to update the subfields +fn = fieldnames(input); +for i=1:numel(fn) + if isstruct(input.(fn{i})) + input.(fn{i}) = fixoldorg(input.(fn{i}), revert); + end +end diff --git a/external/fieldtrip/utilities/private/fixpos.m b/external/fieldtrip/utilities/private/fixpos.m index 31cee40f..88408288 100644 --- a/external/fieldtrip/utilities/private/fixpos.m +++ b/external/fieldtrip/utilities/private/fixpos.m @@ -10,7 +10,7 @@ % convert to structure, otherwise the code below won't work properly ws = warning('off', 'MATLAB:structOnObject'); mesh = struct(mesh); - warning(ws); + ft_warning(ws); end if ~isa(mesh, 'struct') @@ -42,7 +42,7 @@ case 8 mesh.hex = mesh.ConnectivityList; otherwise - error('unsupported ConnectivityList') + ft_error('unsupported ConnectivityList') end % switch mesh = removefields(mesh, {'Points', 'ConnectivityList', 'Constraints', 'UnderlyingObj'}); end diff --git a/external/fieldtrip/utilities/private/fixsegmentation.m b/external/fieldtrip/utilities/private/fixsegmentation.m index bd07498b..caf7cfa6 100644 --- a/external/fieldtrip/utilities/private/fixsegmentation.m +++ b/external/fieldtrip/utilities/private/fixsegmentation.m @@ -13,37 +13,39 @@ indexval = indexval(indexval~=0); % these are the only ones that matter if any(indexval<0) - error('an indexed representation cannot contain negative numbers'); + ft_error('an indexed representation cannot contain negative numbers'); end if ~isfield(segmentation, [fn{i} 'label']) % ensure that the tissues have labels - indexlabel = {}; + indexlabel = cell(size(indexval)); for j=1:length(indexval) indexlabel{indexval(j)} = sprintf('tissue %d', indexval(j)); end segmentation.([fn{i} 'label']) = indexlabel; + else - % ensure that the tissue labels are consistent with the index values + % check for the situation where + % indexval = [1 2 4] + % indexlabel = {'a', 'b', 'c', 'd'} or {'a', 'b', [], 'd'} + % which happens if the segmentation unexpectedly does not contain a certain tissue type indexlabel = segmentation.([fn{i} 'label']); if numel(indexval)>numel(indexlabel) - error('each index value should have a corresponding entry in %s', [fn{i} 'label']); + ft_error('each index value should have a corresponding entry in %s', [fn{i} 'label']); elseif any(cellfun(@isempty, indexlabel(indexval))) - error('each index value should have a corresponding entry in %s', [fn{i} 'label']); + ft_error('each index value should have a corresponding entry in %s', [fn{i} 'label']); + elseif numel(indexval)4 % test for each tissue whether it is overlapping with or contained in each other tissue - warning('more than 4 tissue types, this may take a while'); + ft_warning('more than 4 tissue types, this may take a while'); end for i=1:length(fn) segi = segmentation.(fn{i})>0; @@ -77,5 +79,5 @@ clear segi segj contains otherwise - error('unsupported style "%s"', style); + ft_error('unsupported style "%s"', style); end diff --git a/external/fieldtrip/utilities/private/fixsource.m b/external/fieldtrip/utilities/private/fixsource.m index cc135989..332f6c7e 100644 --- a/external/fieldtrip/utilities/private/fixsource.m +++ b/external/fieldtrip/utilities/private/fixsource.m @@ -133,7 +133,7 @@ end if prod(dim)~=prod(descr) - error('the dimensions of the source data are not consistent with the dimord (%s)', fn{i}) + ft_error('the dimensions of the source data are not consistent with the dimord (%s)', fn{i}) end if iscell(element) diff --git a/external/fieldtrip/utilities/private/fixvolume.m b/external/fieldtrip/utilities/private/fixvolume.m index f23a806b..f02c3ac3 100644 --- a/external/fieldtrip/utilities/private/fixvolume.m +++ b/external/fieldtrip/utilities/private/fixvolume.m @@ -34,9 +34,9 @@ hasfreq = isfield(data, 'freq'); if hastime - error('the volume data representation should be 3-D and is not allowed to contain a time field'); + ft_error('the volume data representation should be 3-D and is not allowed to contain a time field'); end if hasfreq - error('the volume data representation should be 3-D and is not allowed to contain a freq field'); + ft_error('the volume data representation should be 3-D and is not allowed to contain a freq field'); end diff --git a/external/fieldtrip/utilities/private/ft_findcfg.m b/external/fieldtrip/utilities/private/ft_findcfg.m index ea39b132..7dfce3c2 100644 --- a/external/fieldtrip/utilities/private/ft_findcfg.m +++ b/external/fieldtrip/utilities/private/ft_findcfg.m @@ -48,11 +48,11 @@ status = 1; elseif issubfield(cfg, 'previous'); [val, status] = ft_findcfg(cfg.previous, var); - if status, break; end; + if status, break; end elseif iscell(cfg) for i=1:length(cfg) [val, status] = ft_findcfg(cfg{i}, var); - if status, break; end; + if status, break; end end else status = -1; diff --git a/external/fieldtrip/utilities/private/ft_notification.m b/external/fieldtrip/utilities/private/ft_notification.m new file mode 100644 index 00000000..dc9b7369 --- /dev/null +++ b/external/fieldtrip/utilities/private/ft_notification.m @@ -0,0 +1,482 @@ +function [varargout] = ft_notification(varargin) + +% FT_NOTIFICATION works mostly like the WARNING and ERROR commands in MATLAB and +% is called by FT_ERROR, FT_WARNING, FT_NOTICE, FT_INFO, FT_DEBUG. Note that you +% should not call this function directly. +% +% Some examples: +% ft_info on +% ft_info on msgId +% ft_info off +% ft_info off msgId +% ft_info once +% ft_info once msgId +% ft_info on backtrace +% ft_info off backtrace +% ft_info on verbose +% ft_info off verbose +% +% ft_info query % shows the status of all notifications +% ft_info last % shows the last notification +% ft_info clear % clears the status of all notifications +% ft_info timeout 10 % sets the timeout (for 'once') to 10 seconds +% +% See also DEFAULTID + +% Copyright (C) 2012-2017, Robert Oostenveld, J?rn M. Horschig +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +global ft_default + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% determine who is calling + +stack = dbstack('-completenames'); +% st(1) is this function +% st(2) is the calling function +switch stack(2).name + case 'ft_debug' + level = 'debug'; + case 'ft_info' + level = 'info'; + case 'ft_notice' + level = 'notice'; + case 'ft_warning' + level = 'warning'; + case 'ft_error' + level = 'error'; + otherwise + error('this function cannot be called from %s', stack(2).name); +end + +% remove this function itself and the ft_xxx calling function +stack = stack(3:end); + +% remove the non-FieldTrip functions from the path, these should not be part of the default message identifier +keep = true(size(stack)); +p = fileparts(which('ft_defaults')); +for i=1:numel(stack) + keep(i) = strncmp(p, stack(i).file, length(p)); +end +stack = stack(keep); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% handle the defaults + +if isfield(ft_default, 'notification') && isfield(ft_default.notification, level) + % this would be error, warning, notice, info, debug + s = ft_default.notification.(level); +else + s = []; +end + +% start with an empty state structure +if isempty(s) + s = struct('identifier', {}, 'state', {}, 'timestamp', {}); +end + +% set the default notification state +if ~ismember('all', {s.identifier}) + s = setstate(s, 'all', 'on'); +end + +% set the default backtrace state +defaultbacktrace = false; +if ~ismember('backtrace', {s.identifier}) + switch level + case {'debug' 'info' 'notice'} + s = setstate(s, 'backtrace', 'off'); + case 'warning' + defaultbacktrace = true; + t = warning('query', 'backtrace'); % get the default state + s = setstate(s, 'backtrace', t.state); + case 'error' + s = setstate(s, 'backtrace', 'on'); + end % switch +end + +% set the default verbose state +defaultverbose = false; +if ~ismember('verbose', {s.identifier}) + switch level + case 'warning' + defaultverbose = true; + t = warning('query', 'verbose');% get the default state + s = setstate(s, 'verbose', t.state); + otherwise + s = setstate(s, 'verbose', 'off'); + end +end + +% set the default timeout +if ~ismember('timeout', {s.identifier}) + s = setstate(s, 'timeout', 60); +end + +% set the last notification to empty +if ~ismember('last', {s.identifier}) + state.message = ''; + state.identifier = ''; + state.stack = struct('file', {}, 'name', {}, 'line', {}); + s = setstate(s, 'last', state); +end + +if strcmp(level, 'warning') + ws = warning; + % warnings should be on in general + warning on + % the backtrace is handled by this function + warning off backtrace + % the verbose message is handled by this function + warning off verbose +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% set the notification state according to the input + +if numel(varargin)>0 && (isstruct(varargin{1}) || isempty(varargin{1})) + ft_default.notification.(level) = varargin{1}; + return +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% act according to the first input argument + +if isempty(varargin) + varargin{1} = 'query'; +end + +switch varargin{1} + case 'on' + if numel(varargin)>1 + % switch a specific item on + msgId = varargin{2}; + s = setstate(s, msgId, 'on'); + if strcmp(msgId, 'backtrace') + defaultbacktrace = false; + end + if strcmp(msgId, 'verbose') + defaultverbose = false; + end + % return the message state of all + varargout{1} = getreturnstate(s, msgId); + else + % switch all on + s = setstate(s, 'all', 'on'); + % return the message state of all + varargout{1} = getreturnstate(s); + end + + case 'off' + if numel(varargin)>1 + % switch a specific item off + msgId = varargin{2}; + s = setstate(s, msgId, 'off'); + if strcmp(msgId, 'backtrace') + defaultbacktrace = false; + end + if strcmp(msgId, 'verbose') + defaultverbose = false; + end + % return the specific message state + varargout{1} = getreturnstate(s, msgId); + else + % switch all off + s = setstate(s, 'all', 'off'); + % return the message state of all + varargout{1} = getreturnstate(s); + end + + case 'once' + if numel(varargin)>1 + % switch a specific item to once + msgId = varargin{2}; + s = setstate(s, msgId, 'once'); + % return the specific message state + varargout{1} = getreturnstate(s, msgId); + else + % switch all to once + s = setstate(s, 'all', 'once'); + % return the message state of all + varargout{1} = getreturnstate(s); + end + + case 'timeout' + % set the timeout, this is used for 'once' + if ischar(varargin{2}) + s = setstate(s, 'timeout', str2double(varargin{2})); + else + s = setstate(s, 'timeout', varargin{2}); + end + + case {'last' '-last'} + % return the last notification + varargout{1} = getstate(s, 'last'); + + case {'clear' '-clear'} + % reset the notification system + s = []; + + case {'query' '-query'} + if numel(varargin)>1 + % select a specific item + msgId = varargin{2}; + if ~ismember(msgId, {s.identifier}) + error('Unknown setting or incorrect message identifier ''%s''.', msgId); + end + msgState = getstate(s, msgId); + if nargout + varargout{1} = getreturnstate(s, msgId); + elseif strcmp(msgId, 'verbose') + if istrue(msgState) + fprintf('%s output is verbose.\n', level); + else + fprintf('%s output is terse.\n', level); + end + elseif strcmp(msgId, 'backtrace') + if istrue(msgState) + fprintf('%s backtraces are enabled.\n', level); + else + fprintf('%s backtraces are disabled.\n', level); + end + else + fprintf('The state of %s ''%s'' is ''%s''\n', level, msgId, msgState); + end + else + % return all items + r = getreturnstate(s); + + if nargout + % return the state of all items + varargout{1} = r; + else + % show the state of all items that are different from the default + default = getstate(s, 'all'); + fprintf('The default %s state is ''%s''.', level, default); + r = r(~strcmp({r.state}, default)); + % don't show these + r(strcmp('verbose', {r.identifier})) = []; + r(strcmp('backtrace', {r.identifier})) = []; + if ~isempty(r) + fprintf(' Items not set to the default are\n\n'); + end + for i=1:numel(r) + fprintf(' %4s %s\n', r(i).state, r(i).identifier); + end + fprintf('\n'); + end + end + + otherwise + + if nargout + varargout{1} = getreturnstate(s); + end + + % first input might be msgId + if numel(varargin)>1 && ~isempty(regexp(varargin{1}, '^\w*:', 'once')) + msgId = varargin{1}; + varargin = varargin(2:end); % shift them all by one + else + msgId = defaultId; + end + + % get the state for this notification, it will default to the 'all' state + msgState = getstate(s, msgId); + + % errors are always to be printed + if strcmp(level, 'error') + msgState = 'on'; + end + + if strcmp(msgState, 'once') + timeout = getstate(s, 'timeout'); + since = elapsed(gettimestamp(s, msgId)); + if (since>timeout) + % the timeout has passed, update the timestamp and print the message + s = settimestamp(s, msgId, tic); + msgState = 'on'; + else + % the timeout has not yet passed, do not print the message + msgState = 'off'; + end + end + + % use an automatically generated default identifier + if isempty(msgId) + msgId = defaultId; + end + + % store the last notification + state.message = strtrim(sprintf(varargin{:})); % remove the trailing newline + state.identifier = msgId; + state.stack = stack; + s = setstate(s, 'last', state); + + if strcmp(msgState, 'on') + + if strcmp(level, 'error') + % update the global variable, we won't return here after the error + ft_default.notification.(level) = s; + % the remainder is fully handled by the ERROR function + if ~isempty(msgId) + error(msgId, varargin{:}); + else + error(varargin{:}); + end + + elseif strcmp(level, 'warning') + if ~isempty(msgId) + warning(msgId, varargin{:}); + else + warning(varargin{:}); + end + + else + % ensure there is a line end + if isempty(regexp(varargin{1}, '\\n$', 'once')) % note the double \\ + varargin{1} = [varargin{1} '\n']; + end + fprintf(varargin{:}); + + end % if level=error, warning or otherwise + + % decide whether the stack trace should be shown + if istrue(getstate(s, 'backtrace')) + for i=1:numel(stack) + % show the deepest and lowest-level function first + [p, f, x] = fileparts(stack(i).file); + if isequal(f, stack(i).name) + funname = stack(i).name; + else + funname = sprintf('%s>%s', f, stack(i).name); + end + filename = stack(i).file; + if isempty(fileparts(filename)) + % it requires the full path + filename = fullfile(pwd, filename); + end + if ft_platform_supports('html') + fprintf(' In %s at line %d\n', filename, stack(i).line, funname, stack(i).line); + else + fprintf(' In ''%s'' at line %d\n', filename, stack(i).line); + end + end + fprintf('\n'); + end + + % decide whether a verboe message should be shown + if istrue(getstate(s, 'verbose')) + if ~isempty(msgId) + fprintf('Type "ft_%s off %s" to suppress this message.\n', level, msgId) + else + fprintf('Type "ft_%s off" to suppress this message.\n', level) + end + end + + end % if msgState is on + +end % switch varargin{1} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% update the global variable +if defaultbacktrace && ~isempty(s) + % do not keep the default, it will be determined again on the next call + s = s(~strcmp({s.identifier}, 'backtrace')); +end +if defaultverbose && ~isempty(s) + % do not keep the default, it will be determined again on the next call + s = s(~strcmp({s.identifier}, 'verbose')); +end +ft_default.notification.(level) = s; + +if strcmp(level, 'warning') + % return to the original warning state + warning(ws); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTIONS +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +function r = getreturnstate(s, msgId) +if nargin<2 + r = s; + % don't return these + r(strcmp('timeout', {r.identifier})) = []; + r(strcmp('last', {r.identifier})) = []; + % don't return the timestamps + r = rmfield(r, 'timestamp'); +else + msgState = getstate(s, msgId); + r = struct('identifier', msgId, 'state', msgState); +end + +function state = getstate(s, msgId) +identifier = {s.identifier}; +sel = find(strcmp(identifier, msgId)); +if numel(sel)==1 + state = s(sel).state; + if isempty(state) + state = getstate(s, 'all'); + end +else + state = getstate(s, 'all'); +end + +function timestamp = gettimestamp(s, msgId) +identifier = {s.identifier}; +sel = find(strcmp(identifier, msgId)); +if numel(sel)==1 + timestamp = s(sel).timestamp; +else + timestamp = nan; +end + +function s = setstate(s, msgId, state) +if isempty(msgId), return; end % this happens from the command line +identifier = {s.identifier}; +sel = find(strcmp(identifier, msgId)); +if numel(sel)==1 + s(sel).state = state; +else + s(end+1).identifier = msgId; + s(end ).state = state; + s(end ).timestamp = nan; +end + +function s = settimestamp(s, msgId, timestamp) +if isempty(msgId), return; end % this happens from the command line +identifier = {s.identifier}; +sel = find(strcmp(identifier, msgId)); +if numel(sel)==1 + s(sel).timestamp = timestamp; +else + s(end+1).identifier = msgId; + s(end ).state = []; + s(end ).timestamp = timestamp; +end + +function t = elapsed(start) +if isempty(start) || isnan(start) + t = inf; +else + t = toc(start); +end diff --git a/external/fieldtrip/utilities/private/ft_postamble_debug.m b/external/fieldtrip/utilities/private/ft_postamble_debug.m index eb29f2d5..67719f01 100644 --- a/external/fieldtrip/utilities/private/ft_postamble_debug.m +++ b/external/fieldtrip/utilities/private/ft_postamble_debug.m @@ -7,10 +7,18 @@ % .... regular code goes here ... % ft_postamble debug % -% See also FT_PREAMBLE_DEBUG DEBUGCLEANUP +% See also FT_PREAMBLE_DEBUG, DEBUGCLEANUP % these variables are shared by the three debug handlers -global Ce9dei2ZOo_debug Ce9dei2ZOo_funname Ce9dei2ZOo_argin +global Ce9dei2ZOo_debug Ce9dei2ZOo_funname Ce9dei2ZOo_argin Ce9dei2ZOo_ws Ce9dei2ZOo_ns Ce9dei2ZOo_is Ce9dei2ZOo_ds + +if isfield(cfg, 'verbose') && ischar(cfg.verbose) + % restore the previous state of the notifications + ft_warning(Ce9dei2ZOo_ws) + ft_notice(Ce9dei2ZOo_ns); + ft_info(Ce9dei2ZOo_is); + ft_debug(Ce9dei2ZOo_ds); +end if ~isfield(cfg, 'debug') % do not provide extra debugging facilities diff --git a/external/fieldtrip/utilities/private/ft_postamble_history.m b/external/fieldtrip/utilities/private/ft_postamble_history.m index d9f20101..29d65b0e 100644 --- a/external/fieldtrip/utilities/private/ft_postamble_history.m +++ b/external/fieldtrip/utilities/private/ft_postamble_history.m @@ -1,5 +1,6 @@ -% FT_POSTAMBLE_HISTORY stores the configuration structure that is present in the -% present workspace in the output variable. +% FT_POSTAMBLE_HISTORY is a helper script that stores the configuration structure that +% is present in the present workspace (i.e. the workspace of the calling function) in +% the output variable. % % Use as % ft_postamble history outputvar @@ -39,6 +40,3 @@ end end clear tmpindx - -% clear warnings from ft_default, so that they don't end up in the next cfg -ft_warning('-clear'); diff --git a/external/fieldtrip/utilities/private/ft_postamble_provenance.m b/external/fieldtrip/utilities/private/ft_postamble_provenance.m index dcf6083d..5d4be67d 100644 --- a/external/fieldtrip/utilities/private/ft_postamble_provenance.m +++ b/external/fieldtrip/utilities/private/ft_postamble_provenance.m @@ -97,7 +97,7 @@ cfg.callinfo.outputhash{iargout} = ft_hash(tmparg); catch % the mxSerialize mex file is not available on all platforms, do not compute a hash - % http://bugzilla.fcdonders.nl/show_bug.cgi?id=2452 + % http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2452 end else % the data is too large, do not compute a hash diff --git a/external/fieldtrip/utilities/private/ft_preamble_debug.m b/external/fieldtrip/utilities/private/ft_preamble_debug.m index b1d7a0bc..222a0b12 100644 --- a/external/fieldtrip/utilities/private/ft_preamble_debug.m +++ b/external/fieldtrip/utilities/private/ft_preamble_debug.m @@ -14,13 +14,50 @@ % See also FT_POSTAMBLE_DEBUG, DEBUGCLEANUP % these variables are shared by the three debug handlers -global Ce9dei2ZOo_debug Ce9dei2ZOo_funname Ce9dei2ZOo_argin +global Ce9dei2ZOo_debug Ce9dei2ZOo_funname Ce9dei2ZOo_argin Ce9dei2ZOo_ws Ce9dei2ZOo_ns Ce9dei2ZOo_is Ce9dei2ZOo_ds if ~isempty(Ce9dei2ZOo_debug) && ~isequal(Ce9dei2ZOo_debug, 'no') % the debugging handler is already set by a higher-level function return end +if isfield(cfg, 'verbose') && ischar(cfg.verbose) + % store the current state of the notifications + Ce9dei2ZOo_ws = ft_warning; + Ce9dei2ZOo_ns = ft_notice; + Ce9dei2ZOo_is = ft_info; + Ce9dei2ZOo_ds = ft_debug; + switch cfg.verbose + case 'error' + ft_warning off + ft_notice off + ft_info off + ft_debug off + case 'warning' + ft_warning on + ft_notice off + ft_info off + ft_debug off + case 'notice' + ft_warning on + ft_notice on + ft_info off + ft_debug off + case 'info' + ft_warning on + ft_notice on + ft_info on + ft_debug off + case 'debug' + ft_warning on + ft_notice on + ft_info on + ft_debug on + otherwise + % just leave them as they are + end +end + if ~isfield(cfg, 'debug') % do not provide extra debugging facilities return diff --git a/external/fieldtrip/utilities/private/ft_preamble_init.m b/external/fieldtrip/utilities/private/ft_preamble_init.m index b496c487..e7ddc232 100644 --- a/external/fieldtrip/utilities/private/ft_preamble_init.m +++ b/external/fieldtrip/utilities/private/ft_preamble_init.m @@ -72,22 +72,22 @@ % the output file exists, determine how to deal with it switch cfg.outputfilepresent case 'keep' - if nargout>0 + if ft_nargout>0 % continue executing the parent function - warning('output file %s is already present, but you also requested an output argument: continuing function execution', cfg.outputfile); + ft_warning('output file %s is already present, but you also requested an output argument: continuing function execution', cfg.outputfile); ft_abort = false; else % stop executing the parent function - warning('output file %s is already present: aborting function execution', cfg.outputfile); + ft_warning('output file %s is already present: aborting function execution', cfg.outputfile); ft_abort = true; end case 'overwrite' - warning('output file %s is already present: it will be overwritten', cfg.outputfile); + ft_warning('output file %s is already present: it will be overwritten', cfg.outputfile); ft_abort = false; case 'error' - error('output file %s is already present', cfg.outputfile); + ft_error('output file %s is already present', cfg.outputfile); otherwise - error('invalid option for cfg.outputfilepresent'); + ft_error('invalid option for cfg.outputfilepresent'); end % case end else diff --git a/external/fieldtrip/utilities/private/ft_preamble_loadvar.m b/external/fieldtrip/utilities/private/ft_preamble_loadvar.m index abc39236..dd9d4d4e 100644 --- a/external/fieldtrip/utilities/private/ft_preamble_loadvar.m +++ b/external/fieldtrip/utilities/private/ft_preamble_loadvar.m @@ -43,7 +43,7 @@ % the input data should be read from file if (ft_nargin>1) - error('cfg.inputfile should not be used in conjunction with giving input data to this function'); + ft_error('cfg.inputfile should not be used in conjunction with giving input data to this function'); else if isfield(cfg, 'inputlock') && ~isempty(cfg.inputlock) mutexlock(cfg.inputlock); diff --git a/external/fieldtrip/utilities/private/ft_preamble_provenance.m b/external/fieldtrip/utilities/private/ft_preamble_provenance.m index e12204d7..a305d6b6 100644 --- a/external/fieldtrip/utilities/private/ft_preamble_provenance.m +++ b/external/fieldtrip/utilities/private/ft_preamble_provenance.m @@ -79,7 +79,7 @@ cfg.callinfo.inputhash{iargin} = ft_hash(tmparg); catch % the mxSerialize mex file is not available on all platforms, do not compute a hash - % http://bugzilla.fcdonders.nl/show_bug.cgi?id=2452 + % http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2452 end else % the data is too large, do not compute a hash diff --git a/external/fieldtrip/utilities/private/ft_struct2json.m b/external/fieldtrip/utilities/private/ft_struct2json.m index eaff1f32..fdcd3571 100644 --- a/external/fieldtrip/utilities/private/ft_struct2json.m +++ b/external/fieldtrip/utilities/private/ft_struct2json.m @@ -12,7 +12,7 @@ case 'double' fv{i} = num2str(val); otherwise - error('class %s is not supported\n', type(val)); + ft_error('class %s is not supported\n', type(val)); end end f = cat(1, fn', fv'); diff --git a/external/fieldtrip/utilities/private/ft_test_compare.m b/external/fieldtrip/utilities/private/ft_test_compare.m new file mode 100644 index 00000000..0631703e --- /dev/null +++ b/external/fieldtrip/utilities/private/ft_test_compare.m @@ -0,0 +1,105 @@ +function ft_test_compare(varargin) + +% FT_TEST_COMPARE + +% Copyright (C) 2017, Robert Oostenveld +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +narginchk(2, inf); +command = varargin{1}; +feature = varargin{2}; +assert(isequal(command, 'compare')); +varargin = varargin(3:end); + +optbeg = find(ismember(varargin, {'matlabversion', 'fieldtripversion', 'user', 'hostname', 'branch', 'arch'})); +if ~isempty(optbeg) + optarg = varargin(optbeg:end); + varargin = varargin(1:optbeg-1); +else + optarg = {}; +end + +% varargin contains the file (or files) to test +% optarg contains the command-specific options + +% construct the query string that will be passed in the URL +query = '?'; +queryparam = {'matlabversion', 'fieldtripversion', 'hostname', 'user', 'branch', 'arch'}; +for i=1:numel(queryparam) + val = ft_getopt(optarg, queryparam{i}); + if ~isempty(val) + query = [query sprintf('%s=%s&', queryparam{i}, val)]; + end +end + +options = weboptions('ContentType','json'); % this returns the results as MATLAB structure +url = 'http://dashboard.fieldtriptoolbox.org/api/'; + +results = cell(size(varargin)); +functionname = {}; +for i=1:numel(varargin) + result = webread([url query sprintf('&%s=%s', feature, varargin{i})], options); + + % the documents in the mongoDB database might not fully consistent, in which case they are returned as cell-array containing different structures + % merge all stuctures into a single struct-array + result = mergecellstruct(result); + + assert(~isempty(result), 'no results were returned for %s %s', feature, varargin{i}); + functionname = cat(1, functionname(:), {result.functionname}'); + results{i} = result; +end + +% find the joint set of all functions +functionname = unique(functionname); + +% represent a summary of all results in a struct-array +summary = struct(); +for i=1:numel(functionname) + summary(i).function = functionname{i}; + for j=1:numel(varargin) + sel = find(strcmp({results{j}.functionname}, functionname{i})); + fn = fixname(varargin{j}, 'X_base64encode_X'); + summary(i).(fn) = haspassed(results{j}, sel); + end % for each functionname +end % for each of the features + +% convert the struct-array to a table +table = struct2table(summary); +fprintf('%s\n', table{:}); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION to convert the boolean result into a string +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function str = haspassed(result, index) +if isempty(index) + str = []; +elseif isfield(result, 'passed') && all(istrue([result(index).passed])) + str = 'passed'; +elseif isfield(result, 'passed') && all(~istrue([result(index).passed])) + str = 'failed'; +elseif isfield(result, 'result') && all(istrue([result(index).result])) + str = 'passed'; +elseif isfield(result, 'result') && all(~istrue([result(index).result])) + str = 'failed'; +else + % there appear to be multiple representations of the same test, but they are not consistent + str = 'ambiguous'; +end + diff --git a/external/fieldtrip/utilities/private/ft_test_moxunit_run.m b/external/fieldtrip/utilities/private/ft_test_moxunit_run.m new file mode 100644 index 00000000..1cc62918 --- /dev/null +++ b/external/fieldtrip/utilities/private/ft_test_moxunit_run.m @@ -0,0 +1,64 @@ +function passed = ft_test_moxunit_run(unused,varargin) + +% FT_TEST_MOXUNIT_RUN + +% Copyright (C) 2017, Nikolaas N. Oosterhof +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + + % ensure path is set for MOxUnit FieldTrip test functions, but + % set to original state after running this function + + + orig_path=path(); + path_resetter=onCleanup(@()path(orig_path)); + ensure_moxunit_fieldtrip_path_is_set(); + check_dependencies(); + + % By default, running FieldTrip excludes files if their name + % starts with 'failed'. Here this default behaviour is mimicked. + override_default_arg={'exclude_if_prefix_equals_failed',true}; + arg=cat(2,override_default_arg,varargin); + + passed=moxunit_fieldtrip_runtests(arg{:}); + + + +function check_dependencies() +% throw an error if MOxUnit is not available + + if isempty(which('moxunit_runtests')) + ft_error(['MOxUnit is required; see '... + 'https://github.com/moxunit/moxunit']); + end + +function fieldtrip_root_dir=get_fieldtrip_root_dir() + fieldtrip_root_dir=fileparts(which('ft_defaults')); + if isempty(fieldtrip_root_dir) + ft_error('Fieldtrip path is not set'); + end + + + +function ensure_moxunit_fieldtrip_path_is_set() + if isempty(which('MOxUnitFieldTripTestSuite')) + moxunit_fieldtrip_dir=fullfile(get_fieldtrip_root_dir(),... + 'contrib','MOxUnit_fieldtrip'); + addpath(moxunit_fieldtrip_dir); + end diff --git a/external/fieldtrip/utilities/private/ft_test_report.m b/external/fieldtrip/utilities/private/ft_test_report.m new file mode 100644 index 00000000..5d56dddc --- /dev/null +++ b/external/fieldtrip/utilities/private/ft_test_report.m @@ -0,0 +1,86 @@ +function result = ft_test_report(varargin) + +% FT_TEST_REPORT + +% Copyright (C) 2017, Robert Oostenveld +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +narginchk(1, inf); +command = varargin{1}; +assert(isequal(command, 'report')); +varargin = varargin(2:end); + +optbeg = find(ismember(varargin, {'matlabversion', 'fieldtripversion', 'user', 'hostname', 'branch', 'arch', 'showdate', 'showid'})); +if ~isempty(optbeg) + optarg = varargin(optbeg:end); + varargin = varargin(1:optbeg-1); +else + optarg = {}; +end + +% varargin contains the file (or files) to test +% optarg contains the command-specific options +showdate = ft_getopt(optarg, 'showdate', false); +showid = ft_getopt(optarg, 'showid', false); + +% construct the query string that will be passed in the URL +query = '?'; +queryparam = {'matlabversion', 'fieldtripversion', 'hostname', 'user', 'branch', 'arch'}; +for i=1:numel(queryparam) + val = ft_getopt(optarg, queryparam{i}); + if ~isempty(val) + query = [query sprintf('%s=%s&', queryparam{i}, val)]; + end +end + +options = weboptions('ContentType', 'json', 'Timeout', 30); % this returns the result as MATLAB structure +url = 'http://dashboard.fieldtriptoolbox.org/api/'; + +if isempty(varargin) + result = webread([url query], options); + assert(~isempty(result), 'no results were returned'); + result = mergecellstruct(result); +else + results = cell(size(varargin)); + for i=1:numel(varargin) + result = webread([url query sprintf('&functionname=%s', varargin{i})], options); + assert(~isempty(result), 'no results were returned for %s', varargin{i}); + results{i} = mergecellstruct(result); + end + % merge all results + result = mergecellstruct(results); +end + +% rename the automatically added fields +result = renamefields(result, 'x_id', 'id'); +result = renamefields(result, 'createDate', 'date'); + +% remove some of the fields +if ~istrue(showid) + result = removefields(result, 'id'); +end +if ~istrue(showdate) + result = removefields(result, 'date'); +end + +% convert the struct-array to a table +table = struct2table(result); +fprintf('%s\n', table{:}); + diff --git a/external/fieldtrip/utilities/ft_test_run.m b/external/fieldtrip/utilities/private/ft_test_run.m similarity index 61% rename from external/fieldtrip/utilities/ft_test_run.m rename to external/fieldtrip/utilities/private/ft_test_run.m index f67eeb22..999d1d3f 100644 --- a/external/fieldtrip/utilities/ft_test_run.m +++ b/external/fieldtrip/utilities/private/ft_test_run.m @@ -1,25 +1,10 @@ -function status = ft_test_run(varargin) +function passed = ft_test_run(varargin) -% FT_TEST_RUN executes selected FieldTrip test scripts. It checks whether each test -% script runs without problems as indicated by an explicit error and posts the -% results on the FieldTrip dashboard. -% -% Use as -% ft_test_run functionname -% -% Additional optional arguments are specified as key-value pairs and can include -% dependency = string -% maxmem = string -% maxwalltime = string -% -% Test functions should not require any input arguments. -% Output arguments of the test function will not be considered. -% -% See also FT_TEST_RESULT, FT_VERSION +% FT_TEST_RUN -% Copyright (C) 2016, Robert oostenveld +% Copyright (C) 2017, Robert Oostenveld % -% This file is part of FieldTrip, see http://www.ru.nl/donders/fieldtrip +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org % for the documentation and details. % % FieldTrip is free software: you can redistribute it and/or modify @@ -37,31 +22,47 @@ % % $Id$ -optbeg = find(ismember(varargin, {'dependency', 'maxmem', 'maxwalltime'})); +narginchk(1, inf); +command = varargin{1}; +assert(isequal(command, 'run')); +varargin = varargin(2:end); + +optbeg = find(ismember(varargin, {'dependency', 'dccnpath', 'maxmem', 'maxwalltime', 'upload', 'assertclean'})); if ~isempty(optbeg) - optarg = varargin(optbeg:end); + optarg = varargin(optbeg:end); varargin = varargin(1:optbeg-1); else optarg = {}; end +% varargin contains the file (or files) to test +% optarg contains the command-specific options + % get the optional input arguments dependency = ft_getopt(optarg, 'dependency', {}); +hasdccnpath = ft_getopt(optarg, 'dccnpath'); % default is handled below maxmem = ft_getopt(optarg, 'maxmem', inf); maxwalltime = ft_getopt(optarg, 'maxwalltime', inf); +upload = ft_getopt(optarg, 'upload', 'yes'); +assertclean = ft_getopt(optarg, 'assertclean', 'yes'); if ischar(dependency) % this should be a cell-array dependency = {dependency}; end +if isempty(hasdccnpath) + % true when central storage is available, false otherwise + hasdccnpath = exist(dccnpath('/home/common/matlab/fieldtrip/data/'), 'dir'); +end + if ischar(maxwalltime) - % it is probably formatted as HH:MM:SS + % it is probably formatted as HH:MM:SS, convert to seconds maxwalltime = str2walltime(maxwalltime); end if ischar(maxmem) - % it is probably formatted as XXmb, or XXgb, ... + % it is probably formatted as XXmb, or XXgb, convert to bytes maxmem = str2mem(maxmem); end @@ -69,7 +70,9 @@ [revision, ftpath] = ft_version; % testing a work-in-progress version is not supported -assert(istrue(ft_version('clean')), 'this requires all local changes to be committed'); +if istrue(assertclean) + assert(istrue(ft_version('clean')), 'this requires all local changes to be committed'); +end %% determine the list of functions to test if ~isempty(varargin) && exist(varargin{1}, 'file') @@ -88,12 +91,13 @@ filelist{i} = which(functionlist{i}); end -fprintf('considering %d test scripts for execution\n', numel(filelist)); +fprintf('considering %d test functions for execution\n', numel(filelist)); %% make a subselection based on the filters -sel = true(size(filelist)); -mem = zeros(size(filelist)); -tim = zeros(size(filelist)); +dep = true(size(filelist)); +file = false(size(filelist)); % by default ignore file reads +mem = zeros(size(filelist)); +tim = zeros(size(filelist)); for i=1:numel(filelist) fid = fopen(filelist{i}, 'rt'); @@ -102,16 +106,25 @@ line = tokenize(str, 10); if ~isempty(dependency) - sel(i) = false; + dep(i) = false; else - sel(i) = true; + dep(i) = true; end for k=1:numel(line) for j=1:numel(dependency) + % search for the dependencies in each of the test functions [s, e] = regexp(line{k}, sprintf('%% TEST.*%s.*', dependency{j}), 'once', 'start', 'end'); if ~isempty(s) - sel(i) = true; + dep(i) = true; + end + end + + if ~istrue(hasdccnpath) + % search for the occurence of the DCCNPATH function in each of the test functions + [s, e] = regexp(line{k}, 'dccnpath', 'once', 'start', 'end'); + if ~isempty(s) + file(i) = true; end end @@ -130,13 +143,17 @@ end % for each function/file -fprintf('%3d scripts do not meet the requirements for dependencies\n', sum(~sel)); -fprintf('%3d scripts do not meet the requirements for memory\n', sum(mem>maxmem)); -fprintf('%3d scripts do not meet the requirements for walltime \n', sum(tim>maxwalltime)); +fprintf('%3d scripts are excluded due to the dependencies\n', sum(~dep)); +fprintf('%3d scripts are excluded due to loading files from the DCCN path\n', sum(file)); +fprintf('%3d scripts are excluded due to the requirements for memory\n', sum(mem>maxmem)); +fprintf('%3d scripts are excluded due to the requirements for walltime \n', sum(tim>maxwalltime)); -% remove test scripts that exceed walltime or memory +% make selection of test scripts, remove scripts that exceed walltime or memory +sel = true(size(filelist)); sel(tim>maxwalltime) = false; sel(mem>maxmem) = false; +sel(dep==false) = false; +sel(file==true) = false; % make the subselection of functions to test functionlist = functionlist(sel); @@ -152,13 +169,19 @@ try stopwatch = tic; eval(functionlist{i}); - status = true; + passed = true; runtime = round(toc(stopwatch)); fprintf('=== %s PASSED in %d seconds\n', functionlist{i}, runtime); - catch - status = false; + catch me + passed = false; runtime = round(toc(stopwatch)); fprintf('=== %s FAILED in %d seconds\n', functionlist{i}, runtime); + % show the error with the stack trace + fprintf('Error using %s (line %d)\n', me.stack(1).name, me.stack(1).line); + disp(me.message) + for j=2:numel(me.stack) + fprintf('Error in %s (line %d)\n', me.stack(j).name, me.stack(j).line); + end end close all @@ -166,14 +189,25 @@ result.matlabversion = version('-release'); result.fieldtripversion = revision; result.branch = ft_version('branch'); + result.arch = computer('arch'); result.hostname = gethostname; result.user = getusername; - result.result = status; + result.passed = passed; result.runtime = runtime; result.functionname = functionlist{i}; - options = weboptions('MediaType','application/json'); - webwrite('http://dashboard.fieldtriptoolbox.org/api', result, options); + if istrue(upload) + try + % the weboptions function is available in 2014b onward, but behaves inconsistently + options = weboptions('MediaType','application/json'); + catch + options = []; + end + url = 'http://dashboard.fieldtriptoolbox.org/api/'; + webwrite(url, result, options); + else + ft_warning('not uploading results to the FieldTrip dashboard') + end end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/external/fieldtrip/utilities/private/ft_urlread.m b/external/fieldtrip/utilities/private/ft_urlread.m index e0705c2a..c19726cc 100644 --- a/external/fieldtrip/utilities/private/ft_urlread.m +++ b/external/fieldtrip/utilities/private/ft_urlread.m @@ -16,5 +16,5 @@ [output, status] = urlread(event_http); end else - error('method "%s" is not yet implemented', method); + ft_error('method "%s" is not yet implemented', method); end diff --git a/external/fieldtrip/utilities/private/funargname.m b/external/fieldtrip/utilities/private/funargname.m index 6ad6721b..b3174f1f 100644 --- a/external/fieldtrip/utilities/private/funargname.m +++ b/external/fieldtrip/utilities/private/funargname.m @@ -14,7 +14,7 @@ line = fgetl(fid); end if isempty(regexp(line, '^function', 'once')) - error('could not locate function declaration in %s', fname); + ft_error('could not locate function declaration in %s', fname); end % the declaration of the function should look like this diff --git a/external/fieldtrip/utilities/private/getaddress.m b/external/fieldtrip/utilities/private/getaddress.m index 6b240fe5..41d17933 100644 --- a/external/fieldtrip/utilities/private/getaddress.m +++ b/external/fieldtrip/utilities/private/getaddress.m @@ -1,4 +1,4 @@ -function address = getip(hostname) +function address = getaddress(hostname) % GETADDRESS returns the IP address % @@ -41,12 +41,17 @@ return end -if ~isempty(hostname) - address = java.net.InetAddress.getByName(hostname); +if usejava('jvm') + if ~isempty(hostname) + address = java.net.InetAddress.getByName(hostname); + else + address = java.net.InetAddress.getLocalHost; + end + address = char(address.getHostAddress); else - address = java.net.InetAddress.getLocalHost; + % FIXME it would be possible to do a system call, but it would be different for linux, osx and windows + address = '127.0.0.1'; end -address = char(address.getHostAddress); % remember for subsequent calls previous_argin = hostname; diff --git a/external/fieldtrip/utilities/private/getdimord.m b/external/fieldtrip/utilities/private/getdimord.m index e87e1f11..50c59d3c 100644 --- a/external/fieldtrip/utilities/private/getdimord.m +++ b/external/fieldtrip/utilities/private/getdimord.m @@ -7,12 +7,16 @@ % % See also GETDIMSIZ, GETDATFIELD +% Please note that this function is called from many other FT functions. To avoid +% unwanted recursion, you should avoid (where possible) calling other FT functions +% inside this one. + if ~isfield(data, field) && isfield(data, 'avg') && isfield(data.avg, field) field = ['avg.' field]; elseif ~isfield(data, field) && isfield(data, 'trial') && isfield(data.trial, field) field = ['trial.' field]; elseif ~isfield(data, field) - error('field "%s" not present in data', field); + ft_error('field "%s" not present in data', field); end if strncmp(field, 'avg.', 4) @@ -90,11 +94,13 @@ nfreq = length(data.freq); end -if isfield(data, 'trial') && ft_datatype(data, 'raw') +if isfield(data, 'trial') && iscell(data.trial) + % raw data nrpt = length(data.trial); end -if isfield(data, 'trialtime') && ft_datatype(data, 'spike') +if isfield(data, 'trialtime') && isfield(data, 'timestamp') && isfield(data, 'label') + % spike data nrpt = size(data.trialtime,1); end @@ -108,7 +114,7 @@ % this happens after mtmconvol with keeptrials nrpttap = sum(data.cumtapcnt,2); if any(nrpttap~=nrpttap(1)) - warning('unexpected variation of the number of tapers over trials') + ft_warning('unexpected variation of the number of tapers over trials') nrpttap = nan; else nrpttap = nrpttap(1); @@ -156,7 +162,8 @@ nspike = length(data.timestamp{1}); % spike data: only for the first channel end -if ft_datatype(data, 'mvar') && isfield(data, 'coeffs') +if isfield(data, 'dimord') && ~isempty(strfind(data.dimord, 'lag')) && isfield(data, 'coeffs') + % mvar data nlag = size(data.coeffs,3); end @@ -316,7 +323,8 @@ if isequal(datsiz, [npos nfreq ntime]) dimord = 'pos_freq_time'; end - case {'pow'} + + case {'pow' 'noise' 'rv'} if isequal(datsiz, [npos ntime]) dimord = 'pos_time'; elseif isequal(datsiz, [npos nfreq]) @@ -341,7 +349,7 @@ dimord = 'rpt_pos_freq'; end - case {'mom','itc','aa','stat','pval','statitc','pitc'} + case {'mom' 'itc' 'aa' 'stat','pval' 'statitc' 'pitc'} if isequal(datsiz, [npos nori nrpt]) dimord = 'pos_ori_rpt'; elseif isequal(datsiz, [npos nori ntime]) @@ -360,6 +368,8 @@ dimord = 'pos_rpt'; elseif isequalwithoutnans(datsiz, [npos nori nrpt]) dimord = 'pos_ori_rpt'; + elseif isequalwithoutnans(datsiz, [npos nori nrpttap]) + dimord = 'pos_ori_rpttap'; elseif isequalwithoutnans(datsiz, [npos nori ntime]) dimord = 'pos_ori_time'; elseif isequalwithoutnans(datsiz, [npos nori nfreq]) @@ -417,7 +427,11 @@ end case {'cumtapcnt' 'cumsumcnt'} - if isequalwithoutnans(datsiz, [nrpt nan]) + if isequalwithoutnans(datsiz, [nrpt 1]) + dimord = 'rpt'; + elseif isequalwithoutnans(datsiz, [nrpt nfreq]) + dimord = 'rpt_freq'; + elseif isequalwithoutnans(datsiz, [nrpt nan]) dimord = 'rpt_other'; end @@ -431,18 +445,25 @@ dimord = 'chan_topochan'; end - case {'inside'} - if isequalwithoutnans(datsiz, [npos]) + case {'anatomy' 'inside'} + if isfield(data, 'dim') && isequal(datsiz, data.dim) + dimord = 'dim1_dim2_dim3'; + elseif isequalwithoutnans(datsiz, [npos 1]) || isequalwithoutnans(datsiz, [1 npos]) dimord = 'pos'; end - case {'timestamp' 'time'} - if ft_datatype(data, 'spike') && iscell(data.(field)) && datsiz(1)==nchan + case {'timestamp'} + if iscell(data.(field)) && isfield(data, 'label') && datsiz(1)==nchan dimord = '{chan}_spike'; - elseif ft_datatype(data, 'raw') && iscell(data.(field)) && datsiz(1)==nrpt + end + + case {'time'} + if iscell(data.(field)) && isfield(data, 'label') && datsiz(1)==nrpt dimord = '{rpt}_time'; elseif isvector(data.(field)) && isequal(datsiz, [1 ntime ones(1,numel(datsiz)-2)]) dimord = 'time'; + elseif iscell(data.(field)) && isfield(data, 'label') && isfield(data, 'timestamp') && isequal(getdimsiz(data, 'timestamp'), datsiz) && datsiz(1)==nchan + dimord = '{chan}_spike'; end case {'freq'} @@ -548,8 +569,7 @@ % if it does, it might help in diagnosis to have a very informative warning message % since there have been problems with trials not being selected correctly due to the warning going unnoticed % it is better to throw an error than a warning - warning('could not determine dimord of "%s" in the following data', field) - disp(data); + warning_dimord_could_not_be_determined(field,data); dimtok(cellfun(@isempty, dimtok)) = {'unknown'}; if all(~cellfun(@isempty, dimtok)) @@ -567,6 +587,43 @@ end % function +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function warning_dimord_could_not_be_determined(field,data) + msg=sprintf('could not determine dimord of "%s" in:',field); + + if isempty(which('evalc')) + % May not be available in Octave + content=sprintf('object of type ''%s''',class(data)); + else + % in Octave, disp typically shows full data arrays which can result in + % very long output. Here we take out the middle part of the output if + % the output is very long (more than 40 lines) + full_content=evalc('disp(data)'); + max_pre_post_lines=20; + + newline_pos=find(full_content==sprintf('\n')); + newline_pos=newline_pos(max_pre_post_lines:(end-max_pre_post_lines)); + + if numel(newline_pos)>=2 + pre_end=newline_pos(1)-1; + post_end=newline_pos(end)+1; + + content=sprintf('%s\n\n... long output omitted ...\n\n%s',... + full_content(1:pre_end),... + full_content(post_end:end)); + else + content=full_content; + end + end + + id = 'FieldTrip:getdimord:warning_dimord_could_not_be_determined'; + msg = sprintf('%s\n\n%s', msg, content); + ft_warning(id, msg); +end % function warning_dimord_could_not_be_determined + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % SUBFUNCTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -601,11 +658,11 @@ case 'chan' ok = numel(data.label)==1; otherwise - if isfield(data, dimtok{k}); % check whether field exists + if isfield(data, dimtok{k}) % check whether field exists ok = numel(data.(dimtok{k}))==1; - end; + end end - if ok, + if ok break; end end diff --git a/external/fieldtrip/utilities/private/getdimsiz.m b/external/fieldtrip/utilities/private/getdimsiz.m index 90e27771..11b17abe 100644 --- a/external/fieldtrip/utilities/private/getdimsiz.m +++ b/external/fieldtrip/utilities/private/getdimsiz.m @@ -22,7 +22,7 @@ elseif ~isfield(data, field) && isfield(data, 'trial') && isfield(data.trial, field) field = ['trial.' field]; elseif ~isfield(data, field) - error('field "%s" not present in data', field); + ft_error('field "%s" not present in data', field); end if strncmp(field, 'avg.', 4) diff --git a/external/fieldtrip/utilities/private/icosahedron.m b/external/fieldtrip/utilities/private/icosahedron.m index 2798b1f7..b6d65c34 100644 --- a/external/fieldtrip/utilities/private/icosahedron.m +++ b/external/fieldtrip/utilities/private/icosahedron.m @@ -25,7 +25,6 @@ % You should have received a copy of the GNU General Public License % along with FieldTrip. If not, see . % -% $Id$ tri = [ 1 2 3 diff --git a/external/fieldtrip/utilities/private/icosahedron42.m b/external/fieldtrip/utilities/private/icosahedron42.m index 86a1425a..833c11eb 100644 --- a/external/fieldtrip/utilities/private/icosahedron42.m +++ b/external/fieldtrip/utilities/private/icosahedron42.m @@ -20,7 +20,6 @@ % You should have received a copy of the GNU General Public License % along with FieldTrip. If not, see . % -% $Id$ [pos, tri] = icosahedron; [pos, tri] = refine(pos, tri); diff --git a/external/fieldtrip/utilities/private/ignorefields.m b/external/fieldtrip/utilities/private/ignorefields.m index 8a7f861e..5cf9f24b 100644 --- a/external/fieldtrip/utilities/private/ignorefields.m +++ b/external/fieldtrip/utilities/private/ignorefields.m @@ -6,6 +6,35 @@ switch purpose + case 'appendtimelock' + ignore = { + 'cfg' + 'label' + 'time' + 'dimord' + 'grad' + 'elec' + 'opto' + 'trialinfo' % this is dealt with explicitly + 'sampleinfo' % this is dealt with explicitly + }; + + case 'appendfreq' + ignore = { + 'cfg' + 'label' + 'time' + 'freq' + 'dimord' + 'grad' + 'elec' + 'opto' + 'trialinfo' % this is dealt with explicitly + 'sampleinfo' % this is dealt with explicitly + 'cumsumcnt' % this is dealt with explicitly + 'cumtapcnt' % this is dealt with explicitly + }; + case 'deface' ignore = { % some fields should be dealt with explicitly @@ -21,7 +50,7 @@ 'fid' 'cfg' }; - + case 'pipeline' ignore = { % some fields that are always allowed to be present in the configuration @@ -30,10 +59,11 @@ 'cfg' 'previous' }; - + case 'allowed' ignore = { % some fields that are always allowed to be present in the configuration + 'postamble' 'trackconfig' 'checkconfig' 'checksize' @@ -44,16 +74,19 @@ 'callinfo' 'version' 'warning' + 'notification' 'debug' 'previous' 'progress' 'outputfilepresent' + 'toolbox' }; case {'provenance', 'history'} ignore = { % these should not be included in the provenance or history + 'postamble' 'checkconfig' 'checksize' 'trackconfig' @@ -62,6 +95,7 @@ 'trackcallinfo' 'showcallinfo' 'warning' + 'notification' 'debug' 'progress' }; @@ -77,6 +111,7 @@ 'artifact' 'artfctdef' % these fields are for internal usage only + 'postamble' 'checkconfig' 'checksize' 'trackconfig' @@ -87,6 +122,7 @@ 'callinfo' 'version' 'warning' + 'notification' 'debug' 'previous' }; @@ -104,5 +140,5 @@ }; otherwise - error('invalid purpose'); -end % switch purpose \ No newline at end of file + ft_error('invalid purpose'); +end % switch purpose diff --git a/external/fieldtrip/utilities/private/individual2sn.m b/external/fieldtrip/utilities/private/individual2sn.m index 96133bdf..4d7e67dc 100644 --- a/external/fieldtrip/utilities/private/individual2sn.m +++ b/external/fieldtrip/utilities/private/individual2sn.m @@ -37,7 +37,11 @@ % % $Id$ -ft_hastoolbox('spm8up', 1); +% check for any version of SPM +if ~ft_hastoolbox('spm') + % add SPM8 to the path + ft_hastoolbox('spm8', 1); +end % The following is a three-step procedure diff --git a/external/fieldtrip/utilities/private/labelcmb2indx.m b/external/fieldtrip/utilities/private/labelcmb2indx.m index db7f97a5..8fc4dc2e 100644 --- a/external/fieldtrip/utilities/private/labelcmb2indx.m +++ b/external/fieldtrip/utilities/private/labelcmb2indx.m @@ -1,4 +1,4 @@ -function [indx] = labelcmb2indx(labelcmb, label) +function [indx, label, blockindx, blocklabel] = labelcmb2indx(labelcmb, label) % LABELCMB2INDX computes an array with indices, corresponding to the order % in a list of labels, for an Nx2 list of label combinations @@ -46,6 +46,32 @@ % % $Id$ +% check whether the labelcmb contains any square brackets, indicative of +% blockwise decompositions +if all(~cellfun('isempty',strfind(labelcmb(:),'['))) + tmp = strfind(labelcmb, '['); + tmplabelcmb = labelcmb; + tmpblock = labelcmb; + for k = 1:numel(tmplabelcmb) + tmplabelcmb{k} = labelcmb{k}( 1:(tmp{k}-1)); + tmpblock{k} = labelcmb{k}((tmp{k}+1):(end-1)); + end + blocklabel = cell(0,1); + tmp = tmpblock; + while ~isempty(tmp) + blocklabel{end+1, 1} = tmp{1}; + tmp = tmp(~strcmp(tmp(:,1),blocklabel{end}),:); + end + [indx, label] = labelcmb2indx(tmplabelcmb, unique(tmplabelcmb(:))); + [blockindx, blocklabel] = labelcmb2indx(tmpblock, blocklabel); + blockindx = blockindx(:,1); +% for k = 1:numel(blocklabel) +% nperblock(k,1) = sum(blockindx==k); +% end + return; +end + + if nargin==1, label = unique(labelcmb(:)); end @@ -62,7 +88,7 @@ if nargin==1, %autoindx = find(sel1 & sel2); autoindx = find(sel(:,1) & sel(:,2), 1, 'first'); - if isempty(autoindx), error('the required autocombination is not found in the input'); end + if isempty(autoindx), ft_error('the required autocombination is not found in the input'); end else autoindx = k; end diff --git a/external/fieldtrip/utilities/private/leaveoneout.m b/external/fieldtrip/utilities/private/leaveoneout.m index e2b5d9b6..c28cc4a1 100644 --- a/external/fieldtrip/utilities/private/leaveoneout.m +++ b/external/fieldtrip/utilities/private/leaveoneout.m @@ -4,11 +4,11 @@ rptdim = find(strcmp('rpt', dimtok)); % the selected dimension as number if length(rptdim)<1 - error('the ''rpt'' dimension is not present in the data'); + ft_error('the ''rpt'' dimension is not present in the data'); elseif length(rptdim)>1 - error('cannot jackknife over multiple dimensions at the same time'); + ft_error('cannot jackknife over multiple dimensions at the same time'); elseif rptdim~=1 - error('jackknife only works if replicates are in the first dimension of the data'); + ft_error('jackknife only works if replicates are in the first dimension of the data'); end [reduceddim, fn] = dimlength(data); @@ -16,7 +16,7 @@ %data is not source data reduceddim = reduceddim{1}; else - error('jackknife not yet supported for source level data'); + ft_error('jackknife not yet supported for source level data'); end reduceddim(rptdim) = 1; diff --git a/external/fieldtrip/utilities/private/lmoutr.m b/external/fieldtrip/utilities/private/lmoutr.m index 121b8301..acb88964 100644 --- a/external/fieldtrip/utilities/private/lmoutr.m +++ b/external/fieldtrip/utilities/private/lmoutr.m @@ -1,4 +1,4 @@ -function [varargout] = funname(varargin) +function [varargout] = lmoutr(varargin) % LMOUTR computes the la/mu parameters of a point projected to a triangle % @@ -60,7 +60,7 @@ try % try to compile the mex file on the fly - warning('trying to compile MEX file from %s', mexsrc); + ft_warning('trying to compile MEX file from %s', mexsrc); cd(mexdir); if ispc @@ -77,7 +77,7 @@ catch % compilation failed disp(lasterr); - error('could not locate MEX file for %s', mexname); + ft_error('could not locate MEX file for %s', mexname); cd(pwdir); success = false; end diff --git a/external/fieldtrip/utilities/private/lmoutr.mexa64 b/external/fieldtrip/utilities/private/lmoutr.mexa64 index db385e19c20d6e51d3eece19e335e84627fbec09..eb8e4f4765beaef50b18b6103743f1aeffc3f2e8 100755 GIT binary patch delta 1218 zcmY*ZZA@Eb6u#&7^A6VAPx>)iU>4dJx|Z`zUMj5 zdwO%bn!1|$_6hSoF2Cka96V>M@o32!VigQJ|1u3c`|dI4)SfH9jhs%5*M2oH_Kh+N z%K+ahGrE8drWCX3HGoq%Xbw>vGjD?h`(vzKvqUa1@Uf*1IFLkrO{XZ)g<56OCg1WKOgiyamca;bG_)5~#}E z>Kaz9O0sUJtPk##liZ99YLzt|XN-~7`Zo0--(pd9pHzQuZ|rNW&X-M}xyD#d+?>gY zHl4_-Wxb-5T*tx9J6c`9$aE9C10JkW6n|sdoeDSz*gKZ`oWJKqMv7r zcuL&Hmzwbxu^eVluzpy1beXZ2e-K|fL$=9g^1SM+$i#6^-$Q9#Mzw5G(+c(0Iq`n= z*8YER!MYWm!kDexFDWg6ElGILyzs9Aa}*z64%o+n=;_=eZxe233(s};A@joZrZ7UC;u9A7A_6#oALd_q~qqaDpCP<~DyTdmYcE$TRtTa~z( zw{kU@-Ry=8MVAt|&CbId#wwx|_g5StQ+Tl=0yHO+u>BI;JZJ8$3d6aOF1G@A(k delta 1127 zcmYL}eQXnT7{`ClUEB4#Zg;n}>sn|xrCk}))+NM^KmrBpZnHzg&5Rc(3$SH>xI{t& zSybkROAaV>KDZDw1O7oWHO4JB%rJ%*oe|?7!arspFOg_C;v}wSf?M@`u7i2W@A*8> z-S2sx?{jYhodcbjox-?}<&W{ft_!lId?8pQu7*>t6W@H+C;jfa)z$Lpa4t03cd#|k zu1!M@;Iwv+5AbkCvlk2jwBadxnC!RqYS@7@WVhiGp&D8-AX zylvlA$XHJxwG;=P9_)1rum%r1n?3g(jAg~IE?YaqAx4Yp%#GZ>V)CskO@DbuCKc4rJv5B0DD(QL z>BL3Z64cL-i$4}eh19%ZB-ICc1dGHb*pJ)AN_ZLH5dBbx?~8uUH;?DU4P34O{}HQT z5`)s&+M%3byz`TIXq@y=|HNgp;f#&3y=y6Kx@c;-V}=oPoUGVtj^m#~NnQhoF)3I1 zcg^J`B_@8Wi>p)0k*1NPI+s-MC)K-pJsy`o^fiz`CH>|VMZKjLl0QMSGPBPRHkJ&- zYk0RL3<(rVgRmA?l?FM_9BwP^4un$6^iTd=m@~oj(~n)d{vNp+xaxs4G`Ls8X6$#b ztyYEFDE*U_+v7Xpuf*HF`#O`!v?%JYO4^#BON;SKO8>N7Ibxl% zRnq>4#y+o-_J5BK&oa2JMLkc#!2?wB1ZiHGHH=AO8}S$7=R^yY3Xq&2aS!oX;upl- z#O7JUI7-YtFpMvWJv96c;@IDY;p7;5o^IVL;wE|syNSd9(te_gYMTf2Y+-Of!XL_I zxPd>H$6zPQ-U`@@HDo`=7s+Pvb#KKJUQ*Ixro@Y-jRRbfjoa)jurn5!}0Jr+WH6qF7NzP)?J;(WDmbCS#t-pZ3 z28$K)O{l^h9P@=adrrIVJI}qlWIdkrk8*mM))+W%qgPM}#T*^)863^#2LWDGB@aPtzg;LHjS^pbUJfu~A17{!`M zjBI;kKZ(HWktn={LiAN&*cI)B5xg2*2WL@^#b67@WA(xdB@4BAZ7}9Be-0l#eUtkS DX~}#_ diff --git a/external/fieldtrip/utilities/private/lmoutr.mexmaci64 b/external/fieldtrip/utilities/private/lmoutr.mexmaci64 index 4079df72268abdefc3086b0facdcac955419c106..d226f9b07e5aab8aa9ae1ad2516aeb1e2293d563 100755 GIT binary patch literal 13240 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 delta 830 zcmYL{ZAcVB9L9INJ3GufPrXb%#TPCuUov!N_jYF!D_1h`&=XH111khGEfOt?@Qg$7 zSjuX_K4jnrr6l@LXMHH6Lcd2$tFkzP`!^g^?8O9M0W{D05GyfD*K)>C#V zoK^LAxsHjnAQP3f5f~Z9Oo7^IYg6Juk?vCyqwE1ApwYhowncf8^bF&j)YrP@E~^|} zUrp9@>%hATx-7D}hJ>_Q*J)~TWHAi+Fl9qUK2^%}0n_5nD~#HCN3$V{3?818V$<8jlb;$wf-2>660i=g6g6-O?w0 zCpJ~PV_iOJmBdlq%Cv%3;FErnUoc85uDPZUZjmOZ3kz_BX*miv0251Yzkj z$aTqqR8pWSDJ_spvQ<@;siYV=#c9N*&SZM4aeB-tz5RlJz&N4@?TTnxpkt1?1&IEB z^GTgD1T0q)#z2MtUIGTx`j%K^I<%Rw(8ZWSI`2{ntu}y^N~_HGbL! z@wX)3HFzvA38ukpxD{@PyP*@-!zS1a&%jX_p>T0#xAlp?g)308{}?qx4Ea> zG&j$!adD0`N3F-v;5h9#=g8sn`JMa${siB}zvn;jpZPHVhmR393B^LU;1#Y44}>Y< zweVI52}?pEw&5IHfQzvMmtrSw#D{SUK8`!_S$rP%;eI@Tuj65S3;XdyJb_>0863bN d{1vZYAezJkFo&G diff --git a/external/fieldtrip/utilities/private/lmoutr.mexw64 b/external/fieldtrip/utilities/private/lmoutr.mexw64 index 8ad4f5717ed062ac51e339371314fb2148f44c0d..ab5adac34f0bc2b9a2a4442b63d695307ddb8702 100755 GIT binary patch delta 1664 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 + result = appendstruct(result{:}); + else + result = result{1}; + end +end diff --git a/external/fieldtrip/utilities/private/mergeconfig.m b/external/fieldtrip/utilities/private/mergeconfig.m index bfb39371..bc0a6ef1 100644 --- a/external/fieldtrip/utilities/private/mergeconfig.m +++ b/external/fieldtrip/utilities/private/mergeconfig.m @@ -21,21 +21,63 @@ end % merge the input with the fields from default -fieldsused = fieldnames(default); -for i=1:length(fieldsused) - fn = fieldsused{i}; +defaultfields = fieldnames(default); +inputfields = fieldnames(input); +allfields = union(defaultfields, inputfields); + +if numel(default)>1 && numel(default)==numel(input) + % create an empty structure that has all the fields + tmp = emptystruct(allfields); + for i=1:numel(input) + for j=1:numel(allfields) + if isfield(input(i), allfields{j}) + tmp(i).(allfields{j}) = input(i).(allfields{j}); + else + tmp(i).(allfields{j}) = default(i).(allfields{j}); + end + end + end + input = tmp; - if ~isfield(input, fn) && ~isstruct(default.(fn)) - % simply copy the value over - input.(fn) = default.(fn); - elseif ~isfield(input, fn) && isstruct(default.(fn)) - % simply copy the substructure over - input.(fn) = default.(fn); - elseif isfield(input, fn) && ~isstruct(default.(fn)) - % do not copy it over, keep the original value - elseif isfield(input, fn) && isstruct(default.(fn)) - % merge the two substructures - input.(fn) = mergeconfig(input.(fn), default.(fn)); +elseif numel(default)~=numel(input) + for j=1:numel(allfields) + % ensure that the input has all fields + if ~isfield(input, allfields{j}) + input(1).(allfields{j}) = []; + end + % ensure that the default has all fields + if ~isfield(default, allfields{j}) + default(1).(allfields{j}) = []; + end end + % simply concatenate them + input = cat(1, input(:), default(:)); + +else + for i=1:length(defaultfields) + fn = defaultfields{i}; + if ~isfield(input, fn) && ~isstruct(default.(fn)) + % simply copy the value over + input.(fn) = default.(fn); + elseif ~isfield(input, fn) && isstruct(default.(fn)) + % simply copy the substructure over + input.(fn) = default.(fn); + elseif isfield(input, fn) && ~isstruct(default.(fn)) + % do not copy it over, keep the original value + elseif isfield(input, fn) && isstruct(default.(fn)) + % merge the two substructures using recursive call + input.(fn) = mergeconfig(input.(fn), default.(fn)); + end + end % for all default fields -end % for all fields +end % dealing with struct-arrays + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function s = emptystruct(fn) +s = struct; +for i=1:numel(fn) + s.(fn{i}) = []; +end +s = s([]); \ No newline at end of file diff --git a/external/fieldtrip/utilities/private/mxSerialize.m b/external/fieldtrip/utilities/private/mxSerialize.m index 78befccb..a2534051 100644 --- a/external/fieldtrip/utilities/private/mxSerialize.m +++ b/external/fieldtrip/utilities/private/mxSerialize.m @@ -31,7 +31,7 @@ argout = mxSerialize_c(argin); else % use the C++ implementation of the mex file - % see http://bugzilla.fcdonders.nl/show_bug.cgi?id=2452 + % see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2452 argout = mxSerialize_cpp(argin); end diff --git a/external/fieldtrip/utilities/private/pos2dim.m b/external/fieldtrip/utilities/private/pos2dim.m index 6c96f6ff..26622c0a 100644 --- a/external/fieldtrip/utilities/private/pos2dim.m +++ b/external/fieldtrip/utilities/private/pos2dim.m @@ -5,7 +5,7 @@ % % Use as % [dim] = pos2dim(pos) -% where pos is an ordered list of positions +% where pos is an ordered list of positions. % % The output dim is a 3-element vector which correspond to the 3D % volumetric dimensions @@ -15,6 +15,7 @@ % Copyright (C) 2009, Jan-Mathijs Schoffelen if isstruct(pos) + % the input is a FieldTrip data structure pos = pos.pos; end diff --git a/external/fieldtrip/utilities/private/pos2transform.m b/external/fieldtrip/utilities/private/pos2transform.m index 3030bc97..a15403c4 100644 --- a/external/fieldtrip/utilities/private/pos2transform.m +++ b/external/fieldtrip/utilities/private/pos2transform.m @@ -4,8 +4,8 @@ % of positions. % % Use as -% [transform] = pos2transform(pos, dim) where pos is an ordered list of positions -% and should specify a full 3D volume +% [transform] = pos2transform(pos, dim) +% where pos is an ordered list of positions that should specify a full 3D volume. % % The output transform is a 4x4 homogenous transformation matrix which transforms % from 'voxelspace' into the positions provided in the input diff --git a/external/fieldtrip/utilities/private/printand.m b/external/fieldtrip/utilities/private/printand.m new file mode 100644 index 00000000..86ba7230 --- /dev/null +++ b/external/fieldtrip/utilities/private/printand.m @@ -0,0 +1,28 @@ +function str = printand(strs, quote) + +% PRINTAND prints a single or mutiple strings as "x1, x2, x3 and x4". If there is +% only one string, that string is returned without additional formatting. +% +% See also PRINTOR + +if nargin<2 + quote = false; +end + +if quote + if numel(strs)>2 + str = sprintf('''%s'', ', strs{1:(end-2)}); + str = sprintf('%s''%s'' and ''%s''', str, strs{end-1}, strs{end}); + elseif numel(strs)==2 + str = sprintf('''%s'' and ''%s''', strs{end-1}, strs{end}); + else + str = strs{1}; + end +else + if numel(strs)>1 + str = sprintf('%s, ', strs{1:(end-2)}); + str = sprintf('%s%s and %s', str, strs{end-1}, strs{end}); + else + str = strs{1}; + end +end \ No newline at end of file diff --git a/external/fieldtrip/utilities/private/printor.m b/external/fieldtrip/utilities/private/printor.m new file mode 100644 index 00000000..c7c8f8e1 --- /dev/null +++ b/external/fieldtrip/utilities/private/printor.m @@ -0,0 +1,28 @@ +function str = printor(strs, quote) + +% PRINTOR prints a single or mutiple strings as "x1, x2, x3 or x4". If there is +% only one string, that string is returned without additional formatting. +% +% See also PRINTAND + +if nargin<2 + quote = false; +end + +if quote + if numel(strs)>2 + str = sprintf('''%s'', ', strs{1:(end-2)}); + str = sprintf('%s''%s'' or ''%s''', str, strs{end-1}, strs{end}); + elseif numel(strs)==2 + str = sprintf('''%s'' or ''%s''', strs{end-1}, strs{end}); + else + str = strs{1}; + end +else + if numel(strs)>1 + str = sprintf('%s, ', strs{1:(end-2)}); + str = sprintf('%s%s or %s', str, strs{end-1}, strs{end}); + else + str = strs{1}; + end +end \ No newline at end of file diff --git a/external/fieldtrip/utilities/private/project_elec.m b/external/fieldtrip/utilities/private/project_elec.m index 9cb599e0..0454e10a 100644 --- a/external/fieldtrip/utilities/private/project_elec.m +++ b/external/fieldtrip/utilities/private/project_elec.m @@ -34,7 +34,7 @@ Nelc = size(elc,1); el = zeros(Nelc, 4); -% this is a work-around for http://bugzilla.fcdonders.nl/show_bug.cgi?id=2369 +% this is a work-around for http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2369 elc = double(elc); pnt = double(pnt); tri = double(tri); diff --git a/external/fieldtrip/utilities/private/ptriproj.m b/external/fieldtrip/utilities/private/ptriproj.m index 49b78585..2f482b1a 100644 --- a/external/fieldtrip/utilities/private/ptriproj.m +++ b/external/fieldtrip/utilities/private/ptriproj.m @@ -1,4 +1,4 @@ -function [varargout] = funname(varargin) +function [varargout] = ptriproj(varargin) % PTRIPROJ projects a point onto the plane going through a triangle % @@ -42,7 +42,7 @@ try % try to compile the mex file on the fly - warning('trying to compile MEX file from %s', mexsrc); + ft_warning('trying to compile MEX file from %s', mexsrc); cd(mexdir); if ispc @@ -59,7 +59,7 @@ catch % compilation failed disp(lasterr); - error('could not locate MEX file for %s', mexname); + ft_error('could not locate MEX file for %s', mexname); cd(pwdir); success = false; end diff --git a/external/fieldtrip/utilities/private/ptriproj.mexa64 b/external/fieldtrip/utilities/private/ptriproj.mexa64 index f81b3dc2867014088cf87682d39cefede563e615..1717147bf2c1be2e3467712a33a9e0b6279d7765 100755 GIT binary patch delta 1189 zcmY*ZZERCz6u#&7dtbMAZS8KM-G==@a4iy&(adZsv~p{@1jm**M4b`0OwA0+wArGQ z)UO*>DV&99GD3*{FflR8oyh_O!7T!R6pe`k&4`J{4JTpMIoPJJ=WXZ2H@WAz=Q;0r z-se3{?`ZdEcdpYGUn3M&{BX}_@^Do#Sw)P(ap$I`)2A{WTN0h^k-*TmjlulL1H<|( zI7QL#)vh8~sJ@l{+{(U_Bj>LbtTewtI=Ol(sNkiQA+W*n>H#1{&}a$qQcm zO7e+j(>uDUU9D%oRts?}T78mj1%?~?j>~2Gd4u{9Zlv8VLMIh2g0G-jFpLk5TyBT zA&k>6wU;pWH|-~Mk~Uw^-zq@bj@PPW7{R%!2-IM$QVp9iM)7HUg5pU$pj6jhA!qHp zC01eI{)Sj?7I&6etb*VtYL=b~JgIb$*W0jmmyLr7r~&wE1R@{)et(<|aT-j5-zCw&*p zBqs+VwzQicCkSaw2I_6Ol`MxEW&eE!E(PjK>`HN`UC~Q|XN}bV;|7;O5^{uY`ghA4 zT}D};YUReD2+bI+i%{&Tdx`I)_ZgJKkHa&#FWe2|cqQCKb5kM_n8ajchwW5lQQfD% O8*u~wvYgx`8vX%q)043P delta 1131 zcmYL}eQXnT7{`Cl^<}-TPG4;22@}OY~c@^IM)Cp zYRop|ghKJr1#krMuYrjXZx3WT`(t1a6wngJ^*+cCv73Je(^p?W0GtuzC<>Kr^F%HhpqNUpcjwXZ^IFMz5H=l zhu@Wt+jf*Q)?J%jg4Z2xEI341g+Dmb?wfYTO465?EbY>=Lc5f{Qj%oLs9jG~WMI>F zk!svo*D%+sYNn)S4kWb%`!xf+O3tk{45M9&RK$3q(6xws%L?u&W!NGI zVFbJ63l04kn^foksMf~x&kEGK`Mc4d4{Kc1`{ zfETc#Dg+7KRuzEN*jp74+*5e2DpOmZU0QtSuem)FteC&++KPST>Q6eGfHa(NHPVgx z-nB-MOXytu_hScdaY36cDveQlM(Uo8KNsH;-+KA0d_KQX)qYlUmIPf|h@Vn>CT!{< z%Ry@$<=-*7JZjFjAD?kAg>n5A_r37yUh4Q3Xj1l5i;!nhniDqh5OL79lUBvao zPl!8->Dz{Jm^d?O7@rcmY58l!^ZyuzLtyL)`s*GdZlIg6lQ{4%^VF`wuE1J{P%cB$wpohUnH+PAXHd|l%veXSb%<-pmPI) zH)Od;x&|@qt#;;x*~`3Q37uSY3^#lI(2x7PQ8!EVhW?|%KL)?Fl-D*$?gvC w;g#fni%Mi0Jt!|mI$#h-BWu8do@f-_!(_BcJY6~8Lq8F91OGmJ^nhUc4`;P_#Q*>R diff --git a/external/fieldtrip/utilities/private/ptriproj.mexmaci64 b/external/fieldtrip/utilities/private/ptriproj.mexmaci64 index 0a66a1cda8966143afc6d31867cf79fdfa0eb53a..4e2c04d79783bfa34c33d91e64371f8faffe78e3 100755 GIT binary patch literal 13304 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 Hn}+%ii(P(s literal 13360 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 diff --git a/external/fieldtrip/utilities/private/ptriproj.mexw32 b/external/fieldtrip/utilities/private/ptriproj.mexw32 index 1c274de1ec0d8e87e575dd4dc4ec7aab1898613d..caf4b04a31c23b3580069fdcff64e55851170fbe 100755 GIT binary patch delta 964 zcmYk4e{2(F7{}jtz3WEpi=(?r8k=VHv_ zMi8Zh{-MpQX8I-=)EG1o30ur!6NiZtjYX712)Mum8W6Mj8bJ##P=PSt>sI6aanJMp zem{5blPB+%t}R_7LKzIs_PljA2+Mp4Y^yo4jYr{5IF|nflA27}3qZD@Jd$EVP0Sk? zCl_?K42Lv!eL{R!)t(pY)2rHnR&`iPNs3RaDI98Gol0E1Q#D*%ckxAst*J|hOf_}! zR9#Y}|8rcvge0F{U|6R=F5>^^*Z32HR1FvZ-o+Ok7D$SK40Fz0We%V0-6L~OSzJ?P zpYkVj&Q)C(@=oj*Qv$Dbj4IeS=OAR{ZYH$(SUsVLBFRTioCRC3;Q7} ziJelUSXu0rbuF6~AMqYF2siLy^*#TD^oqTuqC9hqhrCnp7{B11fUSIY?aG!p4*(}a zBXT9DPG2lMu#^o#NjoKRg8x}N0H5dU>MmK4pHCNWVl%zpigB5;M|C;#3Fm6DMeLAz zK`wrRB=y`T1<2>8U5zxxZwN&bpi8iPTzg zCO_(X7}ie)|jv?TA*Tj6HDQD5f$Cj_+moAdALKBaR1^1Fghs2N30 zeIt4h4Wp0I6zU5f5C0v0sG}<~7r7h(hS%^LjfQUAYS_j>&g*&i? zyKpb=!<+FoJc`Hh=lC!_iqGKl_!7Q`n@NZuaxYm;5~Pm|kWGY>aWX-^B;Sw&WQxp? zn&{F@^!DgW(NCg(MT4}57zWJf~wYkq6wl-OBSfkcn zYoB$G-C;-VRd%=ixV_%qY9F+JvVXIEw3)7;chWGW^cngb9i}hSt@JheCjEep(a-1} z`V}qE1N1PRrl;sEJxAwg+Z76y1Aye+@}TR`4X72}f$m0OWT8%!K)vW`G>A5!S5Ovh MM?26i-oE0{zd@{9Hvj+t delta 952 zcmXw%YiLwQ7=~xESJRC-rfG7z*|m{Gp<=@Cq`*xvyxSbTIi3Mu9rgE zNCn#j7Ang~8y&F41PLvT7t~r-+p4IjiwQLlXtg(7OiEhE3t@?xhG?74N!h*Oqx?- z+|n^mG-*B)e@dN5D~TCL(k$*MVRiLNL=4VCyAZM_P33`Wz*K--aS*q~q4-K-DPbJ4 ztT-r}7@HD@WL?jG69@Q4hYxP$yBs~9Ba&q{XEXB7Uha3^gadrS`8_P;$6ZUkV>SS8 z`@7{x?u<;PR~E8%DAQ(E+~DJ`?QjckasN|Q`TI!bW%k$RYobrOtXa)?#X(D%zKkmN zS*o#oE-^I3KbyA~PV&_0pJjwSgxF`44qBgiEHC$9<$6|oqV@i=DgYGeT{CS*4jU6AJwjY9S6n&_XF9$WZ+pKPjhQU+H2Y+?MLlr?Y1_mJ<%Zc;YwVE zF>b^$yc2(ddvG7_$5-%m{1YCO0&vW+B2A2~u!kZ;L(k|wvv z1exh1rNMac^WdGJCv-V95V{o_3H=?K4i)NNeYxJCH|zWK{rYMBtlk>l7XB#Q6aFTA zHoVZNG?p632pemRW~1G>WLz_THKq+0eUX;Y3R+Fq(H7cDx6^j|A^n(sN_**-^e8<= z&(QPq3LT`w^cR|;W3>7KeMFy9P!7N{`KN5C5UI$IDo_;)pgPouqUas8741Opqa^A^ KU+|iW;r{^%8&mlJ diff --git a/external/fieldtrip/utilities/private/ptriproj.mexw64 b/external/fieldtrip/utilities/private/ptriproj.mexw64 index 997761e6be39b826caa6b71bd051d63817d256d9..0421d849afc5d1449461b2f6a0dc51f234a0444f 100755 GIT binary patch delta 1756 zcmYjRe{54#6u!6Z!){&IcH0}<*r45BVGM?a4jeL|!>V_-8puWhI246UO#EZfK7ybb zNvTqvgUJnlh$N0E5u<->G|>#BjK~i&#?K|noC!og-yD%Sfek`@e)o05H9hD1&N<(E z=iGbWdpjC-G_+mwefr1EwPgG^OiH~Di=B`>By!Tp5U2EU%bodr0sWdTOAXS9rRBFw zLYU^z&kKx?Q8imc$I_8Cmc?3~t9^u|Gg`#1AD$4pmk_2t%@nV`dL0tDyukz!ZC`ycskh4v>t}L>@lxAAJueyFKC^1j%io)oqW6GrSnq< zr3iH`#3qh}UG9q`F867DR_fjq52bR-Za+fl8@w|k@ZvrT6r#95BBZI-HSfeWODqSO zGrIRtW`!Ekryv?}RiOD!#f?EmTpptTZTml2Fp>OqJjnx@`)MR~Iul3t3164hWbN(k z<;Sx^bp1YO4ej7dou6CAM)~hfg={KzM-5|;W0C0JsD$7*DGa{y3m(q?Y@;oo z5W{~@7G5{~FQ)G`{r9FnV){~eG#meg>RJ4jw~JsvL!OEf(|*KO8M0OI!~jc5_Z6_D z^e2zF-hC>JAkppG(~U`L=bTDPK_r6R!%~ZxwIZd_4<&tR=cZ7%Mc{GV_97@Fub0RLmOJoTICsH zh*qZ^5KdMWLZsiZnX61}H4Foan_`Mq=T88=52Z8G?NUPUbdbcoYV|RUatkqwFMS9g zF(0)5fa%Yew~2Y8+NongU8nULaz83zT6uuK2pn=DAW3} zq3tLba*rFsiMIwH0z-8$?W`ehL2gLx!aG3pS8-(<)Nh*VgOAjjbB&qV&9CPwMGMWm zG!H4JMU{{tm!&g#+?UsE-|i86R1)JKvSbvD#ZQ+1VEALu8vZS&-)j18PJYR9@@PRh zrGeD!!rN3{jn}FwNQf`fLNa$bNHZRi)x2`r$36w;Wx=RdO9(kRoseOez<$I%KrbJh zHpe4Wc(usSc;u?Eb1S*Oc)2{0{l-Vg4cM^2)Z4}1T5aN6pQ`qHZ7mb61-?>%8)6KB zXJKyei@>`@glqs0Oe17JY%6#>@GA_l1H1!x8^d&five>n#u0EYa51bMJOoU@hQZr` z&tlB1Dzc8O1bH21t0JTsxC=HHybag~s{+3UEW`9+@DAV*tPxzS$b+>vfCqr}uy?>W M0B5G=`!Cr31BCYdCIA2c delta 1741 zcmYjRZERCj7(S=%g>GxtyN_GDjlu1>l?}Er=)j4?b)mprS`}m%z=5z~I)dcIOL9+|J~ zm!U+Z9Fs?UM&o>`�U)eVj`x*_fkf-AooY8*xVUN#m~!7o+;LaV5ijYBH>Zj8SB9 zQ{YLR#$C$BDON2kUH%3dCn@$~V=%4i->G=Z%hr<@qPk&pfHvvpRsE6?V=o9Y^{0*r z5$XwG6K{k);_wZR__c9YYHC3qr9#T-JV9v->(8or=#UKx-YgRcX>IgWpMKsJ%SUC< z5bsphYPH6cgZn?Ih%j-(lShoJvjyK=VH5>cpM8{WPK{*axISR5u2weeYM}d>=&q+} z_JI4i%{k4c+zP$IN^+MJe|g(9Cm2?R30ss9;yy)1tQug=x$o^Q^b%qQ7Fcmw;`|RQ z{%pkyR{YG0s}axL`GvNr@jvAO0%xYQ3@ugv276;l1)L|w)TEFV080up>`~848=4hD z5^2wCX*g+IaW*MzKp~i(jC%U3c7Vnfx3+fUZ@{qgH?G0Gob9edS2J{BIV%y17cE0( zN?XxZ6F8;mSd*%|v#nx1+bS+oTxglne+AauLrX0f1_Z~FrF}eowX~ld6Kgs;k;KZ> z`vzmhvy<+|Lzq@l!s9n-ZZlcTW1B8=R z6%ZMJJFHbE+D+4h;ud$&<^CODTtsV7Fv|$Rbs&kUI&C4W{EJ+TuXo{L67xfA=damh zy(X3y)z6;f>L&f1DNR5crd7Qxp0}f74U)u&R&cMh8BEK;>RJ?e;vB^B85$GfGd3-# z>Ov87z5&)-ddWt9a_?Ri%wWa5ZDbFP^aRrMdSp?zqW(oZ7H z@y`TbzNzJ?`uC=E2(@e404_Z-p2U;gP`_fSKfI&X-ECIoZFaLjDc)$+h5J!b^{5gu zrC_F_uvLWzoO&MLqtb)y{X*3l$s}R+PvL3$FgqpfT)iU~Rsy@M7_;KDR%}Pa6)eYc zH4$5Q*#k@30#mxqHhKN@6V~Rvo4(0j_ZF?$=jKzlC^e?^1ZY^l)D#>urN`#+om|ot zRqE!NTi7q&wG~;V*!p6&S5B#%swlcn zr6zn(wLwDs**21WIENg-C23++CGYqPab7l99l{GgUQEb12FGuap9G3*qGUxLSK-ql zgSc`Eb}qyMiyEZ4>Ty3IqZs2HQ_n3rWq0s@?x{Lic67{5&2hVr5E(W&et{u^r-4_C z3E2ZKm*5&~jDB diff --git a/external/fieldtrip/utilities/private/quaternion.m b/external/fieldtrip/utilities/private/quaternion.m index ad8d5e06..bd34c4f6 100644 --- a/external/fieldtrip/utilities/private/quaternion.m +++ b/external/fieldtrip/utilities/private/quaternion.m @@ -48,7 +48,7 @@ % $Id$ if numel(q)~=7 - error('incorrect input vector'); + ft_error('incorrect input vector'); end % all of these quaternions are zero-offset in the original equation, but one-offset in the MATLAB vector diff --git a/external/fieldtrip/utilities/private/refine.m b/external/fieldtrip/utilities/private/refine.m index c2c2fb1d..9dc242d4 100644 --- a/external/fieldtrip/utilities/private/refine.m +++ b/external/fieldtrip/utilities/private/refine.m @@ -45,7 +45,6 @@ % You should have received a copy of the GNU General Public License % along with FieldTrip. If not, see . % -% $Id$ if nargin<3 method = 'banks'; @@ -190,6 +189,6 @@ [trir, pntr] = reducepatch(tri, pnt, numtri); otherwise - error('unsupported method "%s"', method); + ft_error('unsupported method "%s"', method); end diff --git a/external/fieldtrip/utilities/private/rigidbody.m b/external/fieldtrip/utilities/private/rigidbody.m index 8f74ee43..cd02a500 100644 --- a/external/fieldtrip/utilities/private/rigidbody.m +++ b/external/fieldtrip/utilities/private/rigidbody.m @@ -50,7 +50,7 @@ % $Id$ if numel(f)~=6 - error('incorrect input vector'); + ft_error('incorrect input vector'); end % compute the homogenous transformation matrix for the translation diff --git a/external/fieldtrip/utilities/private/rotate.m b/external/fieldtrip/utilities/private/rotate.m index d6b05256..2512a5a8 100644 --- a/external/fieldtrip/utilities/private/rotate.m +++ b/external/fieldtrip/utilities/private/rotate.m @@ -49,7 +49,7 @@ % $Id$ if numel(f)~=3 - error('incorrect input vector'); + ft_error('incorrect input vector'); end % convert degrees to radians diff --git a/external/fieldtrip/utilities/private/scale.m b/external/fieldtrip/utilities/private/scale.m index 7ba67e67..c77b0340 100644 --- a/external/fieldtrip/utilities/private/scale.m +++ b/external/fieldtrip/utilities/private/scale.m @@ -44,7 +44,7 @@ % $Id$ if numel(f)~=3 - error('incorrect input vector'); + ft_error('incorrect input vector'); end H = [ diff --git a/external/fieldtrip/utilities/private/selfromraw.m b/external/fieldtrip/utilities/private/selfromraw.m index 0cf1a0ea..a72b1ca2 100644 --- a/external/fieldtrip/utilities/private/selfromraw.m +++ b/external/fieldtrip/utilities/private/selfromraw.m @@ -10,7 +10,7 @@ if strcmp(selrpt, 'all') selrpt = 1:numel(data.trial); else - error('incorrect specification of requested repetitions'); + ft_error('incorrect specification of requested repetitions'); end else if islogical(selrpt) @@ -27,14 +27,14 @@ end if isempty(selchan) - error('no channels were selected'); + ft_error('no channels were selected'); end if ischar(seltim) if strcmp(seltim, 'all') doseltim = false; else - error('incorrect specification of requested latency'); + ft_error('incorrect specification of requested latency'); end else doseltim = true; diff --git a/external/fieldtrip/utilities/private/seloverdim.m b/external/fieldtrip/utilities/private/seloverdim.m index d1e070b5..80b7b9fe 100644 --- a/external/fieldtrip/utilities/private/seloverdim.m +++ b/external/fieldtrip/utilities/private/seloverdim.m @@ -31,9 +31,9 @@ end % if sum(~cellfun('isempty', seldimnum))<1 -% error('the "%s" dimension is not present in the data', seldim) +% ft_error('the "%s" dimension is not present in the data', seldim) % elseif any(cellfun(@numel, seldimnum)>1) -% error('cannot select over multiple dimensions at the same time') +% ft_error('cannot select over multiple dimensions at the same time') % end [reduceddim, fntmp] = dimlength(data); @@ -97,7 +97,7 @@ case 9 tmp{j} = tmp{j}(:,:,:,:,:,:,:,:,sel); otherwise - error('the number of dimensions is too high'); + ft_error('the number of dimensions is too high'); end tmp{j} = reshape(tmp{j}, reduceddim{i}); @@ -107,7 +107,7 @@ elseif all(seldimnum{i}==[2 3]) tmp{j} = tmp{j}(:,sel,sel,:,:,:,:,:,:,:); else - error('selection of 2 dimensions simultaneously only works for [1 2] or [2 3] at present'); + ft_error('selection of 2 dimensions simultaneously only works for [1 2] or [2 3] at present'); end tmp{j} = reshape(tmp{j}, reduceddim{i}); end @@ -163,5 +163,5 @@ data.inside = data.inside(sel); data = fixinside(data, 'index'); otherwise - error('unknown dimension "%s"', seldim); + ft_error('unknown dimension "%s"', seldim); end diff --git a/external/fieldtrip/utilities/private/selparam.m b/external/fieldtrip/utilities/private/selparam.m index 059f9aa8..c49c49f5 100644 --- a/external/fieldtrip/utilities/private/selparam.m +++ b/external/fieldtrip/utilities/private/selparam.m @@ -10,7 +10,7 @@ dim = dim{1}; elseif numel(fn)>1, %data is source data new style - error('selparam only works with input data which is not of type ''source'''); + ft_error('selparam only works with input data which is not of type ''source'''); end ndim = length(dim); diff --git a/external/fieldtrip/utilities/private/sn2individual.m b/external/fieldtrip/utilities/private/sn2individual.m index 9b8a3a86..e37f4ef9 100644 --- a/external/fieldtrip/utilities/private/sn2individual.m +++ b/external/fieldtrip/utilities/private/sn2individual.m @@ -32,11 +32,12 @@ % only an affine transformation has been done T = P.VF.mat*P.Affine/(P.VG.mat); warped = ft_warp_apply(T, input); + else % we need the spm_dctmtx function for the nonlinear case - hasSPM8 = ft_hastoolbox('spm8', 3); - if(~hasSPM8) - ft_hastoolbox('spm12',1); + if ~ft_hastoolbox('spm') + % add SPM8 or later to the path + ft_hastoolbox('spm8up', 1); end dim = P.VG.dim(1:3); diff --git a/external/fieldtrip/utilities/private/struct2table.m b/external/fieldtrip/utilities/private/struct2table.m new file mode 100644 index 00000000..80c3b25f --- /dev/null +++ b/external/fieldtrip/utilities/private/struct2table.m @@ -0,0 +1,89 @@ +function table = struct2table(s) + +% STRUCT2TABLE converts a struct-array to a cell-array of strings that represents a table +% +% Example +% s(1).a = 1 +% s(1).b = 2 +% s(2).a = 3 +% s(2).b = 4 +% disp(struct2table(s)) +% +% See also PRINTSTRUCT, APPENDSTRUCT + +% Copyright (C) 2017, Robert Oostenveld +% +% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org +% for the documentation and details. +% +% FieldTrip is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% FieldTrip is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with FieldTrip. If not, see . +% +% $Id$ + +fn = fieldnames(s); +colwidth = zeros(size(fn)); + +% first ensure that all fields are strings +for i=1:numel(s) + for j=1:numel(fn) + val = s(i).(fn{j}); + switch class(val) + case 'char' + % nothing to be done + case {'single', 'double'} + val = num2str(val); + case 'logical' + if val + val = 'true'; + else + val = 'false'; + end + otherwise + ft_error('not yet implemented for class "%s"', class(val)); + end + s(i).(fn{j}) = val; + end +end + +for i=1:numel(fn) + colwidth(i) = max(cellfun(@length, {s.(fn{i})})); +end + +header = '|'; +for i=1:numel(fn) + colname = fn{i}; + if numel(colname)>1 && colname(1)=='X' && colname(end)=='X' + % the name of the field has been base64 encoded + % we want to use the original name for the column header + colname = fixname(fn{i}, 'X_base64decode_X'); + end + % update the width of the column to the header + colwidth(i) = max(colwidth(i), length(colname)); + header = [header pad(colname, colwidth(i)+1, 'left', ' '), ' |']; +end + +divider = repmat('-', size(header)); + +% divider = header; +% divider(divider~='|') = '-'; + +line = cell(numel(s),1); +for i=1:numel(s) + line{i} = '|'; + for j=1:numel(fn) + line{i} = [line{i} pad(s(i).(fn{j}),colwidth(j)+1,'left',' '), ' |']; + end +end + +table = cat(1, header, divider, line); diff --git a/external/fieldtrip/utilities/private/translate.m b/external/fieldtrip/utilities/private/translate.m index 4f9c0112..6eb184eb 100644 --- a/external/fieldtrip/utilities/private/translate.m +++ b/external/fieldtrip/utilities/private/translate.m @@ -44,7 +44,7 @@ % $Id$ if numel(f)~=3 - error('incorrect input vector'); + ft_error('incorrect input vector'); end H = [ diff --git a/external/fieldtrip/utilities/private/undobalancing.m b/external/fieldtrip/utilities/private/undobalancing.m index 6b5c555a..e91c7e3e 100644 --- a/external/fieldtrip/utilities/private/undobalancing.m +++ b/external/fieldtrip/utilities/private/undobalancing.m @@ -21,7 +21,7 @@ tmp = tra1*tra2; tmp = null(tmp); % nullspace after ft_componentanalysis and ft_rejectcomponent tmp = tmp*tmp'; % this is the part which was removed at some point - [ix,iy] = match_str(sens.balance.comp.labelorg, sens.balance.invcomp.labelnew); + [ix,iy] = match_str(sens.balance.comp.labelold, sens.balance.invcomp.labelnew); tra3(iy,iy) = (eye(numel(ix))+tmp(ix,ix))*tra1(iy,iy); sens.balance.invcomp.tra = tra3; % FIXME check whether this is robust @@ -49,7 +49,7 @@ end else - warning('cannot undo %s balancing in the gradiometer definition\n', sens.balance.current); + ft_warning('cannot undo %s balancing in the gradiometer definition\n', sens.balance.current); break end end diff --git a/external/fieldtrip/utilities/private/volumefillholes.m b/external/fieldtrip/utilities/private/volumefillholes.m index 574f88e1..8b96d00c 100644 --- a/external/fieldtrip/utilities/private/volumefillholes.m +++ b/external/fieldtrip/utilities/private/volumefillholes.m @@ -4,11 +4,8 @@ % % See also VOLUMETHRESHOLD, VOLUMESMOOTH -% check for any version of SPM -if ~ft_hastoolbox('spm') - % add SPM8 to the path - ft_hastoolbox('spm8', 1); -end +% ensure that SPM is available, needed for spm_bwlabel +hasspm = ft_hastoolbox('spm8up', 3) || ft_hastoolbox('spm2', 1); if nargin<2 inflate = false(size(input)+2); % grow the edges along each dimension @@ -43,10 +40,10 @@ for i=1:dim(3) slice=reshape(input(:,:,i),dim([1 2])); im = imfill(slice,8,'holes'); - output(:,:,3) = im; + output(:,:,i) = im; end otherwise - error('invalid dimension along which to slice the volume'); + ft_error('invalid dimension along which to slice the volume'); end % switch end % if nargin diff --git a/external/fieldtrip/utilities/private/volumeflip.m b/external/fieldtrip/utilities/private/volumeflip.m index bd79d479..7f753a53 100644 --- a/external/fieldtrip/utilities/private/volumeflip.m +++ b/external/fieldtrip/utilities/private/volumeflip.m @@ -1,15 +1,16 @@ function [volume, flipvec] = volumeflip(volume, flipvecin) +% VOLUMEFLIP +% +% See also VOLUMEPERMUTE + if nargin<2 flipvecin = 'auto'; end % do a low-level check on the input data -if ~isfield(volume, 'transform'), error('the input volume needs a transformation matrix'); end -if ~isfield(volume, 'dim'), error('the input volume needs a dim field'); end - -if isfield(volume, 'outside') -end +if ~isfield(volume, 'transform'), ft_error('the input volume needs a transformation matrix'); end +if ~isfield(volume, 'dim'), ft_error('the input volume needs a dim field'); end isrighthanded = det(volume.transform(1:3,1:3))>0; @@ -18,21 +19,21 @@ switch flipvecin case {'left' 'lefthanded'} if isrighthanded - warning('left-handed axes system is requested, performing flip'); + ft_warning('left-handed axes system is requested, performing flip'); flipvecin = [1 0 0]; else flipvecin = [0 0 0]; end case {'right' 'righthanded'} if ~isrighthanded - warning('right-handed axes system is requested, performing flip'); + ft_warning('right-handed axes system is requested, performing flip'); flipvecin = [1 0 0]; else flipvecin = [0 0 0]; end case 'auto' otherwise - error('unsupported option specified'); + ft_error('unsupported option specified'); end end @@ -67,7 +68,7 @@ if flipvec(m) % get the reflection matrix - flipmat = eye(4); flipmat(m,m) = -1; flipmat(m,4) = dim(m)+1; + flipmat = eye(4); flipmat(m,m) = -1; flipmat(m,4) = dim(m)+1; for k = 1:numel(fnames) volume = setsubfield(volume, fnames{k}, flipdim(getsubfield(volume, fnames{k}), m)); end diff --git a/external/fieldtrip/utilities/private/volumepermute.m b/external/fieldtrip/utilities/private/volumepermute.m index 750037ec..eddd068e 100644 --- a/external/fieldtrip/utilities/private/volumepermute.m +++ b/external/fieldtrip/utilities/private/volumepermute.m @@ -1,11 +1,12 @@ function [volume, permutevec] = volumepermute(volume, permutevec) -% do a low-level check on the input data -if ~isfield(volume, 'transform'), error('the input volume needs a transformation matrix'); end -if ~isfield(volume, 'dim'), error('the input volume needs a dim field'); end +% VOLUMEPERMUTE +% +% See also VOLUMEFLIP -if isfield(volume, 'outside') -end +% do a low-level check on the input data +if ~isfield(volume, 'transform'), ft_error('the input volume needs a transformation matrix'); end +if ~isfield(volume, 'dim'), ft_error('the input volume needs a dim field'); end % define some variable locally T = volume.transform; @@ -26,12 +27,13 @@ permutevec = 'auto'; end -if ischar(permutevec) +if isequal(permutevec, 'auto') % determine the order of permutation to make the transformatiom matrix approximately diagonal [dum, m1] = max(abs(T(1,1:3))); [dum, m2] = max(abs(T(2,1:3))); - [dum, m3] = max(abs(T(3,1:3))); - permutevec = [m1 m2 m3]; + % [dum, m3] = max(abs(T(3,1:3))); + [dum, m3] = setdiff(1:3, [m1 m2]); % whichever dimension remains + permutevec = [m1 m2 m3]; end if ~all(permutevec==[1 2 3]) diff --git a/external/fieldtrip/utilities/private/volumesmooth.m b/external/fieldtrip/utilities/private/volumesmooth.m index 99e822ff..631e7271 100644 --- a/external/fieldtrip/utilities/private/volumesmooth.m +++ b/external/fieldtrip/utilities/private/volumesmooth.m @@ -4,17 +4,15 @@ % % See also VOLUMETHRESHOLD, VOLUMEFILLHOLES +% ensure that SPM is available, needed for spm_smooth +hasspm = ft_hastoolbox('spm8up', 3) || ft_hastoolbox('spm2', 1); + if nargin==3 fprintf('smoothing %s with a %d-voxel FWHM kernel\n', str, fwhm); end -% check for any version of SPM -if ~ft_hastoolbox('spm') - % add SPM8 to the path - ft_hastoolbox('spm8', 1); -end - % don't touch the input, make a deep copy output = input+0; + % the mex files underneath the spm function will change the input variable spm_smooth(output, output, fwhm); diff --git a/external/fieldtrip/utilities/private/volumethreshold.m b/external/fieldtrip/utilities/private/volumethreshold.m index ddd18aa0..830b3203 100644 --- a/external/fieldtrip/utilities/private/volumethreshold.m +++ b/external/fieldtrip/utilities/private/volumethreshold.m @@ -6,15 +6,23 @@ % % See also VOLUMEFILLHOLES, VOLUMESMOOTH -% check for SPM8 or later, add to the path if not present -ft_hastoolbox('spm8up', 1); +if nargin<2 || isempty(thresh) + thresh = 0; +end +if nargin<3 || isempty(str) + str = 'volume'; +end + +% ensure that SPM is available, needed for spm_bwlabel +hasspm = ft_hastoolbox('spm8up', 3) || ft_hastoolbox('spm2', 1); % mask by taking the negative of the segmentation, thus ensuring % that no holes are within the compartment and do a two-pass % approach to eliminate potential vitamin E capsules etc. if ~islogical(input) - fprintf('thresholding %s at a relative threshold of %0.3f\n', str, thresh); + if nargin==2, ft_error('if the input volume is not a boolean volume, you need to define a threshold value'); end + if nargin==3, fprintf('thresholding %s at a relative threshold of %0.3f\n', str, thresh); end output = double(input>(thresh*max(input(:)))); else % there is no reason to apply a threshold, but spm_bwlabel still needs a diff --git a/external/fieldtrip/utilities/removefields.m b/external/fieldtrip/utilities/removefields.m index 7920bdb1..0415b163 100644 --- a/external/fieldtrip/utilities/removefields.m +++ b/external/fieldtrip/utilities/removefields.m @@ -38,7 +38,7 @@ if ischar(fields) fields = {fields}; elseif ~iscell(fields) - error('fields input argument must be a cell array of strings or a single string'); + ft_error('fields input argument must be a cell array of strings or a single string'); end remove = intersect(fieldnames(s), fields); diff --git a/external/fieldtrip/utilities/renamefields.m b/external/fieldtrip/utilities/renamefields.m index 0a69ed8f..008c7c9f 100644 --- a/external/fieldtrip/utilities/renamefields.m +++ b/external/fieldtrip/utilities/renamefields.m @@ -3,7 +3,7 @@ % RENAMEFIELDS renames a selection of the fields in a structure % % Use as -% b = renamefields(a, old, new); +% b = renamefields(a, old, new) % which renames the fields with the old name to the new name. Fields that % are specified but not present will be silently ignored. % @@ -43,14 +43,16 @@ end if length(old)~=length(new) - error('the number of field names does not match between old and new'); + ft_error('the number of field names does not match between old and new'); end % keep the fields that were not mentioned b = keepfields(a, setdiff(fieldnames(a), old)); % copy the fields over with their new name for i=1:length(old) - if isfield(a, old{i}); - b.(new{i}) = a.(old{i}); + if isfield(a, old{i}) + for j=1:numel(b) + b(j).(new{i}) = a(j).(old{i}); + end end end diff --git a/external/mne/fiff_define_constants.m b/external/mne/fiff_define_constants.m index b163c74e..0cd2510d 100644 --- a/external/mne/fiff_define_constants.m +++ b/external/mne/fiff_define_constants.m @@ -102,8 +102,7 @@ FIFF.FIFFB_SMSH_RAW_DATA = 119; FIFF.FIFFB_SMSH_ASPECT = 120; FIFF.FIFFB_HPI_SUBSYSTEM = 121; -FIFF.FIFFB_EPOCHS = 122; -FIFF.FIFFB_ICA = 123; + FIFF.FIFFB_PROJ = 313; FIFF.FIFFB_PROJ_ITEM = 314; FIFF.FIFFB_MRI = 200; @@ -148,6 +147,17 @@ FIFF.FIFF_NAME = 233; FIFF.FIFF_DESCRIPTION = FIFF.FIFF_COMMENT; % +% HPI result +% +FIFF.FIFF_HPI_COIL_MOMENTS = 240; +FIFF.FIFF_HPI_FIT_GOODNESS = 241; +FIFF.FIFF_HPI_FIT_ACCEPT = 242; +FIFF.FIFF_HPI_FIT_GOOD_LIMIT = 243; +FIFF.FIFF_HPI_FIT_DIST_LIMIT = 244; +FIFF.FIFF_HPI_COIL_NO = 245; +FIFF.FIFF_HPI_COILS_USED = 246; +FIFF.FIFF_HPI_DIGITIZATION_ORDER = 247; +% % Pointers % FIFF.FIFFV_NEXT_SEQ = 0; @@ -286,6 +296,10 @@ % FIFF.FIFFB_MNE_CTF_COMP = 370; FIFF.FIFFB_MNE_CTF_COMP_DATA = 371; +FIFF.FIFFB_MNE_DERIVATIONS = 372 + +FIFF.FIFFB_MNE_EPOCHS = 373; +FIFF.FIFFB_MNE_ICA = 374; % % Fiff tags associated with MNE computations (3500...) % diff --git a/external/mne/fiff_read_bad_channels.m b/external/mne/fiff_read_bad_channels.m index 5f427460..759c9cfe 100644 --- a/external/mne/fiff_read_bad_channels.m +++ b/external/mne/fiff_read_bad_channels.m @@ -36,7 +36,7 @@ node = fiff_dir_tree_find(node,FIFF.FIFFB_MNE_BAD_CHANNELS); -bads = []; +bads = {}; if ~isempty(node) tag = find_tag(node,FIFF.FIFF_MNE_CH_NAME_LIST); if ~isempty(tag) diff --git a/external/mne/fiff_read_epochs.m b/external/mne/fiff_read_epochs.m index 8acf2acd..3c96381a 100644 --- a/external/mne/fiff_read_epochs.m +++ b/external/mne/fiff_read_epochs.m @@ -40,7 +40,7 @@ error(me,'Could not find epochs data'); end -ep = fiff_dir_tree_find(meas, FIFF.FIFFB_EPOCHS); +ep = fiff_dir_tree_find(meas, FIFF.FIFFB_MNE_EPOCHS); if length(ep) == 0 fclose(fid); error(me,'Could not find epochs data'); diff --git a/external/mne/fiff_read_events.m b/external/mne/fiff_read_events.m index e3511ffc..bc753efb 100644 --- a/external/mne/fiff_read_events.m +++ b/external/mne/fiff_read_events.m @@ -20,7 +20,7 @@ me='MNE:fiff_read_events'; -if nargin ~= 2 & nargin ~= 1 +if nargin ~= 2 && nargin ~= 1 error(me,'Incorrect number of arguments'); end diff --git a/external/mne/fiff_read_hpi_result.m b/external/mne/fiff_read_hpi_result.m new file mode 100644 index 00000000..5c499541 --- /dev/null +++ b/external/mne/fiff_read_hpi_result.m @@ -0,0 +1,69 @@ +function [ res ] = fiff_read_hpi_result(name) + +% +% [ res ] = fiff_read_hpi_result(name) +% +% Read the HPI result block from a measurement file +% + + + +global FIFF; +if isempty(FIFF) + FIFF = fiff_define_constants(); +end + +me='MNE:fiff_read_hpi_result'; + +if nargin ~= 1 + error(me,'Incorrect number of arguments'); +end + +[ fid, tree ] = fiff_open(name); + +hpi = fiff_dir_tree_find(tree,FIFF.FIFFB_HPI_RESULT); + +k = 0; +for p = 1:hpi.nent + kind = hpi.dir(p).kind; + pos = hpi.dir(p).pos; + switch kind + case FIFF.FIFF_DIG_POINT + k = k + 1; + tag = fiff_read_tag(fid,pos); + res.dig(k) = tag.data; + res.dig(k).coord_frame = FIFF.FIFFV_COORD_DEVICE; + case FIFF.FIFF_HPI_DIGITIZATION_ORDER + tag = fiff_read_tag(fid,pos); + res.dig_order = tag.data; + case FIFF.FIFF_HPI_FIT_GOODNESS + tag = fiff_read_tag(fid,pos); + res.goodness = tag.data; + case FIFF.FIFF_HPI_COILS_USED + tag = fiff_read_tag(fid,pos); + res.used = tag.data; + case FIFF.FIFF_HPI_FIT_GOOD_LIMIT + tag = fiff_read_tag(fid,pos); + res.accept_limit = tag.data; + case FIFF.FIFF_HPI_FIT_DIST_LIMIT + tag = fiff_read_tag(fid,pos); + res.dist_limit = tag.data; + case FIFF.FIFF_HPI_FIT_ACCEPT + tag = fiff_read_tag(fid,pos); + res.accepted = tag.data; + case FIFF.FIFF_HPI_COIL_MOMENTS + tag = fiff_read_tag(fid,pos); + res.moments = tag.data; + case FIFF.FIFF_COORD_TRANS + tag = fiff_read_tag(fid,pos); + res.trans = tag.data; + end +end +res.coord_frame = FIFF.FIFFV_COORD_DEVICE; + +fclose(fid); + +return; + +end + diff --git a/external/mne/fiff_read_meas_info.m b/external/mne/fiff_read_meas_info.m index 4ab269cb..6c589459 100644 --- a/external/mne/fiff_read_meas_info.m +++ b/external/mne/fiff_read_meas_info.m @@ -70,11 +70,11 @@ me='MNE:fiff_read_meas_info'; -if nargin ~= 2 & nargin ~= 1 +if nargin ~= 2 && nargin ~= 1 error(me,'Incorrect number of arguments'); end -if nargin == 1 & nargout == 2 +if nargin == 1 && nargout == 2 error(me,'meas output argument is not allowed with file name specified'); end @@ -143,6 +143,9 @@ elseif cand.from == FIFF.FIFFV_MNE_COORD_CTF_HEAD && ... cand.to == FIFF.FIFFV_COORD_HEAD ctf_head_t = cand; + elseif cand.from == FIFF.FIFFV_COORD_HEAD && ... + cand.to == FIFF.FIFFV_COORD_DEVICE + dev_head_t = fiff_invert_transform(cand); end end end diff --git a/external/mne/fiff_read_raw_segment.m b/external/mne/fiff_read_raw_segment.m index 11075fb4..6d58aec2 100644 --- a/external/mne/fiff_read_raw_segment.m +++ b/external/mne/fiff_read_raw_segment.m @@ -75,8 +75,8 @@ if from > to error(me,'No data in this range'); end -fprintf(1,'Reading %d ... %d = %9.3f ... %9.3f secs...', ... - from,to,from/raw.info.sfreq,to/raw.info.sfreq); +%fprintf(1,'Reading %d ... %d = %9.3f ... %9.3f secs...', ... +% from,to,from/raw.info.sfreq,to/raw.info.sfreq); % % Initialize the data and calibration vector % @@ -120,7 +120,7 @@ mult = sparse(mult); end -if isempty(fopen(raw.fid)) +if raw.fid < 0 || isempty(fopen(raw.fid)) fid = fopen(raw.info.filename,'rb','ieee-be'); if (fid < 0) error(me,'Cannot open file %s',raw.info.filename); @@ -210,7 +210,7 @@ % Now we are ready to pick % picksamp = last_pick - first_pick + 1; - if picksamp > 0 + if picksamp >= 0 data(:,dest:dest+picksamp-1) = one(:,first_pick:last_pick); dest = dest + picksamp; end @@ -219,7 +219,7 @@ % Done? % if this.last >= to - fprintf(1,' [done]\n'); + %fprintf(1,' [done]\n'); break; end end diff --git a/external/mne/fiff_setup_read_raw.m b/external/mne/fiff_setup_read_raw.m index a692ea79..5d9d41b1 100644 --- a/external/mne/fiff_setup_read_raw.m +++ b/external/mne/fiff_setup_read_raw.m @@ -67,7 +67,7 @@ % % Open the file % -fprintf(1,'Opening raw data file %s...\n',fname); +%fprintf(1,'Opening raw data file %s...\n',fname); [ fid, tree ] = fiff_open(fname); % % Read the measurement info @@ -79,17 +79,27 @@ raw = fiff_dir_tree_find(meas,FIFF.FIFFB_RAW_DATA); if isempty(raw) raw = fiff_dir_tree_find(meas,FIFF.FIFFB_CONTINUOUS_DATA); - if allow_maxshield - raw = fiff_dir_tree_find(meas,FIFF.FIFFB_SMSH_RAW_DATA); - if isempty(raw) - error(me,'No raw data in %s',fname); - end - else - if isempty(raw) - error(me,'No raw data in %s',fname); - end +end +% +% Special handling of data recorded with Internal Active Shielding +% +raw = fiff_dir_tree_find(meas,FIFF.FIFFB_RAW_DATA); +if isempty(raw) + raw = fiff_dir_tree_find(meas,FIFF.FIFFB_CONTINUOUS_DATA); +end +if isempty(raw) && allow_maxshield + raw = fiff_dir_tree_find(meas,FIFF.FIFFB_SMSH_RAW_DATA); + if ~isempty(raw) + disp([10 '--------' 10 ... + 'WARNING: This file contains raw Internal Active Shielding data. It may be distorted.' 10 ... + 'Elekta recommends it be run through MaxFilter to produce reliable results.' 10 ... + 'Consider closing the file and running MaxFilter on the data.' 10 ... + '--------' 10]); end end +if isempty(raw) + error(me,'No raw data in file'); +end % % Set up the output structure % @@ -212,7 +222,7 @@ data.first_samp,data.last_samp,... double(data.first_samp)/data.info.sfreq,... double(data.last_samp)/data.info.sfreq); -fprintf(1,'Ready.\n'); +%fprintf(1,'Ready.\n'); fclose(data.fid); data.fid = -1; return; diff --git a/external/mne/fiff_write_int_matrix.m b/external/mne/fiff_write_int_matrix.m index dd747207..36d12543 100644 --- a/external/mne/fiff_write_int_matrix.m +++ b/external/mne/fiff_write_int_matrix.m @@ -15,7 +15,7 @@ function fiff_write_int_matrix(fid,kind,mat) % License : BSD 3-clause % % -% $Id: fiff_write_int_matrix.m 8776 2013-11-14 09:04:48Z roboos $ +% $Id$ % % diff --git a/external/mne/mne_babyMEG_dig_trig.m b/external/mne/mne_babyMEG_dig_trig.m new file mode 100644 index 00000000..e9f7d351 --- /dev/null +++ b/external/mne/mne_babyMEG_dig_trig.m @@ -0,0 +1,251 @@ +function mne_baby_meg_dig_trig(infile,outfile,threshold,invert,include,want_eeg) +% +% function mne_baby_meg_dig_trig(infile,outfile,threshold,invert,want_eeg); +% +% Read and write raw data in 60-sec blocks +% + +% +% Author : Matti Hamalainen, MGH Martinos Center +% License : BSD 3-clause +% + + +global FIFF; +if isempty(FIFF) + FIFF = fiff_define_constants(); +end +% +me = 'MNE:mne_baby_meg_dig_trig'; +% +if nargin < 2 + error(me,'Incorrect number of arguments'); +end +if nargin < 3 + threshold = 4.8; +end +if nargin < 4 + invert = false; +end +if nargin < 5 + include = []; +end +if nargin < 6 + want_eeg = true; +end +% +% Setup for reading the raw data +% +try + raw = fiff_setup_read_raw(infile); +catch + error(me,'%s',mne_omit_first_line(lasterr)); +end +% +%raw.info.projs = []; +% +% Set up pick list: MEG + STI 014 - bad channels +% +% +want_meg = true; +want_stim = false; +if isempty(include) + include{1} = 'TRG001'; + include{2} = 'TRG002'; + include{3} = 'TRG003'; + include{4} = 'TRG004'; + include{5} = 'TRG005'; + include{6} = 'TRG006'; + include{7} = 'TRG007'; + include{8} = 'TRG008'; +end +try + picks = fiff_pick_types(raw.info,want_meg,want_eeg,want_stim,include,[]); +catch + error(me,'%s (channel list may need modification)',mne_omit_first_line(lasterr)); +end + +fprintf(1,'Using threshold %.3f\n',threshold); +if invert + fprintf(1,'Invert polarity\n'); +else + fprintf(1,'Keep polarity\n'); +end +try + dtrig = get_event_ch(infile,include,true,threshold,invert); +catch + error(me,'%s',mne_omit_first_line(lasterr)); +end +fprintf(1,'Digital trigger channel data ready.\n'); +% +% +% Only one trigger channel remains and it will be called DTRG001 +% +picksout = picks(1:end-length(include)+1); +raw.info.chs(picksout(end)).ch_name = 'DTRG001'; +[outfid,cals] = fiff_start_writing_raw(outfile,raw.info,picksout); +% +% Set up the reading parameters +% +from = raw.first_samp; +to = raw.last_samp; +quantum_sec = 10; +quantum = ceil(quantum_sec*raw.info.sfreq); +% +% To read the whole file at once set +% +%quantum = to - from + 1; +% +% +% Read and write all the data +% Replace the trigger channels with the single digital trigger channel +% +first_buffer = true; +for first = from:quantum:to + last = first+quantum-1; + if last > to + last = to; + end + try + [ data, times ] = fiff_read_raw_segment(raw,first,last,picks); + catch + fclose(raw.fid); + fclose(outfid); + error(me,'%s',mne_omit_first_line(lasterr)); + end + % + % You can add your own miracle here + % + fprintf(1,'Writing...'); + if first_buffer + first_first = first; + if first > 0 + fiff_write_int(outfid,FIFF.FIFF_FIRST_SAMPLE,first); + end + first_buffer = false; + end + data(end-length(include)+1,:) = dtrig(first-first_first+1:last-first_first+1); + fiff_write_raw_buffer(outfid,data(1:end-length(include)+1,:),cals); + fprintf(1,'[done]\n'); +end + +fiff_finish_writing_raw(outfid); + +return; + + + function [comb] = get_event_ch(rawname,include,all,threshold,invert) + % + % get_event_ch(rawname,include,all,threshold) + % + % rawname Name of the raw data file to scan + % include Stimulus channel names to combine + % + % This defaults to STI 001...STI 006 + % + % all If true, include all trigger line transitions in the file + % instead of the leading edges only + % threshold Threshold for detection of transition between inactive and active states + % + % Create both a fif and eve format event file combining STI 001...STI 006 + % This function facilitates processing of Neuromag 122 data which do not + % contain a composite trigger channel + % + % + + % + % Author : Matti Hamalainen, MGH Martinos Center + % License : BSD 3-clause + % + % Revision 1.4 2009/03/12 11:04:22 msh + % Included a threshold parameter + % + % Revision 1.3 2009/03/09 19:24:16 msh + % Fixed errors in making the event files and allowed the text event file + % not to be specified + % + % Revision 1.2 2009/01/04 14:45:35 msh + % The me string was wrong. + % + % Revision 1.1 2008/10/31 13:07:04 msh + % Added mne_make_combined_event_file function + % + % + + % + me='MNE:get_event_ch'; + % + % Setup for reading the raw data + % + try + raw = fiff_setup_read_raw(rawname); + catch + error(me,'%s',mne_omit_first_line(lasterr)); + end + % + % Set up pick list + % + if nargin < 2 || isempty(include) + include{1} = 'STI 001'; + include{2} = 'STI 002'; + include{3} = 'STI 003'; + include{4} = 'STI 004'; + include{5} = 'STI 005'; + include{6} = 'STI 006'; + end + if nargin < 3 + all = false; + end + if nargin < 4 + threshold = 0.1; + end + want_meg = false; + want_eeg = false; + want_stim = false; + % + picks = fiff_pick_types(raw.info,want_meg,want_eeg,want_stim,include,raw.info.bads); + + from = raw.first_samp; + to = raw.last_samp; + % + % Read a data segment + % times output argument is optional + % + try + [ data, times ] = fiff_read_raw_segment(raw,from,to,picks); + catch + fclose(raw.fid); + error(me,'%s',mne_omit_first_line(lasterr)); + end + fprintf(1,'Read %d samples of trigger inputs.\n',size(data,2)); + % + % Remember to close the file descriptor + % + % + % Make the combined channel + % + samples=[from:to]; + if invert + comb=zeros(1,size(data,2)); + for j = 1:size(data,1) + for k = 1:size(data,2) + if data(j,k) < threshold + data(j,k) = 1; + comb(k) = comb(k) + 2^(j-1); + end + end + end + else + comb=zeros(1,size(data,2)); + for j = 1:size(data,1) + for k = 1:size(data,2) + if data(j,k) > threshold + data(j,k) = 1; + comb(k) = comb(k) + 2^(j-1); + end + end + end + end + + return; + diff --git a/external/mne/mne_load_coil_def.m b/external/mne/mne_load_coil_def.m index dcb4f25f..9e39953b 100644 --- a/external/mne/mne_load_coil_def.m +++ b/external/mne/mne_load_coil_def.m @@ -174,6 +174,8 @@ % 4002 Magnes WH3600 gradiometer size = 18.00 mm base = 50.00 mm % 5001 CTF axial gradiometer size = 18.00 mm base = 50.00 mm % 7001 BabySQUID I axial gradiometer size = 6.0 mm base = 50 mm +% 7002 BabyMEG magnetometer +% 7003 BabyMEG reference magnetometer FV = struct('faces',[],'vertices',[]); % standard convention @@ -204,7 +206,7 @@ LongSide = CoilDef.size*1000; % mm, length of one side FV.vertices = [-1 1 0;1 1 0;1 -1 0; -1 -1 0]*LongSide/1000/2; FV.faces = [1:length(FV.vertices)]; - case {4001,4003,5002} + case {4001,4003,5002,7002,7003} % round magnetometer Radius = CoilDef.size*1000/2; % mm, radius of coil Len_cir = 15; % number of points for circle diff --git a/help/index.html b/help/index.html index 3cad9d89..762c53af 100644 --- a/help/index.html +++ b/help/index.html @@ -47,7 +47,7 @@

    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 ks0<2}J4%-Xp0-bGBVgLXD literal 152177 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�Z&WmlY9Ie>t^@eWRiXG`eJAvJT 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%0D>T4&2+6U#$E;^!}GTzbVHh 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 literal 152008 zcmb?^349bq_J0paAadAI14b8d)KP;VMgdI(G$9G}z(k{f;0YKKVV6rX1E?Hl~ySOvUL*CifEkAs3Df_UWr{l4m+=^W#_zt2C)bXV1@ zSFc{ZdiAR6RrTW1z=%#BkLLWPX_sgWtvX4?6xs>KXGxesEnn-R6>5F7UkGf54b#!1 z_Ma-B^VBr2fHAf+{!RKorBC|cG>Lbfk9U)x)@(nWe4XrkHFmxlJD>9`Bmn-LXQm2j z>3H(rHdS1^r_Y9So`mIJ`JUhuzF#+8Wo-MLa;$)9&eO?v1@f_eKld-o2E5WPFBM-_ z+Vyjuc6Fp~*}##8esL<&5oq<~+Wf}VR);Q1;A zd~S;P_fz2M1^ABm`AG^q|4tEq81*_%`?3YawECNd(D7P#ZPm#tdM@DPZ{oz8X3Uy7 zu{t<;PH^HxZK8i{*~BT8b1H9|RvoOIGq$XF`mC9iV<+D@y;7xhoHDUu{^W^O(`HVd zKJ8Wjj+#61N*hD*^vTuLmDSpe%K0NgGb@7AX3gY#>6|%b)i;fuAJk^dA6Xe36Pz<` z=1mhX%F9EzcuwWyU?rkL6~VH}NSWU%p=4GF)U-+fhVnV?oIs{k2j>K5O+oCK%HW7; zmD8sPma3a7gVkD9<*X|F%$YN5j#f2q&a_~qRy8{mtdQSoWSufA6x6EbR3aW3DnRm# zirKdiXT{{|%8D7Y`HKG~#!i?jp_zo6IB{C_tcrqyiPhB=lV?^TToJrwcICw2tkCS) zm2)OepH(3_iDx#d9;}jJ_3WAQoE*dhtpJ2G?PL&8T?uYYp3c1ZH+gz++KftVay590 z=Zs&;!zt)SRm9D6fVrw_dZ>D;RDtCoj)lyr0KIc6=S`al9#zhmF>7umql2@iYp8MM z%(>d!D!c576G6(%SwuNm8W2?==PKt<1CuJI&#JBjCc#iOYj)+#3kQ*Plc#7^)s>aM znx$0*D?v4}t9+oHl>mr55kC`%nLZ^nTbn-Z#u@VmRL_!^%Ea5`pc9AZfD4%l9#!<~ zmk7=dPGzYK=P|iLr7&({W##ON!8tb#fapyId1a*&w2=Y-@ZyOV47gyx;Kcj+gA%U; z6K@yUT_p|Hq56*z>4|sRjA>eigp+ScNGF&3+1bwRj!V81i^9s^E?TAy-39ii>bM?F z{rB~^|Mbvq?TvpQ+kG0U0Z<<8@hdcqY5b#J;2(3X!nyulGqo-tlsHeAHm!#SUL0?SPn2-F*4qxN^3oFcocW3~BW(^Pw2 z;=~u)@$=inJK?#Qxi(!rI=}@yF6o#b0Kd_~Y&PtTyoud`_GA6K!~JoA};# zd~TcgGwk@hHu3%K`205U1MT?2Hu2w_r|M_4iLcF5@#Ssee=$hKPiPZA?E)1)sZD&v zg(`k(oA_mR{OmUIBkj&HzfJsh8@}Fd7tWOuZG-o1u6PJw;%~bvp7P}UHM`>7Qzy$6 zpW^`IdB7EKvp`ahxZ;Pq;B%UloOD5)-4!I&>xySzbpCQ(@y?u;X?d=A_q;ye6;EC` ze}%4imhJo*u6Q@!%3bkY9bh~sxZ)F2e#B35#dmkXPj$tk!zTV_yW;Jsxunf^#p?-Z zOnqJPZu{j9SG;@Pv)mPbf(y?ISG=RMn7q;z-^&I6xGVldSNtkhyjvdDx#I1m8Oc@e zinmpa#BX!O|H6fTyDOeL*ZJG!ia*7P#IxBI-^Ueix#CZC#UF6RdtLEIT=BMMQ>h;& z<@R(Je5Nb@3|D-XE8gdd&vC_{>5BKd;?Hu$=epw0cE#tp;&WZ``L6iBuJ}S%{5h_8 z!xi7p6<_X(=Um(Qo8XE+*NMb)k}H0ID}Jgg-d3rSI@=X*t5k`f?}|U)g{Q_9Z>v;E zy~7nh&;`HT6+hS&zrq!7t4>K>>56yk5GFkCiqCi9S>=i^aK*24#b4}-uXn`{am8Wa5q@rADV1FrZYSNsuIe6cHD`zR^@C9ZfQyf4#; zWSsKyX_`@2AIz}ANHoG*GB>+`@Y*tXI6zv?EWxjSY9Zbjo=Tuta|`~?yqIAR!`mf% z0mB?3V)YU}hv77aS4sGEhB+j}R!aC}hB*|(mP`0}hB*YpY9!p1VXFSvYzcQ_m?}Ru zNy0~8LYPBjtX#rhF-+ATE0pkO3{&OD@+ABb!&LP#uY})Ym?}P&CE=Y6Q?y7^W(Z)kyf)3{!>2W=nV}!&Kd|NfN%5VXEv{xrFC1OjR8#l<+SZrizZ`N%%&F zshVS6317o7RdOs#!dEg(RUFeKJc?ne;Mjp5SpVS+dl_z)@Wl*M$YR?id;!B$wXu2$ zpTqDO46l;#=?qh~##T!BWQM6yW6LFcJi}C_u^I_?Wtb{7He14-7^dosO_K1@Z3t6k z#>yr96~k1Ou|f%d#xPZ6EKkB8F-+AM^Gf(VhN%)`SrXpKFjZkplkm$7Qw7Ejd@t?K zFjZfyS;FfXrpk+Lm+;dJQ`N=lCHz;0sp4X*B>V@4X>!F@O86m$sp?|OC43LVRB^Ey z3ICd5s(#|R%ec5Y9oiyyZtb#ct~EzMQ>sZc1_Z?59s0R7Zj zpnwXA4m(cr5ALe+|H%9eKc*Sx0i(gX)bKPKJAMr209k{Lth+*{^0&oTGpyk?2v_KA zBRuRuWB^I#o?v$rbMofXH0yUD*)q^9*EeRY0HEh!dwOD(0Ez~V`10WUMD8H{= zevBwvwqGy$qG){4RYl{9#*Q0fEZH{|YRxc%zFfonCpdB---BR@FAwiA`#m4;pV;q( zc>lnDH^N6fLS`Hh)~AppBYK^0(t1r${@aKw)GW4-5gmM10nzTZbgbnPy%!2O#2P-p ztWQYRvA(N}XwWyoh%E4Vt+T$>G{4zsL<7FO_37YxWED4PHUhV1y@w2bbBjN`fpMB% z%O%!zc+;Nej}gr-^ha*bM4A!pzkNO9HZY^gJza8dHOwaKxT7F1G7jUz&iUP{^!@c; z8TvV!;wKsA4r50w{E^2vW``5q@RdHH{ww|J65oWc^y9R)SbMP&s9GlRKKJc^jdw!E zs~34RVm88Cfn>k+HHibpthPlx0jB!RCKgoAf&i1Vft6&gFUavo(3b;Lodagfi1z#i z5S#xFn0u`qLRSDpMtgQm#6EAwW+C>w3mw=;5gRbSMclqb+;0#U-s~|dHv5O%PTuQF z?}i3dO;&g;8aGnn%MF-bW62gu*0t9cT~~B{(G5itH&-={EChv3Bg=)-rjZ7pn{7el zP;Gu^n1`hmjiv@jam!bKHxBPG!ZA;94y4m>eyy(^Q&?5EGjt+E>M; z5kFO5yVHmcdW*3}7U`PT0#D<|d}q@WP1`7n|1Z4Xo= z9mH>b5{M4_Y=}pT7dzR=q`ycu(iH3$Fh32LEzhyzk(PS>o=ttX>l^Be%*HCDca!w} z))|xwRPQo~3_5$as?xe|f*D5L`=Q798j{x&P^l0qB|NhtnJD*Ekk>{C%x%Wu?MB%0 z_&uel&3@~bBxlJMwt`E-5?amt4zf}eUR(&xz;@O*&YPgG9iOLf9NC)vtlBf(JmA@f z>&ar_0Z1wz1gXgo`TumIG|H}TP-0VYIRjPU+X}Vds2A}H?r$ac0~LoTSfe6C51{(i zL!{3ROI^?p(ISa@7@p$t@K%q$wz#msTD*zHlbufSzr@a&bvwl%TwI<`B5y(QPE9u( zk&)oSh;n`H$igaf1bRe$@J4q(I^;LM*Vi5~8uq54qbwWkjcSd~0R>OlKp>2Um|Cq1TENtl-yrk}>;MqW&W>*5#CMt0axqJ;uD2Yt* zb&uzu50><`N(=VsmzDUs7nxh)8In@>zFt>Mtq^YXKq-tYEGamk-%ULM#D9H}+{sfS zSNSysU`vkE?$Dt!W}81a4E6`lmxc^fd~8HYDSgdGT}$vd>tbeQOjCL@XmqvXn;4Z1 z0`;(Z5~!(E+LWE@S`0TVYctSK;LkN8X`2mnn+Zl5Wv)Sb5PQ;7n~W8PXIoNz=NMFn z2RT?C)Q>}z)qnNDn1$BSc2J)!qdmb zGZc7?=)!J>`R;n@NNfzND`FcbqS@)H(I6M}Oj<@uj<8Y))$ZL)7yn z`o@narA7KvTS}t7&X8W%1ld_g8!^bWq}-%kXGr<`>e3;>Y;WBg5Zy3m#7c z2dSkfr|6E(sKy@X7^C9-qQ(-;A&bzuUESk%HL&=jp)BV4B~2haUpnB@*RZq2ykY-P zJU~r_m-)y_>wwkzJH~pvU&Hr5;9WsF5`Qcq*M{<#N~=JnI#PZh9r7RYGV!KFq9fdI zAQ4%!nd(oZI#T_tO6|qeeu-2^oF7E0Gyu%v(wu|()fAF_ykDHxNd;{SAQ4u zDhdONn6O`j0>+wBlHq-5kArCZO-8gkj6OELZ=1ex)&$6dV+U+)gzeT?;)BKeg%n9l ze}X##TH4nYdgCJ$cfFgqA`}-5bxi=z1F#>)HVT7E!|)}BoGsAQXx2zTFmde{LSU9? zSo1(t-8b`l>l?qJSyJ%!!V^JhJ*O?C)QF~U-z?0qf1!)>sF1Vy(~DZ!yBSO#nQIRS zG54!z|8+A(N*CPZvW*-}siT zCpo(S4zDs$@?fBRY^QvS5d&7~{hRbPJL4Hrn7Lgl#1W`tlJrcu6x_scM#d?J`X}Kd_lhb3*oA!;t6MI_`N2}QRa_> zNOO~@!n&P$-4c{y6Zy>{A-_srTb)<;&7xmQ?Fl!Jy3(~Pvy`TEA&AO~ZvF%Qrh zKZ2nwt++gzO*M)kVyB@$HO6arwi{+qR+2A&!UPX|$rip;=M{Xh_%Cs#*fCk422-3s zSNCHbz)?F5AECtYD6yfTxf2S~pBm{k(uPA|8byi%n8cm$@o400y}qWN#?@wU@(pV$ z#c736uuCOet72!ijkRq8NPCfq(Y=ddc7}j}mm{$FITGcJ$ifrD^9U?Rplox57tdTg zbMef>GY`*vJoE7^#FIj3;0YT{8Jc)PMU9wXgcs#&!F+u!vLr?7ioOu3)t!_`VTy&c z?pH#V|0&#zgn+uqG9dmi`#%ZxFwB2bLtcbtii67C*2m~m!n&jh3;We?9x~rzUxn-! zY+BG$l(e*ERZ)0>FHZ{%idTWlXjiA#4Bf6Y$g7`8L;W*8Iy%lnB=5n{!jeY8=7och z<1G#cewYjBXhXLL%r8`~2UM0ZlvRD>`_LA@6Z}AtC0x=smiVS3)SG2= zCj7}-FxPxfI>>(OeoV|*UT3I>TWASqgDk~^uHSL8G}hNS67corA_5v{ztvX>J{HHu zdBHAD_A{-kB~mQu>&|xaKZ^YR$WSab95MQp=J=z*I?ce;BFi%NQT=W9_`_SeRTZG> z`rTZpDnn1to+YN^S7eO^}9-;E&`Ef zd^KpeXmJZvbhzHbOaT+RHWu*2{RJNw`tVl_6U$#kQqzFh%mHb~XW?e7N?~p^)|Vge z%JmlXVJth9n4bmAA2EmXS*uZ5%sAM-*^G-0J9MT~=d-b{hINQHpQFqKFjvVT=a_5w zchYUZy0K{Y@Fo~RUyyaPBtGa>RjvD6ucf?EFy7b;l}^nUix8Rl6-jrXhy@QosGVjlB3gOJ#8q6v%36% zZcdr=>l?FuQ1@>s$d3T|GFDu(s+vlfwW*XeY8!?z08PL8Q_|2VD_c7dCsn9f1YWC! zE|wf!n6+MJ0wX|hV`+}2q+i64 z(o9TSyqTn2gbHhBi8UP0W+<|*Wd&b{Hbc|T(ALq`iR z#1SJ0MQyOb7Dsb8Nj0p$eJuU_Yz%bcF}l3GDzhLKJP*opryq7gmD#%-Bkag5&pK{s z#(P2F3O)#}4wy$V9(1R!?gZ739_C({zyv3!3G-a!z*>4s@X`$z*sPX`lr9t9!KkNcgCCUQYOkz9=Vbb&2;9$$)i5Nq}|5N7%}QH5ARR z!4AaBe?JZEOJ7bZTpjTT>oj1L6{mQbi1FJ2&u50d;bJT~MY=zCN7veyLVJ;a)IXSi zLbpJ4)m(`Ei(LCFdI5a_V~|*#SA+1n`Vzea`$C($LBIk92SXoYO$SrmtY8l;MdIbS z61}WB-nr-nuKFUJyDpb6`ej?3HglFooGyu;_(mXdW2V0L9QM96vZvi@CzhO|SG2&Y zy=yhl8BxqnqE})QWo&k*jfl|nHAYL#x4EI?8w*>sntXJgdkAMX#gD1^wr?n%(Mr#5 z54|C*V~fnKxl{|@Y`u=bzsTGw(M91OT7oyA;Xem2mF?TG2VHop-?I;^G=8jTpS)gH zKi7k;oD=yl(Ouv>2SW|ovB>MRW4DiBQH0YxG8VLMHLTJmg_suX!ElSd=+x-=Z)s;o z)9=B0{cs~~@bbT+MW7-M09E{y==dY8lW(?@cOcm?cU`+#=G4maI%t^hSXY;5+&h6z z;*L=c<&C=Zu~TW5szp8PzUG#e=cq`-M>^?sEAfJnE(cQGyWlJRuH^`SrC*~KSzf{b zfz^?78o$CS%A4rYcyj4vC)Zo%>RdND3#hSM)W1I70~mkl8me`~Au6 zK#Qdp$-cKwtL(d+ptPJ>oGA(q3&vs)iRo{c(5=v@>?O|YK7lC;x}J% z_8qD~UBGNS_*kL-U?cV(3iBI-zbLB79~0_dR5RZ*HgqN)ok~J|@Ia9#8j;~>o8eRO zgmE%_wkV$XNto-P?5P2iJygmT)rf%=wamn_a@%6})O`ZI}=++s-XYf&4Sc+&#h<& ztk9REPtU@u6kdb9O}&;WSP#>HRljQn0@T--THIrJxWBryH-_c&FkoY_n_xtXVY_YC zH)K(mpjm@ohL0W-+-GaJ=($e-I`&5pJG8%Ei}|D)9(G#?K??U=x$}e}9y)D{$6v7p z-LxhU9SWX~o6wj(9MCNoE+@d=8?c?HNcw^##p2jAf1~Ex{vq_(j)~USq}5_-+%U8&)*Whh1bYn~5^sV4mh#G`i>oR0{NlCfMYIQzNYV&`PWlcHy*=g674$ zp|e}``)J`cG^fQ+7Iw!^P>;me14L{JNV7Nx-4#J(DbBT@d3-u6Bu&MIcC?|QC)vTN_H(w1p09%88b0x7 zG==X_Z(JZLmjWg*qLsic*_Vs4S#~TBb0Pydr;(5K7CHBKl7+*)jZ%Y;Uw2HgCO0 zU(-9c_WjWNSbAawF+w!fW|Kw`Irx*4lwrM}*kE#CwrWpbeKH$riZv;~EjD0dJHTsg z!2bncQFLTW_=sm-SI#S*`vPhf+}dxwj$yLq1)*IF-eQ=TdmcsMw*aRR!K~J?6|E!h zu~#d@(bD#4T3N;G24>Y*ivi_gk&*Mk#(rqx7fyC)xPPzE5bsF>LN)<(sfyhS zF~V3+DRYdUb_Of!KR*z8(zl!~5xLLDB1{43rHQqlhDtLAA zF(Q3fO!5^Kyyk?qF6;$jUWOb9fmUA-v!29Y2XJwBbNi6%urC^YN+Q0Hi0O==s3G6Z zM7}RSb}A7@63AMGheq`{?DGWBs}4~746x)FnROa48Hq&uCY_-UkT zK?aDF++QU?ra2%`eQrZvRvYz=@XN{GO3I9eW>}2du{{W*Ha8HNl(~Vm=Dg#Y{nR-1 zRpB2zi>~y;GpH*p&1fl>BhqWiqEkw;4SVn0o|vFFaeno(ad>A{QBz4)i&t?FgA5l* zg9;t&@veb_k3%m7%z8?iEP-PVZiE+4(1KS$F^3nIYm0h`@&!Yzo){TlM+e5*OFY|& zeUGv1)`*41K8Wh9;gTT6&Oznu=-b|5|Fz=7gt>we2?Du9NCNfRD7d3Y>?@oCx`{;BALzg>5l4U17IY_=)C)CjaZY@K12~L; zX$mm@7MyToIuzlEKd2l$5?bL*AkH7;VWz`FGH{^Ei1{1`KpvMGhqgtInG--s{XW(35x4`9lF`P`q@)SC$poRKr%+;Hz5}{6du=E| z*CZ`Sx@NbcYc+fv$)Tkuw&hT7(v_Q_YpSAa_Rpm2JU3kn-&CU8F}(VJRvv(XSyQ$gZMbrvG@`Y>>3o{$u-~(&NNt}!PlP|H6a0s$g@lx2j+itIk|7&q_4r;tS%p>KpG3 zuNBv%THiKQ3X84K+Iy}0P>x|@qk8bC*eG`lL+e?|Y_DCs`#!oXHFvF)2JO8D)bD}2 zfujC7q$A=ZAW#vHBZ6B$kgQQg^cktRs@7<16hp7mVbQCKU7N^N#4_vN=T_`)>+9Fa zB0wpOSCNDld=@B&=Gcwj)_7;P!@DqnH%3$r-iKS`{qa3AzE-*uELFYsexgQ6nbN=d z=^MAxub9joCH%3i>idbtVeWH45}ybT%t~~N#}H*iRiCux*-n-AAZeLQbO`Du1Pyx- zQ(;xrUlAL7@iz$uPe2rC$`YE6#ak}l^jg??!skA)9lx{*_cCeGg{|2W!~QqfPM_vs z&n56`ZbFv6hOS|=7<&eGA;C*pW4g#;w3>%0j87#5`S0(#s+I?gwisLmZ*N-O&+*^} zmK}+-5R@J?9<|2M7i`HECd26O4+@th@ZA7>@so(8k5X+9Cz6U;)RHaK$8M`1p5?H} zs^E{lNUh$>_IoRX(VqtOLv}>wXDWYz+y4m?nu;l18Wvn(SEc*ld$2|AJivHA)~W!A zAIr=F1N(-aw@l69!T-S}8*m=3|*0fU`0JNXLR=sh1|i-7q1L=PEl7@mS$x zp1t%Ri;T-pbQ&A&q$J1|fWWxR1;~Z&l7}Th9wC->*AAatJ*~nEhhPjJ>!wbgIkR%Q zw?sA_$>Yhv$=6rmC7bR%Lhvso+mPv#Zv-H846}K?6}TAUMmTb_;W9MA**i8^m#)ByRPP$2;bVC6y=SD2%QK>*z>};|aCy&y zXGL^y2;D0HUvjb2X1v0o=Nk?^JK$Yr=c&0B+sS8On-jSQUuVOk82Dc&;U96sU##FS z2K+^C_#R34n+czGeO}FNB?OL+DFJXVH*oXI31UhJ936Zbd`3yzU<8ZQ>QpXPr}VqC zIYLEXd}AT;Q~i9-QzHf_PHecRy(su=!Y*Q z$SxJKUtCF+Uqe=4kpj!BgC_%?{5aE<-jC^KBctgE2dEJ?R7<+8vtcLBc65+?sddS| ze3a}rzrj9PATkT{imX#AKpQ3~*ZFdvN9jQKq)fB9)RjkR4I~`q_ghbGBgJYIPWJV~ zJ4&Kcx?$<@W2^?P0*-6-x?nm{4Su>iY29yCv8qrT^WE4cr@&Sey{2>D=IY=+@<>I&JUt#ZaCqiF#sfzEhT$muAv2UO&p34wv7&eq;M+W(lM=e4<2u=}>MF}Y0lhI*0DFCT=Vp9l+MPdlW zuy0942N=g*^Kvp3Z1Eo&=V!ZAQ+>R(lSg(Nxl!aEU z^%71oI9y6fd6JnB2kObO3dcH>frV}4iD6TO$S<*x-`o-M>HisdA#ixy$StgZ#CV|@ z625?jWRJ>L$n{zPV%&%C8m-0i1c=+hL(Adh*a;agSqWDN9JQp!J=eq*?AAx zfzht1R7ciKqStk6u{-n-z4kujqQf{gu8BS!=;6X=Zt|y%%x^4A2Tj;M^uxIiMNU>U zD$eu+dZ**A0Fn)-6BBCiG&up@BgbrPi5#{QxM2IBopdwI1tWq1k)^=Mz+O|jfu-y$ z>n%WpK@Ge!@arEkGEZN6Hpd7a#u|~OFD?C!W6ORkpo)*5r9?a4$A0#*pU2uy>|BF) zShH`24M#2M=ufWPwlY<4Fzb*ZeRctCk;EW$g0K;OSMUjd*8(hs;#o6sZ4l6DdY|pyBD>jjj*TT2uX6VbVfm}w$K;dPai1sonvX{f?R7SaQ7s@!lR8Ec>%{iXI6br66Bj71cbdb)5ZcMnl&p4@&-ZR zZ7qZ8ert;g-e4=*XBnhJuv#AyNp@_mJx&h@L4P{K3`_+ zSh9n?CRMOa+9*)ieERZxXP-M`9aU>8qaeI57i$|6bNyIa)}LCt3!w0|)N9u>4|_FN zmofttu~E_Vzp*jIO!YT>3hgoi9XH*lw#?X3GmXe{h`%-p6PERG@7;x$lJ%Vo&t_Pt zos3AjuV#Kr_s}#hN8}o5*d&6h;ETWsq;e*6K{E-Zd)t=ufajpU;PcQPxVm{1a(&~3 zTydc^JQ&Zg0)n+q{i!7+IZ$v!Uv>+)B5h@_L&96eu6Zj*O1I|_)C$+muqon&dtrZY zVk9`x*oqT>C4Sa_kX?T|KT7@Qp#Ioda~QzA#K;3S1A2GF0I&!yDcxEBzO293sXsjJ z(zyOH7i$S*04on3kO7}425`Sj-&ln8;!UXZZ&+z=BIOt!xM>6mj_S*9L-iB;fhDL6 zRWwg0!FxNrCEu;lTCpI2vm&|D=C3$4P5&F-q@{C|69zXvBg>j;kLVk7*qSw$bl2-1 z5h$8!WMfh&P*25__yue_u%(81Ar8IgD^b9*wqatgL=dAIHAB004_znfk=!|l+`%5o z6kn!WKCb(>Vvj8!0k?dRJ%zatgn4%=AvnR21qwk@7E&@IGyJ0`cnW?NAA{qW$HsI} z9R4v)zq>PD0+D(7@h*YL+9RxT1r{#4Z^auoeKL){*h##z%L?=kuJ{@SJ3jRnKudlCg5K={u$H}*h2UR>%GNWBx;ZQ+8-m2 z5gDD?daZ+{8Ic##ETp!@L~9n&nl-U4vf7o1j{Sxh$@NyW|2+DZqXW05ub9~WZ}gql z4%s)LuY-zub{UaXtZKkqNyZpWHQVvvA9ewQLHt0@J`d_K?u3SaNLw^N_9)(rNTgZF zdtS?+LGqRLAa*8(wo&H@Y|RH8j*~fYEQ!>U*N5W zUW5TAdN6*u5xI9eWUa*fl53iWu?km&ZLfTz!tM2jX4;A!>3+L_-G+P>))XO+RYD6t zKS5Yx)`PEZZxGkkM0j5t-I`Q0cY*vi1B$IsheM&3IJzT+=0N&S>(C3hjM$+Lr6!`1 zpb-hh3Dr$?@gQ^qC<2eiQfYofrMbPm(xguo#@oZNKQ?Yd(^#);M;>TnI#b}Ssiq#W z@*2fLUU=^j4pDu-UD814hFF^Uk`#mE@J&lG>(=H>o;T2Fs)x$}#_Xk(k*1~H(LBMb zDPBbITEeEK>Cim@#D>k%$MM><^n3i`qQ@zSSP8|}wDfUc2a1-arJzTZ-!xp71*u@s zKJ=KwVWf>KkjT}+EbFZ2P-Ih>5&SbE&o}cSX8J2f5^9s55c)cr7?nka(ssrQNpd3djL3A?*lCQ?#9|(ioxAZp%{GJPKQu zihX`1p4M%2V2a$9V=efQ`R&btch=(6j^p17DKUSDj#q|A)smwvUFP+x^6QJX@?hFJ zx(l0|1Ljn3l{pocLrluEes~(F%rNV(HgoL`l{ma-zR?=pc{uAsbg$|gal6Ue=nqy6 z`M?7(<_a*m2Zo`1Vrz-<$Vq zWGe=zc>k0*UicG08Z4}!);Z8dA%b@cQ8>3f=iC3$2r*1rgP7k>!%rT%N`9 z?8xvsMq(1d+tJ00v5&9tP&DqAcoxW{e&<4_aP;RJEB6iNzE{eQmdv1afg^KEr6g#l z?uMC#3t6ILkrKH>Vxxn0FtfF7Cz?GvWrpT&_#{onHbn%CN+WHZfQFkg#SKUK;yw9N zlF&#E0qEkN1*!f#h!etgwIl(Suh)q58dWgXYlX0tgVS_efNYU9A}$Oy;NFY;9ax!_ z4V{m_wU>{QYevCzWz}zmB`=r*1&@OOj+&4=?K`g7S8in7`^K508w%V=;u&&`tRCMCdNcc$~LwI z=g?zBpIy!erC<|OvrSK$iyk8)WU0*+E)?C(4B;1<58}Cmq3F=93}J-JJpvj3g5qH+ zdocVWE2Ra;t2uB0yT9c7hPqIP zI3m(Q!_`oJ`6`TpO#)7eG0aOjVuB1*X#%g(#Q0bmfx>|$(b`2=^bGeTalTTduE2<1 z2IFro1ZZ*QdJ&p_f3&?CDPK_J>bfml8dMft$k}wLZ!FA$+GV`);Y7yZE3taO_#@KH z@PU9M`CjYM*ElRJ)G|V+8j-ThGV_R1+noT)^d8Vp;K8Z!+d53X0ZIb?-<3Qb$D=xr zC|tO#Wg#YTp+fx2$G<%M%eDS#i#{r$jbv?&pz!N%)=s)vT@BLc?OPJRva&jO(!$(gtIujq!&h zJ;A4ASdnlDy3kg5*xlI0#pewUjxzH=k|?H(0#Rtf3uCgbuGFNHtFT=z7R+3=C>SmK zOF8&h@H=+ld9^k(&KBQ*mS<}a*%F%H5}Mr-nreNqvQ4`U>=5iCjHLgedBuVh<&iv^ z?pToL7}2|FCBiDq6&=9Vt(-m8>Vo2J-UkQ721@I83|aQu1f*WaJq_vL*2cZSYHnT6 z9x6K=`}qPZ1Jl>_yXnq>QRu=zvhnC z4T<<5Cs)i$)D=rmAk6i+^wKoM++T?I%SAH|YibOh{XOhL+`FERtdXbRkAR3r)v zhNNvK56XcPg7xG!lz>YQ(w+j!Ymu%5U`laJBty@%5IT&;2k%9K`_HnVD$)yXwn42bdTZ^=H^8q&aMkZ6@5 z0938A{v+XWQVDvA!~7WD52e60_}BXww0FuPf947UT#xoz`;m_@T(!E@4Rccx<`uvg z(K5`-d(HyL2441`*it+1u>`I^3S3lXx6z(s+JUAgLFe0`nZ(@lqIRI~KAONiYJ=to=fz&~Bog)F zSrV!1jR#up37ovJrOftSed&+jMtBRnjbsb3KoNAD0$=}GTkwYnu0W5qtC=U5|J)9A zRuc4M?5o*IeXu_=1C!Rh)&XYcV%%QqZFy}fi`Gexw9N$+W35~Pm&MI-j07sv^T|w) zq|EgGZ)j|6}7DO3MFfE)FVqhGVxe1`s`V**K#!lNH{Ey zjJ<-i{|d$7J6oZ^Ni$+EN0V;=PO)|W_y~=G#hKPXxHr(k$SsT9M31!||M;A0?YMw1 z|9Jw#mjd^2kbvpFLO=ZB#T@ZR>qJ)}BXk?QT^S1#s2^yh<65ayj1`Q%O^Ty~_lPaL-#W=I^%{4n**~+?hixSH zt+Y!mX{yYQ&gnDMqO^B z4!BW|?ie+1y#@O^w*a+L4TD#6E#7WGYs>F}pPSae|M{n?%mYLP!%Up$-DT_ru#?l( z^ocU$^nEl+jfLW<@E}g2@$eLtho|T~JVoi@DO#^A8l~EU9--C)EprtuB4yU8EEk#% zN5S>FSHNd%>5GAqjx) zE`YO>04FB^FrX$d9G?XE76(Oevx^!=697N%A!~)iT?v337lwEeU~K{bLuLZQyGeit z5&&Koz?LLHC;@=sF@fP9Nr15l01S!=fQOR+0}}uk3KIZ#CIOC50ALVF0Nk1c_!6f; z;J!k?vSrlN`qH)743&jToC5G+^;8xMyNWi9H9!KXwIrRpjJejNr)A{9MoW=Daye!b zYn2jTtMvX_rT0buu7|o-C*?WYABUwxx1KGESN(SgY9p->gwBRufyHROxEhK^RE$Jq zT2DF=if$P?I7GNSMsSr^7LGr5*$fSZ8yE4L(f2*-s~bjodF6-ieFpm1Zyp2HJkqPL z?NSv!l8H+n!bdW&>}q~z!3DTw{S;IXQ5B1^ld;=cgD5QhZ8yw&SE9K1#Z>P*-xaiQ zoX+Jf^BFHoG5zaT@E(zaIxj!X>hUNdaf9nN_+9Nlf#bc`@;b;|`wmE~+{ep*Fh2-bG$f0a|EU1ghlo}*trI2SLGQI9Msp1$S6>EIo66t zVMM$f9yp`0cXByyG#ll`(~BpX<#H@&j)LWNIdYA{7v(SiKX&B~sgEwsE zZ;m|pIAmWuR>DVH;ImnQBU-H;V9W-U{DRKiTdvbaYV~b+1-pQ`v#|J}EFo7lb?F4H zw~-6TYUTF+hrp$#FeCVfR|*9GC=wgrfz*gN+)ymiwq}=-HjxS3EmIFU+y*XOha2*Y-fC~) z@4yCrxS_n&?!CROe$ch!>o>Q{9xs1hm{+T)`(5)#^Q_duf!G_-UCSHwH7wdcgUU;wmy=*0E^jh*5a~|$OjmW zSEJx?u#cQ*gq3VUgm%`kEJ^aHA~6by^5rhF(zUF@FT@c~puH*t$x(s%^T zRs=hbrc}_2pT#{m^25^5VmKXyYmVT@1=m_F_9mjj&(kv2f}5~i0a3z0J+uxF>}C|_ zs@h@80=ETP*56s_t=MQFm=;|4A|JA)f@>1#IQbQr08hw8>DcA?HsINh&gj|6Gf(r0w`7cW1;Cm(XL4%W(>M@dT+oDC9kXFGpKdoP3FrLV`Zixz*)dUOSax}RqD zb5xw_ba3EE-w5uGw7t>$VYS@47j_!KD5R{Id$+F;GG`uwtI$okaKsB8Yl9e`dbngZ z%VO&l?VYV6_odOHhL?>)v0;lZg&Tu)&h1ikV(u~~R!4^NM%-48We!4K2l*4|Di*gw zr`KK7A+|vD$uufO*r4{EYQ1rZn7N5dkQvBfN1phh6G=Izlh{DVN$i9ey|LgVrr)&! z9E-io+CrK9>JvLlEw&7`nE06?`oIzTYhkr|x3vOo3ndo`uOMl*oZ~>@7IkgC+M4?< zB*gmu3E~XXK@4&&+jgpRL?U+HD9S(@cJn+qsyuiWb2X}5&BzrGvA`h84pi*H?ME=8 zAb1U*WcvHQ>G%B0AGy;LBMUf{z$FLpn61;D)j`y zmfNrvU_~fKwr@k6=}enITxdb;b$RhG2miA0FLV7A_~TpgTBLF&3-ySZY-mBe^#6jU z@1oXd2DeAjR4W1iYSeAz>g?nq+?rr+!X{d0#KY44`_Lf59zerXt`vHAGr(3&*G7s7}RImya z+XDrg=Da6J4sOO(=Er z+Yl9CFfq~=VWh?Boc%`H^UZ+axfxN_)(`j48WmA!EXnPs2%#>%_WFaHjp#CqrHH#= zbR*x_V|J)nO~}<4K8#md7SUyoI@mTg4+bh4aq3_zQTpML?C)DITpk`)F3XsFalObe-@?a8 zPQ?u_aGAyl1W_{jQ_DpgrY+x29pHH@{GBJ%gG+J`aMpothmZ5@wff-dZ3NcAx`l=G zR`tzB#VcSUC_}j6L-@ir1Uw(&_8T>$JNyqpK4b}T2TwpwwG#OZrjgL+J45H=+X%=H zfnffRksovDp}ms`)(QgiK~g1RAkzzZ!>xZC#SKwia-NuC$cZC(q~|;7A+8^tgr2sM zOJ-K_V<^iEGb=hGAF`B&dAjw%Z{S^p+p7hyGPTdSTTE>!h(t=`%Y}pdWE=e3i3X+V zHj*Z51(6(|T%I$`CM*3eVBr`pl*5MBYoU@g=crT>KT(D2b`N5LWZnEnD)vSraxD(0 zzaP9d(6<89k!pLAjG68*0N_^I;3+NDIW5&$E!CMV10lWE@wQ?`*FGgaq)p<2c|yDw zdK<0{f;#l5v=SWYn0xOZY!2fz2$;$_T`2)j$mC|* z9H^7M_Q<^}NHZolqoo)g@y0^a>Rfj@L!5HXj{QjJ@Ftw`Qy@-3If;TWoIu9H`K++H ziQk07*%DJ6i5;67H^J?;MkeeVj6EE6GD#r_DG@@vHX(+akf-4rOPeU@jnB8KkaUNN zd+c<479|+~&Xsy^(TulX9 z%~}ErIPvWXYz6coi5*nll6$x(v;gG$PI50_{eBe9hP+Eq_hf=sQoo_wcF45P{%2f+z z8A04Jg5|Rl@Y_k<${8)u(qrsQO2{^nL7F!#$O{)R5lRpBU8Z-krf$yrxHEsLtG9CwR^Jo za(aH?)!&cHIFLMd2YmL>lK6muW2a!n>^2A((h}~*SthylVH(mg9xqj za3Y2jg>Jn6B0oPfbGo6z8Jk)pPb(qq+AnOiiswGY!D(PDk#gOwJuQ;}1%Ub9m} zC!v7(?gEHe^pVU1xJsx#X7UrW;YgT55I)j^^((B$w3@(TgpwIYLJSurbodp*Z1_!G zYD6QMz|g)2In!UvpmG4s8I<+(Eg+E13h6G6;VuNQ?Z3$W@tj0pdBl#t1|u`Xb)mKk?qxhHf% z>?jjUkSJHav~Ft;yba})pAlJifDMBMqBE?bx(?|Ai(p4k z)`jj~f;Z>0MWdq&&P9t4?)ft4*a4Rof5n@aS-GqtoVKVvfvA&?DghwCX->Ts-+58i zERGD2lrwtU~V%6AI(1!(KYJ2{T zax_|Wu=x^bDFrQ1Qk*m<3w{HkB2h`QR_CnWg{H-JfD)Kx1jlT*^N%d}Bz^6Ij32Aa zOXyjs*6bLg#k251gU-oF^Buy38{q1XFM@>YvF6A5aKYR2{^l2Q!)!wR_8BNcCcZ%n zbGTzViG;*W#qM$>@=dWjD|QA+#WLKYA+a116%jvYD|Q2`wc9eWQKx!A3o@!2+OE*h zafpiT#ZL!9ff1V{zmkQ);Z(9f82+)W=RPG=yJn5{Kf#DZIo@@!bn__Xq2aegP$%U@ zUbGU$ZdjVCSi(rLTpJeZTkj@B`{NKxos_9oe_(SD#V+XJAK2zssPc#;wu;2#kQ#X> zp5A^G3VC6Klz@sg!}#VcR$ynG?8NxyUJk>zaonq6J6XgRD_AA98U{b|1ok*K6@Z-) zg8gT$lo`bMu)@fk?VHQBKx9uUevq*!-dz@l5^F@x?4^T^BJ3e`7~9dN(s3Qaa+k?9 zO1Iu>z*&3jd*Qnk$?b-x$Z55=RbY?yKO?_a78ST^JS&<1JSRW8RI80PbhDq@Y;%aZ zII-b&auR9rPawVcXHZ&_K)RK!u4-EL6G%(2QQY>7va?o!=?K=9MEAWNslAAzy;&BW zkcTxsB;q9LjY!X8y35s?Lxth_yv?FG7T~P*MJh`#QSeanApI0^N&gngH0ITCrKF#9 z1@8K7Rjxns%wW;T{C?72>-VTNKDFesSoICdR$<6n^Jd&6zc(VlqA`VXT|!9XMdVH}`yOHR1NO3%xf^3wm#yj!;%pan7uYUsdAr z_uf`{mZ{S@Nh zv>BD>R^hTdkXw0k2)EVVf_l!*+yI^l(_WD22(FBHS=Szct1bdo~HDY+WChWx1`IF{^;XvRC6@TQmS!pvAA;Tidh zwTM!yhpve%oC}X(Ufvl4M;NU9o}xiHVBz;+A93Rb4Xz&9cVS}3ww#`M7};ypRrqw% zi>DQt9~e<}|174Z8)`@gM(+W)LbG(x%06<}Flp?e9>EUe^PPzl8o-Mu`zEr?T7Hz`XX2JEM^?wg(G8 zuHv4@F0nO76{pwU&RTa+Ypnp_rRU>N>*@x) zT9wq}E;JuqB7}0V-tfkTwRsFzhD@<{ z(7rBitOtNK#V%@GM@5bAuqd2aJiI-6U53N|a`+Go{t`8FsIp$4htj6CE^RzZ`vwTb z^KU%$YGk?(7xI_p@8;B^O7dtuSbF?qhDvKDkznsClg#MtPnk zF2q0#cMA9xp@2MpX^XqALz!CaYA*A$T7l@)j2FQad_-oye&-i>DT`KO zBWdvI8nig3ts!<&;S=8sU-Y2;))FD zBrGrLb$3&2%uiFf@yOv)W;&+=aL{Yab1m{zHKk>M^|E{QA2WZB5}nMlZ2<#g;9)Kl z5FHiaPm#b&dPu^q$qts#Wr64u28WmMJ}-!1&7MOa2b#SHA6?HAdQex)Q|&4_DxALe zaXe%vYPU7|aamno6uzx6eeq(NJtgZU=2o@cd(6#fUwgY3&D_sE4*Lt-ZjK-}dtH~? z3?nSo&d6B&sfnSzz;OF}7#DE(5fg^=P(0q}MKDl{pD2wG&r+ddRH&1=)wIAX`|7m+ z+?r|E{2yBLLu7Iq#BNP~8T9A1=AT@doz|>8^xwATJy$y<{QTBD$5nFs)?A2#aZq-y z)||V}-I_yYb=aC^xOlu>YtABUiq>4W>;K%E_Q(GCy?V7LFPjF|pTpnzIz{5f=^$$(HMznBJj9@xec5SxI~u?0JYY z*?1530t9*`GDCRzu*Sie06J_D79J%6nlIyTi0_RZFeeH_Uk?WDDTt$BQ1Ex~|AteD z-~1;$jUhtj7(^ZxYbdGAF&{Qx2i}ihQCb=XZBC_R9Bs1Zg3)$wET*@J>dfnlFB|LS zaJ&jq0v(a~M!nK=YEdMzQ7TYpQ|5T2D^u*b)og6Is+Z!+DOlhv1G>>(Jah4cm5I*) znWOXYgq9o)SM0JvJPYwO@HFtmWNCCcp4gijJps>2cuvA|DxOpEoQ>yfJh8PjdOj9y zYrssyjL0Jry+eiM5xHMQ1LFoG@ zNy)31mcq`l#)ASn3Ci(t=aM3Y)W+5N3Z{s<`Uo6gInnGwcyMrKS;&a2A{uMmO!)b) zO_LqhuK2|@h`3W+3%{5NBMSTYoe=;psiMJ4d0-b)ld>_y{JhhW>(PYv-lR8*Ub;R?dOo6de1Wl@v7ZJu@6GrOUAnPbfnTxA+9De0$98 zI-ZNo?0Nj@QWP!3*DsEE=4Q#pHI6`H(XZ})Qrzx_Onmc8REW#JYr0g8=cCNGFxi45 z)pyFzD-c=9B~mN!s(omC@^d!`AvC+Lq>Yg z?;j%DAfZBk&WQCP5*TgzK1(pNxl( z!lA$rR6wt*f?iw4WLR!k8lZO+L(rzJE+23=YL4xppjY7|>9~T2+3WkeO5&0m0H*YLld0DU;R$Z$k_&; zBg95{%nmxcq)-@o?FvL1X0}h(n##=m;5d9952?>Rl~vTY@f;i#?cK%kYe+gj;Oni= ztA_ZDbE&`m65^54`2pVOoX>sqz6{`AKfmVb`8+UWkT3LT$Gmi3ii3kRa+;d~HF#f1_=sbK8Qv z+YST=TU+yG4L}@uhsKgt(AO-_LLL zcc;jU{*=i3+T`}UG7ni}RaU2S72feUJ6Bub1z^8+fO2<1YbloLmy6X;MGY94k&-bAM`b+;#1{=ImLz-=egF=8(LaMMT2L;u-))JhWBqu zuJL$->5Zk@L>^w$*IcgwKEo(D6#76-6mYtOV=FQ67;%4WeBfMY+N``^y*GNv=3455 ziuXl>+4sDhQcX+wL-9V`fIb9$vESM^2WRD-0I0-3SUp5?af$6Sr1CgmcLttY$UybT zMCz+{Y9>?v2dOyDgCkZ4^{Zj5;7mEs5|`m5YF5u$tW6*=E~l!g)Em00vGjCMve!Cv zy|Bf;R@tr)=O$R$lu|Z?Pz^#(mZF}g*F>TUu$J+WVVgk?a$q&wh8&DaxkO-|tl2?sNh;>if?7fBw&hcJ95k*QrzIoH}*tl-#QN z#c)@ocZs3ZuC$2j_C(M(l+$VR z=1#0$+3DJV;gsc^dw%4XRNN~f04yD#k7k{U=ADMDdPS)|w%Au9LL|yu*1GA#N{be4 z)0HoDD!=o(EU5nC1`#j0vDiF|17ZLx_XLVZV&vF<&r+|>S?hq|yDH~Ha?VD2QSt*C zuD;AwV~b`tJ(8&Jya*kVYr`-09l)5?63gwqst8Hmhuj$}bF-m{<^&T@K6MyOH_sQC z#v}r8b{^g-(ldE#ORSM^NWRhf5B})Sj~l@}~Q;*y+o1 zY7yL0*i(BwAMD^UKeank)-Scam#P8J!CZQi?L;KIvmloxs|*n*-sCkHFCC)F4(`Jv zf9&THWZu6X<;@W3_HC2Vs&U~Z*Q3KBCB#E*$k}(7jHOZ{05|e;uLr!-&C9_Gxy8C?>_^i7#0`3Z zgUo5qoTAq_0@LoqI7^(1C0H+UP}6n!1-TGbM{kj{%8Lq1j7VRFy1~j-vS@7@`0&6+u+NR_B>CcGxR7SU>j!S7o zMah+Sg;XzR8fR!_dPqeX#_o~IsLvs0)`!8Ii5Sb}l}OvzCLg|@K0E-z>3Q9oVmK4V zeLw@Sh!Mh4a)w|7TdR?x0@2D#(*nM&Oa3A_LjDH9L&~`QUfOuEY9qHaWJNiKi2F(N z;yt7}N2Q6aXEZ@PxjR7qIpZ1o5#OpG=5jeptou@Cu0n6R?Qu!S#S?-VJ}^VJL&RH+ zTy&&xZI?a634T%qqpIWpUa7)lC~1#B{XtXIpBQFE?k(!$swT5&J*o{k1L}LG`fV1f zn|^8-wO~np?hPu*l}*WG6f4EHRMKTT@tvtv+5RipvdfmjgNe~>EZ;2bB{EukLYS*| z&)z$>4oi4?h5cguHbu`|8<{4ru!SRm=F zSI|L1<3GPgN_F3iawD}3Waa#YCfDZuF;!rWDiH4!ZAUd9k}j#q5FDlwMS3`T?Y9B6 zTtAgQ6{=FAft5D3{*gvCZ19^uS*r(k#mk9^;T9m7_kTLOacr)F+0PYZI9E~feZ83= z=TXY)--~n&y8b5RB(J8g>g96UtIi3xH`WZg?mS=ORST2n9d1P$w6YWQ6yo^1wbF2$ zf`ev8`X=6N9p4Z!+CtAaqX_leCmN7fGREws086-r`REClgKYxyGq=>CXcK)Mzz!4^ zXtY+d5Tan#k0NvHGZHIbCrMEp7*F4r{6VUMBrbdDe_F48Q~)s!A1#{xX=c3Dgc zQFu=G`(75(t~1Jf##9?vFiceI;1=7f?G8_F{k;fD zZODX;j}#>s;iyZ?v5IM!2qRTpYONu?cux?m77%(5`+nh%*wL^h20MjIr|d@L)!@&u znK2s%kY2fU5;ny4Qp)~4k#ef5LGGf2Ie7n)Vo4b}UKncpA=L@ZsqAlEMlmtfFO;{< zu3*lb!h&+&&gh-GEn@hu^r&3d*6;=&54bZ&!GvCi<9`xhpfvrHbSRwjCn+5jxn0B- zWIOHnT|}sZ8q0a%%$OQa%@oo=cGTA#7~9Jk37M|yz}PPP`b#P7s3S2ZGZGK!k+@8a z#7WrFxg4&##g5*oRw5_2DlZ;K84m6Zkh5mn%?5~>GaT=MSXz~Q2#CJQm%uX33?M62 z!>+$c`D!4Or>k9$9@%AGmmZ8r8%KnFh05*|23iIq+ zMY@rrkvZelup%I21cR(WWuOeZR%LZcUnvVN7;lrv)Z?5&^;jqj2oYqik{dZFJbA6I zC2OpTiI>&Gnz$Mhx#)dT?#f%`qu*|oX$6@M$AC)@#{hfGIMsF!ZRd!PS^uFB@iwkk zw|%{|m6O`I08qS7pTg}V$2|9UTGCziFC(Y6K2A2ZJzRgae#0x481A>;!yh$;m#%7* zNozLTA;A&;q(kaw@S#llMVda557FCuwT<^>=k*607;J8YEutZ>DMHY0+!BFqsp&0- z*V|mu$ytt45oveXsi{hUXjn_tGVopowk2$@$b5@EHI$n!)Lw0)uyplZn9#Nx+I&C-`8j9PR&b>GSS}#()|4Q0#H@DP;{t2AM>^B@ybb?&b>JB!5>H zP`au3!4Wn&4G*z7g@pOP~C+2y&4gT0lm?D|#AK=lQGK)7!h<6^OKZ8uoGo z)ejf)<5zjqscw#&q%SpFd=(O+7=6jK$(k*(?US6T64XBC)Ntyp;T4aHI;&(U_h|Oz zZ%*_=nZgr5D9EaI6#3aQHH90&fx_e}%jp@rOh~gNF3D*iMh= zvZzlDXPiy+-EoWNTMgm`HlmQHz1TgqsSbnC;tsgzPU(6ejIM@x(T;pSYz z;>!gBFECgd0>Pip-rcsk4i$fr2+I<3gPg|uMGzG!8adwe9N71fzC8-}Lkj(NGD&FI zPh>@zUgM>$9I_2{xhknlVC>V;~;Fk(%OY_@z zu0d6Vegq=`YSwqGD4o1LP9`cO@A&pPCaN5f9{v`$a@yURFM}r8br%wYpJqhc?v0C{ zB9R5@$UnA=j0|m;Gtn+G+Fv63q;t-0AE_3@Zj1o@O!wA$89~(uk9r%N*FN723Z1mOPTJ=PNmI;Wm6SHH>O%pel&ki+V}t|Y)R5xlr;F<*uuzi;&Cc*bh`B_+ zd21^5q(-96&|pXS$8zu(HEx*QxXt>3u!DA#8NpGGdP?k)?%YJoi>vnJq^XuW%2cPm z9)K%ZrS*MzlPdPE#vbT3zT}MQ>>Xq4*44val5{eCQ+_M3^YH@1z=~{*n5!RQ)B?CdJq>!Ud@t z%@vKUXA#Pgmm%3dJMN4n#RLhtB#0Z9EPBJiS5P>@L;rv|ER@d%&3!Qd>3N^dzICHTELL zfjKU|GdG$%tWWXDYEOp2&b@$I%vDzw&3-d$VG4qmjuOJNPBoXUeeRnF=Q6Id72&b_ zUM@l7(|Dy;c%NP-VdJ>yOCK0?_^OKggvtbG$53`CzSxs`xbV-k^N0`orNJZyUDPE5 zeaVr9b^TRa7JKX-glDj>fKbX>ri(oMVR!wGE^>t2lMrPmw6LJWY&d~g+WG>26k_UN zz-CCW2y`RlZdD!ZHXB+QvDV+JU~bUT!KgM~l;B$=Sk4jXV31t&?@A{%A{?4nVK&Sp z1sptFcTi5?MtevTIQcBc%#yuT;B+0h)NEKHfhX1-ltZr3p22-2H3-sDRI;G%pd4|~ zHRYQPA~&_Z$Dg``v#y;_)w_AunW)oj7%1`o)T9N+^v<`mXKchdCm=~sp_ytF)^@U$th`$uHP$-sJ&1KdL_M&?L zt+{HyczU+0hASScuu4e{F*Xrf$8A~GK8V|v-W+zkueTdzT`9wWxziBR8+;PX+My!I7u=cjto;B zZg_L?#SB}bltvD3fH7*?B=`4JtP?8}_ervc=dPEH2H(0Rwj*e$;%~!h%xQK+ui6`S zENM>uQ+gofr+aX8OgrMhy!-2{cK+AUb^{Yx;ta|f5@ij_%npO{`}drlkC#Ci@f8Q< zcevdFqfYk6JBuR%Js@vNcm7B-(%s1(kc{c@yTAfnvyeT6g~Z*;TsOD>O`<%=M^M6` zU?W!otd<)9!~%tl;482&n3DUeg<8MBNM{{8`U0mTK?)&tBdNviy2slMvf8@5DXWMp z+0)x)|6Ps4VU~zuH9JJ2#M*d^eUWQ`D>6lK#vuhxs*S{ca#}g{#c>#-fwUtj&Hk5jjf`$jQ6e&+IAlt-f(L3J4Wm zX4(FiwpzP?;orC4THW;FX|9c%_WNB;W#;{x{H`|wzE>7^_FHDadL`i66R=({i}xxF z_%|R`&RD*P-guL2mm;{ zO@vacq9SupLN*=j)O8~%0u~-eJ9i_Gf0^GE@6xotfR|44lFv(yym)wV$Gh-X`=+G} zfx^%CZRYQO?Y``ZE&`<|JM-7s=W?0LgFq^IaiFVBH8A;4xcEa#%ZqI_rD|Opt@L*a zm@B&YX|dw#*`;$z#$5h6r7DkN{wEP_MFsUqAh8gHnCI4d9oaLpTl@tLv_9seR<&|%aS>`^mbthne_4wIQUH(_zU3&wGD_shD zaTDwaS2p^sXZ%eEJ!6*ja>W`uq5SqQ%j+o~wgbM+(KiyKUCRA|B5tvR$oapLBKIzy zjs-<9S`04uBYWJrfh8F!c?7$ahZq8#Iw`6hIQM>uZF&HAbIc>z$4m z$st;D8>k;=X-zyk?p77TS*s|R<5R#XZGA!TI0;_PpCh8WI^v4Ym>jR)m-~s9{wEl$l>eo70=^e8rC4LGsL3g5 z-023Pn|bfV%_D)X%}wv*Y0YTYkM}k&jpkaH8p*D8SR25tE;V8)&*EO3Zg!cs$!IHK zq*c!Jsj%e-2ouAgL~m?nIKI^H7A}u=``MN`6i!V0iDzXW+7qta7p$~Hl`sZ)k@a!Y zK}O{nbA`J*N14nO;qETidb}V?(~CbUKJbzqXt2@XBziyeL&F%=-TfeDe~I27)ba5x z_k*rO0pG@GRT&1cSNpAf{-#t;sPZ*)Mc#2uZ|8H{+;J{Sb*-n|<2t$4k4ofyQJ@MA z6mNLRrkqo0XoLH&k)FI?LIp}H>h8WJX%bLJB`V-s?pp$`=lvFIu10scSRtT0Nww~$ zDBa)J$oiG~`*qrw-T4*L-*o3&m;TRm{&ZTM?);_czNR~0PbEj`Jm{CQc0=Gx_BMCH zJ~-J9O=1iG%SJE%CVgP0$RVU{3fGae+@xqXMC|3wpM zj7u7EG|?2Mnl%MEJ{dJ1a0!9>7ui~G;19KqckxF^eW!rc7~48LU~On@?aajLy54U! zCT4Qd|Lu`wiR+kmV>&f$EwEPelGC&`zw1VG#pSu`ubVc*KVZq`imN*NR{^(_)#`s~ zTbXaY`IA85KK%WUxfi&V*7xZi zIkmiUJ>Px!9@D*7+>e)%?%_m_@QrYX?!7FygJ~TiKL9~UFjw?BLDkd>%#1SM!DwXZ zqQZSft}r_}Fop&-p%0PyxiR`|nu?p!1k-8~;@pL*vWPPz z*|T({aeWv29TxD(Tzed=QxO}pBrwthgVu0%r%)2&e3sQ2_V4I*Vh6e`iLm4x9`BTE zEM;BKJwe8T!NJ5Rcj98MR1E*ro$M7Kkoc)YvNUmnx02$dpl^Lt+kj&;$Vjk~d_r{O z*bK@ejGm!DGjb({p=_YSeRd0*9IaECV!^n(Fq~NEZ9#VTpbJjO7HJQGXQLw0GD&sHPsW=?tU(c z&j*gOX}?4?9rbbyT2wA^p3)*5-KoaJkqO;}(i+k(9uP>(JS4kaO7HHEFZ#9HfA;WS z`>jQHx$XNu0op&01sV+Gi8XkpO-A1e#`~~UIJO{|nAnS+_Y-d; zsX7V9fb#kUlOc#8@L(2Bb~{<9a| zEgA0e*hL+i@mchrk`RLuX^TF9p19*-DoeL$va~4n6d|p5gIBsm6X?HCK&M4%5Cjna z06~iefjZtSYICnN17HY5a?%jF8^uIBh^tEZLN#44NKTMyk?mKbw?F#6_#ns&VKNXm!2<2Y; zx6|0bD;0(t|{}2Ew)?Q?`jU=s$D~GIMCaspw~}9FM{Q4 z!aYc%+W-x~+pI_r_BfM73KhA^N8G@#7PkJ@`UFTVQya`Qr1 z&dyX6o`HY&4{=w%L&n&?guY@?#b#JDV?P9bv|O-9ycU#OpC?LE<%viOM~ZgYMJlCR zqz;eVt&r69qq}+&&E}NC!q#7sF<{ZgGT-}=K4=Ngmq@cHsp8#c(Mx90yR8D#v2pi4 z!JQ&>kEhJ5QU@UV3~3!f0p_Yjg=f&IOu25-%wh10UNMW_H;dj@g>`av3Lw<@in7oahBOv4&Nbv$`dAt68+0SbmdUby5WiDI9H{nWJJ_dkyy)Ua3@93J=qg|K3rs&OCN~NJ_Kc19+6OiNp~R3T_l<=dKRJUgtF~PU zZu8Eprr@wtK84<0xjO0AJ?q&i6nD3%SxD>Lk1;lApx!qVQMi|wbp?EE8=K2N1?FYe zry`}cX4}PMQv(WWi|SUt;&^hxs)gjR!6B|Cqg#K;dnlgQvS*ap6Q%pZ>sIgDH=Z~4|JqGz0Arx4|W}7Md5pGQQzbc<&;*fw#n0b=K`Qp^hN;AG8{z_ zG6hDc4KFTkVe27q-XZSP>ZE9Q@@8p7+LSgvM>d#-Z?RK_!eG|8d~Yq;CH85%_)Z4e zK~td9`qtt7F>k9D+HrqKS46i|MP|{nS}tnOw#0G!eCK?rSPIK`*j_5tVf`~qK6CBs zq&0PG?g1WQ-@DOm!T8gP?yATNiHtw3=&=eYl>jEwFewDdl@9Q0bX7u;+lQWx1yr%WA>NFAc( zzDgC4lWFvxC|mg3?4Sz9+lSgim5>WmNP}+uo93NdO54b_FP_!W-13H0)Rc~F2FQA_ z`ixCfoCDjTtuiVH`bslx=VU$vI$NQxfLga*?g?jeAgxh-DT{=%SUtaM7jEF zlO6lO73?bXKn0^HpTtj�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 diff --git a/external/eeprobe/write_eep_avr.mexa64 b/external/eeprobe/write_eep_avr.mexa64 index 0ac88154c2d8470564bf31989a1dd101d69f3994..b569427c59a77f79dfa0679205a799e44e0eea10 100755 GIT binary patch literal 166669 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 q(8f^r69127nS7076=97X?R=h~HJB+{;AKh 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