Question about floating point operations...
Michael101
Posts: 3
Hey guys,
···· I am attempting to measure a pulse width that represents a magnetic heading for an Acroname Devantech Electronic compass.· The pulse range is from 123 to 4228.· If you subtract the total range of the pulses (4228-123) you get 4105.· If you divide 4105, the entire possible pulse range by 360 (degrees in a circle), you receive a conversion factor of 11.4.
···· When the pulse comes in you need to divide the pulse by the conversion factor to receive the correct heading in degrees.· The problem is - no floating point supported by the Javelin, at least not without some work.· I tried a number of different things including using a conversion factor of 114 (divide the actual pulse width by 114) and then multiplying by 10, but the loss of precision is giving me poor heading readings.
····· I also downloaded and successfully ran the Float32 APP mod for the Javelin which works great, however, it uses a lot of memory and processing power to perform a floating point calculation.· I would like to use the Float32 APP mod, however, I fear with an entire robot operating system, it may not have adequate memory or processing power to complete the job.
····· Below is what I coded initially to give you an idea of what I am attempting.· I am new to the Javelin and embedded programming, however, I feel I need an efficient way to get around the non-floating point capability of the chip.· I have other sensors I am adding that also measure pulse width that I would like to convert to meaningful values.
····· On possible solution I could not figure out is how to strip off the sign bit to utilize an integer to its full potential.· The manual mentions using a left bit shift to do this but does not give an adequate (for me)explanation.
···· Thanks,
····· Mike
//11-21-2005
//This converts the pulse width of the compass into degrees
//for the Acroname Electronic Compass
import stamp.core.*;
public class CompassCalibration {
static int pulse;
static int heading;
static int maxPulse = 4228;
static int minPulse = 123;
static int conversion = 11;//coversion factor from pulse width the actual
//to degrees of heading 0-360
//value should be 11.4
public static void main() {
while (true) {
pulse = CPU.pulseIn(15000,CPU.pin14, true);
if(pulse<minPulse || pulse > maxPulse) {
heading = 360;
System.out.print("Heading = ");
System.out.println(heading);
}
else{
heading = (pulse-minPulse)/conversion;
if(heading>360){
heading = 360;
System.out.print("Heading = ");
System.out.println(heading);
}
else{
System.out.print("Heading = ");
System.out.println(heading);
}
}
}
}
}
···· I am attempting to measure a pulse width that represents a magnetic heading for an Acroname Devantech Electronic compass.· The pulse range is from 123 to 4228.· If you subtract the total range of the pulses (4228-123) you get 4105.· If you divide 4105, the entire possible pulse range by 360 (degrees in a circle), you receive a conversion factor of 11.4.
···· When the pulse comes in you need to divide the pulse by the conversion factor to receive the correct heading in degrees.· The problem is - no floating point supported by the Javelin, at least not without some work.· I tried a number of different things including using a conversion factor of 114 (divide the actual pulse width by 114) and then multiplying by 10, but the loss of precision is giving me poor heading readings.
····· I also downloaded and successfully ran the Float32 APP mod for the Javelin which works great, however, it uses a lot of memory and processing power to perform a floating point calculation.· I would like to use the Float32 APP mod, however, I fear with an entire robot operating system, it may not have adequate memory or processing power to complete the job.
····· Below is what I coded initially to give you an idea of what I am attempting.· I am new to the Javelin and embedded programming, however, I feel I need an efficient way to get around the non-floating point capability of the chip.· I have other sensors I am adding that also measure pulse width that I would like to convert to meaningful values.
····· On possible solution I could not figure out is how to strip off the sign bit to utilize an integer to its full potential.· The manual mentions using a left bit shift to do this but does not give an adequate (for me)explanation.
···· Thanks,
····· Mike
//11-21-2005
//This converts the pulse width of the compass into degrees
//for the Acroname Electronic Compass
import stamp.core.*;
public class CompassCalibration {
static int pulse;
static int heading;
static int maxPulse = 4228;
static int minPulse = 123;
static int conversion = 11;//coversion factor from pulse width the actual
//to degrees of heading 0-360
//value should be 11.4
public static void main() {
while (true) {
pulse = CPU.pulseIn(15000,CPU.pin14, true);
if(pulse<minPulse || pulse > maxPulse) {
heading = 360;
System.out.print("Heading = ");
System.out.println(heading);
}
else{
heading = (pulse-minPulse)/conversion;
if(heading>360){
heading = 360;
System.out.print("Heading = ");
System.out.println(heading);
}
else{
System.out.print("Heading = ");
System.out.println(heading);
}
}
}
}
}
Comments
Take a look a my class UnsignedIntMath.java here
http://groups.yahoo.com/group/JavelinCode/files/Javelin%20Stamp%20IDE/lib/stamp/math/
It allows you to multiply an unsigned integer with an unsigned fraction, without the overhead
of the floating point class.
I used it in my ScaledTimer16.java class here
http://groups.yahoo.com/group/JavelinCode/files/Javelin%20Stamp%20IDE/lib/stamp/core/
It has example formulae that show how to use the UnsignedIntMath class.
regards peter
···· Thanks for the link to your code.· It looks like it will work very efficiently for what I need to do.· I will try it tomorrow on the stamp.· In order to multiply·4105·times 0.087719, I would send what parameters to your method?
int pulseSpread = 4105;
int conversion = 87719; //obviously too big as a signed integer
UnsignedIntMath.umulf(pulseSpread,conversion);
How do I accomplish a bit shift properly?
Mike
/**
* Multiply unsigned int with unsigned fraction.
*
* @param value Unsigned int to multiply
* @param fraction Multiplier (represents Multiplier / 65536)
* @return value * fraction rounded off integer result
*/
public static int umulf(int value, int fraction) {
int i, result=0, rest=0;
for (i=1; i<17; i++) {
if (fraction < 0) { //b15 set
result += (value >>> i); //accumulate integer result
rest += ( (value & ((1<<i)-1)) << (16-i) ); //accumulate rest R/65536
if (CPU.carry()) result++; //update result if rest overflows
}
fraction <<= 1; //next bit
}
if (rest < 0) result++; //roundoff
return result;
}
}
5 * 4105 = 20525·· no overflow (your *10 would give 41050 which is -24886)
5 * 11.4 = 57
So try heading = ((value - 123) * 5) / 57
regards peter
X = 65536 / 11.4 = ·5748.77 so your fraction int is 5748 or 5749
regards peter
A >>> n shifts right value A by n bits, '0' bits shift in at MSB
A >> n shifts right value A by n bits, preserving the sign bit (b15)
regards peter
The formula heading = ((value - 123) * 5) / 57 works perfectly. Now I just need to brush up on my algebra. I am sure I will use your UnsignedMath class as it is very small and efficient if I run into other problems requiring floating point.
I was looking at the Yahoo site and you have posted some very nice work. I will definately use some of your ideas.
Thank you again for your help!
Regards,
Mike