Transformation de Fourrier?

Source :
https://www.youtube.com/watch?v=spUNpyF58BY

L’image ci dessus montre un graphique d’intensité sonore en fonction du temps. Comment faisons nous pour déterminer les différentes fréquences qui composent ce graphique? Tout d’abord, nous devons comprendre comment la superposition d’ondes sonores fonctionne. En effet, c’est beaucoup plus simple que vous le pensez!

Source :
https://www.youtube.com/watch?v=spUNpyF58BY

Comme vous pouvez observer, le graphique ci-dessus (pression en fonction du temps) nous montre deux fréquences différentes (Mauve = 294Hz || Jaune = 440Hz). Le graphique de couleur verte est la superposition des deux ondes. Nous pouvons observer qu’à certains endroits l’amplitude est très grande puisque c’est un temps qui coincide avec l’amplitude maximale des deux droites. À d’autres endroits l’addition des amplitudes s’annulent et crée une pression nulle. Comme nous pouvons voir, c’est simple de construire des graphiques à plusieurs fréquences. La question que nous nous posons ici c’est comment déduire les fréquences qui ont composé un graphique?

Source :
https://www.youtube.com/watch?v=spUNpyF58BY

Pour arriver à déduire la fréquence d’une onde complexe nous devons comprendre comment y arriver avec une onde prédéterminé. L’image ci-dessus nous montre une onde de 3Hz qui est divisé en 2 secondes. Un tour de cercle corresponds à deux secondes dans le graphique. Le centre du cercle corresponds à une intensité nulle et plus on s’éloigne du centre du cercle plus l’intensité est grande. Nous ne travaillons pas dans le négatif, puisque le centre du cercle ne correspondra plus au bas de l’onde.


Source :
https://www.youtube.com/watch?v=spUNpyF58BY

Quand nous changeons la valeur d’un tour de cercle (Le temps qui corresponds à un tour) le graphique résultant change aussi. (Afin de continuer les explications nous allons appeller la valeur d’un tour de cercle gamma.) Dans la deuxième image, nous observons une forme hors du commun puisque la valeur de gamma équivaut à la fréquence de l’onde. Hélas! Nous devons nous questionner sur cet effet.

Source :
https://www.youtube.com/watch?v=spUNpyF58BY&t=243s

Avec le graphique et les informations que nous avons trouvé nous pouvons maintenant déduire la fréquence de l’onde. Pour ce faire, nous devons trouver le centre de la masse du graphique gamma. Pourquoi? Quand la valeur de gamma est égale à la valeur de la fréquence de l’onde, la valeur en X du centre de masse est grande. Pour déduire la fréquence, il suffit d’observer le graphique de la coordonnée en X et trouver ou il y a un pic!

Source :
https://www.youtube.com/watch?v=spUNpyF58BY&t=243s

Comme vous l’avez deviné, la somme de deux ondes de différentes fréquences fonctionne similairement! C’est à dire, dans le graphique de la coordonnée en X du centre de masse il y a deux pics. Chaque pic est égale à une fréquence qui compose l’onde.

Source :
https://www.youtube.com/watch?v=spUNpyF58BY&t=243s

Pour trouver le point du centre de masse plus précisément nous devons faire une intégrale d’un infinité de points sur la forme obtenue. Voici la fonction finale qui est utilisé afin de calculer les différentes fréquences sur le spectromètre.

Source :
https://www.youtube.com/watch?v=spUNpyF58BY&t=243s
Source :
https://www.mathworks.com/help/matlab/examples/fft-for-spectral-analysis.html

Comme vous l’avez deviné, la voix humaine est une composition de différentes fréquences. Pour déterminer quelle fréquences est la plus dominante, nous devons analyser d’avantage le graphique d’intensité en fonction de la fréquence. Par la suite nous prenons la valeur maximale d’intensité afin de déterminer la fréquence qui est la plus dominante. J’ai choisi de faire cette partie en processing puisqu’il existe une libraire qui utilise la transformation de fourrier. Voici comment déterminer la fréquence dominante :

Nous parcourons les bandes données par la transformation de fourrier afin de trouver elle qui à l’intensité la plus grande. Par la suite, afin de déterminer la fréquence de celle-ci nous devons trouver la vitesse à laquelle nous prenons les données et le diviser par le nombres de bandes que nous avons.

Lors des premiers essaies, nous avons déterminé que la fréquence obtenue est grandement influencé par le bruit ambiant. Nous nous sommes penché fortement sur ce sujet afin de comprendre comment éliminer le bruit ambiant et calculer la fréquence plus précisément. Pour ce faire, nous avons décidé de faire une moyenne en décibels du bruit ambiant. Quand nous avons un bruit qui nettement supérieur à la fréquence ambiante nous calculons la fréquence de celui-ci!

C’est assez simple comme fonction! La fonction CalculPower() envoie un chiffre entre 0 et 3 inclus au port serial dépendant de la fréquence déterminée. Le arduino comprends ces chiffres et fait avancer / reculer l’automobile en fonction du chiffre obtenue.

Contrôler l’automobile téléguidée

Comment s’y prendre?

Pour commencer nos tests, nous avons utilisé l’automobile téléguidée d’un groupe d’étudiants dans une année antérieur.


Comme vous pouvez observer, il manque un pneu sur deux des roues de l’automobile! C’est simplement pour faire en sorte que l’automobile tourne sur place en faisant tourner les moteurs en sens opposé. Le graphique ci-dessous nous informe dans quel sens on doit

Afin de pouvoir envoyer des commandes à l’automobile nous avons resoudé les points de contact sur la télécommande puisqu’elles étaient désuets.

Création de l’environnement graphique pour l’electroencephalogram

Le but de ce programme est de trouver une norme de valeurs de concentration afin de cerner ou pourrait être le seuil de concentration.

Voici un petit sketch à quoi devrait ressembler mon graphique. Mon but est de le graduer par 10 points sur 100 à chaque ligne. De plus, chaque point va avoir sa valeur indiqué au dessus de lui (x = Méditation ; y = Concentration).

Voici à quoi va ressembler la construction des lignes du graphique:

Pour y arriver je vais faire une boucle for qui va parcourir 10 données (0-9). La première donnée indiquera le point (0,0) dans le graphique. Voici à quoi ressemble le code :

Voici à quoi ressemble mon graphique :

Afin de mieux comprendre mes données je vais créer deux fichiers .txt qui vont sauver toutes les valeurs reçus de l’electroencephalogram. Un fichier sera pour les valeurs de méditation et l’autre sera pour les valeurs de concentration. Par la suite je vais prendre les données récoltées dans les fichiers et l’importer dans excel afin de mieux pouvoir jouer avec les données expérimentales.

Avec ce bout de code, les informations seront sauvées dans le fichier .txt correspondant.

Création d’un programme en processing qui va mettre les valeurs du EEG dans un graphique

Pendant ma semaine de relâche j’ai fortement pensé à mon projet. Afin de déterminer qu’elle sera la valeur du niveau d’attention qui déterminera quand l’automobile avancera j’ai décidé de faire un graphique qui aura tous les points reçu par l’electroencephalogram.

Source : https://labwrite.ncsu.edu/res/gh/gh-linegraph.html

En premier lieu, je dois créer mon environnement processing avec le graphique. Je vais m’inspirer du graphique ci-dessus! Pour l’instant mon intention est de donner l’option à la personne qui porte le casque de sélectionner les options suivantes : (Concentrer (rouge), Relaxer(Vert), Rien (Aucun point)). Voici ma classe qui va créer le point dans le graphique:

Il reste seulement à créer des variables et des boutons qui vont activer certaines couleurs:

Afin de savoir quel bouton le sujet essaie de peser je dois vérifier la position de la sourie sur l’écran:

Afin de pouvoir découper le message du arduino j’ai copié la fonction que j’ai fait dans mon programme graphique.

C’est dans ma fonction draw() qui déterminera quel sera la couleur du cercle. J’ai seulement activé ou désactivé des booléens dépendamment du choix de l’utilisateur:

J’ai fini le programme, il reste seulement à essailler avec les données de l’electroencephalogram.

Réglage du délais dans le code processing

En premier lieu, afin voir si mon code fonctionnait j’ai recréer à quoi peux ressembler le ouput serial avec un potentiomêtre brancé dans le Arduino. J’ai réussi à faire varier la varaible qui représente le niveau de concentration (0-100) à l’aide du potentiomètre. Voici le code que j’ai importer dans le arduino :


Comme nous pouvons observer, je fait varier la variable value(entre les deux virgules) qui elle représente un chiffre donné par le potentiomètre, et ce toujours entre 0 et 100.

Après avois compilé le programme dans le arduino, voici à quoi ressemble le port Serial 9600 baud (vitesse que j’ai défini afin de transmettre l’information):

Dans mon code processing, je dois lire chaque ligne serial et voir lesquelles commencent par #EEG. Cette méthode sert à définir les informations qui sont dédiés au graphique de l’electroencephalogram de celle qui sont dédiés au graphique du gyroscope.

Le premier problème que j’ai rencontrer était que je n’avais pas de manière afin de déterminer qu’une ligne serial était null. Par conséquent, il y avait des lignes qui étaients vides et donnait l’erreur : ArrayOutOfBoundsException. Avec ce bout de code, je peux vérifier que aucune ligne qui est envoyé sera == null.

Le second problème que j’ai encontré c’est que mon graphique ne répondait pas rapidement. C’est à dire que je modifiais la valeur d’attention et la sphère changeait de grosseur que quelques disaines de secondes après. Afin de régler ce problème, j’ai du réduire le nombre de données que mon programme décryptait afin de l’alléger.

Comme nous pouvons observer, j’ai mis un protocole qui autorise le changement de la variable “Niveauattention” si seulement elle est différente de sa variable précédente. De plus, afin d’éviter mon programme de prendre des données qui ne sont pas bonnes, j’ai mis un restriction de pouvoir jouer avec les lignes qui contiennent seulement trois valeurs. J’ai fait cela puisqu’il y avait certains cas ou mon code processing lisait la ligne plus vite que la vitesse que mon arduino. Cela faisait en sorte qu’il y avait des lignes qui n’avaient pas les 3 variables nécessaires au fonctionnement du programme.

J’ai aussi ajouté cette condition puisque le niveau d’attention passait de 80 à 0 pendant une miliseconde et retournait à sa valeur d’orginine. Cela faisait en sorte que la sphère nous parraissait très sacadé puisqu’elle faisait cette action plus d’une fois par seconde. Ce bout de code à règler le problème en enlevant complètlement le 0 de l’échelle des valeurs.

La partie Processing EEG est terminé

Après un bière et un programme qui ne compile pas, je me suis repatrié! J’ai repris ma tristesse envers mon code morbide afin de m’ouvrire une seconde bière.

“Quand l’alcool coule,

le code aussi!”

Vincent Houde 2019/03/05 23h32

Ça m’a pris 1 heure comprendre mon erreur :

Comme nous pouvons observer, je veux transformer le contenu de l’index 1 de mon tableau en float! 1 heure plus tard, j’ai réalisé que j’utilisais la mauvaise variable! Voici mon historique de recherche, vous pouvez rire de moi!

Suite à la correction de mon erreur je peux finalement dire que j’ai fini la partie graphique. Il reste seulement à tester mon graphique avec le casque en main propres.

J’ai aujouté une fonction qui parse le code serial qui est envoyé. Quand la ligne contiendra des données provenant de l’électroencephalogram il y aura #EEG au début de la ligne.

Travail sur la shère de concentration en processing

Dans mon programme, le niveau d’attention est graphiquement représenté avec une sphère qui grossit selon le niveau d’attention(0-100). J’ai séparé l’écran en deux afin de pouvoir représenter en parallèle un volant qui traitera les informations du gyroscope.

[video-to-gif output image]

rayon++ à chaque itération.

Pour augmenter la grosseur de la sphère je modifie la valeur de son rayon. Par contre, en modifiant cette valeur, la sphère qui n’est pas centrée nous donne l’impression qu’elle glisse doucement vers la gauche(Video ci-dessus).

Afin de régler ce problème, j’ai dû faire recours à un peu des mathématiques. Vu qu’une sphère est un objet 3 dimensionnel, rendu à une certaine grosseur, le rayon de la sphère dépasse la caméra. Pour régler ce problème, je dois reculer la sphère sur son plan z en fonction du rayon de la sphère. Avec cette méthode, la sphère ne dépassera jamais la caméra puisqu’elle sera tout le temps à la même distance de celle-ci.

Pour régler le deuxième problème, nous devons comprendre la position (0,0) de notre sphère. Elle se situe à la position (500, 550, 0) de notre fenêtre(2000, 1000). Comme nous pouvons observer, la position X de notre sphère est au quart de la longueur totale de notre fenêtre(500/2000 == 1/4). À cet effet, si nous voulons donner l’impression que notre sphère garde son emplacement, nous devons la déplacer vers la gauche. Pour garder un effet centré, on doit la déplacer à gauche d’un quart de la distance ajouté au rayon minimal puisque le point d’origine de la sphère est un quart de la distance du point central de la fenêtre.

[video-to-gif output image]
rayon++ à chaque itération.

Voici à quoi ressemble le code de la sphère avec toutes les modifications :

Protocole de communication

Aujourd’hui, j’ai appris comment un protocole de communication entre deux objets fonctionne. En effet, ce mode de communication sert à valider ou non un packet envoyé d’un objet à l’autre.

Source : https://stackoverflow.com/questions/43618222/how-to-send-packet-using-binary-communication-protocol-on-tcp-port

Vue qu’on envoie de l’information à travers un système sans-fil, la possibilité de corruption est trop haute puisqu’il peut y avoir de l’interférence avec d’autres signaux. C’est de cette problématique que s’élève les protocoles de communications complexes. Dans mon projet, ce protocole est utilisé afin d’envoyer l’information entre l’electroencephalogram et l’objet receveur (L’ordinateur dans mon cas). Il s’agit d’additionner toutes les bytes du packet ensemble et d’inverser les 8 bytes les plus bas. Si cette somme est égale à la somme envoyé dans ce même packet, alors le packet reçu n’est pas corrompu.

Analyse des connaissances nécessaires afin de créer un graphique processing

Àprès avoir étudié la librairie Brain.h de notre ami Mika, je peux comprendre le message Serial qu’il envoie.:

Source : Brain.h //Eric Mika

Comme nous pouvons observer dans la capture d’écran ci-dessus, il y a toutes les informations en ordre du packet. J’ai décidé de prendre le language Processing puisqu’il y a plus d’options afin de créer un graphique en real time! Pour ce faire, je vais devoir apprendre comment la communication serial fonctionne en processing afin d’extraire l’information émis par le arduino. De plus, je vais devoir trouver un manière afin de représenter graphiquement mes informations. À premère vue, je crois que la manière la plus simple est de créer un Cercle et grandir sa grosseur (Radius) en fonction de la valeur attention ou méditation.

Voici à quoi va ressembler le graphique (Sketch de base):

Étude de la librairie Brain.h

Source : Eric Mika, Brain.h

Tout d’abord, on doit donner un très gros crédit à Eric Mika qui a fait tout le travail difficile de rendre simple l’information reçue par notre électroencéphalogramme. Eric est entré dans les documents de NeuroSky, la compagnie qui fait plusieurs headset EEG, dont le notre, pour venir lire les informations qui sont transmises par le headset. En regardant ces informations, il observe qu’il y a deux types de signaux qui sont envoyés par le headset. Le premier est le niveau de la qualité de la connexion entre le headset et le dispositif qu’il contrôle; c’est sur une échelle de 0 à 200. 0 signifie une connexion parfaite, 200 signifie une connexion interrompue. Le deuxième signal que l’électroencéphalogramme envoie est le niveau de concentration ou de méditation de l’individu. C’est sur ce signal que nous allons nous attarder d’avantage! Ce que nous recevons, c’est seulement un numéro sur une échelle de 0-100. Intuitivement, 100 signifie un niveau de concentration élevée et 0 un état mental de méditation. Le problème avec notre EEG c’est qu’il ne transmet pas la fréquence réelle qu’émet le cerveau. Par conséquent, ce que Eric a fait, c’est de donner sept zones qui correspondent chacune à des ondes qu’émet le cerveau.

Source : Eric Mika

Pour aller plus en profondeur, la librairie fonctionne comme une application qui vient extraire des informations d’un fichier texte. Dans Brain.cpp, la fonction update() extrait les informations prises par l’électroencéphalogramme dans tableau de type unsigned int 32 (uint32_t). Il est important de noter que la partie unsigned de la variable signifie qu’on ne peut pas prendre des données négatives (Range = 0 à 4,294,967,295 ).

Une fois que le packet est rempli (32 éléments dans le tableau) on viens confirmer que nous avons un nouveau packet. Par la suite, il y a la fonction parsePacket() qui va venir lire le nouveau packet et identifier de quel type de fréquence cérébrale il fait parti. Nous sommes chanceux puisque le fabriquant du EEG (Neurosky Mindset) nous a donné un protocole de communication fabriqué par eux.

Source : mindset_communications_protocol.pdf (Neurosky)

Voici ce qui est enregistré dans le tableau packet. En observant de plus près, nous pouvons comprendre qu’il y 35 bytes qui sont tous reliés à des informations transmises par électroencéphalogramme. Les bytes de 7-30 indique les fréquences émises par le cerveau, pour un total de 8 zones possibles de fréquences contenant chacune 3 bytes. Les autres bytes servent à signifier la longueur :

-([ 7]: 0x18 // [VLENTGH] 24 bytes && [ 2]: 0x20 // [PLENGTH] (payload length) of 32 bytes).

Un booléen d’attention ou de méditation (j’imagine que c’est ce qu’utilise le jeu):

-([31]: 0x04 // [ATTENTION] eSense && [33]: 0x05 // [MEDITATION]eSense ).

Des bytes qui transmettent des informations de signal :

-( [ 3]: 0x02 // [POOR_SIGNAL] Quality && [ 4]: 0x00 // No poor signal detected (0/200) ).

Finalement, il y a des bytes qui se nomment SYNC qui se situent au début de chaque packet.

-( [ 0]: 0xAA // [SYNC] && [ 1]: 0xAA // [SYNC] ).

Comment on parse le packet?

Avant de parser, on doit vérifier si le packet est bon. D’après le PDF distribué par Neurosky, pour parser un packet, on doit lire tous les bytes jusqu’à la rencontre d’un byte SYNC. Si le byte qui le succède est aussi un SYNC, on continue la fonction. Ensuite, nous allons prendre la valeur du byte [PLENGTH] et s’assurer que [PLENGTH]<170 (C’est trop large comme packet si ça dépasse 170 de longueur). La prochaine étape est compliquée, mais cela assure qu’il n’y a pas de corruption dans le packet. À cet effet, le but est d’arriver au même nombre que dans le byte [CHKSUM]. Pour ce faire, on additionne tous les bytes dans un unsigned char puis on inverse les 8 bytes les plus bas(** Pourquoi??? **). Si le nombre que nous venons de calculer est égale à la valeur du byte [CHKSUM], le packet est alors valide et prêt à être utilisé.

Source : Brain.cpp //Eric Mika

Eric Mika a décidé de faire un switch qui parcourt le packet avec les valeurs de bytes qui l’intéressent. Il enregistre la qualité du signal [0x2], le niveau d’attention [0x4] et le niveau de méditation [0x5] dans des variables de type unsinged int de 8 bytes. De plus il enregistre le signal que nous allons utiliser d’avantage : [0x83], c’est la valeur des bytes qui correspond aux 8 zones que l’électroencéphalogramme peut capter (8 = fréquences Gamma && 0 = fréquences Delta). Enfin, toutes les informations ont été ressorties du packet et mises dans des variables, il est possible maintenant d’envoyer l’information recueillie par signal Serial, ou de l’utiliser comme on veut.