Prepare for spherical average

This commit is contained in:
Pascal Serrarens 2026-01-06 17:18:31 +01:00
parent 1e1e5b1344
commit d026996ce2
5 changed files with 83 additions and 25 deletions

View File

@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
#if UNITY_5_3_OR_NEWER
using Vector3 = UnityEngine.Vector3;
#endif
@ -137,6 +139,19 @@ namespace LinearAlgebra {
return r;
}
public static Spherical operator *(Spherical v, float d) {
Spherical r = new(v.distance * d, v.direction);
return r;
}
public static bool operator ==(Spherical v1, Spherical v2) {
return (v1.distance == v2.distance && v1.direction == v2.direction);
}
public static bool operator !=(Spherical v1, Spherical v2) {
return (v1.distance != v2.distance || v1.direction != v2.direction);
}
public static float Distance(Spherical v1, Spherical v2) {
// Convert degrees to radians
float thetaARadians = v1.direction.horizontal.inRadians;
@ -162,5 +177,37 @@ namespace LinearAlgebra {
return distance;
}
public static Spherical Average(List<Spherical> vectors) {
float sumSinPhiCosTheta = 0.0f;
float sumSinPhiSinTheta = 0.0f;
float sumCosPhi = 0.0f;
int n = vectors.Count;
// Step 1: Accumulate sine and cosine components
foreach(Spherical v in vectors) {
float sinHorizontal = AngleFloat.Sin(v.direction.horizontal);
sumSinPhiCosTheta += v.distance * sinHorizontal * AngleFloat.Cos(v.direction.vertical);
sumSinPhiSinTheta += v.distance * sinHorizontal * AngleFloat.Sin(v.direction.vertical);
sumCosPhi += v.distance * AngleFloat.Cos(v.direction.horizontal);
}
// Step 2: Calculate average components
float avgSinPhiCosTheta = sumSinPhiCosTheta / n;
float avgSinPhiSinTheta = sumSinPhiSinTheta / n;
float avgCosPhi = sumCosPhi / n;
// Step 3: Calculate the magnitude of the average vector
float rAvg = MathF.Sqrt(avgSinPhiCosTheta * avgSinPhiCosTheta +
avgSinPhiSinTheta * avgSinPhiSinTheta +
avgCosPhi * avgCosPhi);
// Step 4: Calculate average angles
AngleFloat horizontalAvg = AngleFloat.Acos(avgCosPhi / rAvg); // Handle rAvg != 0 case
AngleFloat verticalAvg = AngleFloat.Atan2(avgSinPhiSinTheta, avgSinPhiCosTheta);
return new Spherical(rAvg, new Direction(horizontalAvg, verticalAvg));
}
}
}

View File

@ -1,3 +1,4 @@
using System.Collections.Generic;
using UnityEngine;
using LinearAlgebra;
@ -73,7 +74,7 @@ public class Neuroid : Nucleus {
UpdateState();
}
public virtual void UpdateState() {
public override void UpdateState() {
Vector3 resultVector = Vector3.zero;
foreach (Synapse synapse in this.synapses) {
Nucleus synapseNucleus = synapse.nucleus;
@ -93,18 +94,23 @@ public class Neuroid : Nucleus {
resultVector /= this.synapses.Count;
Spherical result = Spherical.FromVector3(resultVector);
float d = Spherical.Distance(result, this.outputValue);
if (d < 0.1f) {
//Debug.Log($"insignificant update: {d}");
return;
}
this.outputValue = result;
// List<Spherical> vectors = new();
// foreach (Synapse synapse in this.synapses) {
// if (synapse.nucleus.isSleeping)
// continue;
// vectors.Add(synapse.nucleus.outputValue);
// }
// Spherical result2 = Spherical.Average(vectors);
// if (average == false)
// result2 *= vectors.Count;
foreach (Receiver receiver in this.receivers) {
if (receiver.nucleus is Neuroid neuroid)
neuroid.SetInput(this);
}
// if (result2 != result)
// Debug.Log($"update error {result2} != {result}");
UpdateResult(result);
}
}

View File

@ -151,6 +151,20 @@ public class Nucleus {
synapses.Add(newSynapse);
}
public virtual void UpdateState() { }
public void UpdateResult(Spherical result) {
float d = Spherical.Distance(result, this.outputValue);
if (d < 0.1f) {
//Debug.Log($"insignificant update: {d}");
return;
}
this.outputValue = result;
foreach (Receiver receiver in this.receivers)
receiver.nucleus.UpdateState();
}
}
[System.Serializable]

View File

@ -74,19 +74,9 @@ public class Perceptoid : Neuroid {
this.receivers = new();
}
public void UpdateState(int thingId, Spherical receptorValue) {
this.thingId = thingId;
Spherical result = receptorValue;
float d = Spherical.Distance(result, this.outputValue);
if (d < 0.1f) {
//Debug.Log($"insignificant update: {d}");
return;
}
this.outputValue = result;
foreach (Receiver receiver in this.receivers)
if (receiver.nucleus is Neuroid neuroid)
neuroid.SetInput(this);
public override void UpdateState() {
Spherical result = this.receptor.localPosition;
UpdateResult(result);
}

View File

@ -87,6 +87,7 @@ public class Receptor {
return;
}
// Debug.Log($"Stimulus {thingType} {thingId} {selectedPerceptoid.name}");
selectedPerceptoid.UpdateState(thingId, this.localPosition);
selectedPerceptoid.thingId = thingId;
selectedPerceptoid.UpdateState();
}
}