0

I'm trying to calculate the scalar product and the normalized vector of temp_a and E in python.

I'm using this c++ example:

vector temp_a = a;
vector_normalize(&temp_a);
vector E;
vector_normalize(&E);

float LSM303DLH::vector_dot(const vector *a,const vector *b)
{
  return (a->x * b->x) + (a->y * b->y) + (a->z * b->z);
}

void LSM303DLH::vector_normalize(vector *a)
{
  float mag = sqrt(vector_dot(a,a));
  a->x /= mag;
  a->y /= mag;
  a->z /= mag;
}

This is what I've got so far in python:

vector_a = [321,321,321]
vector_e = [123,123,123]

#calculating the scalar product between two vectors
vector_dot_a = numpy.dot(vector_a, vector_a)
vector_dot_e = numpy.dot(vector_e, vector_e)

#normalizing the vectors
scalar_a = math.sqrt(vector_dot_a)
vector_a[0] /= scalar_a
vector_a[1] /= scalar_a
vector_a[2] /= scalar_a

scalar_e = math.sqrt(vector_dot_e)
vector_e[0] /= scalar_e
vector_e[1] /= scalar_e
vector_e[2] /= scalar_e

For the normalization can I just use this instead?

numpy.linalg.norm(vector_a)
numpy.linalg.norm(vector_e)

-+-+-+-+Edit 1-+-+-+-+

This is my result:

def readMagneticHeading(x_offset_min_m, y_offset_min_m, z_offset_min_m, x_offset_max_m, y_offset_max_m, z_offset_max_m):

  #shift and scale the calibrated min/max magnetic data
  x_heading_m = (x_data_m - x_offset_min_m) / (x_offset_max_m - x_offset_min_m) * 2 - 1.0;
  y_heading_m = (y_data_m - y_offset_min_m) / (y_offset_max_m - y_offset_min_m) * 2 - 1.0;
  z_heading_m = (z_data_m - z_offset_min_m) / (z_offset_max_m - z_offset_min_m) * 2 - 1.0;

  vector_from = [0,-1,0] #from vector
  vector_a = readAccelerations() #accelerations vector
  vector_e = [0,0,0] #east vector
  vector_n = [0,0,0] #north vector
  vector_m = readMagnetics() #magnetics vector

  #vector_a dot vector_a, the scalar dot product between two vectors
  scalar_dot_a = numpy.dot(vector_a, vector_a)
  #get the vector norm
  vector_norm__a = numpy.linalg.norm(scalar_dot_a)
  vector_a /= vector_norm__a

  #create the cross product of the east vector
  vector_e = numpy.cross(vector_m, vector_a)

  #vector_e dot vector_e, the scalar dot product between two vectors
  scalar_dot_e = numpy.dot(vector_e, vector_e)
  #get the vector norm
  vector_norm__e = numpy.linalg.norm(scalar_dot_e)
  vector_e /= vector_norm__e

  #create the cross product of the north vector
  vector_n = numpy.cross(vector_a, vector_e)

  vector_dot_e_from = numpy.dot(vector_e,vector_from)
  vector_dot_n_from = numpy.dot(vector_n,vector_from)

  #calculate the heading
  heading_m = round(math.atan2(vector_dot_e_from, vector_dot_n_from) * 180 / math.pi)

  if (heading_m < 0):
    heading_m += 360

  return heading_m

compared to the c++ version:

// Returns the number of degrees from the -Y axis that it
// is pointing.
int LSM303DLH::heading(void)
{
return heading((vector){0,-1,0});
}

// Returns the number of degrees from the From vector projected into
// the horizontal plane is away from north.
//
// Description of heading algorithm:
// Shift and scale the magnetic reading based on calibration data to
// to find the North vector. Use the acceleration readings to
// determine the Down vector. The cross product of North and Down
// vectors is East. The vectors East and North form a basis for the
// horizontal plane. The From vector is projected into the horizontal
// plane and the angle between the projected vector and north is
// returned.
int LSM303DLH::heading(vector from)
{
    // shift and scale
    m.x = (m.x - m_min.x) / (m_max.x - m_min.x) * 2 - 1.0;
    m.y = (m.y - m_min.y) / (m_max.y - m_min.y) * 2 - 1.0;
    m.z = (m.z - m_min.z) / (m_max.z - m_min.z) * 2 - 1.0;

    vector temp_a = a;
    // normalize
    vector_normalize(&temp_a);
    //vector_normalize(&m);

    // compute E and N
    vector E;
    vector N;
    vector_cross(&m, &temp_a, &E);
    vector_normalize(&E);
    vector_cross(&temp_a, &E, &N);

    // compute heading
    int heading = round(atan2(vector_dot(&E, &from), vector_dot(&N, &from)) * 180 / M_PI);
    if (heading < 0) heading += 360;
return heading;
}

void LSM303DLH::vector_cross(const vector *a,const vector *b, vector *out)
{
  out->x = a->y*b->z - a->z*b->y;
  out->y = a->z*b->x - a->x*b->z;
  out->z = a->x*b->y - a->y*b->x;
}

float LSM303DLH::vector_dot(const vector *a,const vector *b)
{
  return a->x*b->x+a->y*b->y+a->z*b->z;
}

void LSM303DLH::vector_normalize(vector *a)
{
  float mag = sqrt(vector_dot(a,a));
  a->x /= mag;
  a->y /= mag;
  a->z /= mag;
}

are there any differences left regarding the logic?

2
  • 1
    You can simply do vector_a /= scalar_a and vector_e /= scalar_e, no need to explicitly modify every item. And np.linalg.norm(a) is equivalent to np.sqrt(a.dot(a)), you'd still need the division. Commented May 24, 2014 at 15:25
  • You can also get the same result with less lines of code and you don't care about the dimension of the vector: scalar_a = math.sqrt(reduce(lambda a,b: a+b, map(lambda x: x**2, vector_a))) vector_a = map(lambda x: x/scalar_a, vector_a) Commented May 24, 2014 at 15:50

1 Answer 1

2

Yes, you can use numpy.linalg.norm. It gives the same results as your code.

Also note you could do your division in vectorized form, like so:

vector_a /= scalar_a

That's much faster than the three separate ones you had, and arguably clearer too.

Sign up to request clarification or add additional context in comments.

3 Comments

What confuses me is that the c++ function vector_normalize calls vector_dot and using its results in the calculation. Using numpy.linalg.norm would not actualle use the numpy.dot, right? This is the point why I think the results might be different...
The exact code of norm can be checked here, it should be equivalent (but slower) to calling dot and sqrt.
I was hoping somebody would also write about detecting "zero vectors" - can the norm be too small to divide by?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.