CCP Informatique PSI 2021

Corrigé

(c'est payant, sauf le début): - - - - - - - - - - - - - - - - - - - - - - - - -

Extrait gratuit du corrigé

(télécharger le PDF)
           

Énoncé complet

(télécharger le PDF)
                                                           

Rapport du jury

(télécharger le PDF)
        

Énoncé obtenu par reconnaissance optique des caractères


SESSION 2021 @ PSISIN

CONCOURS
COMMUN
INP

ÉPREUVE MUTUALISÉE AVEC E3A-POLYTECH

ÉPREUVE SPÉCIFIQUE - FILIÈRE PSI

INFORMATIQUE

Durée : 3 heures

N.B. : le candidat attachera la plus grande importance à la clarté, à la 
précision et à la concision de la rédaction.
Si un candidat est amené à repérer ce qui peut lui sembler être une erreur 
d'énoncé, il le signalera sur sa copie
et devra poursuivre sa composition en expliquant les raisons des initiatives 
qu'il a été amené à prendre.

RAPPEL DES CONSIGNES

e _ Utiliser uniquement un stylo noir ou bleu foncé non effaçable pour la 
rédaction de votre composition ; d'autres
couleurs, excepté le vert, peuvent être utilisées, mais exclusivement pour les 
schémas et la mise en évidence
des résultats.

e Ne pas utiliser de correcteur.
«_ Écrire le mot FIN à la fin de votre composition.

Les calculatrices sont interdites.

Le sujet est composé de trois parties indépendantes.

L'épreuve est à traiter en langage Python. La syntaxe de Python est rappelée en 
Annexe en fin de
sujet.

Les différents algorithmes doivent être rendus dans leur forme définitive sur 
le document réponse dans
l'espace réservé à cet effet en respectant les éléments de syntaxe du langage 
(les brouillons ne sont
pas acceptés).

La réponse ne doit pas se cantonner à la rédaction de l'algorithme sans 
explication, les programmes
doivent être expliqués et commentés.

Énoncé et Annexes : 12 pages
Document Réponse : 8 pages

Seul le Document Réponse doit être rendu dans son intégralité.

1/12
Autour des montres multisports

Présentation

On s'intéresse dans ce sujet aux montres multisport, en déve-
loppement croissant depuis les dix dernières années.

Ces montres permettent aux sportifs amateurs ou profession-
nels d'enregistrer diverses données physiques et physiologiques.
Elles permettent maintenant de connaître sa position GPS, d'en-
registrer un trajet et tous les paramètres associés, de suivre un
trajet prédéfini. Les plus sophistiquées intègrent également un altimèêtre, un 
baromètre, un thermo-
mètre, une boussole, un lecteur MP3, etc.

On se limite dans ce sujet à :

- l'acquisition et le traitement des données GPS sur un parcours : partie ] ;

- l'acquisition du rythme cardiaque : partie IT;

- le partage des activités : partie LIT.
Dans tout le sujet, on supposera que les bibliothèques numpy 
etmatplotlib.pyplot sont importées
par from numpy import * et from matplotlib.pyplot import *

Partie I - Acquisition et traitement des données GPS

I.1 - Introduction

Dans la montre, un module électronique capte les signaux GPS à l'aide d'une 
antenne et décode ces
signaux pour générer une chaîne de caractères constituée de plusieurs lignes. 
On ne s'intéresse qu'au
traitement de cette chaîne de caractères qui est transmise par le module GPS.

Les données envoyées par le récepteur GPS suivent la norme NMEAO83 définie dans 
l'annexe 1. On
suppose que la variable donneesGPS est une chaîne de caractères reçue par le 
récepteur. Cette chaîne
contient plusieurs lignes dont le séparateur est le caractère spécial " \n". 
Pour la lisibilité, cette chaîne
est afhichée avec les sauts de ligne.

"SGPRMC,092828.00,A,4754.68988,N,00154.69147,E,0.444,,070619,,A*7C\n
SGPVTG,,T,,M,0.444,N,0.822,K,A*2F\n
$GPGGA,092828.00,4754.68988,N,00154.69147,E,1,04,2.61,84.3,M,46.5,M,,*64\n
$GPGSA,A,3,25,29,24,32,,,.,,,,3.99,2.61,3.02*0E\n

$SGPGS V,3,1,11,02,32,075,,04,,,22,06,15,037,,12,47,072,16*4A\n

$SGPGS V,3,2,11,14,38,276,11,24,18,141,19,25,80,353,24,29,56,196,30*7F\n
$SGPGS V,3,3,11,31,34,306,25,32,35,250,36,33,32,202,27*4F\n
$GPGLL,4754.68986,N,00154.69154,E,092828.00,A,A*6B\n"

2/12
L.2 - Récupération des données brutes

L'objectif est de récupérer l'heure, la latitude, la longitude et l'altitude 
dans les données de la trame
GPGGA (voir annexe 1). Cette procédure va se décomposer en 3 étapes :

- récupérer la trame GPGGA dans la série de trames reçues ;

- vérifier la validité de la trame ;

- extraire les données.

Pour répondre aux questions suivantes, 1l est conseillé d'utiliser les 
propriétés et fonctions sur les
caractères et chaînes de caractères données en annexe 2.

Pour récupérer la trame GPGGA, on a écrit la fonction recupererGPGGA(chaine) 
(donnée sur le
Document Réponse) qui prend en argument la chaîne de caractères chaine et qui 
renvoie la ligne
correspondant à la trame GPGGA s1 elle existe sous forme de liste découpée 
suivant les virgules.
Sinon elle renvoie une liste vide.

La fonction indice_GPGGA(listeChaine) renvoie l'indice de l'élément contenant " 
$GPGGA" de
listeChaine.

Q1. Expliquer les lignes 2 à 8 de cette fonction.

Q2. Écrire une fonction indice_GPGGA(listeChaine) prenant en argument une liste 
de chaînes
de caractères et qui renvoie l'indice de la position de la chaîne contenant " 
$GPGGA" quand elle
existe ou la longueur de listeChaïne sinon. Vous utiliserez une boucle while.

Q3. Donner l'instruction à écrire pour récupérer la trame GPGGA de la variable 
donneesGPsS et la
stocker dans la variable 1isteGPGGABrute.

I.3 - Test de validité de la trame GPGGA

Pour que la trame soit valide, il faut vérifier que :

- les valeurs soient présentes ;
par exemple, la trame "$GPGGA,09281 1.00,,,,,0,00,99.99,,..,,*65\n" n'est pas 
valide ;

- le coefficient de précision soit inférieur à 5 ;

- Ja somme de contrôle soit valide. La somme de contrôle est obtenue par une 
opération " ou ex-
clusif "entre une représentation binaire de chaque caractère entre '$' et '*" 
(ces deux caractères
étant exclus). Sa valeur dans la trame est donnée en base hexadécimale.

On suppose dans cette sous-partie que la trame, constituée de 14 éléments, a 
été récupérée et stockée
dans 1isteGPGGABrute soit 1c1 :

listeGPGGABrute= ["'GPGGA", '092828.602', '4754.68988', 'N°', '60154.69147°, 
'E', 'l',
04", '2.61', '84.3, 'M, '46.5', M', '"64']

Pour les questions suivantes, trame correspond à une variable ayant la même 
forme que
listeGPGGABrute.

Q4. Ecrire une fonction testPresence(trame) qui prend en argument la liste de 
chaînes de
caractères trame correspondant à une trame GPGGA et qui renvoie True s1 les 
données sont
présentes et non vides, False sinon.

Q5. Ecrire une fonction testPrecision(trame) qui prend en argument la liste de 
chaînes de
caractères trame correspondant à une trame GPGGA et qui renvoie True s1 la 
précision est
inférieure à 5, False sinon.

3/12
On donne dans le Document Réponse une fonction testSC(trame) qui prend la liste 
de chaînes
de caractères trame correspondant à une trame GPGGA et qui renvoie True s1 la 
trame est valide,
False sinon.

Q6. Donner la valeur renvoyée par la fonction testSC appliquée à la liste 
['GPG", "AO" ].
Donner notamment la valeur de la variable csHex. On donne les résultats 
suivants :
bin(ord('G')) renvoie '6b®01000111', bin(ord('P')) renvoie ''6b601616060600".
bin(ord("*')) renvoie '6b00101010', bin(ord('A')) renvoie 'Ob0160060001,
bin(ord('®@")) renvoie '6bO6110060.

L.4 - Récupération des données

La trame étant valide, on recherche maintenant à récupérer les données qui nous 
intéressent en les
stockant dans le format adéquat :

l'horaire exprimé en secondes ;

la latitude exprimée en degrés (0 correspond à l'équateur, elle varie de -- 90° 
à 90°). Au Nord
l'angle sera compté positivement et au Sud négativement ;

la longitude exprimée en degrés (0 correspond au méridien de Greenwich, elle 
varie de -- 180°
à 180"). L'Ouest sera compté positivement et l'Est négativement ;

- l'altitude exprimée en mètres.
Pour la latitude, comme la longitude, les minutes d'angle sont toujours 
représentées avec 8 caractères

(dont la virgule) alors que les degrés sont représentés avec 2 ou 3 caractères.

Q7. Écrire une fonction convHoraire(chHoraire) qui prend en argument la chaîne 
de caractères
chHoraire représentant l'horaire avec le format de la norme GPGGA (092828.00 
correspon-
dant à 09 h 28 min 28,00 secondes) et qui renvoie la valeur de l'horaire 
exprimé en secondes.

QS8. Écrire une fonction convAngle(chAngle,chCard) qui prend en argument la 
chaîne de ca-
ractères chAngle correspondant à la latitude ou la longitude, ainsi que la 
chaîne de caractères
chCard correspondant à la direction (N/S ou E/O) et qui renvoie le flottant 
signé correspondant
à la valeur de l'angle en degré (il faudra convertir les minutes d'angle en 
valeur décimale).

Q9. Compléter l'ébauche de la fonction recupDonnees(trame) qui prend en 
argument trame
correspondant à une trame GPGGA et qui renvoie une liste de 4 réels contenant 
(Heure, Lati-
tude, Longitude, Altitude).

LS - Sauvegarde d'une activité

Lors d'une activité, on récupère toutes les secondes :

- les données du GPS : horaire (en seconde), latitude (en degré), longitude (en 
degré) et altitude

(en mètre) ;

- la fréquence cardiaque.
Toutes les secondes, ces 5 données sont enregistrées dans un fichier texte, en 
les séparant par une
virgule. Chaque ligne du fichier correspond à un "point" de mesure.
Exemple d'une ligne du fichier texte : "34108,47.91 
1498,001.911526,0084.3,105\n".
L'horaire, en secondes, est un entier représenté avec 5 caractères. On garde 6 
chiffres après la virgule
pour les angles en degrés. La partie entière de l'altitude est représentée avec 
4 caractères et on prend
une précision au décimèêtre. La fréquence cardiaque est un entier représenté 
avec 3 caractères. Tous
les caractères sont stockés sur 1 octet (asc1i).

Q10. On suppose que l'on réalise une activité d'une heure. Donner l'ordre de 
grandeur de la taille
mémoire en octets du fichier texte généré. Dans le cahier des charges, on 
impose que la montre
peut sauvegarder 200 h d'activités. Donner l'ordre de grandeur de la taille 
mémoire nécessaire
au stockage des données pour répondre au cahier des charges.

4/12
La mémoire des montres est de l'ordre de 20 Mo.
Q11. Proposer une solution permettant de ne pas dépasser la mémoire disponible.

Partie II - Acquisition du rythme cardiaque

Lors d'une activité sportive, les montres multisport permettent 
l'enregistrement et la consultation du
rythme cardiaque. Cela permet au sportif de contrôler son effort et d'optimiser 
ses performances.
Cette donnée est intéressante durant les compétitions et les entraînements.

La première méthode utilisée est d'enregistrer l'ElectroCardioGramme (ECG). On 
mesure l'activité
électrique du coeur à l'aide d'électrodes. Cette méthode nécessite d'installer 
une ceinture cardiothora-
cique qui mesure et envoie les données à la montre par Bluetooth ou ANT + en 
fonction des marques.

La seconde méthode est la PhotoPlestysmoGraphie (PPG) ou Oxymétrie de
pouls. L'hémoglobine, lorsqu'elle est chargée en oxygène, absorbe davan-
tage les infrarouges que lorsqu'elle n'est pas chargée en oxygène. On peut
donc avec un émetteur et un récepteur infrarouge mesurer en temps réel la
saturation en oxygène du sang et en déduire le rythme cardiaque. En centre
hospitalier, le capteur est positionné au bout d'un doigt. L'épaisseur de peau
étant faible et la zone très vascularisée, on utilise des longueurs d'onde
" optimales " de l'ordre de 800 nm (lumière rouge). Dans les montres, la
prise de mesure s'effectue au poignet. La peau y étant plus épaisse, on uti-
lise des longueurs d'onde de l'ordre de 570 nm (lumière verte) qui pénètrent
mieux les tissus.

Le capteur PPG renvoie une valeur de longueur d'onde avec un temps 
d'échantillonnage 7°, = 0,025.
Tous les 7}, on enregistre la valeur de ce signal (sans unité) dans une liste 
notée signal et le temps
(en s) dans une liste notée temps. Chaque élément de la liste signal est un 
nombre entier, image de
la quantité d'infrarouge absorbée.

HIT)

£
3 500
©
É
D
5 400
5
5 300 A) A AN | f\ A\ \ | \ A
. R COIN UV |
200 ;
0 I 2 3 4 5 6

Temps (s)

Figure 1 - Mesure PPG : tracé de la liste signal en fonction de la liste temps

Un essai d'une durée d'environ 6 secondes permet de tracer la courbe de la 
figure 1.

5/12
On observe que la valeur du signal infrarouge se décompose en deux valeurs :
- une valeur quasi constante, de l'ordre de 300 sur la figure 1, qui correspond 
à l'absorption due
aux tISSUS, au flux veineux et à une partie constante du flux artériel ;
- une partie variable due exclusivement à la variation du flux artériel.

IL.1 - Application d'un filtre passe-bas

Pour atténuer certaines perturbations, on applique un filtre passe-bas. Il est 
caractérisé par l'équation
différentielle : à
[
+27 fe S(t) = 2x fe e(t) (1)
où e(f) est le signal d'entrée du filtre, s(7) le signal en sortie du filtre et 
f. la fréquence de coupure du
filtre.

On peut intégrer l'équation (1) sur un intervalle [f, f + T,] et poser :

t+T,
St + dt) = S(f) + 2x. [ (e(u) -- s(u)) du. (2)

On obtient un signal discrétisé avec une fréquence d'échantillonnage f, = 1/T..
On note e, = e(f,) et sx = s(f7) les valeurs respectives des signaux d'entrée e 
et de sortie s à l'instant #4.

Q12. Montrer qu'on obtient, après discrétisation et en appliquant la méthode 
des trapèzes pour cal-
culer une valeur approchée de l'intégrale dans l'équation (2), la relation de 
récurrence sui-
vante : (1 --G) 5x + G(ey:1 + ex)

--= 3
Sx+1 1+G (3)

où G est une constante dont vous donnerez l'expression en fonction des 
paramètres f. et f..

Q13. Écrire la fonction filtrage(e,G) d'argument e tableau du signal d'entrée, 
G la constante
définie précédemment et qui renvoie le tableau de valeurs du signal filtré.

IL.2 - Méthode 1 - Récupération des pics

Le signal ayant été filtré, une première méthode consiste à récupérer les

instants des pics, puis d'en déduire la fréquence cardiaque à partir du temps 
P..
l

entre deux pics consécutifs.

Pour repérer un pic, nous allons prendre trois points de mesures consécutifs Pit
P;, P;,1 et P;,:. On considère que l'on trouve un pic si :

- Ja valeur en P;,, est supérieure à la valeur en P;;

- Ja valeur en P;,, est supérieure à la valeur en P;,; ;

- les valeurs des trois points sont supérieures à une valeur seuil m1-
nimale (par exemple 550 sur la figure 1) afin de ne trouver que des
extrema " valides ".

Pour récupérer chaque pic, 1l est inutile de travailler sur l'ensemble du 
signal, mais 1l faut prendre
suffisamment de points pour être certain d'avoir un pic. La fréquence cardiaque 
au repos usuelle étant
de 60 pulsations par minute, soit un pic par seconde, on fait le choix de 
travailler, par sécurité, sur un
intervalle de 3 s, ce qui correspond à des fenêtres de 150 points avec notre 
temps d'échantillonnage
de 0,02 5. Cette partie du signal sera notée extSignal.

Q14. Compléter le test du while de la fonction detectionPics(extSignal, seuil) 
qui prend en
argument extSignal, liste des données du signal partiel avec 150 points de 
mesure, ainsi que
la valeur minimale seuil et qui renvoie l'indice du premier " pic " dans la 
partie extSignal
du signal traité.

6/12
Q15. Commenter précisément la fonction pulsationCardiaque(signal,Te,seuil) qui 
prend
en argument signal, liste des données du signal complet, Te le temps 
d'échantillonnage en
seconde et seuil la valeur du seuil de détection. Expliciter ce que représente 
la valeur ren-
voyée.

IL.3 - Méthode 2 - Transformée de Fourier discrète

Une seconde méthode consiste à effectuer une étude fréquentielle du signal. 
Pour cela, on applique
aux données une Transformation de Fourier Discrète (TFD).

Pour un signal s de N échantillons obtenus à une fréquence j,, la TFD du 
signal, notée S (&k), est

donnée par :
N-1

S (k) -- > ne KN pour O>> chaine = 'Ceci est un test.\nOn peut mettre une tabulation entre a et
b : atb."

>>> print(chaine)

Ceci est un test.

On peut mettre une tabulation entre a et b : a b.

11/12
Fonctions sur les chaînes de caractères
Une chaîne de caractères est gérée comme une liste.
Exemple : chaine = "Concours Commun INP \n".

chaine[5] --u
chaine[9:15] -- Commun

Renvoie le 1ème terme de la chaine

Renvoie la chaîne comprise entre le ième et le
Jjième-Î] terme

Découpe la chaîne au caractère désigné, par
défaut 'espace'.

chaine!{1l]
chainel[1:];l

chaine.split('C') --  [",

'oncours ", 'ommun INP \n'l

chaine.split()

bin(int1) Convertit un entier en la chaîne de caractères | bin(12) -- '6b1100"
de son expression binaire, précédée de 'Ob'
pour indiquer la base binaire

hex(int1) Convertit un entier en la chaîne de caractères | hex(12) -- 'Oxc'

de son expression hexadécimale, précédée de | hex(O0b601610600) -- '6x50"

'0x' pour indiquer la base héxadécimale

Annexe 3 - Ou Exclusif

La fonction Ou Exclusif renvoie le ou exclusif bit à bit de deux entiers.
Exemple : 10 ° 15 renvoie 5

ou en représentation binaire : bin(@b16010 6b1111) renvoie '6b6101".

Annexe 4 - Fonctions sur les tableaux et les listes
Remarque : sous Python, l'import du module numpy permet de réaliser des 
opérations pratiques sur
les tableaux : from numpy import *. Les indices de ces tableaux commencent à 0.

Python

L=[1,2,3] (liste)

leau à
tableau à une dimension v=array([1,2,31]) (vecteur)

créer un vecteur rempli de 0 de taille n zeros(n)

accéder à un élément

V[0] renvoie 1 (L[®] également)

ayouter un élément

L.append(5) uniquement sur les listes

tableau à deux dimensions (matrice)

M=array(([1,2,3],[3,4,5]))

accéder à un élément M[1,2] donne 5

extraire une portion de tableau (2 premières co-

M[:,0:21
lonnes)
extraire la colonne 1 M[:,1]
extraire la ligne 1 M[1,:]

tableau de 0 ( 2 lignes, 3 colonnes) zeros((2,3))

a = array([l1,2,31])

b = a.reschape(3,l)
print(b)

>>> array ([[1],[2],[3]])

Transformer une ligne en colonne

a = array([[1,2,31,[4,5,6],[17,8,91]1])
b = array([1,2,3])

print(a.dot(b))

>>> array ([14,32,50])

produit matrice-vecteur

12/12

IMPRIMERIE NATIONALE - 211170 - D'après documents fournis

Numéro N
d'inscription
C Nom :

| N D Numéro
de table

CONCOURS »

COMMUN Prénom :
Née) le

Filière: PSI Session: 2021

Épreuve de: INFORMATIQUE

+ Remplir soigneusement l'en-tête de chaque feuille avant de commencer à 
composer
+ Rédiger avec un stylo non effaçable bleu ou noir
Consignes ° Ne rien écrire dans les marges (gauche et droite)
+ Numéroter chaque page (cadre en bas à droite)
* Placer les feuilles A3 ouvertes, dans le même sens et dans l'ordre

Emplacement
QR Code

PSISIN

DOCUMENT RÉPONSE

Ce Document Réponse doit être rendu dans son intégralité.

Q1 - Expliquer les lignes 2 à 8

def recuperer GPGGA( chaine ):
chaineDecoupe=chaine.split("\n')
IndGGA = indice GPGGA(chaineDecoupe)
ligne = {]
if indGGA != len(chaineDecoupe ):
ligne = chaineDecoupe[indGGAlI][1:]
ligne = ligne.split(",')
ligne .pop(len(ligne ) ---2)
return ligne

© © I ON 1 R © D

- Écriture de la fonction indice _GPGGA(lListeChaine)

1/8

NE RIEN ÉCRIRE DANS CE CADRE

Q3 - Instruction permettant de créer listeGPGGABrute

- Écriture de la fonction testPresence (trame)

- Écriture de la fonction testPreci sion(trame)

Q6 - Valeur de csHex et valeur renvoyée par testSC(['GPG','"*A0"])

def testCS(trame ):

somme=trame[| ---1]|[1:]

CS =0

for chaine in tramel[:-1\|:
for ch in chaine

cs=cs ord(ch)
csHex=hex(cs)[2:|
return csHex==somme

218

- Écriture de la fonction convHoraire (chHoraire)

- Écriture de la fonction convAngle (chAngle, chCard)

Q9 - Complétion de la fonction recupDonnees(trame)

def recupDonnes (trame ):
Horaire =................
Latitude =...............
Longitude =..............

Altitude =...............

318

Q10 - Espace mémoire pour stocker une activité d'une heure. Espace mémoire pour 
stocker 200 h

D

Q11 - Solution ne la tité de mémoire di ible

12 - Démonstration de la relation de récurrence

13 - Écriture de la fonction filtrage(e,G)

418

Ge sum _

CONCOURS
COMMUN
INP

Numéro
d'inscription N

de table

Prénom :

Née) le

Emplacement
QR Code

Filière: PSI Session: 2021

Épreuve de: INFORMATIQUE

+ Remplir soigneusement l'en-tête de chaque feuille avant de commencer à 
composer
+ Rédiger avec un stylo non effaçable bleu ou noir
Consignes ° Ne rien écrire dans les marges (gauche et droite)
+ Numéroter chaque page (cadre en bas à droite)
* Placer les feuilles A3 ouvertes, dans le même sens et dans l'ordre

PSISIN

Q14 - Complétion du test de la fonction detectionPics(extSignal,seuil)

def detectionPics(extSignal , seuil ):

PO ,PI1,P2=extSignall:3]
1 =]
while 1 

Extrait du corrigé obtenu par reconnaissance optique des caractères



CCINP Informatique PSI 2021 -- Corrigé
Ce corrigé est proposé par William Aufort (professeur en CPGE) ; il a été relu
par Cyril Ravat (professeur en CPGE) et Benjamin Monmege (enseignant-chercheur
à l'université).

Ce sujet aborde différents aspects informatiques des montres multisport. Ces 
objets connectés sont devenus très populaires dans le monde du sport amateur et 
professionnel, notamment parce qu'ils permettent, à travers l'enregistrement de 
mesures
physiques et physiologiques, de mesurer les performances des sportifs. Les 
trois parties du sujet sont indépendantes.
· La partie I est consacrée à l'acquisition et au traitement des données issues 
du
module GPS d'une montre multisport. Celles-ci sont organisées sous la forme
de trames qui suivent une norme décrite en annexe de l'énoncé. On implémente 
dans cette partie des fonctions permettant l'extraction et la vérification
des trames, puis d'en isoler les données relatives à la localisation du coureur.
Ces questions de programmation portent principalement sur les manipulations
de chaînes de caractères (extraction et conversion en valeur numérique).
· La partie II se concentre sur l'acquisition du rythme cardiaque par une 
montre,
à partir d'une analyse infrarouge de la saturation en oxygène du sang. Deux
méthodes distinctes de traitement du signal sont employées, dont une utilise
la transformée de Fourier discrète. La plupart des questions de cette partie
demandent de compléter ou documenter un code déjà fourni dans l'énoncé.
· Enfin, la partie III introduit une base de données stockant les activités des
utilisateurs de la montre. Plutôt courte (seulement trois questions) et facile,
elle sert surtout de prétexte à écrire et interpréter des requêtes SQL.
La longueur du sujet est raisonnable et comparable à celles des années 
précédentes. Le programme de deuxième année n'est pas abordé et l'ingénierie 
numérique
n'est évaluée que sur une seule question. Il s'agit donc avant tout de 
comprendre,
commenter et écrire du code. Le candidat était également évalué sur sa capacité 
à
absorber les nombreuses informations de l'énoncé et à réutiliser celles qui 
sont pertinentes. Il s'agit donc d'un bon sujet d'entraînement pour les 
étudiants de première
année. On regrettera cependant l'absence de documentation de certaines fonctions
spécifiques et non exigibles.

Indications
1 Pour interpréter le test de la ligne 5, il est nécessaire de lire la question 
2.
2 La condition du while doit permettre de détecter les bons caractères de début 
de
chaîne, par exemple à l'aide d'un slicing, ou l'arrivée à la fin de la liste. 
Attention
à l'ordre dans lequel seront vérifiées ces deux conditions.
4 Il suffit de vérifier que la liste contient le bon nombre de chaînes et que 
celles-ci
sont non vides.
5 Où se trouve la précision dans la liste trame, et sous quelle forme ?
6 Attention aux différents slicings présents dans ce code. Utiliser les annexes 
2
et 3 pour comprendre la fonction hex et l'opérateur ^, et les valeurs fournies 
par
l'énoncé pour l'évaluation des ord(ch).
7 Séparer les heures, minutes et secondes avec des slicings, puis effectuer les 
conversions nécessaires.
8 Utiliser le fait que les minutes occupent 8 caractères pour les isoler des 
degrés.
10 Les données fournies par l'énoncé permettent d'évaluer le nombre maximal de
caractères sur une ligne. Ne pas oublier les caractères non numériques.
11 Comment peut-on représenter autrement une valeur numérique ?
12 La méthode des trapèzes permet d'obtenir l'approximation suivante
Z t+Te
(e(t + Te ) - s(t + Te ) + e(t) - s(t))
(e(u) - s(u)) du ' Te ×
2
t
13 Construire un tableau de la bonne taille et le remplir à l'aide d'une boucle 
en utilisant la question 12. On pourra poser s(t0 ) = e(t0 ), non renseigné 
dans l'énoncé.
14 On continue d'exécuter la boucle tant que l'une des trois conditions données 
dans
l'énoncé n'est pas respectée : attention aux opérateurs booléens utilisés.
15 Justifier notamment que la liste pics contient bien les indices des 
différents pics
relevés dans la liste signal à l'issue de la boucle while.
16 Deux boucles imbriquées sont nécessaires dans cette fonction. Utiliser la 
constante
pi et la fonction exp définies dans le module numpy.
19 Utiliser la fréquence d'échantillonnage pour relier l'intervalle de temps t 
aux
indices indDepart et indFin du programme.
20 Utiliser le comportement du filtre aux instants Td et Tf , ou l'expression 
de la
fonction donnée dans l'énoncé.
23 Seule la table activite est nécessaire. Ne pas oublier les conversions.
24 Interpréter d'abord le contenu de la table amis1.

I. Acquisition et traitement des données GPS
1 L'instruction de la ligne 2 sépare les différentes lignes de la chaîne de 
caractères en
entrée, en les stockant dans une liste nommée chaineDecoupe. L'instruction 
suivante
permet de récupérer l'indice de la ligne correspondant à la trame GPGGA dans 
cette
liste. Si cette trame est bien présente (test de la ligne 5), la ligne 6 permet 
de récupérer
la ligne associée, à laquelle on enlève le premier symbole $. On en extrait 
ensuite les
différentes informations dans une liste (ligne 7), sauf l'avant-dernière (ligne 
8) qui
correspond à un champ toujours vide d'après l'annexe 1.
L'énoncé ne précisait pas à ce stade que le test de la ligne 5 permettait
de vérifier la présence d'une trame GPGGA dans la liste. Cette information
ne se trouve qu'à la question suivante expliquant le comportement de la
fonction indice_GPGGA en cas d'absence d'une telle trame. D'où la nécessité
de prendre un peu d'avance sur la lecture de l'énoncé (sans forcément le lire
en intégralité) avant de se lancer.
La méthode pop, utilisée à la ligne 8 pour la suppression du champ vide,
n'était pas décrite dans l'annexe, probablement parce qu'elle figure 
implicitement au programme. En effet, lors de la représentation usuelle des 
piles par
les listes Python, l'instruction P.pop() permet de dépiler un élément de P
avec une complexité élémentaire. Néanmoins, cette méthode était utilisée ici
avec un argument optionnel, correspondant à l'indice de l'élément à extraire,
ce qui a pu perturber certains candidats.
2 L'énoncé impose ici l'utilisation d'une boucle while. Cette boucle doit 
s'arrêter
dès que l'on arrive à la fin de la liste, ou que l'on a trouvé une chaîne 
commençant par
les caractères '$GPGGA'. Ce dernier test est réalisé ici à l'aide d'un slicing 
récupérant
les 6 premiers caractères de la chaîne à tester.
def indice_GPGGA(listeChaine):
i = 0
while i < len(listeChaine) and listeChaine[i][:6] != '$GPGGA': i = i + 1 return i L'ordre des deux conditions dans cette boucle while est crucial. Lorsque Python évalue une expression booléenne, il le fait de façon paresseuse, c'està-dire que si la condition i < len(listeChaine) n'est pas vérifiée, la condition de droite n'est pas évaluée. Une évaluation de cette condition dans le cas où i = len(listeChaine) aurait déclenché une erreur car l'élément listeChaine[i] n'existe pas. Remarquons enfin que dans ce cas, la fonction renvoie bien len(listeChaine), comme demandé dans la question. 3 La variable donneesGPS contient la chaîne reçue par le récepteur. On peut lui appliquer la fonction recupererGPGGA de la question 1 pour isoler la trame demandée. listeGPGGABrute = recupererGPGGA(donneesGPS) 4 On teste dans un premier temps si la trame est bien constituée de 14 éléments, puis on vérifie le cas échéant si aucune donnée de la liste ne correspond à la chaîne de caractères vide. def testPresence(trame): if len(trame) != 14: return False for chaine in trame: if chaine == '': return False return True L'énoncé est ambigu sur la nécessité de vérifier la première condition : la liste trame est supposée avoir la même forme que la liste donnée en exemple listeGPGGABrute contenant 14 éléments, mais la question demande tout de même de vérifier que les données sont bien présentes. 5 On remarque sur l'exemple donné dans l'énoncé que le coefficient de précision se trouve à l'indice 8 dans la liste des données de la trame, sous la forme d'une chaîne de caractères. Il suffit alors de comparer ce coefficient à la valeur 5, en prenant soin de le convertir en flottant au préalable. def testPrecision(trame): return float(trame[8]) < 5 Le coefficient de précision dont il est question ici permet de mesurer la qualité d'une mesure de position du récepteur GPS. Plus ce coefficient est grand, plus les satellites concernés dans cette détermination de position étaient proches lors de la mesure, ce qui augmente les incertitudes sur le relevé. 6 L'instruction somme = trame[-1][1 :] permet de récupérer la dernière chaîne de la trame privée de son premier caractère, ce qui donne sur cet exemple 'A0'. Comme la liste trame ne contient que deux éléments, la boucle for chaine in trame[ :-1] n'examine que la première chaîne de caractères de la trame, la seconde étant exclue à cause du slicing. Après initialisation, et à l'issue de la seconde boucle for ch in chaine: cs = cs ^ ord(ch) la variable cs contiendra, d'après l'annexe 3, le « ou exclusif » bit à bit des représentations entières des lettres de chaine, soit ord('G') ^ ord('P') ^ ord('G'). Cet opérateur est défini sur les bits par 0 ^ 0 = 0, 0 ^ 1 = 1, 1 ^ 0 = 1 et 1 ^ 1 = 0 On remarque que cette opération renvoie 1 s'il y a un nombre impair de bit égaux à 1, et renvoie 0 dans le cas contraire. À l'aide des valeurs fournies dans l'énoncé et de l'observation précédente, on obtient après calculs bit par bit : cs = '0b01000111' ^ '0b01010000' ^ '0b01000111' = '0b01010000' On remarque qu'on retrouve la valeur donnée dans l'énoncé pour ord('P'), ce qui n'a rien d'une coïncidence. En effet, on peut montrer que l'opérateur « ou exclusif » est commutatif, associatif et vérifie x ^ x = 0 pour tout x (bit ou entier), ce qui permet de simplifier le calcul précédent : cs = = = cs = ord('G') ^ ord('P') ^ ord('G') (ord('G') ^ ord('G')) ^ ord('P') 0 ^ ord('P') ord('P') D'après l'annexe 2, l'instruction csHex = hex(cs)[2 :] convertit l'entier associé à l'écriture en binaire '0b01010000' de cs, soit 24 + 26 = 80, en son expression hexadécimale sans le préfixe '0x' utilisé par Python, ce qui donne '50' car 80 = 16 × 5.