Dernière mise à jour le 02 juillet 2017

MATLAB : FAQ et erreurs courantes

Cette page se veut un complément de la FAQ MATLAB sur Developpez.com à laquelle j'ai participé, qui se décompose en deux parties :

  • Une première qui traite les thèmes les plus courants sur MATLAB (programmation générale, tableaux, fichiers, interfaces graphiques, etc.) ;
  • Une seconde qui explique une bonne majorité des messages d'erreurs et avertissements obtenus sur MATLAB.

(Il existe une troisième page sur Simulink non officiellement publiée, avec encore peu de contenu pour le moment.)

Je suis ouvert à toute critique, demande d'éclaircissement, ou suggestion visant à améliorer/compléter les sujets actuels ou à ajouter de nouveaux éléments.

Généralités

Boucle for : incrémentation

Dans MATLAB, une boucle for se présente la plupart du temps sous la forme :

for i = valeur_depart : pas : valeur_fin
    % …
end

avec un pas de 1 par défaut si celui-ci est omis.

Mais contrairement à d'autres langages, l'incrémentation de la variable itérative (ici i) se fait implicitement, sans avoir à l'écrire. Il est donc incorrect de rajouter i = i + pas; ou i = i + 1; au sein de votre boucle.

Les codes qui suivent, aussi surprenant que cela puisse vous paraître, vont afficher les mêmes valeurs :

Code Sortie
for i = 1 : 10
    fprintf('i = %d\n', i)
end
i = 1
i = 2
i = 3
i = 4
i = 5
i = 6
i = 7
i = 8
i = 9
i = 10
for i = 1 : 10
    fprintf('i = %d\n', i)
    i = i + 5;
end
i = 1
i = 2
i = 3
i = 4
i = 5
i = 6
i = 7
i = 8
i = 9
i = 10

En effet, la variable i aura beau être modifiée au sein de la boucle, cette modification ne sera pas retenue pour l'itération suivante, et i reprendra tout bonnement la valeur suivante dans les valeurs d'entrée 1 : 10. MATLAB vous avertira avec le message :

LOOP index is changed inside of a FOR loop

La seule chose que vous pouvez faire est d'utiliser l'instruction continue qui passera directement à l'itération suivante.

Si vous souhaitez modifier la variable itérative à votre guise, il vous faudra utiliser une boucle while à la place :

Code Sortie
i = 1;
while i <= 10
    fprintf('i = %d\n', i)
    i = i + 2;
end
i = 1
i = 3
i = 5
i = 7
i = 9

Fonction size : valeur erronée

Il peut arriver lorsque vous travaillez par exemple avec une image couleur que la fonction size vous retourne une mauvaise valeur sur la deuxième dimension, pouvant mener à une erreur du style « index out of bounds » ou « index exceeds ». Par exemple pour un image couleur ayant une hauteur de 512 pixels et une largeur de 256 pixels, vous obtiendrez le résultat suivant :

>> size(im)

ans = 

    512     256     3

>> [height, width] = size(im)

height =

     512

width =

     768 % au lieu de 256

Ceci vient du fait que vous demandez seulement deux sorties au lieu de trois à la fonction, elle vous renvoie donc le produit des deux dernières dimensions (256 * 3 = 768) sur la seconde sortie, comme l'explique la documentation :

[d1,d2,d3,…,dn] = size(X), for n > 1, returns the sizes of the dimensions of the array X in the variables d1,d2,d3,…,dn, provided the number of output arguments n equals ndims(X). If n does not equal ndims(X), the following exceptions hold:
n < ndims(X) di equals the size of the ith dimension of X for 0<i<n, but dn equals the product of the sizes of the remaining dimensions of X, that is, dimensions n through ndims(X).

Ainsi, si vous devez travaillez avec des images couleur (sur trois dimension donc : hauteur x largeur x 3, 3 pour les trois canaux rouge, vert, bleu), n'oubliez pas de demander une troisième sortie à la fonction :

>> [height, width, nb_channels] = size(im)

height =

     512

width =

     256 

nb_channels = 

     3

% ou si cette valeur ne vous intéresse pas pour la suite de votre programme :
>> [height, width, ~] = size(im)

Cela vous permettra d'éventuellement vérifier par la suite si votre image comporte un seul canal (image en niveaux de gris) ou trois canaux (image couleur).

Notez que vous pouvez aussi demander une dimension particulière à la fonction size :

>> height = size(im, 1)

height =

     512

>> width = size(im, 2)

width =

     256

>> nb_channels = size(im, 3)

nb_channels =

     3

Quelle est la signification du symbole tilde « ~ » ?

Outre son utilisation la plus connue sous la forme d'opérateur logique NOT :

>> a = [true, false, false, true]

a = 

     1    0    0    1

>> ~a

ans = 

     0    1    1    0
>> a = [32, 16, 0, 7];
>> ~a % équivalent à : a == 0

ans = 

     0    0    1    0
le symbole « ~ » peut aussi servir depuis la version MATLAB R2009b :
  • dans la définition d'une fonction : à éviter d'avoir une variable inutilisée (et son message d'avertissement rattaché) dans les paramètres d'entrée :

    function ma_fonction(entree1, ~)
        % code de la fonction

    équivalent à

    function ma_fonction(entree1, entree2)
        % code de la fonction

    avec la variable entree2 qui ne sera pas utilisée au sein de la fonction.

    Ceci est particulièrement utilisé lors de l'affectation de fonctions anonymes aux propriétés des objets graphiques (cf. Comment utiliser une fonction callback ?) où le second paramètre eventData est rarement utilisé, mais obligatoire pour une fonction callback :

    uicontrol(...
        'Style', 'pushbutton',...
        'String', 'Tirage :',...
        'Callback', @(hObject, ~) set(hObject, 'String', num2str(rand(), 'Tirage : %.2f')) )
  • lors de l'appel d'une fonction : à demander la sortie correspondante à la fonction sans toutefois la stocker dans une variable qui ne sera pas utilisée.

    Vous n'avez habituellement pas besoin de séparer par une virgule vos paramètres de sortie, mais si vous utilisez ce symbole il vous faudra nécessairement le faire ou vous aurez une erreur de syntaxe.

    [~, sortie2] = ma_fonction();
    % suite du code

    équivalent à

    [sortie1, sortie2] = ma_fonction();
    % suite du code

    avec la variable sortie1 qui ne sera jamais utilisée dans la suite du code.

    Vous pourriez vous demander à quoi cela peux servir… après tout si l'on ne veut pas une variable, on ne la demande pas. Je vous renvoie alors à ce sujet sur la fonction size, ou au dernier exemple de celui-ci :

    >> nomsPrenoms = {...
    	'Martin'  , 'Durand' , 'Dupond' ;
     	'Jacques' ,  'Jean'  ,  'Paul'};
    >> [~, indices] = sort(nomsPrenoms(1,:));  % Nous n'avons besoin que de la seconde sortie
    >> nomsPrenoms(:,indices)
    
    ans = 
    
        'Dupond'    'Durand'    'Martin' 
        'Paul'      'Jean'      'Jacques'

    où si l'on ne demande qu'une seule sortie, ce sont les éléments triés (que l'on n'utilise pas) que l'on obtient et non les indices.

Utilisation la fonction textscan

Interfaces graphiques

GUIDE

Pourquoi j'obtiens une erreur lorsque mon premier argument est une chaine de caractères ?

La particularité de l'outil GUIDE de MATLAB est qu'il appelle ses fonctions callback de la manière suivante (nom_interface étant le nom que vous avez fixé) :

nom_interface('nom_fonction_callback', autres paramètres…);

appelant ainsi la fonction principale, comme vous l'appelleriez communément pour l'utiliser. Afin de traiter ces appels spéciaux, les lignes suivantes (insérées automatiquement au début de chaque fichier .m créé par GUIDE) se chargent de vérifier si le premier paramètre est une chaine de caractères, et le cas échant de « tenter » de la convertir en handle de fonction avec str2func.

%      NOM_INTERFACE('CALLBACK',hObject,eventData,handles,...) calls the local
%      function named CALLBACK in NOM_INTERFACE.M with the given input arguments.
[...]
if nargin && ischar(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end

Mais si dans votre utilisation vous passez n'importe quelle chaine de caractères cette conversion échouera inévitablement, vous donnant le message suivant :.

Warning: The input to STR2FUNC "<votre chaîne>" is not a valid function name. This will generate an error in a future release.

Afin de contourner cela, une astuce toute simple consistera à passer votre chaine au sein d'un tableau de cellules.

% au lieu de :
nom_interface('ma chaine', autres paramètres…);
% nous aurons : 
nom_interface({'ma chaine'}, autres paramètres…);

(La condition ischar(varargin{1}) = ischar({'ma chaine'}) retournant alors false, contrairement à ischar('ma chaine') = true)

La récupération de cette chaine dans la fonction nom_interface_OpeningFcn se fera alors comme ceci (notez l'utilisation d'accolades) :

function nom_interface_OpeningFcn(hObject, eventdata, handles, varargin)
ma_chaine = varargin{1}{1};