Commit fcf68542 authored by Rafael Laboissière's avatar Rafael Laboissière
Browse files

New upstream version 6.0.38

parent 611f3b4b
Loading
Loading
Loading
Loading
+71 −4
Original line number Diff line number Diff line
/* EEG.cpp
 *
 * Copyright (C) 2011-2012,2013,2014,2015,2017 Paul Boersma
 * Copyright (C) 2011-2018 Paul Boersma
 *
 * This code is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
@@ -571,6 +571,26 @@ autoEEG EEG_extractChannel (EEG me, const char32 *channelName) {
	}
}

autoEEG EEG_extractChannels (EEG me, numvec channelNumbers) {
	try {
		integer numberOfChannels = channelNumbers.size;
		Melder_require (numberOfChannels > 0,
			U"The number of channels should be greater than 0.");
		autoEEG you = EEG_create (my xmin, my xmax);
		your sound = Sound_extractChannels (my sound.get(), channelNumbers);
		your numberOfChannels = numberOfChannels;
		your channelNames = NUMvector <char32 *> (1, numberOfChannels);
		for (integer ichan = 1; ichan <= numberOfChannels; ichan ++) {
			integer originalChannelNumber = Melder_iround (channelNumbers [ichan]);
			your channelNames [ichan] = Melder_dup (my channelNames [originalChannelNumber]);
		}
		your textgrid = Data_copy (my textgrid.get());
		return you;
	} catch (MelderError) {
		Melder_throw (me, U": channels not extracted.");
	}
}

autoEEG EEGs_concatenate (OrderedOf<structEEG>* me) {
	try {
		if (my size < 1)
@@ -636,9 +656,12 @@ void EEG_replaceTextGrid (EEG me, TextGrid textgrid) {
	}
}

autoMixingMatrix EEG_to_MixingMatrix (EEG me, integer maxNumberOfIterations, double tol, int method) {
autoMixingMatrix EEG_to_MixingMatrix (EEG me,
	double startTime, double endTime, integer numberOfCrossCorrelations, double lagStep,
	integer maxNumberOfIterations, double tol, int method)
{
	try {
		autoCrossCorrelationTableList tables = Sound_to_CrossCorrelationTableList (my sound.get(), 0.0, 0.0, 0.002, 1);
		autoCrossCorrelationTableList tables = Sound_to_CrossCorrelationTableList (my sound.get(), startTime, endTime, numberOfCrossCorrelations, lagStep);
		autoMixingMatrix thee = MixingMatrix_create (my sound -> ny, my sound -> ny);
		MixingMatrix_setRandomGauss (thee.get(), 0.0, 1.0);
		for (integer ichan = 1; ichan <= my numberOfChannels; ichan ++) {
@@ -652,4 +675,48 @@ autoMixingMatrix EEG_to_MixingMatrix (EEG me, integer maxNumberOfIterations, dou
	}
}

autoEEG EEG_MixingMatrix_to_EEG_unmix (EEG me, MixingMatrix you) {
	Melder_require (my numberOfChannels == your numberOfRows,
		U"To be able to unmix, the number of channels in ", me, U" (", my numberOfChannels, U")",
		U" should be equal to the number of rows in ", you, U"(", your numberOfRows, U").");
	for (integer ichan = 1; ichan <= your numberOfRows; ichan ++) {
		Melder_require (Melder_equ (my channelNames [ichan], your rowLabels [ichan]),
			U"To be able to unmix, the name of channel ", ichan,
			U" should be the same in ", me, U" (where it is ", my channelNames [ichan], U")",
			U" as in ", you, U" (where it is ", your rowLabels [ichan], U").");
	}
	autoEEG him = EEG_create (my xmin, my xmax);
	his sound = Sound_MixingMatrix_unmix (my sound.get(), you);
	his textgrid = Data_copy (my textgrid.get());
	his numberOfChannels = your numberOfColumns;
	his channelNames = NUMvector <char32 *> (1, his numberOfChannels);
	//his channelNames = NUMstrings_copy (your columnLabels, 1, his numberOfChannels);
	for (integer ichan = 1; ichan <= his numberOfChannels; ichan ++) {
		his channelNames [ichan] = Melder_dup (your columnLabels [ichan]);
	}
	return him;
}

autoEEG EEG_MixingMatrix_to_EEG_mix (EEG me, MixingMatrix you) {
	Melder_require (my numberOfChannels == your numberOfColumns,
		U"To be able to mix, the number of channels in ", me, U" (", my numberOfChannels, U")",
		U" should be equal to the number of columns in ", you, U"(", your numberOfColumns, U").");
	for (integer ichan = 1; ichan <= your numberOfColumns; ichan ++) {
		Melder_require (Melder_equ (my channelNames [ichan], your columnLabels [ichan]),
			U"To be able to mix, the name of channel ", ichan,
			U" should be the same in ", me, U" (where it is ", my channelNames [ichan], U")",
			U" as in ", you, U" (where it is ", your columnLabels [ichan], U").");
	}
	autoEEG him = EEG_create (my xmin, my xmax);
	his sound = Sound_MixingMatrix_mix (my sound.get(), you);
	his textgrid = Data_copy (my textgrid.get());
	his numberOfChannels = your numberOfRows;
	his channelNames = NUMvector <char32 *> (1, his numberOfChannels);
	//his channelNames = NUMstrings_copy (your rowLabels, 1, his numberOfChannels);
	for (integer ichan = 1; ichan <= his numberOfChannels; ichan ++) {
		his channelNames [ichan] = Melder_dup (your rowLabels [ichan]);
	}
	return him;
}

/* End of file EEG.cpp */
+9 −2
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@
#define _EEG_h_
/* EEG.h
 *
 * Copyright (C) 2011-2012,2014,2015,2017 Paul Boersma
 * Copyright (C) 2011-2012,2014,2015,2017,2018 Paul Boersma
 *
 * This code is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
@@ -53,11 +53,18 @@ void EEG_setChannelToZero (EEG me, const char32 *channelName);
void EEG_removeTriggers (EEG me, kMelder_string which, const char32 *criterion);
autoEEG EEG_extractChannel (EEG me, integer channelNumber);
autoEEG EEG_extractChannel (EEG me, const char32 *channelName);
autoEEG EEG_extractChannels (EEG me, numvec channelNumbers);
static inline autoSound EEG_extractSound (EEG me) { return Data_copy (my sound.get()); }
static inline autoTextGrid EEG_extractTextGrid (EEG me) { return Data_copy (my textgrid.get()); }
autoEEG EEG_extractPart (EEG me, double tmin, double tmax, bool preserveTimes);
void EEG_replaceTextGrid (EEG me, TextGrid textgrid);
autoMixingMatrix EEG_to_MixingMatrix (EEG me, integer maxNumberOfIterations, double tol, int method);

autoMixingMatrix EEG_to_MixingMatrix (EEG me,
	double startTime, double endTime, integer numberOfCrossCorrelations, double lagStep,
	integer maxNumberOfIterations, double tol, int method);

autoEEG EEG_MixingMatrix_to_EEG_unmix (EEG me, MixingMatrix you);
autoEEG EEG_MixingMatrix_to_EEG_mix (EEG me, MixingMatrix you);

/* End of file EEG.h */
#endif
+22 −1
Original line number Diff line number Diff line
@@ -21,7 +21,7 @@
void manual_EEG_init (ManPages me);
void manual_EEG_init (ManPages me) {

MAN_BEGIN (U"EEG", U"ppgb", 20120511)
MAN_BEGIN (U"EEG", U"ppgb", 20180329)
INTRO (U"EEG means electro-encephalography: brain potentials recorded via e.g. 32 or 64 electrodes on the scalp. "
	"In Praat, an EEG object looks like a combination of a Sound object with e.g. 32 or 64 channels "
	"and a TextGrid object that marks the events.")
@@ -86,6 +86,27 @@ NORMAL (U"Once you have an ERPTier, you can extract each of the 150 ERPs from it
NORMAL (U"Once you have an ERP object, you can look into it with ##View & Edit#. "
	"If you want to see in the ERP window the scalp distribution at the time of the cursor, or the average scalp distribution in the selected time stretch, "
	"you have to switch on ##Show selection viewer# in the #Preferences window (available from the #File menu).")
ENTRY (U"See also")
LIST_ITEM (U"\\bu @@Independent Component Analysis on EEG@")
MAN_END

MAN_BEGIN (U"Independent Component Analysis on EEG", U"ppgb", 20180329)
INTRO (U"Independent Component Analysis (ICA) is often used to improve @EEG signals. "
	"See @@blind source separation@ for the algorithm.")
ENTRY (U"1. Selecting your channels")
NORMAL (U"You typically will not want to do ICA on all 80 channels of your signal, "
	"some of which may not even be EEG channels. To create a smaller EEG with e.g. only the 64 scalp channels, "
	"use ##EEG: Extract channels...#. From here on we will assume that your reduced EEG has 64 channels.")
ENTRY (U"2. How to get a MixingMatrix")
NORMAL (U"Once you have your reduced EEG, you can start to do ICA on it. "
	"This starts by creating a @MixingMatrix: select your EEG object and choose ##To MixingMatrix...#. "
	"The resulting MixingMatrix has one row for each of your 64 EEG channels, and columns called \"ic1\" through \"ic64\".")
ENTRY (U"3. How to see the independent components")
NORMAL (U"Select you EEG and your MixingMatrix together and choose ##Unmix#. "
	"The resulting ICA-EEG will have 64 channels called \"ic1\" through \"ic64\".")
ENTRY (U"4. Just checking back")
NORMAL (U"If you select your ICA-EEG together with your MixingMatrix choose ##Mix#, "
	"the resulting EEG should be very similar to your original 64-channel EEG.")
MAN_END

}
+29 −1
Original line number Diff line number Diff line
/* praat_EEG.cpp
 *
 * Copyright (C) 2011-2012,2013,2014,2015,2016,2017 Paul Boersma
 * Copyright (C) 2011-2018 Paul Boersma
 *
 * This code is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
@@ -198,6 +198,15 @@ DO
	CONVERT_EACH_END (my name, U"_", channelName)
}

FORM (NEW_EEG_extractChannels, U"EEG: Extract channels", nullptr) {
	NUMVEC (channels, U"Channel numbers", U"to# (64)")
	OK
DO
	CONVERT_EACH (EEG)
		autoEEG result = EEG_extractChannels (me, channels);
	CONVERT_EACH_END (my name, U"_ch")
}

FORM (NEW_EEG_extractPart, U"EEG: Extract part", nullptr) {
	REAL (fromTime, U"left Time range (s)", U"0.0")
	REAL (toTime, U"right Time range (s)", U"1.0")
@@ -281,6 +290,9 @@ DIRECT (NEW1_EEGs_concatenate) {
}

FORM (NEW_EEG_to_MixingMatrix, U"To MixingMatrix", nullptr) {
	praat_TimeFunction_RANGE (startTime, endTime)
	NATURAL (numberOfCrossCorrelations, U"Number of cross-correlations", U"40")
	POSITIVE (lagStep, U"Lag step (s)", U"0.002")
	NATURAL (maximumNumberOfIterations, U"Maximum number of iterations", U"100")
	POSITIVE (tolerance, U"Tolerance", U"0.001")
	OPTIONMENUx (diagonalizationMethod, U"Diagonalization method", 2, 1)
@@ -290,10 +302,23 @@ FORM (NEW_EEG_to_MixingMatrix, U"To MixingMatrix", nullptr) {
DO
	CONVERT_EACH (EEG)
		autoMixingMatrix result = EEG_to_MixingMatrix (me,
			startTime, endTime, numberOfCrossCorrelations, lagStep,
			maximumNumberOfIterations, tolerance, diagonalizationMethod);
	CONVERT_EACH_END (my name)
}

DIRECT (NEW_EEG_MixingMatrix_to_EEG_unmix) {
	CONVERT_TWO (EEG, MixingMatrix)
		autoEEG result = EEG_MixingMatrix_to_EEG_unmix (me, you);
	CONVERT_TWO_END (my name, U"_", your name)
}

DIRECT (NEW_EEG_MixingMatrix_to_EEG_mix) {
	CONVERT_TWO (EEG, MixingMatrix)
		autoEEG result = EEG_MixingMatrix_to_EEG_mix (me, you);
	CONVERT_TWO_END (my name, U"_", your name)
}

// MARK: - EEG & TextGrid

DIRECT (MODIFY_EEG_TextGrid_replaceTextGrid) {
@@ -730,6 +755,7 @@ void praat_EEG_init () {
		praat_addAction1 (classEEG, 0, U"Set channel to zero...", nullptr, 1, MODIFY_EEG_setChannelToZero);
	praat_addAction1 (classEEG, 0, U"Analyse", nullptr, 0, nullptr);
		praat_addAction1 (classEEG, 0, U"Extract channel...", nullptr, 0, NEW_EEG_extractChannel);
		praat_addAction1 (classEEG, 0, U"Extract channels...", nullptr, 0, NEW_EEG_extractChannels);
		praat_addAction1 (classEEG, 0, U"Extract part...", nullptr, 0, NEW_EEG_extractPart);
		praat_addAction1 (classEEG, 0, U"To ERPTier -", nullptr, 0, nullptr);
		praat_addAction1 (classEEG, 0, U"To ERPTier (bit)...", nullptr, 1, NEW_EEG_to_ERPTier_bit);
@@ -790,6 +816,8 @@ void praat_EEG_init () {
		praat_addAction1 (classERPTier, 0, U"Extract ERP...", nullptr, 0, NEW_ERPTier_to_ERP);
		praat_addAction1 (classERPTier, 0, U"To ERP (mean)", nullptr, 0, NEW_ERPTier_to_ERP_mean);

	praat_addAction2 (classEEG, 1, classMixingMatrix, 1, U"To EEG (unmix)", nullptr, 0, NEW_EEG_MixingMatrix_to_EEG_unmix);
	praat_addAction2 (classEEG, 1, classMixingMatrix, 1, U"To EEG (mix)", nullptr, 0, NEW_EEG_MixingMatrix_to_EEG_mix);
	praat_addAction2 (classEEG, 1, classTextGrid, 1, U"Replace TextGrid", nullptr, 0, MODIFY_EEG_TextGrid_replaceTextGrid);
	praat_addAction2 (classERPTier, 1, classTable, 1, U"Extract -", nullptr, 0, nullptr);
	praat_addAction2 (classERPTier, 1, classTable, 1, U"Extract events where column (number)...", nullptr, 1, NEW1_ERPTier_Table_extractEventsWhereColumn_number);
+3 −3
Original line number Diff line number Diff line
@@ -81,10 +81,10 @@ autoActivationList FFNet_Categories_to_ActivationList (FFNet me, Categories thee

		autoActivationList him = ActivationList_create (thy size, my nOutputs);
		for (integer i = 1; i <= thy size; i ++) {
			const char32 *citem = OrderedOfString_itemAtIndex_c (thee, i);
			integer pos = OrderedOfString_indexOfItem_c (my outputCategories.get(), citem);
			SimpleString category = thy at [i];
			integer pos = OrderedOfString_indexOfItem_c (my outputCategories.get(), category -> string);
			if (pos < 1) {
				Melder_throw (U"The FFNet doesn't know the category ", citem, U".");
				Melder_throw (U"The FFNet doesn't know the category ", category -> string, U".");
			}
			his z [i] [pos] = 1.0;
		}
Loading