求解 Javascript 中的非平方线性方程组

Solving non-square system of linear equations in Javascript

我有一个电阻系统,像这样: Resistor schematic

我制作了一个网站,可以呈现这样的图表(不完全是这个)。用户可以改变每个电阻的阻值。我想计算系统中的每一个电流。

我找到了一个使用基尔霍夫定律的解,它给了我一个线性方程组。我使用逆矩阵用 math.js 解决了它。这种方法在较小的电路上效果很好。

在这个电路中,我的方程比变量多,这意味着我无法计算逆矩阵来求解它们。手动简化它们,以匹配未知数的数量是一种选择,但这需要人工。网站应该可以自己计算一切。

现在我正在寻找一种方法来求解不能表示为方阵的线性方程组。有什么建议吗?

谢谢!

编辑:

我目前的做法是这样的。

let R1 = 3;
let R2 = 10;
let R3 = 3;
let R4 = 2;
let R5 = 4;
let R6 = 4;
let V1 = 5;

let I1 = 0;
let I2 = 0;
let I3 = 0;
let I4 = 0;
let I5 = 0;
let I6 = 0;

const matrix = [
  [-1, 1, 1, 0, 0, 0],
  [1, -1, 0, 0, 0, -1],
  [0, 0, -1, 1, 1, 0],
  [0, -R2, 0, 0, 0, 0],
  [0, 0, 0, -R6, -R5, 0],
  [0, 0, -R1, -R6, 0, -(R3 + R4)]
];
const result = [0, 0, 0, -V1, 0, -V1];

const inverse = math.inv(matrix);
const currents = math.multiply(inverse, result);

console.log(currents);
[I1, I2, I3, I4, I5, I6] = currents;
<script src="https://cdn.jsdelivr.net/npm/mathjs@9.4.4/lib/browser/math.min.js"></script>

问题是在这个例子中,我得到了错误的解决方案。我将其缩小到缺少条件(方程式)。

我有 6 个电流,这意味着我只能有 6 个方程来计算逆矩阵...但是在这种情况下以及我拥有的许多其他情况下,6 个方程是不够的。

问题是我需要一台电脑来理解它。不是人类。所以,我需要找到一种方法来解决此类 6 个变量的问题,但方程式要多于 6 个。

  • 这种方法减少了矩阵的行,结果给出了一个具有未知值的字符串。如果系统具有无限分辨率,这将 returns 简化方程式,以便您稍后可以进行参数化。

EDIT :独立项在数组的最后一列。

let eq = [
  [1, 0, 1],
  [1, -2, 0],
  [0, 2, 1]
];

console.log(rowReduction());

function rowReduction() {
  for (let columnIndex = 0; columnIndex < eq[0].length; columnIndex++) {
    if (columnIndex < eq.length) {
      let rowCheck = 0;
      while (isEqual(eq[columnIndex][columnIndex], 0) && rowCheck < eq.length) {
        if (rowCheck !== columnIndex) {
          eq[columnIndex] = eq[rowCheck].map((e, i) => eq[columnIndex][i] + e);
        }
        rowCheck++;
      }
    }
  }
  for (let columnIndex = 0; columnIndex < eq[0].length; columnIndex++) {
    if (columnIndex < eq.length) {
      let diagElement = eq[columnIndex][columnIndex];
      if (nonEqual(diagElement, 0)) {
        eq[columnIndex] = eq[columnIndex].map((e, i) => e / diagElement);
      }
      for (let rowIndex = 0; rowIndex < eq.length; rowIndex++) {
        if (rowIndex !== columnIndex && nonEqual(eq[rowIndex][columnIndex], 0)) {
          const opuesto = -eq[rowIndex][columnIndex];
          eq[rowIndex] = eq[columnIndex].map((e, i) => eq[rowIndex][i] + opuesto * e);
        }
      }
    }
  }
  let compatible = true;
  for (let f = 0; f < eq.length; f++) {
    let nulo = true;
    for (let c = 0; c < eq[f].length - 1; c++) {
      if (nonEqual(eq[f][c], 0)) nulo = false;
    }
    if (nulo && nonEqual(eq[f][eq[f].length - 1], 0)) compatible = false;
  }
  return compatible ? evaluateEq() : "Incompatible system";

  function evaluateEq() {
    let str = "";
    eq.forEach(function a(row, i) {
      //avoid null rows
      if (nonEqual(row.reduce((l, n) => l + Math.abs(n), 0), 0)) {
        row.forEach(function b(e, j) {
          e = e.toFixed(3); //decimals after comma
          if (j + 1 === row.length) { //independent term
            str += " = " + e;
          } else if (nonEqual(e, 0)) {
            str += " + ";
            if (nonEqual(e, 1)) str += "(" + e + ")*";
            str += "x[" + j + "]";
          }
        });
        str += "\n";
      }
    });
    return str;
  }

  //to avoid problems due to margin error
  function isEqual(n, target) {
    return parseFloat(n).toFixed(8) == target;
  }

  function nonEqual(n, target) {
    return parseFloat(n).toFixed(8) != target;
  }
}

经过反复试验,我发现 ml-matrix 中的 solve 函数允许包含 N 个变量的 N 个以上的方程。

我也尝试过使用伪逆的方法,但这也要求矩阵是方阵。

如果方程和未知数的数量相等,您可以使用 LU 分解求解矩阵。

如果方程的数量多于未知数的数量,则使用最小二乘法。

如果方程的数量少于未知数的数量,则使用奇异值分解。

Here 是如何使用 R 完成的示例。我确信 Python、JAMA 和其他库都有 SVD 求解器。我不知道 Javascript。