361
Comment:
|
31063
|
Deletions are marked like this. | Additions are marked like this. |
Line 1: | Line 1: |
= Tutorial 17: Time-frequency = ''Authors: Francois Tadel, ''''''Dimitrios Pantazis, ''Elizabeth Bock, Sylvain Baillet'' |
= Tutorial 24: Time-frequency = ''Authors: Francois Tadel, Dimitrios Pantazis, Elizabeth Bock, Sylvain Baillet'' This tutorial introduces how to compute time-frequency decomposition of MEG/EEG recordings and cortical currents using complex Morlet wavelets and Hilbert transforms. |
Line 6: | Line 8: |
<<EmbedContent("http://neuroimage.usc.edu/bst/get_prevnext.php?prev=Tutorials/Scouts&next=Tutorials/Statistics")>> | == Introduction == Some of the MEG/EEG signal properties are difficult to access in time domain (graphs time/amplitude). A lot of the information of interest is carried by oscillations at certain frequencies, but the amplitude of these oscillations is sometimes a lot lower than the amplitude of the slower components of the signal, making them difficult to observe. The averaging in time domain may also lead to a cancellation of these oscillations when they are not strictly locked in phase across trials. Averaging trials in time-frequency domain allows to extract the power of the oscillation regardless of the phase shifts. For a better understanding of this topic, we recommend the lecture of the following article: Bertrand O, Tallon-Baudry C (2000), [[http://www.sciencedirect.com/science/article/pii/S0167876000001665|Oscillatory gamma activity in humans: a possible role for object representation]] In Brainstorm we offer two approaches for computing time-frequency decomposition (TF): the first one is based on the convolution of the signal with series of complex Morlet wavelets, the second filters the signal in different frequency bands and extracts the envelope of the filtered signals using the Hilbert transform. {{attachment:slide.gif}} == Morlet wavelets == Complex Morlet wavelets are very popular in EEG/MEG data analysis for time-frequency decomposition. They have the shape of a sinusoid, weighted by a Gaussian kernel, and they can therefore capture local oscillatory components in the time series. An example of this wavelet is shown below, where the blue and red curves represent the real and imaginary part, respectively. Contrary to the standard short-time Fourier transform, wavelets have variable resolution in time and frequency. When designing the wavelet, we basically decide a trade off between temporal and spectral resolution. To design the wavelet, we first need to choose a ''central frequency'', ie the frequency where we will define the mother wavelet. All other wavelets will be scaled and shifted versions of the mother wavelet. Unless interested in designing the wavelet at a particular frequency band, the default 1Hz should be fine. Then, the desirable'' time resolution'' for the central frequency should be defined. For example, we may wish to have a temporal resolution of 3 seconds at frequency 1 Hz (default parameters). These two parameters, uniquely define the temporal and spectral resolution of the wavelet for all other frequencies, as shown in the plots below. Resolution is given in units of Full Width Half Maximum of the Gaussian kernel, both in time and frequency. The relevant plots are given below. {{attachment:waveletOptions.gif||width="650px"}} == Edge effects == Users should pay attention to edge effects when applying wavelet analysis. Wavelet coefficients are computed by convolving the wavelet kernel with the time series. Similarly to any convolution of signals, there is zero padding at the edges of the time series and therefore the wavelet coefficients are weaker at the beginning and end of the time series. From the figure above, which designs the Morlet wavelet, we can see that the default wavelet (central frequency '''fc'''=1Hz, '''FWHM_tc'''=3sec) has temporal resolution 0.6sec at 5Hz and 0.3sec at 10Hz. In such case, the edge effects are roughly half these times: 300ms in 5Hz and 150ms in 10Hz. More precisely, if '''f''' is your frequency of interest, you can expect the edge effects to span over FWHM_t seconds: '''FWHM_t = FWHM_tc * fc / f / 2'''. Examples of such edge effects are given in the figures below. {{attachment:edgeEffect5Hz.gif||height="244",width="299"}} {{attachment:edgeEffect10Hz.gif||height="245",width="302"}} == Simulation == We will illustrate the time-frequency decomposition process with a simulated signal. * The following code generates a sum of three sinusoids (2Hz, 20Hz, 50Hz).<<BR>>The 50Hz is present everywhere, the two others start only after two seconds.<<BR>> {{{ f1 = 2; f2 = 20; f3 = 50; i =2000:6000; Data(1,i) = sin(f1*2*pi*t(i)) + 0.4 * cos(f2*2*pi*t(i)); Data = Data + 0.2 * sin(f3*2*pi*t); }}} * Empty the Process1 list (right-click > Clear list) then click on [Run]. * Select process: '''Simulate > Simulate genertic signals'''. <<BR>>Ntime='''6000''', Sampling frequency='''1000Hz''' (signal duration = 6000/1000 = 6 seconds).<<BR>>Copy-paste the few lines of code above to generate the sum of three sinusoids.<<BR>><<BR>> {{attachment:simulate_process.gif||height="412",width="489"}} * Double-click on the new file to look at the simulated signal.<<BR>><<BR>> {{attachment:simulate_display.gif||height="159",width="667"}} * In Process1, select the simulated signal. * Select process: '''Frequency > Time-frequency (Morlet wavelets)'''. <<BR>>Select the option '''1/f compensation''': The normalization will be discussed later.<<BR>><<BR>> {{attachment:example_process.gif||height="271",width="557"}} * Click on the button ['''Edit'''] to see all the process options.<<BR>>Time definition: '''Same as input''', Frequency definition: '''Linear 1:1:60''', Compute measure: '''Power'''. <<BR>><<BR>> {{attachment:example_options.gif||height="542",width="403"}} == Process options == '''Comment''': String that will be displayed in the database explorer to represent the output file. '''Time definition''' * '''Same as input file''': The output file has the same time definition as the input file. <<BR>>In this example, it means: 6000 samples between 0 and 6s. * '''Group in time bands''': This option adds a step of computation. First it computes the TF decomposition for all the input file, then averages the power by time band. To define a time band: * Enter your own time bands in the text area, one line per time band, with the following format: '''"name / time definition / function" ''' * Click on the button [Generate] to automatically create a list of time bands with the same length. You will be asked the maximal length of each time band. * The function is the measure we take to combine the values for all the individual frequencies into one for the frequency band. Possible values are: '''mean, max, std, median'''. '''Frequency definition''': Frequencies for which the power will be estimated at each time instant. * '''Linear''': You can specify the frequencies with the Matlab syntax start:step:stop. <<BR>>The default is "1:1:60", which produces 60 values [1, 2, 3, 4, ..., 59, 60]. * '''Log''': With the option start:N:stop, produces a list of N frequencies logarithmically scaled between "start" and "stop". For example "1:40:80" is converted to [1, 1.5, 2.1, 2.7, ..., 61.5, 65.8, 75, 80] * '''Group in frequency bands''': As for the time definition, this option leads to a two-step process. First it computes the TF decomposition for several values in the frequency band, then it averages the power of TF coefficients per frequency band. To define a frequency band: * One line per frequency band, with the format '''"name / frequency definition / function" ''' * The frequency definition is a Matlab expression evaluated with an eval() call. If the frequency definition contains only two values, Brainstorm adds two extra values in the middle so that the final averaged value is a bit more robust. Example of valid expressions:<<BR>>"'''2,4'''": Evaluates to [2,4], and then expands to the frequency vector [2, 2.66, 3.33, 4]<<BR>>"'''2:0.5:4'''": Evaluates to [2 2.5 3 3.5 4]<<BR>>"'''2, 2.5, 3, 3.5, 4'''": Evaluates to [2 2.5 3 3.5 4] * The function is the measure we take to combine the values for all the individual frequencies into one for the frequency band. Possible values are: '''mean, max, std, median'''. '''Morlet wavelet options''' * '''Central frequency''': Frequency where the mother wavelet is designed. All other wavelets will be shifted and scaled versions of the mother wavelet * '''Time resolution (FWHM)''': Temporal resolution of the wavelet at the central frequency (in units of Full Width Half Maximum). Click [Display] to see the resolution of the wavelet for other frequencies. '''Compute the following measure''': * The convolution of the signal with complex Morlet wavelets returns the complex coefficients for each frequency/time/sensor. Typically, what we display is the power of the coefficients (square of the amplitude: abs(TF).^2). You can choose if you want to apply this transformation or not. * '''Power''': Computes the "power" transformation immediately after the TF decomposition. This discards the phase information, but produces files that are twice smaller and a lot easier to process. * '''None''': Save the TF coefficients as they are computed. This can be useful if you plan to use these decompositions for other purposes that require the phase. * Some combinations of options may disable this choice. If you select frequency bands, the program will have to compute the power before averaging the values, therefore "none" is not an option. == Display: One channel == * Right on the new time-frequency file > '''Time-freq: One matrix''' (same as double-clicking). <<BR>>This menu displays the time-frequency decomposition of the first (and only) signal. The Brainstorm window shows two new elements: the tab "Display" and the frequency slider.<<BR>><<BR>> {{attachment:example_file.gif||height="210",width="660"}} * We can easily identify the three horizontal bars as the three sinusoids in the simulated signals, and the trade-off between accuracy in time and accuracy in frenquency. Click on the figure to move the time-frequency cursor and explore the two axes of the plane. * 2Hz: High frequency resolution but poor time resolution (supposed to start sharply at 2s) * 20Hz: Better time resolution but poorer frequency resolution (17-24Hz) * 50Hz: Continuous over the 6s - Frequency resolution gets even worse (40-60Hz) * '''Current frequency''': Slider that shows the current frequency selected in all the figures. <<BR>>Just like the time, the frequency selection is centralized and managed by one control only for all the figures. As a consequence, it is impossible to display TF files with different frequency definitions at the same time. This can be perceived as an annoying limitation, but it allows all the simultaneous displays to be consistent at anytime and makes the interface more intuitive to manipulate, with lower risks of mistakes in the interpretation of the different figures. * '''List of signals''': This drop-down list shows the current entry displayed in the selected figure. In this case, there is only one channel of data called "s1". It will be more useful later. * '''Hide edge effects''': When this option is selected, the time-frequency coefficients that could not be properly estimated because of a lack of time samples are hidden. It allows you to see only the information that is really reliable. The lower the frequency, the longer the edge effects.<<BR>><<BR>> {{attachment:example_hide.gif||height="207",width="555"}} * '''Smooth display''': Re-interpolates the time-frequency maps on a finer grid to produce nicer plots. * '''Measure''': Type of measure that is currently represented in the selected figure. The entries that are enabled depend on the type of data that is saved in the file. In this case, we saved directly the power of the wavelet coefficients in the file, we discarded the angle/phase information, so the "phase" option is disabled. The other options are: '''Magnitude''' = sqrt(power), '''Log''' = 10*log10(power) * '''Colormap''': As explained in the previous tutorials, you can change the colormap by clicking+moving on the colorbar on the right of the figure. Double-click on the colorbar to restore the defaults. == Display: Mouse and keyboard shortcuts == ==== Mouse shortcuts ==== * '''Left-click''': Selection of current time and frequency. * '''Left-click + move''': Select a time/frequency range. The legends of the X/Y axis show the selection. <<BR>><<BR>> {{attachment:example_select.gif||height="159",width="362"}} * '''Mouse wheel''': Zoom in time, centered on the current time cursor. * '''Control + mouse wheel''': Zoom in frequencies, centered on the current frequency cursor. * '''Right-click + move''', or Control + left-click + move: Move in the zoomed image. * '''Double-click''': Restore initial view. ==== Keyboard shortcuts: ==== * '''Left/right arrows''': Change the current time. * '''Page-up/page-down''': Change the current time, 10 time samples at a time. * '''Up/down arrows''': Change the the sensor displayed in this figure. * '''Control + up/down arrows''': Change the current frequency. * '''Enter''': View the original time series for this sensor. * '''Control + R''': View the original MEG recordings. * '''Control + T''': View the time-frequency 2D topography. * '''Control + I''': Save as image. * '''Control + D''': Dock figure in the Matlab environment. ==== Figure popup menu ==== . {{attachment:example_popup.gif||height="191",width="480"}} * '''Set selection manually''': Does the same thing as drawing a time/freq selection square on a figure, but by typing the values for time and frequency manually. * '''Export to database''': Save the selection for the displayed sensor in a new file in the database. * '''Export to file''': Same as "Export to database", but the saved file is not registered in the database. * '''Export to Matlab''': Same as "Export to database", but the output structure is sent to a variable in the Matlab base workspace instead of being saved to a file. == Display: Power spectrum and time series == These two menus generate similar figures: * '''Power spectrum''': For the current time, shows the power of all the sensors across the frequencies. * '''Time series''': For the current frequency, shows the power of all the sensors in time. * Example: Power spectrum density at '''0.6s''' and the power time series at '''2Hz'''. <<BR>>We see only the oscillation at the 2Hz in both dimensions.<<BR>><<BR>> {{attachment:example_psd1.gif||height="148",width="660"}} * Example: Power spectrum density at '''4s''' and the power time series at '''20Hz'''. <<BR>>At this time, we can see the three oscillations in the PSD figure.<<BR>><<BR>> {{attachment:example_psd2.gif||height="148",width="661"}} * Note that if you right-click on the file in the '''database explorer''' and then select one of these menus, it will show '''all the signals'''. If you right-click on an existing '''time-frequency figure''', it will show only the '''selected signal'''. It doesn't make any difference here because there is only one signal, but it will with the MEG recordings. == Normalized time-frequency maps == The brain is always active, the MEG/EEG recordings are never flat, some oscillations are always present in the signals. Therefore we are often more interested in the transient changes in the power at certain frequencies than at the actual power. A good way to observe these changes is to compute a '''deviation of the power with respect with a baseline'''. There is another reason for which we are usually interested in standardizing the TF values. The power of the time-frequency coefficients are always lower in the higher frequencies than in the lower frequencies, the signal carries a lot less power in the faster oscillations than in the slow brain responses. This '''1/f decrease in power''' is an observation that we already made with the power spectrum density in the [[Tutorials/ArtifactsFilter|filtering tutorial]]. <<BR>>If we represent the TF maps with a linear color scale, we will always see values close to zero in the higher frequency ranges. Normalizing each frequency separately with respect with a baseline helps obtaining more readable TF maps. The values we were looking at were already normalized (option: "1/f compensation" in the process options). We will now compute the non-normalized power obtained with the Morlet wavelets and try the various options available for normalizing them. * In Process1, keep the simulated signal selected. * Run process: '''Frequency > Time-frequency (Morlet wavelets)''', "Spectral flattening: '''None'''"<<BR>><<BR>> {{attachment:example_process_none.gif||height="223",width="458"}} * Double-click on the file. As expected, we only the lower frequencies when looking at this map, because the power of the 2Hz oscillation is a lot larger than the power at 20Hz or 60Hz. <<BR>><<BR>>{{attachment:example_display_none.gif}} * In Process1: Select this new non-normalized file "Power,1-60Hz". * Run process: '''Standardize > Baseline normalization''', * Double-click on the original TF file and the two normalized files (center=Z-score, right=ERD/ERS). Select the option "Smooth display" to make the figures look nicer. <<BR>><<BR>> {{attachment:tf_norm.gif||height="169",width="583"}} * The normalized maps seem to show a response of the left primary auditory cortex (A1L is the first scout in the file) around 35Hz and 80ms. The large red part at the lower frequency is probably part of the evoked response to the stimulus, but all these values could not be estimated properly because the time window is not long enough. Because we used the baseline between -100ms and 0ms, we cannot really trust anything below 30Hz or 40Hz.<<BR>><<BR>> {{attachment:tf_norm_hide.gif||height="202",width="356"}} * A better approach would have been to import longer epochs (+200ms on each side), then to normalize the values based on the "safe" part of the baseline (100ms-0ms). If you include the edge effects in your baseline, you end up propagating them in all the epoch. * The figures do not use the same colormaps because the original TF file is displayed using the colormap "'''Timefreq'''" while the normalized files are displayed using the colormap "'''Stat 2'''". If you want to look at the normalized maps using a different colormap, right-click on the figure and change the colormap configuration. <<TAG(Advanced)>> == Tuning the wavelet parameters [TODO] == * Different resolutions * Log scaled frequencies: 1:40:80 <<TAG(Advanced)>> == Hilbert transform [TODO] == == MEG recordings: Single trials [TODO] == == Display: All channels [TODO] == Three menus display the time-frequency of all the sensors with different spatial organizations. * '''All channels''': All the maps are displayed one after the other, in the order they are saved in the file. <<BR>><<BR>> {{attachment:tf_allchannels.gif||height="370",width="450"}} * '''2D Layout (maps)''': Show each TF map where the sensor is located on a flattened 2D map. <<BR>><<BR>> {{attachment:tf_2dlayout_maps.gif||height="370",width="450"}} * '''2D Layout (no overlap)''': Similar to the the previous display, but the positions of the images are reorganized so that they do not overlap. <<BR>><<BR>> {{attachment:tf_2dlayout_nooverlap.gif||height="370",width="450"}} Useful shortcuts for these figures: * '''Click''': clicking on any small TF image opens a new figure to display only the selected sensor. * '''Shift + click''': Same, but opens the original recordings time series of the sensor instead of the TF. * '''Mouse wheel''': Zoom in/out. * '''Right click + move''': Move in a zoomed figure. == Display: Sensor topography [TODO] == The menus below show the distribution of TF power over the sensors, for one time point and one frequency bin, very similarly to what was introduced in tutorial [[Tutorials/ExploreRecordings|Visual exploration]]. * '''2D Sensor cap''' / '''2D Disc''' / '''3D Sensor cap''': 90ms, 8Hz<<BR>><<BR>> {{attachment:tf_topo.gif||height="137",width="474"}} * '''2D Layout''': 8Hz (black), 35Hz (white)<<BR>><<BR>> {{attachment:tf_2dlayout8.gif||height="241",width="260"}} {{attachment:tf_2dlayout35.gif||height="240",width="259"}} Useful shortcuts for these figures: * '''Left/right arrows''': Change the current time. * '''Up/down arrows''': Change the current frequency. * '''Control + E''': Display the sensors markers/names. * '''Shift + click on a sensor''': Displays the time-frequency decomposition for that specific sensors. * '''Right click + move''': Select a group of sensors. * '''Shift +'''''' scroll''': Change the gain of the time series (2D Layout). * '''Control +'''''' scroll''': Change the length of the window displayed around the current time (2D Layout). == Scouts [TODO] == Similar calculations can be done at the level of the sources, either on the full cortex surface or on a limited number of regions of interests. We will start with the latter as it is usually an easier approach.<<BR>>We will use this section to illustrate the online averaging of the trials TF decomposition as well. * Drag and drop all the '''deviant trials''' from '''both runs''', select ['''Process sources''']. * Run process "'''Frequency > Time-frequency (Morlet wavelets)'''". <<BR>>Select the option "Use scouts" and '''select all the scouts''' defined in the previous tutorial. <<BR>><<BR>> {{attachment:scouts_process.gif||height="347",width="448"}} * In the advanced options, select "Scout function: '''After'''" and "Output: '''Save average'''". <<BR>>Run the process (it may take a while).<<BR>><<BR>> {{attachment:scouts_options.gif||height="637",width="380"}} * The scout function was introduced in the previous tutorial. It is the method we use to group the time series for the 40*3=120 unconstrained dipoles we have in each scout into one unique signal per orientation (three signals in the unconstrained case). When computing the TF of one scout, we have the choice between applying this function before or after the time-frequency decomposition itself. * '''Before''': Extract the 120 source signals, apply the scout function to get three signals (one per orientation), run the TF decomposition of the three signals, and finally sum the power of the three TF maps. This is faster but may lose some frequency resolution (especially for constrained sources). * '''After''': Extract the 120 source signals, run the TF decomposition of the 120 signals, apply the scout function on the power of the TF maps for each orientation separately, and finally sum the three orientations. You should always prefer this option if the computation times are not insane. * '''Save individual TF maps''': This option stops the computation here and saves in the database one time-frequency file for each input file (40 files), with one TF map for each scout. * '''Save average TF maps''': Instead of saving the TF for each file separately, it automatically computes the average of the power of all the TF. This is a good choice if you do not plan to use independently all the TF files, because it saves a lot of time and disk space. * Rename the new file to add a tag "Deviant" in it. Then right-click > '''Time-freq: All scouts'''. <<BR>><<BR>> {{attachment:scouts_file.gif||height="185",width="508"}} <<TAG(Advanced)>> == Full cortical maps [TODO] == Computing the time-frequency decomposition for all the sources of the cortex surface is possible but complicated because it can easily generate gigantic files, completely out of the reach of most computers. For instance the full TF matrix for each epoch we have here would be [Nsources x Ntimes x Nfrequencies] = [45000 x 361 x 40] double-complex = '''9.7 Gb'''! We have two ways of going around this issue: computing the TF decomposition for '''fewer frequency bins''' or frequency bands at a time, or computing the '''TF decomposition of the sensor values''' and projecting it dynamically to the cortex using the inverse operator. This latter approach is possible because the two processes (TF decomposition and inversion) are linear and permutable. However this is enabled only for contrained sources (so not possible in the present case). <<BR>>TF(Inverse(Recordings)) = Inverse(TF(Recordings))<<BR>>=> Power(TF(Inverse(Recordings))) = Power(Inverse(TF(Recordings))) For illustration purpose, we will use the other time-frequency decomposition option available in Brainstorm, which is based on Hilbert transforms of band-passed signals, using only 6 pre-defined frequency bands. * Drag and drop in Process1 the sources for the '''deviant average''' in '''Run#01'''.<<BR>>Select the process "'''Frequency > Hilbert transform'''".<<BR>>To process the entire brain, do '''not '''select the option "Use scouts".<<BR>><<BR>> {{attachment:tf_hilbert_process.gif||height="376",width="480"}} * In the advanced options, select "'''No, save full hilbert(sources)'''" because the other option is not available on unconstrained sources, and "'''magnitude'''" to divide the size of the file by two.<<BR>><<BR>> {{attachment:tf_hilbert_options.gif||height="435",width="374"}} * Right-click on the Hilbert file > '''Display on cortex'''. <<BR>><<BR>> {{attachment:tf_hilbert_popup.gif||height="182",width="284"}} * The frequency slider now shows frequency bands ("alpha:8-12Hz") instead of frequencies ("12Hz").<<BR>>At 90ms, we observe a strong response in the auditory cortex in the alpha band (left) and a response in the motor cortex in the low gamma (right). <<BR>>This could make sense, but this is for illustration purpose only, as we said before we cannot interpret what is happening at 10Hz, and we shouldn't have been computing the decomposition of the average, but rather the average of the TF of all the trials. <<BR>><<BR>> {{attachment:tf_hilbert_alpha.gif||height="175",width="401"}} {{attachment:tf_hilbert_gamma.gif||height="175",width="222"}} * '''Shift + click '''on the cortex surface: Displays the TF decomposition of the selected source.<<BR>>In the TF figure, it doesn't show as a high value because this file hasn't been normalized.<<BR>><<BR>> {{attachment:tf_sources.gif}} * '''Right-click on the brain''': Selects the closest vertex and displays the popup menu at the same time. The first three menus are relative to the source that was just clicked. <<BR>><<BR>> {{attachment:tf_sources_popup.gif}} <<TAG(Advanced)>> == On the hard drive == Right click one of the first TF file we computed > File > '''View file contents'''. . {{attachment:tf_contents.gif||height="450",width="563"}} ==== Structure of the time-frequency files: timefreq_*.mat ==== * '''TF''': [Nsignals x Ntime x Nfreq] matrix containing all the values of the time-frequency decomposition (complex wavelet coefficients, or double values for power/magnitude/Z-score). * '''TFmask''': [Nfreq x Ntime] logical mask indicating the edge effects (0=edge, 1=valid value). * '''Std''': [Nsignals x Ntime x Nfreq] standard deviation if this file is an average. * '''Comment''': String displayed in the database explorer to represent the file. * '''DataType''': From what kind of data this file was computed: {'data', 'results', 'scout, 'matrix'} * '''Time''': [1 x Ntime] Time vector used to estimate this file. * '''TimeBands''': [Ntimebands x 3] Cell array where each line represents a time band: <<BR>>{'band_name', 'time definition', 'function'} * '''Freqs''': For regular frequency binning: vector containing all the frequencies.<<BR>>If using frequency bands: [Nfreqbands x 3] cell array, where each line represents a frequency band {'band_name', 'frequency definition', 'function'} * '''RefRowNames''': Used only for connectivity matrices. * '''RowNames''': [1 x Nsignals] Cell array of strings that describes each row of the TF matrix. In this specific case, it would be the list of all the MEG sensor names. But it could also be a list of names of scouts or clusters. * '''Measure''': Contains the name of the function that was applied right after the computation of the wavelet coefficients. So it represents the type of data contained in the TF matrix. Possible values: * '''none''': No measure applied, TF contains the complex wavelet coefficients. * '''power''': Power for each frequency, ie. the square of the amplitude: abs(coefficients).^2 * '''magnitude''': abs(coefficients) * '''log''': 10 * log10( abs(coefficients).^2) * '''phase''': angle(coefficients) * '''Method''': String that identifies the process that generated the file: <<BR>>{'morlet', 'fft', 'psd', 'hilbert', 'corr', 'cohere', 'granger', 'plv'} * '''DataFile''': Initial file from which this file was computed. In the database explorer, the TF file will be shown as a child of this DataFile file. * '''SurfaceFile''' / '''GridLoc''' / '''GridAtlas''': Source space that was used, only for source files. * '''nAvg''': Number of trials that were averaged to obtain this file. * '''ColormapType''': String, force a specific colormap type to be used when displaying this file. * '''DisplayUnits''': String, force to use specific units when displaying this file. * '''Options''': Options that were selected in the time-frequency options window. * '''History''': List of operations performed on this file (menu File > View file history). ==== Useful functions ==== * '''in_bst_timefreq'''(TimefreqFile): Read a time-frequency file. * '''in_bst'''(FileName, TimeWindow): Read any Brainstorm file with the possibility to load only a specific part of the file. "TimeWindow" is an range of time values in seconds: [tStart, tStop]. * '''bst_process'''(''''LoadInputFile'''', FileName, Target, TimeWindow): The most high-level function for reading data files. "Target" is a string with the list of sensor names or types to load. * '''morlet_transform'''(): Applies complex Morlet wavelet transform to the timeseries in input <<TAG(Advanced)>> == References [TODO] == * Bertrand O, Tallon-Baudry C (2000)<<BR>> [[http://www.sciencedirect.com/science/article/pii/S0167876000001665|Oscillatory gamma activity in humans: a possible role for object representation]] * Add reference for bandpass+Hilbert <<TAG(Advanced)>> == Additional documentation == * Forum: Time and frequency resolution: http://neuroimage.usc.edu/forums/showthread.php?1848 == Delete all your experiments == Before moving to the next tutorial, '''delete '''all the time-frequency files you computed in this tutorial. It will make the database structure less confusing for the following tutorials. <<HTML(<!-- END-PAGE -->)>> <<EmbedContent("http://neuroimage.usc.edu/bst/get_prevnext.php?prev=Tutorials/Scouts&next=Tutorials/Difference")>> |
Tutorial 24: Time-frequency
Authors: Francois Tadel, Dimitrios Pantazis, Elizabeth Bock, Sylvain Baillet
This tutorial introduces how to compute time-frequency decomposition of MEG/EEG recordings and cortical currents using complex Morlet wavelets and Hilbert transforms.
Contents
- Introduction
- Morlet wavelets
- Edge effects
- Simulation
- Process options
- Display: One channel
- Display: Mouse and keyboard shortcuts
- Display: Power spectrum and time series
- Normalized time-frequency maps
- Tuning the wavelet parameters [TODO]
- Hilbert transform [TODO]
- MEG recordings: Single trials [TODO]
- Display: All channels [TODO]
- Display: Sensor topography [TODO]
- Scouts [TODO]
- Full cortical maps [TODO]
- On the hard drive
- References [TODO]
- Additional documentation
- Delete all your experiments
Introduction
Some of the MEG/EEG signal properties are difficult to access in time domain (graphs time/amplitude). A lot of the information of interest is carried by oscillations at certain frequencies, but the amplitude of these oscillations is sometimes a lot lower than the amplitude of the slower components of the signal, making them difficult to observe.
The averaging in time domain may also lead to a cancellation of these oscillations when they are not strictly locked in phase across trials. Averaging trials in time-frequency domain allows to extract the power of the oscillation regardless of the phase shifts. For a better understanding of this topic, we recommend the lecture of the following article: Bertrand O, Tallon-Baudry C (2000), Oscillatory gamma activity in humans: a possible role for object representation
In Brainstorm we offer two approaches for computing time-frequency decomposition (TF): the first one is based on the convolution of the signal with series of complex Morlet wavelets, the second filters the signal in different frequency bands and extracts the envelope of the filtered signals using the Hilbert transform.
Morlet wavelets
Complex Morlet wavelets are very popular in EEG/MEG data analysis for time-frequency decomposition. They have the shape of a sinusoid, weighted by a Gaussian kernel, and they can therefore capture local oscillatory components in the time series. An example of this wavelet is shown below, where the blue and red curves represent the real and imaginary part, respectively.
Contrary to the standard short-time Fourier transform, wavelets have variable resolution in time and frequency. When designing the wavelet, we basically decide a trade off between temporal and spectral resolution.
To design the wavelet, we first need to choose a central frequency, ie the frequency where we will define the mother wavelet. All other wavelets will be scaled and shifted versions of the mother wavelet. Unless interested in designing the wavelet at a particular frequency band, the default 1Hz should be fine.
Then, the desirable time resolution for the central frequency should be defined. For example, we may wish to have a temporal resolution of 3 seconds at frequency 1 Hz (default parameters). These two parameters, uniquely define the temporal and spectral resolution of the wavelet for all other frequencies, as shown in the plots below.
Resolution is given in units of Full Width Half Maximum of the Gaussian kernel, both in time and frequency. The relevant plots are given below.
Edge effects
Users should pay attention to edge effects when applying wavelet analysis. Wavelet coefficients are computed by convolving the wavelet kernel with the time series. Similarly to any convolution of signals, there is zero padding at the edges of the time series and therefore the wavelet coefficients are weaker at the beginning and end of the time series.
From the figure above, which designs the Morlet wavelet, we can see that the default wavelet (central frequency fc=1Hz, FWHM_tc=3sec) has temporal resolution 0.6sec at 5Hz and 0.3sec at 10Hz. In such case, the edge effects are roughly half these times: 300ms in 5Hz and 150ms in 10Hz.
More precisely, if f is your frequency of interest, you can expect the edge effects to span over FWHM_t seconds: FWHM_t = FWHM_tc * fc / f / 2. Examples of such edge effects are given in the figures below.
Simulation
We will illustrate the time-frequency decomposition process with a simulated signal.
The following code generates a sum of three sinusoids (2Hz, 20Hz, 50Hz).
The 50Hz is present everywhere, the two others start only after two seconds.
f1 = 2; f2 = 20; f3 = 50; i =2000:6000; Data(1,i) = sin(f1*2*pi*t(i)) + 0.4 * cos(f2*2*pi*t(i)); Data = Data + 0.2 * sin(f3*2*pi*t);
Empty the Process1 list (right-click > Clear list) then click on [Run].
Select process: Simulate > Simulate genertic signals.
Ntime=6000, Sampling frequency=1000Hz (signal duration = 6000/1000 = 6 seconds).
Copy-paste the few lines of code above to generate the sum of three sinusoids.
Double-click on the new file to look at the simulated signal.
- In Process1, select the simulated signal.
Select process: Frequency > Time-frequency (Morlet wavelets).
Select the option 1/f compensation: The normalization will be discussed later.
Click on the button [Edit] to see all the process options.
Time definition: Same as input, Frequency definition: Linear 1:1:60, Compute measure: Power.
Process options
Comment: String that will be displayed in the database explorer to represent the output file.
Time definition
Same as input file: The output file has the same time definition as the input file.
In this example, it means: 6000 samples between 0 and 6s.Group in time bands: This option adds a step of computation. First it computes the TF decomposition for all the input file, then averages the power by time band. To define a time band:
Enter your own time bands in the text area, one line per time band, with the following format: "name / time definition / function"
- Click on the button [Generate] to automatically create a list of time bands with the same length. You will be asked the maximal length of each time band.
The function is the measure we take to combine the values for all the individual frequencies into one for the frequency band. Possible values are: mean, max, std, median.
Frequency definition: Frequencies for which the power will be estimated at each time instant.
Linear: You can specify the frequencies with the Matlab syntax start:step:stop.
The default is "1:1:60", which produces 60 values [1, 2, 3, 4, ..., 59, 60].Log: With the option start:N:stop, produces a list of N frequencies logarithmically scaled between "start" and "stop". For example "1:40:80" is converted to [1, 1.5, 2.1, 2.7, ..., 61.5, 65.8, 75, 80]
Group in frequency bands: As for the time definition, this option leads to a two-step process. First it computes the TF decomposition for several values in the frequency band, then it averages the power of TF coefficients per frequency band. To define a frequency band:
One line per frequency band, with the format "name / frequency definition / function"
The frequency definition is a Matlab expression evaluated with an eval() call. If the frequency definition contains only two values, Brainstorm adds two extra values in the middle so that the final averaged value is a bit more robust. Example of valid expressions:
"2,4": Evaluates to [2,4], and then expands to the frequency vector [2, 2.66, 3.33, 4]
"2:0.5:4": Evaluates to [2 2.5 3 3.5 4]
"2, 2.5, 3, 3.5, 4": Evaluates to [2 2.5 3 3.5 4]The function is the measure we take to combine the values for all the individual frequencies into one for the frequency band. Possible values are: mean, max, std, median.
Morlet wavelet options
Central frequency: Frequency where the mother wavelet is designed. All other wavelets will be shifted and scaled versions of the mother wavelet
Time resolution (FWHM): Temporal resolution of the wavelet at the central frequency (in units of Full Width Half Maximum). Click [Display] to see the resolution of the wavelet for other frequencies.
Compute the following measure:
- The convolution of the signal with complex Morlet wavelets returns the complex coefficients for each frequency/time/sensor. Typically, what we display is the power of the coefficients (square of the amplitude: abs(TF).^2). You can choose if you want to apply this transformation or not.
Power: Computes the "power" transformation immediately after the TF decomposition. This discards the phase information, but produces files that are twice smaller and a lot easier to process.
None: Save the TF coefficients as they are computed. This can be useful if you plan to use these decompositions for other purposes that require the phase.
- Some combinations of options may disable this choice. If you select frequency bands, the program will have to compute the power before averaging the values, therefore "none" is not an option.
Display: One channel
Right on the new time-frequency file > Time-freq: One matrix (same as double-clicking).
This menu displays the time-frequency decomposition of the first (and only) signal. The Brainstorm window shows two new elements: the tab "Display" and the frequency slider.
- We can easily identify the three horizontal bars as the three sinusoids in the simulated signals, and the trade-off between accuracy in time and accuracy in frenquency. Click on the figure to move the time-frequency cursor and explore the two axes of the plane.
- 2Hz: High frequency resolution but poor time resolution (supposed to start sharply at 2s)
- 20Hz: Better time resolution but poorer frequency resolution (17-24Hz)
- 50Hz: Continuous over the 6s - Frequency resolution gets even worse (40-60Hz)
Current frequency: Slider that shows the current frequency selected in all the figures.
Just like the time, the frequency selection is centralized and managed by one control only for all the figures. As a consequence, it is impossible to display TF files with different frequency definitions at the same time. This can be perceived as an annoying limitation, but it allows all the simultaneous displays to be consistent at anytime and makes the interface more intuitive to manipulate, with lower risks of mistakes in the interpretation of the different figures.List of signals: This drop-down list shows the current entry displayed in the selected figure. In this case, there is only one channel of data called "s1". It will be more useful later.
Hide edge effects: When this option is selected, the time-frequency coefficients that could not be properly estimated because of a lack of time samples are hidden. It allows you to see only the information that is really reliable. The lower the frequency, the longer the edge effects.
Smooth display: Re-interpolates the time-frequency maps on a finer grid to produce nicer plots.
Measure: Type of measure that is currently represented in the selected figure. The entries that are enabled depend on the type of data that is saved in the file. In this case, we saved directly the power of the wavelet coefficients in the file, we discarded the angle/phase information, so the "phase" option is disabled. The other options are: Magnitude = sqrt(power), Log = 10*log10(power)
Colormap: As explained in the previous tutorials, you can change the colormap by clicking+moving on the colorbar on the right of the figure. Double-click on the colorbar to restore the defaults.
Display: Mouse and keyboard shortcuts
Mouse shortcuts
Left-click: Selection of current time and frequency.
Left-click + move: Select a time/frequency range. The legends of the X/Y axis show the selection.
Mouse wheel: Zoom in time, centered on the current time cursor.
Control + mouse wheel: Zoom in frequencies, centered on the current frequency cursor.
Right-click + move, or Control + left-click + move: Move in the zoomed image.
Double-click: Restore initial view.
Keyboard shortcuts:
Left/right arrows: Change the current time.
Page-up/page-down: Change the current time, 10 time samples at a time.
Up/down arrows: Change the the sensor displayed in this figure.
Control + up/down arrows: Change the current frequency.
Enter: View the original time series for this sensor.
Control + R: View the original MEG recordings.
Control + T: View the time-frequency 2D topography.
Control + I: Save as image.
Control + D: Dock figure in the Matlab environment.
Figure popup menu
Set selection manually: Does the same thing as drawing a time/freq selection square on a figure, but by typing the values for time and frequency manually.
Export to database: Save the selection for the displayed sensor in a new file in the database.
Export to file: Same as "Export to database", but the saved file is not registered in the database.
Export to Matlab: Same as "Export to database", but the output structure is sent to a variable in the Matlab base workspace instead of being saved to a file.
Display: Power spectrum and time series
These two menus generate similar figures:
Power spectrum: For the current time, shows the power of all the sensors across the frequencies.
Time series: For the current frequency, shows the power of all the sensors in time.
Example: Power spectrum density at 0.6s and the power time series at 2Hz.
We see only the oscillation at the 2Hz in both dimensions.
Example: Power spectrum density at 4s and the power time series at 20Hz.
At this time, we can see the three oscillations in the PSD figure.
Note that if you right-click on the file in the database explorer and then select one of these menus, it will show all the signals. If you right-click on an existing time-frequency figure, it will show only the selected signal. It doesn't make any difference here because there is only one signal, but it will with the MEG recordings.
Normalized time-frequency maps
The brain is always active, the MEG/EEG recordings are never flat, some oscillations are always present in the signals. Therefore we are often more interested in the transient changes in the power at certain frequencies than at the actual power. A good way to observe these changes is to compute a deviation of the power with respect with a baseline.
There is another reason for which we are usually interested in standardizing the TF values. The power of the time-frequency coefficients are always lower in the higher frequencies than in the lower frequencies, the signal carries a lot less power in the faster oscillations than in the slow brain responses. This 1/f decrease in power is an observation that we already made with the power spectrum density in the filtering tutorial.
If we represent the TF maps with a linear color scale, we will always see values close to zero in the higher frequency ranges. Normalizing each frequency separately with respect with a baseline helps obtaining more readable TF maps.
The values we were looking at were already normalized (option: "1/f compensation" in the process options). We will now compute the non-normalized power obtained with the Morlet wavelets and try the various options available for normalizing them.
- In Process1, keep the simulated signal selected.
Run process: Frequency > Time-frequency (Morlet wavelets), "Spectral flattening: None"
Double-click on the file. As expected, we only the lower frequencies when looking at this map, because the power of the 2Hz oscillation is a lot larger than the power at 20Hz or 60Hz.
- In Process1: Select this new non-normalized file "Power,1-60Hz".
Run process: Standardize > Baseline normalization,
Double-click on the original TF file and the two normalized files (center=Z-score, right=ERD/ERS). Select the option "Smooth display" to make the figures look nicer.
The normalized maps seem to show a response of the left primary auditory cortex (A1L is the first scout in the file) around 35Hz and 80ms. The large red part at the lower frequency is probably part of the evoked response to the stimulus, but all these values could not be estimated properly because the time window is not long enough. Because we used the baseline between -100ms and 0ms, we cannot really trust anything below 30Hz or 40Hz.
- A better approach would have been to import longer epochs (+200ms on each side), then to normalize the values based on the "safe" part of the baseline (100ms-0ms). If you include the edge effects in your baseline, you end up propagating them in all the epoch.
The figures do not use the same colormaps because the original TF file is displayed using the colormap "Timefreq" while the normalized files are displayed using the colormap "Stat 2". If you want to look at the normalized maps using a different colormap, right-click on the figure and change the colormap configuration.
Tuning the wavelet parameters [TODO]
- Different resolutions
- Log scaled frequencies: 1:40:80
Hilbert transform [TODO]
MEG recordings: Single trials [TODO]
Display: All channels [TODO]
Three menus display the time-frequency of all the sensors with different spatial organizations.
All channels: All the maps are displayed one after the other, in the order they are saved in the file.
2D Layout (maps): Show each TF map where the sensor is located on a flattened 2D map.
2D Layout (no overlap): Similar to the the previous display, but the positions of the images are reorganized so that they do not overlap.
Useful shortcuts for these figures:
Click: clicking on any small TF image opens a new figure to display only the selected sensor.
Shift + click: Same, but opens the original recordings time series of the sensor instead of the TF.
Mouse wheel: Zoom in/out.
Right click + move: Move in a zoomed figure.
Display: Sensor topography [TODO]
The menus below show the distribution of TF power over the sensors, for one time point and one frequency bin, very similarly to what was introduced in tutorial Visual exploration.
2D Sensor cap / 2D Disc / 3D Sensor cap: 90ms, 8Hz
2D Layout: 8Hz (black), 35Hz (white)
Useful shortcuts for these figures:
Left/right arrows: Change the current time.
Up/down arrows: Change the current frequency.
Control + E: Display the sensors markers/names.
Shift + click on a sensor: Displays the time-frequency decomposition for that specific sensors.
Right click + move: Select a group of sensors.
Shift + scroll: Change the gain of the time series (2D Layout).
Control + scroll: Change the length of the window displayed around the current time (2D Layout).
Scouts [TODO]
Similar calculations can be done at the level of the sources, either on the full cortex surface or on a limited number of regions of interests. We will start with the latter as it is usually an easier approach.
We will use this section to illustrate the online averaging of the trials TF decomposition as well.
Drag and drop all the deviant trials from both runs, select [Process sources].
Run process "Frequency > Time-frequency (Morlet wavelets)".
Select the option "Use scouts" and select all the scouts defined in the previous tutorial.
In the advanced options, select "Scout function: After" and "Output: Save average".
Run the process (it may take a while).
- The scout function was introduced in the previous tutorial. It is the method we use to group the time series for the 40*3=120 unconstrained dipoles we have in each scout into one unique signal per orientation (three signals in the unconstrained case). When computing the TF of one scout, we have the choice between applying this function before or after the time-frequency decomposition itself.
Before: Extract the 120 source signals, apply the scout function to get three signals (one per orientation), run the TF decomposition of the three signals, and finally sum the power of the three TF maps. This is faster but may lose some frequency resolution (especially for constrained sources).
After: Extract the 120 source signals, run the TF decomposition of the 120 signals, apply the scout function on the power of the TF maps for each orientation separately, and finally sum the three orientations. You should always prefer this option if the computation times are not insane.
Save individual TF maps: This option stops the computation here and saves in the database one time-frequency file for each input file (40 files), with one TF map for each scout.
Save average TF maps: Instead of saving the TF for each file separately, it automatically computes the average of the power of all the TF. This is a good choice if you do not plan to use independently all the TF files, because it saves a lot of time and disk space.
Rename the new file to add a tag "Deviant" in it. Then right-click > Time-freq: All scouts.
Full cortical maps [TODO]
Computing the time-frequency decomposition for all the sources of the cortex surface is possible but complicated because it can easily generate gigantic files, completely out of the reach of most computers. For instance the full TF matrix for each epoch we have here would be [Nsources x Ntimes x Nfrequencies] = [45000 x 361 x 40] double-complex = 9.7 Gb!
We have two ways of going around this issue: computing the TF decomposition for fewer frequency bins or frequency bands at a time, or computing the TF decomposition of the sensor values and projecting it dynamically to the cortex using the inverse operator.
This latter approach is possible because the two processes (TF decomposition and inversion) are linear and permutable. However this is enabled only for contrained sources (so not possible in the present case).
TF(Inverse(Recordings)) = Inverse(TF(Recordings))
=> Power(TF(Inverse(Recordings))) = Power(Inverse(TF(Recordings)))
For illustration purpose, we will use the other time-frequency decomposition option available in Brainstorm, which is based on Hilbert transforms of band-passed signals, using only 6 pre-defined frequency bands.
Drag and drop in Process1 the sources for the deviant average in Run#01.
Select the process "Frequency > Hilbert transform".
To process the entire brain, do not select the option "Use scouts".
In the advanced options, select "No, save full hilbert(sources)" because the other option is not available on unconstrained sources, and "magnitude" to divide the size of the file by two.
The frequency slider now shows frequency bands ("alpha:8-12Hz") instead of frequencies ("12Hz").
At 90ms, we observe a strong response in the auditory cortex in the alpha band (left) and a response in the motor cortex in the low gamma (right).
This could make sense, but this is for illustration purpose only, as we said before we cannot interpret what is happening at 10Hz, and we shouldn't have been computing the decomposition of the average, but rather the average of the TF of all the trials.
Shift + click on the cortex surface: Displays the TF decomposition of the selected source.
In the TF figure, it doesn't show as a high value because this file hasn't been normalized.
Right-click on the brain: Selects the closest vertex and displays the popup menu at the same time. The first three menus are relative to the source that was just clicked.
On the hard drive
Right click one of the first TF file we computed > File > View file contents.
Structure of the time-frequency files: timefreq_*.mat
TF: [Nsignals x Ntime x Nfreq] matrix containing all the values of the time-frequency decomposition (complex wavelet coefficients, or double values for power/magnitude/Z-score).
TFmask: [Nfreq x Ntime] logical mask indicating the edge effects (0=edge, 1=valid value).
Std: [Nsignals x Ntime x Nfreq] standard deviation if this file is an average.
Comment: String displayed in the database explorer to represent the file.
DataType: From what kind of data this file was computed: {'data', 'results', 'scout, 'matrix'}
Time: [1 x Ntime] Time vector used to estimate this file.
TimeBands: [Ntimebands x 3] Cell array where each line represents a time band:
{'band_name', 'time definition', 'function'}Freqs: For regular frequency binning: vector containing all the frequencies.
If using frequency bands: [Nfreqbands x 3] cell array, where each line represents a frequency band {'band_name', 'frequency definition', 'function'}RefRowNames: Used only for connectivity matrices.
RowNames: [1 x Nsignals] Cell array of strings that describes each row of the TF matrix. In this specific case, it would be the list of all the MEG sensor names. But it could also be a list of names of scouts or clusters.
Measure: Contains the name of the function that was applied right after the computation of the wavelet coefficients. So it represents the type of data contained in the TF matrix. Possible values:
none: No measure applied, TF contains the complex wavelet coefficients.
power: Power for each frequency, ie. the square of the amplitude: abs(coefficients).^2
magnitude: abs(coefficients)
log: 10 * log10( abs(coefficients).^2)
phase: angle(coefficients)
Method: String that identifies the process that generated the file:
{'morlet', 'fft', 'psd', 'hilbert', 'corr', 'cohere', 'granger', 'plv'}DataFile: Initial file from which this file was computed. In the database explorer, the TF file will be shown as a child of this DataFile file.
SurfaceFile / GridLoc / GridAtlas: Source space that was used, only for source files.
nAvg: Number of trials that were averaged to obtain this file.
ColormapType: String, force a specific colormap type to be used when displaying this file.
DisplayUnits: String, force to use specific units when displaying this file.
Options: Options that were selected in the time-frequency options window.
History: List of operations performed on this file (menu File > View file history).
Useful functions
in_bst_timefreq(TimefreqFile): Read a time-frequency file.
in_bst(FileName, TimeWindow): Read any Brainstorm file with the possibility to load only a specific part of the file. "TimeWindow" is an range of time values in seconds: [tStart, tStop].
bst_process('LoadInputFile', FileName, Target, TimeWindow): The most high-level function for reading data files. "Target" is a string with the list of sensor names or types to load.
morlet_transform(): Applies complex Morlet wavelet transform to the timeseries in input
References [TODO]
Bertrand O, Tallon-Baudry C (2000)
Oscillatory gamma activity in humans: a possible role for object representation- Add reference for bandpass+Hilbert
Additional documentation
Forum: Time and frequency resolution: http://neuroimage.usc.edu/forums/showthread.php?1848
Delete all your experiments
Before moving to the next tutorial, delete all the time-frequency files you computed in this tutorial. It will make the database structure less confusing for the following tutorials.