2009-11-25 7 views
3

J'essaye d'écrire un programme Matlab qui accepte des variables pour un système de l'utilisateur, mais il y a plus de variables que de paramètres système. Pour être précis, six variables de trois équations:Résolution de variables dans un système sur-paramétré

w - d - M = 0 
l - d - T = 0 
N - T + M = 0 

Cela pourrait être représenté sous forme matricielle A*x=0

A = [1 0 0 -1 0 -1; 
    0 1 0 -1 -1 0; 
    0 0 1 0 -1 1]; 

x = [w l N d T M]'; 

Je voudrais être en mesure de résoudre ce système donné un sous-ensemble connu du variables Par exemple, si l'utilisateur donne d, T, M, alors le système est trivialement résolu pour les trois autres variables. Si l'utilisateur fournit w, N, M, il devient alors un système 3-DOF résoluble. Etc. (Si l'utilisateur sur ou sous-spécifie le système, une erreur peut évidemment entraîner.)

Compte tenu de tout un de ces combinaisons, il est simple à (a priori) utiliser l'algèbre matricielle pour calculer les quantités inconnues. Mais je ne sais pas comment résoudre le cas général, mis à part l'utilisation de la boîte à outils symbolique (que je préfère ne pas faire pour des raisons de compatibilité). Quand j'ai commencé avec cette approche, j'ai pensé que cette étape serait facile, mais mon algèbre linéaire est rouillée; Ai-je manqué quelque chose de simple?

Répondre

4

D'abord, laissez x être un vecteur avec NaN pour les valeurs inconnues. Cela vous permet d'utiliser ISNAN pour trouver les indeces des inconnues. Si vous calculez A*x uniquement pour les termes spécifiés par l'utilisateur, cela vous donne une colonne de constantes b. Prenez ces constantes du côté droit de l'équation, et vous avez une équation de la forme A*x = -b.

A = [1 0 0 -1 0 -1; 
    0 1 0 -1 -1 0; 
    0 0 1 0 -1 1]; 

idx = ~isnan(x); 
b = A(:,idx)*x(idx); % user provided constants 
z = A(:,~idx)\(-b); % solution of Ax = -b 
x(~idx) = z; 

Avec entrée x = [NaN NaN NaN 1 1 1]', par exemple, vous obtenez le résultat [2 2 0 1 1 1]'. Cela utilise MLDIVIDE, je ne suis pas assez versé dans l'algèbre linéaire pour savoir si PINV ou quelque chose d'autre serait mieux.

+0

Cela semble prometteur, merci! –

+0

En effet, fonctionne comme un charme :) Après avoir vu la solution j'aurais pu être en mesure de comprendre que pour moi-même ... trop longtemps une soirée pour moi, je pense! –

0

Le système d'équations est-il fixe? Que faire si vous stockez les variables présentes dans vos trois équations dans une liste par l'équation:

(w, d, M) 
(l, d, T) 
(N, T, M) 

Ensuite, vous obtenez l'entrée d'utilisateur et vous pouvez calculer le nombre de variables données dans chaque équation:

User input: w, N, M 
Given variables: 
(w, d, M) -> 2 
(l, d, T) -> 0 
(N, T, M) -> 1 

Cela vous donnerait trivialement d à partir de la première équation. Par conséquent, vous vous retrouvez avec deux équations contenant deux variables et vous connaissez le système d'équation que vous devez résoudre.

C'est fondamentalement votre propre solveur symbolique simple pour un seul système d'équations.

+0

Oui, c'est ce que j'essaie de faire ... mais ce sont les détails manquants ici que j'ai des problèmes. Je suis d'accord que c'est facile à faire algébriquement mais la partie difficile est de le faire en général (mais peut-être que je suis trop optimiste/ambitieux en essayant de le faire en général). –

3

Étant donné le système linéaire

A = [1 0 0 -1 0 -1; 
    0 1 0 -1 -1 0; 
    0 0 1 0 -1 1]; 

A*x = 0 

Lorsque les éléments de x sont identifiés comme:

x = [w l N d T M]'; 

Maintenant, supposons que {d, T, M} ont connu, des valeurs fixes. Ce dont nous avons besoin, ce sont les indices de ces éléments dans x.Nous avons choisi les 4ème, 5ème et 6ème éléments de x pour être connus.

known_idx = [4 5 6]; 
unknown_idx = setdiff(1:6,known_idx); 

Maintenant, permettez-moi de choisir des nombres arbitraires pour ces variables connues.

xknown = [1; -3; 7.5]; 

Nous allons partitionner A en deux sous-matrices, correspondant aux variables connues et inconnues.

Aknown = A(:,known_idx); 
Aunknown = A(:,unknown_idx); 

Maintenant, déplacez les valeurs connues du côté droit de l'égalité et résolvez-les. Voir que Aknown est une matrice 3x3, donc le problème est (espérons-le) bien posé.

xunknown = Aunknown\(-Aknown*xknown) 
xunknown = 
     -8.5 
      2 
     10.5 

Combinez tout dans la solution finale.

x = zeros(6,1); 
x(known_idx) = xknown; 
x(unknown_idx) = xunknown; 
x = 
     -8.5 
      2 
     10.5 
      1 
      -3 
      7.5 

Notez que j'ai développé tout cela en quelques lignes pour montrer ce qui se passe plus clairement. Mais j'aurais pu tout faire en une ou deux lignes de code si j'avais voulu être parcimonieux. Enfin, voir que si j'avais choisi d'autres ensembles de nombres pour être connus, tels que {l, d, T}, alors le système résultant serait singulier. Donc, vous devez regarder pour cet événement. Un test sur le rang d'Aunknown pourrait être utile pour éliminer les problèmes. Ou vous pouvez choisir d'utiliser pinv pour construire la solution.