Convert decimal to latitude and longitude - algorithm

I have a GPS device which sends data to my server, I need to convert the decimal values that the device sends into latitude and longitude. I am bad at math so all my attempts failed, here are the specs:
Latitude
Occupy 4 bytes, representing the latitude value.
Number range is from 0 to 162000000, which represents the range form 0°to 90°.
Unit: 1/500 second Conversion method:
A) Convert the latitude (degrees, minutes) data from GPS module into a new form which represents the value only in minutes;
B Multiply the converted value by 30000, and then transform the result to hexadecimal number
For example22°32.7658′,(22×60+32.7658)×30000=40582974, then convert it to hexadecimal number 0x02 0x6B 0x3F 0x3E
Longitude
Occupy 4 bytes, representing the longitude value of location data. Number ranges from 0 to 324000000, representing the range form 0°to 180°.Unit: 1/500 seconds, Conversion method is the same as latitude’s.
I came up with this function but it doesn't seem to work:
procedure GetDegree(const numar : DWORD; out min,sec : Extended);
var
eu : Extended;
begin
eu := numar / 30000;
min := Trunc(eu / 60);
sec := eu - min * 60;
end;

numar is specified in 1/500th of a second. So, the following equations hold:
num/500 = seconds
num/500/60 = minutes
num/500/60/60 = degrees
I would calculate it all like this:
var
degrees, minutes, seconds: Integer;
....
degrees := num div (500*60*60);
minutes := num div (500*60) - degrees*60;
seconds := num div 500 - minutes*60 - degrees*60*60;
If you need to calculate the fractional part of seconds then do it like this. Note that there's simply no need for Extended here.
var
degrees, minutes: Integer;
seconds: Double;
....
degrees := num div (500*60*60);
minutes := num div (500*60) - degrees*60;
seconds := num/500 - minutes*60 - degrees*60*60;
Plug your value of 40582974 into these formula and the results are:
degrees: 22
minutes: 32
seconds: 45
Judging from comments what you actually want is degrees as an integer and minutes as a floating point. That you can do like this:
var
degrees: Integer;
minutes: Double;
....
degrees := num div (500*60*60);
minutes := num/(500*60) - degrees*60;
Plug your value of 40582974 into these formula and the results are:
degrees: 22
minutes: 32.7658

Related

Random number within range and a given granularity in Golang

I've written the following code to create a random number between 0.0 and 10.0.
const minRand = 0
const maxRand = 10
v := minRand + rand.Float64()*(maxRand-minRand)
However, I would like to set the granularity to 0.05, so having all the digits as the least significant decimal should not be allowed, only 0 and 5 should be allowed, e.g.:
the value 7.73 is NOT VALID,
the values 7.7 and 7.75 ARE VALID.
How can I produce such numbers in Go?
You can divide with the granularity, get a pseudo random integer and then multiply with the granularity to scale the result down.
const minRand = 8
const maxRand = 10
v := float64(rand.Intn((maxRand-minRand)/0.05))*0.05 + minRand
fmt.Printf("%.2f\n", v)
This will print:
8.05
8.35
8.35
8.95
8.05
9.90
....
If you don't want to get the same sequence every time rand.Seed(time.Now().UTC().UnixNano()).
From the docs
Seed uses the provided seed value to initialize the default Source to a deterministic state. If Seed is not called, the generator behaves as if seeded by Seed(1). Seed values that have the same remainder when divided by 2^31-1 generate the same pseudo-random sequence. Seed, unlike the Rand.Seed method, is safe for concurrent use.
With lower bounds
const minRand = 0
const maxRand = 10
const stepRand = 0.05
v := float64(rand.Intn((maxRand-minRand)/stepRand))*stepRand + minRand
fmt.Printf("%.2f\n", v)

A game with 100 oponnents, win as much money as possible

You play a game with 100 opponents. The game has k rounds. Every round you can eliminate some opponents (always atleast 1). You are rewarded for eliminating them.
The reward is: 100.000 * '# of eliminated opponents' / '# of opponents' <= in integers (rounded down)
I want to eliminate the opponents in a way, that gets me the largest amount of money possible.
Example game:
number of rounds = 3
first round we eliminate 50 opponents, so we get 100.000 * 50 / 100 = +50.000
second round we eliminate 30, so we get 100.000 * 30 / 50 = +60.000
last round we eliminate last 20 opponents, so we get 100.000 * 20 / 20 = +100.000
so the total winnings are: 210.000
I tried to write up something, but I don't think it's the most effective way to do it?
Program EliminationGame;
var
selectedHistory : array [1..10] of integer;
opponentCount,roundCount : integer;
maxOpponents,numberSelected : integer;
totalMoney : integer;
i : integer;
begin
totalMoney := 0;
maxOpponents := 100;
opponentCount := maxOpponents;
roundCount := 3; {test value}
for i:=1 to roundCount do begin
if (i = roundCount) then begin
numberSelected := opponentCount;
end else begin
numberSelected := floor(opponentCount / roundCount);
end;
selectedHistory[i] := numberSelected;
totalMoney := floor(totalMoney + (numberSelected / opponentCount * 100000));
opponentCount := opponentCount - numberSelected;
end;
writeln('Total money won:');
writeln(totalMoney);
writeln('Amount selected in rounds:');
for i:= 0 to Length(selectedHistory) do
write(selectedHistory[i],' ');
end.
Also it seems that floor function does not exist in pascal?
It seems the question has a maths answer that can be calculated in advance. As #Anton said it was obvious that the number of points given during the third round did not depend upon the number of eliminated enemies. So the third round should eliminate 1 enemy.
So We get the following function for a thre-round game.
f(x)=100000x/100+100000(99-x)/(100-x)+100000*1/1, where x- the number
of enemies eleminated at first round.
if we find the extrema (local maximum of the function) it appears equal to 90. That means the decision is the following: the first round eliminates 90 the second - 9, the third - 1 enemy.
Of course, for consideration: 90=100-sqrt(100).
In other words: the Pascal decision of the task is to loop a variable from 1 to 99 and see the maximum of this function. X-will be the answer.
program Project1;
var
x, xmax: byte;
MaxRes, tmp: real;
begin
xmax := 0;
MaxRes := 0;
for x := 1 to 99 do
begin
tmp := 100000 * x / 100 + 100000*(99 - x) / (100 - x) + 100000 * 1 / 1;
if tmp > MaxRes then
begin
MaxRes := tmp;
xmax := x;
end;
end;
writeln(xmax);
readln;
end.
The general decision for other number of enemies and rounds (using recursion) is the following (Delphi dialect):
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
Uses System.SysUtils;
var
s: string;
function Part(RemainingEnemies: byte; Depth: byte;
var OutputString: string): real;
var
i: byte;
tmp, MaxRes: real;
imax: byte;
DaughterString: string;
begin
OutputString := '';
if Depth = 0 then
exit(0);
imax := 0;
MaxRes := 0;
for i := 1 to RemainingEnemies - Depth + 1 do
begin
tmp := i / RemainingEnemies * 100000 + Part(RemainingEnemies - i, Depth - 1,
DaughterString);
if tmp > MaxRes then
begin
MaxRes := tmp;
imax := i;
OutputString := inttostr(imax) + ' ' + DaughterString;
end;
end;
result := MaxRes;
end;
begin
writeln(Part(100, 3, s):10:1);//first parameter-Enemies count,
//2-Number of rounds,
//3-output for eliminated enemies counter
writeln(s);
readln;
end.
This problem can be solved with a dynamic approach.
F(round,number_of_opponents_remained):
res = 0
opp // number_of_opponents_remained
for i in [1 opp]
res = max(res, opp/100 + F(round-1,opp - i) )
return res
I should say this not the complete solution and you add some details about it, and I am just giving you an idea. You should add some details such as base case and checking if opp>0 and some other details. The complexity of this algorithm is O(100*k).

Generating Position Set Points for Trapezoidal Motion Profile

I'm working on a prototype for a motion controller which will accelerate a motor to a maximum velocity, coast at the maximum velocity and then commence deceleration at the correct position for the motor to stop at the target position.
The theoretical position for each timestep will be compared with the feedback from a quadrature encoder and the resulting error will be subjected to a PID loop, the result of which will be represented using PWM.
I currently have the following code to determine the theoretical position for each timestep:
Pos:=0;
Vel:=0;
Acc:=3;
Demand:=300;
Max_Vel:=19;
AccDist := (Max_vel/Acc * Max_vel) / 2;
DecelPoint := Demand - AccDist;
Writeln(AccDist:5:2);
Writeln(DecelPoint:5:2);
Writeln('ACCEL');
While Vel <> Max_vel
Do Begin
Pos := Pos + Vel + Acc/2;
Vel := Vel + Acc;
If Vel >= Max_Vel
Then Begin
Vel := Max_Vel;
Pos := AccDist
End;
Writeln('Position:',Pos:5:2);
End;
Writeln('FLAT');
While Pos < DecelPoint
Do Begin
Pos := Pos + Vel;
Writeln('Position:',Pos:5:2);
End;
Error := Pos - DecelPoint;
Writeln('DECEL');
While Vel > 0
Do Begin
If Error > 0
Then Begin
Pos := Pos - Error;
Error := 0;
End;
Pos := Pos + Vel - Acc/2;
Vel := Vel - Acc;
If Vel <= 0
Then Pos := Demand;
Writeln('Position:',Pos:5:2);
End;
end.
This code seems to give approximate results, but I really need exact results. The accel and flat section seem to yield exact results, but when we come to the decel section, things start behaving oddly.
Where have I gone wrong?
I believe that there are two problems.
Problem 1: You are displaying a list of positions but not the time at which the vehicle reaches those positions. If it is assumed that the accelerations, velocities, positions etc are all in m/s^2, m/s, and m then the data is consistent with 1 second intervals except when the vehicle transitions between acceleration and coasting (or coasting and deceleration). If I add columns for velocity and time then your output data would look like this:
60,17
239.83
ACCEL
Position: 1.50 Velocity: 3.00 Time:1.00
Position: 6.00 Velocity: 6.00 Time:2.00
Position:13.50 Velocity: 9.00 Time:3.00
Position:24.00 Velocity:12.00 Time:4.00
Position:37.50 Velocity:15.00 Time:5.00
Position:54.00 Velocity:18.00 Time:6.00
Position:60.17 Velocity:19.00 Time:6.33 ...vehicle stops accelerating at this point
FLAT
Position:79.17 Velocity:19.00 Time:7.33
Position:98.17 Velocity:19.00 Time:8.33
...
You can see that the actual time the vehicle stops accelerating is only 0.33 seconds (rather than a full second) after the 6 second measurement point at position 54.00 m.
The same problem will occur when the vehicle reaches the deceleration point (which I estimate should occur at approximately T = 15.79 seconds (that is 9.46 seconds after it stops accelerating).
Problem 2 The second issue is that you write the position during the FLAT period before you check if the vehicle should have started decelerating.
While Pos < DecelPoint
Do Begin
Pos := Pos + Vel;
Writeln('Position:',Pos:5:2);
End;
Your code above can increment the position past the deceleration point and output an erroneous data point before it 'corrects' it later. Your program would output:
...
Position:231.17
Position:250.17
DECEL
Position:257.33
...
but the last position before the DECEL is incorrect as the vehicle will already have started decelerating when it reaches 239.83 m.

How to generate a random combination of digits that are already defined in Pascal?

I would like to ask if anybody can give a hand in solving the following issue: How should I use the random function in Pascal in order to generate a random combination of digits that are already initialized (I mean that I have given values to four variables and I want via the random function to create a random combination of these four digits).
Thanks in advance!
Rossi
var digits : array[0..3] of integer = (10,20,30,40);
i : integer;
begin
Randomize; // initialize the random generator. Only once per program
for i:=0 to 50 do
Writeln(digits[random(4)]);
end.
The Writeln line draws a number 0<=x<4 so 0..3, and looks it up in the digits array, then writes it to console output. It is draws 50 random numbers and then quits.
var
randomnumber,i:integer;
number:array[0..3] of integer;
begin
randomize;
for i:= 0 to 3 do
begin
readln(number[i]);
end;
randomnumber:= (number[random(4)] * 1000) + (number[random(4)] * 100) + (number[random(4)] * 10) + (number[random(4)] * 1);
writeln(randomnumber);
end.
I hope this could help.
But the given initial value should be between 0 to 9.
If you want that the output contains each digit only once, then you would need to stored the digits which have already been chosen in a set to prevent them from being chosen again.
const
digits: array [0..3] of integer = (1, 3, 5, 7);
var
i, n, total: integer;
stored: set of integer;
begin
Randomize;
stored:= [];
total:= 0;
for i:= 1 to 4 do
begin
repeat
n:= random (4);
until not (n in stored);
stored:= stored + [n];
total:= total * 10 + digits[n];
end;
writeln (total)
end.

How to convert a string to integer

Example :
a = 1
b = 2
c = 3
..
..
z = 26
aa = 27
ab = 28
how to convert another string into an integer? for example i want to convert 'lmao' to an integer. please help me :) thank you.
in pascal :)
To convert ordinary base-10 strings into numbers, you take each character from left to right, convert it to its numeric value (between 0 and 9) and add it to the total you already have (which you initialize to zero). If there are more characters following the one you just processed, then multiply the total by 10. Repeat until you run out of characters.
For example, the number 374 is 3×102 + 7×101 + 4×100. Another way of writing that, which more closely models the conversion algorithm I described above, is (((3)×10+7)×10+4.
You can adapt that to handle any string of characters, not just numeric characters. Instead of 10, the base is 26, so multiply by that. And instead of digits, the characters are a through z. Your example string would be evaluated like this: (((l)×26+m)×26+a)×26+o. Substitute numbers for those letters, and you get 219,742.
Here's some code to do it. It doesn't check for errors; it assumes that the string will only contain valid characters and that the string won't represent a number that's too big to fit in an Integer variable.
function SpecialStrToInt(const s: string): Integer;
var
i: Integer;
subtotal: Integer;
c: Char;
charval: Integer;
begin
subtotal := 0;
for i := 1 to Length(s) do begin
c := s[i];
charval := Ord(c) - Ord('a') + 1;
subtotal := subtotal * 26;
subtotal := subtotal + charval;
end;
SpecialStrToInt := subtotal;
end;
An oddity about your format is that there's no way to represent zero.

Resources