1

My requirement is to provide a function in Java that uses linear algebra to find a 'calibrated' xyz location within a three-dimensional coordinate frame. The following is the interface I am trying to implement. The arguments can be changed to fit a specific library if needed.

/**
 * Given a nominal target xyz point within a three dimensional robotic coordinate system, calculate the theoretical x'y'z'
 * transformation using input arrays that represent the nominal coordinates and actual measured coordinates corresponding to
 * each nominal point.
 *
 * @param nominalPoints - a sampling of nominal values (per engineering specs) for a 3-axis robotic system
 *    e.g.     double[][] nominalPoints = new double[][]{
 *                 new double[]{30.0d, 68.0d, 1.0d},
 *                 new double[]{50.0d, 6.0d, 1.0d},
 *                 new double[]{110.d, 20.0d, 1.0d},
 *                 new double[]{35.0d, 15.0d, 1.0d},
 *                 new double[]{45.0d, 97.0d, 1.0d}
 *              };
 * @param actualPoints - actual/measured values corresponding to the nominal data points.  These points represent the
 *                     variance from nominal due to manufacturing tolerances.
 *    e.g     double[][] measuredPoints = new double[][]{
 *                 new double[]{30.5d, 68.1d, 1.01d},
 *                 new double[]{50.4d, 6.2d, 1.02d},
 *                 new double[]{110.3d, 20.3d, 1.03d},
 *                 new double[]{35.2d, 15.4d, 1.04d},
 *                 new double[]{45.1d, 97.5d, 1.05d}
 *             };
 * @param targetPoint - an x/y/z point in system to transform into an estimated value based on a least-squared evaluation of the
 *                    nominal and actual arrays
 *
 *     e.g.    float[] targetPoint = new float[]{75.21f, 17.56f, 2.765f};
 *
 * @return
 */
public float[] getCalibratedPoint(float[][] nominalPoints, float[][] actualPoints, float[] targetPoint);

The following code is one solution that I'm told would work in Python using numpy but I suck at linear algebra and am having trouble finding implementations in Java to do this. Specifically, I have not found an equivalent to np.hstack(..), np.ones(..), and a least-squares function that takes 2 array arguments like np.linalg.lstsq(..). I've looked at Apache Commons and EJML so far

import numpy as np

# These are the points in the Tray Coordinate System.
primary = np.array([[40., 1160., 0.],
                    [40., 40., 0.],
                    [260., 40., 0.],
                    [260., 1160., 0.]])

# These are points in the Stage Coordinate System.
secondary = np.array([[610., 560., 0.],
                      [610., -560., 0.],
                      [390., -560., 0.],
                      [390., 560., 0.]])

# Pad the data with ones, so that our transformation can do translations too
def pad(x): return np.hstack([x, np.ones((x.shape[0], 1))])
def unpad(x): return x[:, :-1]

# This is the transform function. Pass Tray Coordinates to this.
def transform(x): return unpad(np.dot(pad(x), A))

X = pad(primary)
Y = pad(secondary)

# Solve the least squares problem X * A = Y
# to find our transformation matrix A
A, res, rank, s = np.linalg.lstsq(X, Y, rcond=None)  # This is where the important work is done.

# Transforming a single point.
print('Transforming point (1, 2, 3) ...')
print(transform(np.array([[1, 2, 3]])))
Eric Hansen
  • 187
  • 1
  • 1
  • 10
  • Ugh, this Java code uses an array of arrays to represent a matrix (guaranteeing awful performance, since different rows are going to be in random places in the heap). Nonetheless, (1) the `pad` function (which uses hstack and ones) is trivial to write in Java: you add 1 at the end of each row of the input. And (2) what's wrong with http://commons.apache.org/proper/commons-math/userguide/linear.html#a3.4_Solving_linear_systems ? Your array `X` in Python is square, so you can use `LUDecomposition` just like the example there, and then `solver.solve(Y)`. Try this & update with any problems. – Ahmed Fasih Dec 25 '19 at 18:55
  • As a follow up, I was not able to find a Java based solution that matches the output of the python code above. LUDecomposition and Solver did not yield the same result as the np.linalg.lstsq. What I ended up doing, was using jep to execute the python code from inside my java service. It is working well, but I would still be interested in a pure java solution. – Eric Hansen Jan 31 '20 at 16:34
  • Post a Java [MCVE](https://stackoverflow.com/help/minimal-reproducible-example) and the expected output you get from Python and we can try to figure it out. – Ahmed Fasih Feb 01 '20 at 01:09

0 Answers0