Tony's web stuff

Responsive image

Javascript

I am a Javascript engineer with skill in modern Javascript, ES6, Nodejs, Express, and React

Responsive image

Full Stack

I am a full stack engineer delivering products using Javascript, Java, C#, SQL, Mongodb, Firebase

Resume »

Responsive image

Unity

I am a Unity engineer delivering for iOS, Android, desktop

I made a game that you play in a tesseract on an iphone. Not much else to say really. Here are some moving pictures.
GPU Grid Computing for Gene Sequencing

It's always stimulating to have conversations with people outside your field of expertise and recently during a very educational conversation with some friends in biology, I noticed some of the bottlenecks they face might be solved in an interesting way.

So as a side project, I'm creating an open source application that uses spare GPU cycles for grid computing. There are obviously a lot of applications for this but given the magnificent work their labs do, it is most practical to start with a gene sequencing package.

You can see the stub/concept landing page here (gpyou.org).

4D rotation: Axis vs Plane of rotation

The idea of an axis of rotation maybe intuitive in 3D but it is only a coincidence that axis of rotation just happens to work. And indeed it works for no other number of dimensions. So we need to think of rotation in another way.

As it turns out we can; planes of rotation. In 3D the are three planes of rotation, the XY, XZ, YZ planes.

If we call the four coordinates of 4D w,x,y,z then in 4D there are three additional planes of rotation: the WX, WY, WZ planes.

Matrices

Since there are rotation matrix for point in 3D we simply need to find rotation matrix for those other planes. And here they are (I present the derivation elsewhere)

XY rotation matrix
cos(θ)sin(θ)00
-sin(θ)cos(θ)00
0010
0001
XZ rotation matrix
cos(θ)0-sin(θ)0
0100
sin(θ)0cos(θ)0
0001
YZ rotation matrix
1000
0cos(θ)sin(θ)0
0-sin(θ)cos(θ)0
0001

4D rotation Matrices

XW rotation matrix
cos(θ)00sin(θ)
0100
0010
-sin(θ)00cos(θ)
YW rotation matrix
1000
0cos(θ)0-sin(θ)
0010
0sin(θ)0cos(θ)
ZW rotation matrix
1000
0100
00cos(θ)-sin(θ)
00sin(θ)cos(θ)
PID controller for a target orientation

Suppose we have an object we want to rotate to a goal direction. So we have our current direction and a goal direction and we want to apply torque to reach that goal.

Let us express or current and goal direction as points on a unit sphere.

Likewise angular acceleration is expressed as a 3D vector axis and an angle. The angle is the acceleration around that axis that the object is experiencing.

So those two points on the unit sphere (current direction and goal direction) lie on a geodesic on that unit sphere. That geodesic tell us the direction we wish to accelerate. And of course the axis of angular acceleration must be perpendicular to this.
So we can compute

Vector3 axis = curentDirection cossProduct goalDirection

Now we need the magnitude of that acceleration, ie the angle of the angular acceleration axis angle. This is obviously related to the angle between curentDirection and goalDirection. The magnitude of the cross product relates to this angle. We know that the magnitude of the cross product equals the product of the two vector lengths times the sine of angle between them. ie magnitude of the cross product of A and B = magnitude of A times magnitude of B times sin( angle between A and B ) or pseudo code:

magnitude( A cossProduct B ) = magnitude( A ) x magnitude( B ) x sin( angleBetween( A and B ) )

Since the current and goal direction lie on a unit sphere, they are normalized by definition. So the product of their magnitudes is one. This leaves magnitude of axis = 1 * 1 * sin( angle between current and goal) or pseudo code:

magnitude( A cossProduct B ) = 1 x 1 x sin( angleBetween( A and B ) )

Thus to get that angle we merely need the arc sin of the magnitude of axis.
ie angle = arcsin(magnitude of axis ) resulting in units of radians/sec^2

New we can find the needed change in angular velocity

Vector3 deltaAngleVel = axis.normalized * angle

To convert this delta velocity into a torque, we will need to take rotational inertia into account . If there is inertia ix to rotation around the global x axis and iy resistance around the global y axis and iz resistance to the z axis then we can calculate the torque with

Vector3 torque = deltaAngleVel.x * ix, deltaAngleVel.y * iy, deltaAngleVel.z * iz

We can just add this torque to a non rotating rigid body to create a spin of angle per second along the geodesic connecting curentDirection to goalDirection.

And if the rigidbody is already spinning in a different direction, we merely need to subtract the existing spin from the desired spin. so

generalizedDeltaAngleVel = deltaAngleVel - alreadyExsitingSpin

Applying this straight forward subtraction at intervals will bring the rotation to a stop at exactly the desired direction at an optimal speed with no oscillation.

PID

The astute may have noticed that the torque above strongly resembles a PID spring force and infact we can treat it eactly like this. We easily add a spring constant by doing:

generalizedDeltaAngleVel = springConstant * ( deltaAngleVel - alreadyExsitingSpin )

This will produce an oscillation between two directions which we can fix with a damping force. Normally a damping force be simply calculated as

dampingForce = -dampingConstant*curentVelocity

But because we are dealing with torque we need to integrate it into the desired velocity from which we will calculate the torque. This is very simple:

generalizedDeltaAngleVel = (springConstant * ( deltaAngleVel - alreadyExsitingSpin ))+( -dampingConstant* alreadyExsitingSpin)

And torque is calculated just as above

Vector3 torque = generalizedDeltaAngleVel.x * ix, generalizedDeltaAngleVel.y * iy, generalizedDeltaAngleVel.z * iz

The apparent location of distant objects moving near light speed.

While working on a game playing with relativity, I came upon this problem. Typically, this question is reversed: given that I see an object at P that moves a constant velocity V, what is its current position A. And this is very easily answered: P = A + V*t which we solve for A: A = P - V*t where t is the time light took to get to us from P

But in a simulation we need the inverse of this question: given the current position A what position B does the object appear at for an observer.

Any obvious answer looks like it will require a combination of trigonometry and calculus to solve, both of which are software performance nightmares. But what if there were a solution that only required matrix transforms and arithmetic? Then not only would we have acceptable performance, we might even be able to offload the work to the gpu.

And there is such a solution

The first step is to simplify the observer's coordinates so we don't have to worry about them.

So we have an observer, the object's current position, and its trajectory. Let's move all these such that the observer is at the origin. This is obviously simple: just subtract the observers position from everything. Now we don't have to worry about the observer anymore.

The second step is to reduce the problem to just one coordinate instead of three.

Let's rotate the current position and trajectory so they both lie on the Y coordinate. To do this we treat the velocity as a direction and create a quaternion that rotates from that direction to {0,1,0} and apply it to the objects position and velocity.

We form a quaternion from these two directions d1 and d2 from the cross product and dot product as follows:

a = crossProdcut( d1, d2 )
q.x = a.x, q.y = a.y, q.z = a.z
q.w = 1 + dotProduct( normalized( d1 ), normalized( d2 ) )
q = normalized( q )

Now we use that quaternion q to rotate the velocity to yield rotated velocity V. Because of this rotation velocity V only varies along the y coordinate, the others are now 0. Let's call this v.

So now the rotated object moves only along the y axis. The actual position of the object at any arbitrary time t is D(t). The x coordinate is unvarying x0 and the z coordinate is unvarying z0 and the y coordinate is v*t so D(t)={ x0, v*t, z0 } likewise B(t) = { x0, y(t), z0 }

What is y(t)

At time t, we see the object at B(t)
The time it take light to reach the origin (the observer) from B(t) is t'
This is related to the distance from B(t) to the origin so
t' = magnitude( B(t) ) / c
The object has been moving for time t' since it was seen at B(t) so the object was at B(t) but t' ago so
B(t) = D(t-t')
Substituting from above we have
D(t-t') = D( t – magnitude( B(t) ) / c )
So B(t) = D( t – magnitude( B(t) ) / c )

Now we only need to solve for B(t)
And because we have rotated everything so that only y changes, we only need to solve for y(t) at time t.

y(t) = v( t - t' ) y(t) = v ( t - magnitude( B(t) ) / c )

recall that B(t) = { x0, y(t), z0 }
so magnitude( B(t) ) = sqrt( x0^2 + y(t)^2 + z0^2 )
substituting we get
y(t) = v * ( t - sqrt( x0^2 + y(t)^2 + z0^2 ) / c )

solving for y(t) we get

y(t) = 1/(1-v^2/c^2) (v*t - v/c * sqrt( v^2*t^2 + (x0^2 + z0^2) * (1-v^2/c^2))

recall that the current position of the object is D( t ) = { x0, v*t, z0}
and now we know the observed position B( t ) = { x0, y(t), z0 }

this then needs to be rotated by the inverse of the quaternion used above and we're done.

Dual boot with MBR intact

Linux Windows dual boot is normally done by installing Grub in place of the MBR then chainloading to windows. This is well documented on several boards.

I haven't seen the reverse described where the MBR is left intact and allowing a boot to GRUB on another part of the disk.

This is actually a pretty good idea because the Windows configuration is left intact, you don’t need to change the Windows boot sector, removing Linux is trivial, you can do radical actions such as fdisk /mbr without worry.

And actually it is necessary in several cases. For example, certain Dell computers rewrite the MBR seemingly randomly. (Dell uses a technology called DSR which does this)

The process is relatively straightforward but obviously messing with the MBR can render machine unbootable so don't try this unless you know what's going on

  1. Install Linux from a CD
  2. Install GRUB on the boot partition of Linux (eg./dev/sda5) instead of MBR
  3. Boot to Linux using using a CD
  4. Extracted the GRUB bootloader onto an external device by copying the first 512 bytes of the boot sector to somewhere.
    eg sudo dd if=/dev/sda5 of=grub.bin bs=512 count=1
  5. Place this copy on the windows drive at " c:\grub.bin"
  6. Tell windows about it by editing c:/boot.ini and add the operating systems e.g. c:\grub.bin="Ubuntu 4.10 "