Je pense que tout le monde conviendrait que le langage MATLAB n'est pas joli, ni particulièrement cohérent. Mais peu importe! Nous devons encore l'utiliser pour faire avancer les choses.
Quelles sont vos astuces préférées pour faciliter les choses? Ayons une par réponse pour que les gens puissent les voter s'ils sont d'accord. Essayez également d'illustrer votre réponse avec un exemple.
Utilisation du profileur intégré pour voir où se trouvent les parties chaudes de mon code:
profile on
% some lines of code
profile off
profile viewer
ou simplement en utilisant les tic
et toc
intégrés pour obtenir des temps rapides:
tic;
% some lines of code
toc;
Extraire directement les éléments d'une matrice qui satisfont une condition particulière, à l'aide de tableaux logiques:
x = Rand(1,50) .* 100;
xpart = x( x > 20 & x < 35);
Maintenant, xpart ne contient que les éléments de x qui se trouvent dans la plage spécifiée.
Fournissez un accès rapide à la documentation des autres fonctions en ajoutant une ligne "VOIR AUSSI" aux commentaires d'aide. Tout d'abord, vous devez inclure le nom de la fonction dans toutes les majuscules comme première ligne de commentaire. Faites votre en-tête de commentaire habituel, puis mettez VOIR AUSSI avec une liste séparée par des virgules d'autres fonctions connexes.
function y = transmog(x)
%TRANSMOG Transmogrifies a matrix X using reverse orthogonal eigenvectors
%
% Usage:
% y = transmog(x)
%
% SEE ALSO
% UNTRANSMOG, TRANSMOG2
Lorsque vous tapez "help transmog" sur la ligne de commande, vous verrez tous les commentaires dans cet en-tête de commentaire, avec des hyperliens vers les en-têtes de commentaire pour les autres fonctions répertoriées.
Transformez une matrice en vecteur à l'aide d'un seul côlon.
x = Rand(4,4);
x(:)
Vectorisation des boucles . Il existe de nombreuses façons de le faire, et il est amusant de rechercher des boucles dans votre code et de voir comment elles peuvent être vectorisées. Les performances sont étonnamment plus rapides avec les opérations vectorielles!
Fonctions anonymes, pour plusieurs raisons:
quad
et fminbnd
qui prennent des fonctions en arguments. Il est également pratique dans les scripts (fichiers .m qui ne commencent pas par un en-tête de fonction) car contrairement aux vraies fonctions, vous ne pouvez pas inclure de sous-fonctions..
% quick functions
f = @(x) 3*x.^2 + 2*x + 7;
t = (0:0.001:1);
plot(t,f(t),t,f(2*t),t,f(3*t));
% closures (linfunc below is a function that returns a function,
% and the outer functions arguments are held for the lifetime
% of the returned function.
linfunc = @(m,b) @(x) m*x+b;
C2F = linfunc(9/5, 32);
F2C = linfunc(5/9, -32*5/9);
bsxfun , arrayfun , cellfun et structfun de Matlab sont assez intéressants et enregistrent souvent une boucle.
M = Rand(1000, 1000);
v = Rand(1000, 1);
c = bsxfun(@plus, M, v);
Ce code, par exemple, ajoute le vecteur colonne v à chaque colonne de la matrice M.
Cependant, dans les parties critiques de votre application, vous devez comparer ces fonctions par rapport à la boucle for triviale, car les boucles sont souvent encore plus rapides.
mode LaTeX pour les formules dans les graphiques : Dans l'une des versions récentes (R2006?), Vous ajoutez les arguments supplémentaires ,'Interpreter','latex'
à la fin d'un appel de fonction et il utilisera le rendu LaTeX. Voici un exemple:
t=(0:0.001:1);
plot(t,sin(2*pi*[t ; t+0.25]));
xlabel('t');
ylabel('$\hat{y}_k=sin 2\pi (t+{k \over 4})$','Interpreter','latex');
legend({'$\hat{y}_0$','$\hat{y}_1$'},'Interpreter','latex');
Je ne sais pas quand ils l'ont ajouté, mais cela fonctionne avec R2006b dans les fonctions text (), title (), xlabel (), ylabel (), zlabel () et même legend (). Assurez-vous simplement que la syntaxe que vous utilisez n'est pas ambiguë (donc avec legend () vous devez spécifier les chaînes comme un tableau de cellules).
Utilisation de xlim et ylim pour tracer des lignes verticales et horizontales. Exemples:
Tracez une ligne horizontale à y = 10:
line(xlim, [10 10])
Tracez une ligne verticale à x = 5:
line([5 5], ylim)
Voici un exemple rapide:
Je trouve la syntaxe de liste séparée par des virgules très utile pour créer des appels de fonction:
% Build a list of args, like so:
args = {'a', 1, 'b', 2};
% Then expand this into arguments:
output = func(args{:})
Voici un tas de fonctions non évidentes qui sont utiles de temps en temps:
mfilename
(retourne le nom du script MATLAB en cours d'exécution)dbstack
(vous donne accès aux noms et numéros de ligne de la pile de fonctions matlab)keyboard
(arrête l'exécution et cède le contrôle à l'invite de débogage; c'est pourquoi il y a un K dans l'invite de débogage K>>
dbstop error
(vous met automatiquement en mode débogage arrêté sur la ligne qui déclenche une erreur)Appel de Java depuis Matlab
J'aime utiliser les poignées de fonction pour de nombreuses raisons. D'une part, ils sont la chose la plus proche que j'ai trouvée dans MATLAB des pointeurs, vous pouvez donc créer un comportement de référence pour les objets. Il y a aussi quelques choses intéressantes (et plus simples) que vous pouvez faire avec eux. Par exemple, remplacer une instruction switch:
switch number,
case 1,
outargs = fcn1(inargs);
case 2,
outargs = fcn2(inargs);
...
end
%
%can be turned into
%
fcnArray = {@fcn1, @fcn2, ...};
outargs = fcnArray{number}(inargs);
Je pense juste que de petites choses comme ça sont cool.
Utilisation de nargin pour définir les valeurs par défaut des arguments facultatifs et utilisation de nargout pour définir les arguments de sortie facultatifs. Exemple rapide
function hLine=myplot(x,y,plotColor,markerType)
% set defaults for optional paramters
if nargin<4, markerType='none'; end
if nargin<3, plotColor='k'; end
hL = plot(x,y,'linetype','-', ...
'color',plotColor, ...
'marker',markerType, ...
'markerFaceColor',plotColor,'markerEdgeColor',plotColor);
% return handle of plot object if required
if nargout>0, hLine = hL; end
Afin de pouvoir tester rapidement une fonction, j'utilise nargin
comme ceci:
function result = multiply(a, b)
if nargin == 0 %no inputs provided, run using defaults for a and b
clc;
disp('RUNNING IN TEST MODE')
a = 1;
b = 2;
end
result = a*b;
Plus tard, j'ajoute un script de test unitaire pour tester la fonction pour différentes conditions d'entrée.
cellfun et arrayfun pour automatisé pour les boucles.
arguments conditionnels dans la partie gauche d'une affectation:
t = (0:0.005:10)';
x = sin(2*pi*t);
x(x>0.5 & t<5) = 0.5;
% This limits all values of x to a maximum of 0.5, where t<5
plot(t,x);
L'opérateur deux-points pour la manipulation des tableaux.
@ ScottieT812, en mentionne une: aplatir un tableau, mais il y a toutes les autres variantes de sélection des bits d'un tableau:
x=Rand(10,10);
flattened=x(:);
Acolumn=x(:,10);
Arow=x(10,:);
y=Rand(100);
firstSix=y(1:6);
lastSix=y(end-5:end);
alternate=y(1:2:end);
Oh, et inversez un tableau
v = 1:10;
v_reverse = v(length(v):-1:1);
Soyez strict en spécifiant les dimensions lorsque vous utilisez des fonctions d'agrégation comme min, max, moyenne, diff, somme, tout, tout, ...
Par exemple, la ligne:
reldiff = diff(a) ./ a(1:end-1)
pourrait bien fonctionner pour calculer les différences relatives d'éléments dans un vecteur, mais dans le cas où le vecteur dégénère en un seul élément, le calcul échoue:
>> a=Rand(1,7);
>> diff(a) ./ a(1:end-1)
ans =
-0.5822 -0.9935 224.2015 0.2708 -0.3328 0.0458
>> a=1;
>> diff(a) ./ a(1:end-1)
??? Error using ==> rdivide
Matrix dimensions must agree.
Si vous spécifiez les dimensions correctes de vos fonctions, cette ligne renvoie une matrice 1 par 0 vide, ce qui est correct:
>> diff(a, [], 2) ./ a(1, 1:end-1)
ans =
Empty matrix: 1-by-0
>>
Il en va de même pour une fonction min qui calcule généralement des minimums sur les colonnes d'une matrice, jusqu'à ce que la matrice ne se compose que d'une seule ligne. - Ensuite, il retournera le minimum sur la ligne, sauf indication contraire du paramètre de dimension, et cassera probablement votre application.
Je peux presque vous garantir que, par conséquent, la définition des dimensions de ces fonctions d'agrégation vous fera économiser un certain travail de débogage plus tard.
Au moins, cela aurait été le cas pour moi. :)
Connaissez votre propriétés de l'axe ! Il y a toutes sortes de choses que vous pouvez définir pour ajuster les propriétés de traçage par défaut pour faire ce que vous voulez:
set(gca,'fontsize',8,'linestyleorder','-','linewidth',0.3,'xtick',1:2:9);
(à titre d'exemple, définit la taille de police à 8 pt, les styles de ligne de toutes les nouvelles lignes à être pleins et leur largeur à 0,3 pt, et les points xtick à [1 3 5 7 9])
Line et figure les propriétés sont également utiles, mais je me retrouve à utiliser les propriétés des axes le plus.
Demander `` pourquoi '' (utile pour me sortir d'une transe de débogage avec échec d'exécution Matlab à 3 heures du matin ...)
Utilisation de ismember () pour fusionner des données organisées par identificateurs de texte. Utile lorsque vous analysez différentes périodes où les entrées, dans mon cas, les symboles de l'entreprise, vont et viennent.
%Merge B into A based on Text identifiers
UniverseA = {'A','B','C','D'};
UniverseB = {'A','C','D'};
DataA = [20 40 60 80];
DataB = [30 50 70];
MergeData = NaN(length(UniverseA),2);
MergeData(:,1) = DataA;
[tf, loc] = ismember(UniverseA, UniverseB);
MergeData(tf,2) = DataB(loc(tf));
MergeData =
20 30
40 NaN
60 50
80 70
Exécuter un modèle Simulink directement à partir d'un script (plutôt qu'interactif) à l'aide de la commande sim
. Vous pouvez faire des choses comme prendre des paramètres à partir d'une variable d'espace de travail et exécuter à plusieurs reprises sim
dans une boucle pour simuler quelque chose tout en variant le paramètre pour voir comment le comportement change, et représenter graphiquement les résultats avec les commandes graphiques que vous aimez. Beaucoup plus facile que d'essayer de le faire de manière interactive, et cela vous donne beaucoup plus de flexibilité que les blocs "oscilloscope" Simulink lors de la visualisation des résultats. (bien que vous ne puissiez pas l'utiliser pour voir ce qui se passe en temps réel pendant l'exécution de la simulation)
Une chose très importante à savoir est les options DstWorkspace
et SrcWorkspace
de la commande simset
. Celles-ci contrôlent où les blocs "To Workspace" et "From Workspace" obtiennent et placent leurs résultats. Dstworkspace
utilise par défaut l'espace de travail actuel (par exemple, si vous appelez sim
depuis l'intérieur d'une fonction, les blocs "To Workspace" apparaîtront comme des variables accessibles depuis cette même fonction) mais SrcWorkspace
par défaut dans l'espace de travail de base et si vous voulez encapsuler votre appel à sim
vous voudrez définir SrcWorkspace
à current
donc il y a une interface propre pour fournir/récupérer paramètres d'entrée et sorties de simulation. Par exemple:
function Y=run_my_sim(t,input1,params)
% runs "my_sim.mdl"
% with a From Workspace block referencing I1 as an input signal
% and parameters referenced as fields of the "params" structure
% and output retrieved from a To Workspace block with name O1.
opt = simset('SrcWorkspace','current','DstWorkspace','current');
I1 = struct('time',t,'signals',struct('values',input1,'dimensions',1));
Y = struct;
Y.t = sim('my_sim',t,opt);
Y.output1 = O1.signals.values;
Tracez le contour avec [c,h]=contour
Et clabel(c,h,'fontsize',fontsize)
. J'utilise généralement le paramètre fontsize
pour réduire la taille de la police afin que les chiffres ne se rencontrent pas. C'est idéal pour visualiser la valeur des fonctions 2D sans avoir à fouiller avec des graphiques 3D.
Vectorisation:
function iNeedle = findClosest(hay,needle)
%FINDCLOSEST find the indicies of the closest elements in an array.
% Given two vectors [A,B], findClosest will find the indicies of the values
% in vector A closest to the values in vector B.
[hay iOrgHay] = sort(hay(:)'); %#ok must have row vector
% Use histogram to find indices of elements in hay closest to elements in
% needle. The bins are centered on values in hay, with the edges on the
% midpoint between elements.
[iNeedle iNeedle] = histc(needle,[-inf hay+[diff(hay)/2 inf]]); %#ok
% Reversing the sorting.
iNeedle = iOrgHay(iNeedle);
Utilisation de variables persistent
(statiques) lors de l'exécution d'un algorithme en ligne. Cela peut accélérer le code dans des domaines tels que l'apprentissage automatique bayésien où le modèle est entraîné de manière itérative pour les nouveaux échantillons. Par exemple, pour calculer les loglikelihoods indépendants, je calcule initialement le loglikelihood à partir de zéro et le mets à jour en additionnant ce loglikelihood précédemment calculé et le loglikelihood supplémentaire.
Au lieu de donner un problème d'apprentissage automatique plus spécialisé, permettez-moi de donner un code de moyenne en ligne général que j'ai pris à partir d'ici :
function av = runningAverage(x)
% The number of values entered so far - declared persistent.
persistent n;
% The sum of values entered so far - declared persistent.
persistent sumOfX;
if x == 'reset' % Initialise the persistent variables.
n = 0;
sumOfX = 0;
av = 0;
else % A data value has been added.
n = n + 1;
sumOfX = sumOfX + x;
av = sumOfX / n; % Update the running average.
end
Ensuite, les appels donneront les résultats suivants
runningAverage('reset')
ans = 0
>> runningAverage(5)
ans = 5
>> runningAverage(10)
ans = 7.5000
>> runningAverage(3)
ans = 6
>> runningAverage('reset')
ans = 0
>> runningAverage(8)
ans = 8
Je suis surpris que, bien que les gens aient mentionné l'approche logique de tableau d'indexation d'un tableau, personne n'a mentionné la commande find.
par exemple. si x est un tableau NxMxO
x (x> 20) fonctionne en générant un tableau logique NxMxO et en l'utilisant pour indexer x (ce qui peut être mauvais si vous avez de grands tableaux et recherchez un petit sous-ensemble
x (find (x> 20)) fonctionne en générant une liste (c'est-à-dire 1x quel que soit) d'indices de x qui satisfont x> 20, et en indexant x par lui. "find" devrait être utilisé plus qu'il ne l'est, d'après mon expérience.
Plus ce que j'appellerais des "trucs"
vous pouvez agrandir/ajouter des tableaux et des tableaux de cellules si vous ne connaissez pas la taille dont vous aurez besoin, en utilisant end + 1 (fonctionne également avec des dimensions plus élevées, tant que les dimensions de la tranche correspondent - vous aurez donc avoir à initialiser x à autre chose que [] dans ce cas). Pas bon pour les chiffres mais pour les petites listes dynamiques de choses (ou les tableaux de cellules), par exemple l'analyse des fichiers.
par exemple.
>> x = [1,2,3] x = 1 2 3 >> x (fin + 1) = 4 x = 1 2 3 4
Un autre pense que beaucoup de gens ne savent pas que pour les travaux sur n'importe quel tableau dim 1, donc pour continuer l'exemple
>> pour n = x; disp (n); fin 1 2 3 4
Ce qui signifie que si vous n'avez besoin que des membres de x, vous n'avez pas besoin de les indexer.
Cela fonctionne également avec les tableaux de cellules, mais c'est un peu ennuyeux, car en les parcourant, l'élément est toujours enveloppé dans une cellule:
>> pour el = {1,2,3,4}; disp (el); end [1] [2] [3] [4]
Donc, pour obtenir les éléments, vous devez les souscrire
>> pour el = {1,2,3,4}; disp (el {1}); end 1 2 3 4
Je ne me souviens pas s'il y a un meilleur moyen de contourner cela.
-Vous pouvez créer un raccourci Matlab vers un fichier d'initialisation appelé startup.m. Ici, je définis le formatage, la précision de la sortie et les paramètres de tracé pour ma session Matlab (par exemple, j'utilise un axe/taille de police plus grand pour que les fichiers .fig soient clairement visibles lorsque je les mets dans des présentations.) article de blog d'un des développeurs à ce sujet http://blogs.mathworks.com/loren/2009/03/03/whats-in-your-startupm/ .
-Vous pouvez charger un fichier ascii numérique entier en utilisant la fonction "charger". Ce n'est pas particulièrement rapide, mais fait le travail rapidement pour le prototypage (ne devrait-ce pas être la devise de Matlab?)
-Comme mentionné, l'opérateur du côlon et la vectorisation sont des sauveteurs. Boucles à vis.
x = repmat ([1:10], 3,1); % disent, x est un exemple de tableau de données
l = x> = 3; % l est un vecteur logique (1s/0s) pour mettre en évidence les éléments du tableau qui rempliraient une certaine condition.
N = sum (sum (l));% N est le nombre d'éléments qui remplissent cette condition donnée.
cheers - script heureux!
Voici ce que j'utilise fréquemment:
% useful abbreviations
flat=@(x) x(:);
% print basic statistics
stats=@(x) sprintf('mean +/- s.d. \t= %f +/- %f\nmin, max \t\t= %f, %f\nmedian, mode \t= %f, %f', ...
mean(flat(x)), std(flat(x)), min(flat(x)), max(flat(x)), median(flat(x)), mode(flat(x)) );
nrows=@(x) size(x,1);
ncols=@(x) size(x,2);
nslices=@(x) size(x,3);
% this is just like ndims except it returns 0 for an empty matrix and
% ignores dimensions of size 0.
ndim=@(x) length(find(size(x)));
</code>
Ces abréviations sont utiles pour trouver la moyenne et l'écart type des valeurs de pixels dans une petite zone d'une image. J'utiliserais la logique suivante:
phantomData = phantom();
stats( phantomData(50:80, 50:80) )
</code>
Et si je voulais mettre la taille d'une image dans son titre?
imagesc( phantomData );
title( sprintf('The image size is %d by %d by %d.', nrows(phantomData), ncols(phantomData), nslices(phantomData)) )
</code>