Find symmetric points on a parabola C# - c#

I have searched through many posts and cannot find what I need. I see solutions to find the closest number to a target but I need one that finds that number, then can select the closest number on the other side of a "parabola" shaped set of data that is not completely symmetrical. I essentially use:
List<int> list = new List<int> { 2, 5, 7, 10 };
int number = 9;
int closest = list.Aggregate((x,y) => Math.Abs(x-number) < Math.Abs(y-
number) ? x : y);
This is how I find my first target number. Now I need to find a second number that is almost equal in value but on the other side of a parabola (I really need the indexes of these numbers but I can put the pieces together). My methods keeps coming up a single number. Essentially I need to move to an approximately symmetric index across a parabola to select an equivalent number. To put this in context, I am calculating beam width, i.e. the distance between the sides of a parabola at a specific point. Please let me know if this makes sense and if I need to explain more before you down vote me. I have done extensive research and testing. It is difficult for me to provide more code because it is coming from a $500,000 testing system that does not have internet so I can't copy and paste my code. I can go the extra yard if more code is needed though, just trying to avoid compromising an expensive embedded Windows system.
Here is a related post that I need to go a step further from
located here
Edit adding full code:
fileName = textBox10.Text;
SetupControlState(true);
if (comboBox2.SelectedIndex == 0)
{
cent = false;
}
else if (comboBox2.SelectedIndex == 1)
{
cent = true;
}
testHPositions = new List<double>();
testHMeasurements = new List<double>();
testVPositions = new List<double>();
testVMeasurements = new List<double>();
double horzRange = Double.Parse(textBox12.Text);
double vertRange = Double.Parse(textBox11.Text);
double refGain = Double.Parse(textBox14.Text);
double stepSize = Double.Parse(textBox13.Text);
testBorePos = new double[1, 2];
_worker = new BackgroundWorker();
_worker.WorkerSupportsCancellation = true;
testBoreRun.Enabled = false;
button2.Enabled = true;
_worker.RunWorkerAsync();
_worker.DoWork += new DoWorkEventHandler((state, args) =>
{
// try
// {
dev1 = new VisaDevice("inst0", "TCPIP0::192.168.0.10::inst0::INSTR"); //textBox1.Text);
if (!cent)
{
Double startfreq = double.Parse(textBox2.Text) * 1000000000;
Double stopfreq = double.Parse(textBox1.Text) * 1000000000;
dev1.SendBlocking("FREQ:STAR " + startfreq.ToString(), true);
string responseFreq = "";
dev1.QueryBlocking("FREQ:STAR?", ref responseFreq, true);
dev1.SendBlocking("FREQ:STOP " + stopfreq.ToString(), true);
dev1.QueryBlocking("FREQ:STOP?", ref responseFreq, true);
}
else if (cent)
{
Double freq = double.Parse(textBox9.Text) * 1000000000;
Double span = double.Parse(textBox8.Text) * 1000000000;
dev1.SendBlocking("FREQ:CENT " + freq.ToString(), true);
string responseFreq = "";
dev1.QueryBlocking("FREQ:CENT?", ref responseFreq, true);
dev1.SendBlocking("FREQ:SPAN " + span.ToString(), true);
dev1.QueryBlocking("FREQ:SPAN?", ref responseFreq, true);
// this.InvokeEx(f => f.stringReadTextBox.AppendText("Spectrum Analyzer Connected" + Environment.NewLine));
}
string progID;
Util U = new Util();
progID = "ASCOM.iOptron.Telescope";
if (progID != "")
{
PauseClass pause;
pause = new PauseClass();
Telescope T = new Telescope(progID);
T.Connected = true;
pause.Pause(5000);
T.Tracking = false;
T.TargetDeclination = 1;
T.TargetRightAscension = 1;
this.InvokeEx(f => f.stringReadTextBox.AppendText(" Connected to " + progID + Environment.NewLine));
this.InvokeEx(f => f.stringReadTextBox.AppendText(" Connected to Spectrum Analyzer" + Environment.NewLine));
T.SlewToAltAz(180.00, 45 - vertRange);
double Alt = T.Altitude;
for (int i = 0; i < ((vertRange * 2) / stepSize) + 1; i++)
{
if (_worker.CancellationPending)
break;
T.SlewToAltAz(180, Alt + stepSize * i);
this.InvokeEx(f => f.stringReadTextBox.AppendText("Test Altitude = " +(T.Altitude - 45).ToString("F") + Environment.NewLine));
testVPositions.Add(T.Altitude);
dev1.SendBlocking("INIT", true); //Start single measurement
string respOPC = "", responseState = "", responseMarkerY = "";
dev1.QueryBlocking("*OPC?", ref respOPC, true); //Wait for operation complete
dev1.QueryBlocking("STAT:QUES:MEAS?", ref responseState, true); //Check State
dev1.QueryBlocking("CALC:MARK:Y?", ref responseMarkerY, true); // Get the result
this.InvokeEx(f => f.stringReadTextBox.AppendText(responseMarkerY + Environment.NewLine));
testVMeasurements.Add(Double.Parse(responseMarkerY));
if (testVMeasurements.Count > ((vertRange * 2) / stepSize))
{
this.InvokeEx(f => f.stringReadTextBox.AppendText("Vertical Scanning Is Complete!" + Environment.NewLine));
double maxVamp = testVMeasurements.Max();
int index2 = testVMeasurements.IndexOf(testVMeasurements.Max());
double maxVPos = testVPositions[index2];
testBorePos[0, 1] = maxVPos;
this.InvokeEx(f => f.stringReadTextBox.AppendText("Vertical Max Amplitude = " + maxVamp + Environment.NewLine));
this.InvokeEx(f => f.stringReadTextBox.AppendText("Vertical Position of Max Amplitude = " + (maxVPos - 45).ToString("F") + Environment.NewLine));
}
}
if (!_worker.CancellationPending)
{
T.SlewToAltAz(180.00 - horzRange, testBorePos[0, 1]);
}
double Az = T.Azimuth;
for (int i = 0; i < ((horzRange * 2) / stepSize) + 1; i++)
{
if (_worker.CancellationPending)
break;
if (vertRange > 20)
{
this.InvokeEx(f => f.stringReadTextBox.AppendText("Vertical Range Cannot Be Greater than +/- 20 Degreez" + Environment.NewLine));
break;
}
T.SlewToAltAz(Az + stepSize * i,testBorePos[0,1]);
this.InvokeEx(f => f.stringReadTextBox.AppendText("Test Azimuth = " + (T.Azimuth-180).ToString("F") + Environment.NewLine));
testHPositions.Add(T.Azimuth);
dev1.SendBlocking("INIT", true); //Start single measurement
string respOPC = "", responseState = "", responseMarkerY = "", responseMarkerX = "";
// string responseFreq = "";
dev1.QueryBlocking("*OPC?", ref respOPC, true); //Wait for operation complete
dev1.QueryBlocking("STAT:QUES:MEAS?", ref responseState, true); //Check State
dev1.QueryBlocking("CALC:MARK:Y?", ref responseMarkerY, true); // Get the result
dev1.QueryBlocking("CALC:MARK:X?", ref responseMarkerX, true); // Get the result
this.InvokeEx(f => f.stringReadTextBox.AppendText(responseMarkerY + Environment.NewLine));
testHMeasurements.Add(Double.Parse(responseMarkerY));
if (testHMeasurements.Count > ((horzRange * 2) / stepSize))
{
_worker.CancelAsync();
stop = false;
this.InvokeEx(f => f.testBoreRun.Enabled = true);
this.InvokeEx(f => f.button2.Enabled = false);
this.InvokeEx(f => f.stringReadTextBox.AppendText("Horizontal Scanning Is Complete!" + Environment.NewLine));
double maxHamp =testHMeasurements.Max();
int index =testHMeasurements.IndexOf(testHMeasurements.Max());
double maxHPos =testHPositions[index];
testBorePos[0, 0] = maxHPos;
this.InvokeEx(f => f.stringReadTextBox.AppendText("Horizontal Max Amplitude = " + maxHamp + Environment.NewLine));
this.InvokeEx(f => f.stringReadTextBox.AppendText("Horizontal Position of Max Amplitude = " +( maxHPos-180).ToString("F") + Environment.NewLine));
this.InvokeEx(f => f.stringReadTextBox.AppendText("Antenna Under Test Peak Amplitude located at (" + (testBorePos[0, 0] - 180).ToString("F") + " , " + (testBorePos[0, 1] - 45).ToString("F") + ")" + Environment.NewLine));
this.InvokeEx(f => f.SetupControlState(false));
T.SlewToAltAz(testBorePos[0, 0], testBorePos[0, 1]);
dev1.SendBlocking("INIT", true); //Start single measurement
maxAmpTest = new double();
string respOPC2 = "", responseState2 = "", responseMarkerY2 = "";
dev1.QueryBlocking("*OPC?", ref respOPC2, true); //Wait for operation complete
dev1.QueryBlocking("STAT:QUES:MEAS?", ref responseState2, true); //Check State
dev1.QueryBlocking("CALC:MARK:Y?", ref responseMarkerY2, true); // Get the result
maxAmpTest = Double.Parse(responseMarkerY2);
double target = maxAmpTest - 3;
Here is where I am stuck:
// int indexbeam = testHMeasurements.IndexOf(target);
// indexList = testHMeasurements.IndexOf(testHMeasurements.FindAll(s => s.Equals(target)).First());
double closest = testHMeasurements.Aggregate((x, y) => Math.Abs(x - target) < Math.Abs(y - target) ? x : y);
var result = Enumerable.Range(0, testHMeasurements.Count).Where(j => testHMeasurements[j] ==closest).ToList();
// int beamIndex1 = testHMeasurements.IndexOf(testHMeasurements.OrderBy(item => Math.Abs(target - item)).First());
// int beamIndex2 = testHMeasurements.IndexOf(testHMeasurements.OrderBy(item => Math.Abs((beamIndex1 + 1) - item)).First());
double beam1 =( testHPositions[result[0]]) - 180;
double beam2 = (testHPositions[result[1]]) - 180;
beamWidth = Math.Abs(beam1) + Math.Abs(beam2);
this.InvokeEx(f => f.stringReadTextBox.AppendText("Antenna Under Test Amplitude = " + responseMarkerY2 + Environment.NewLine));
this.InvokeEx(f => f.stringReadTextBox.AppendText(" Antenna Under Test Gain = " + (maxAmpTest - refAmp + refGain) + Environment.NewLine));
this.InvokeEx(f => f.stringReadTextBox.AppendText(" Antenna Under Test Beam Width = " +beamWidth.ToString("F") + Environment.NewLine));
testGain = maxAmpTest - refAmp + refGain;
}
}
T.Connected = false;
T.Dispose();
dev1.Dispose();
if (_worker.CancellationPending)
{
Save();
// Cleanup Excel resources
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
});

First, you must find the parabola. Because your data only approximates the parabola, you need a statistical method called Quadratic Regression, or Polynomial Regression to find the parameters a, b and c of the equation
y = ax2 + bx + c
defining the parabola, that best fits the dataset given by the points
(xi, yi)
Use a math library or google for an algorithm.
Once you have the parabola, determine the symmetry axis of it, i.e. find the x-value of where the minimum or maximum (if the parabola is upside down) of the parabola is.
xs = -b / 2a
Now, once you have a given x-value, you can find a point at the opposite side of the parabola by mirroring x at xs
x' = 2xs - x
This is the explanation for a parabola in 2-D. If you have a parabola in 3-D, i.e. a Paraboloid the principle remains the same, but with more complex math. Google for Paraboloid Regression. A parabolic antenna has a curved surface with the cross-sectional shape of a parabola, called a paraboloid in geometrical terms.
Only once you have solved the mathematical problems, you can start programming and finding points in lists.

Turns out this question could actually be solved through programming with no advanced math required. Given a y-value and asked to find two corresponding x values on an asymmetrical/parabola arc you can simply split the arc at the vertex in two pieces then scan each of the two arrays for the matching x-value. It works like a charm - just requires a little critical thinking and a lot less over thinking it (math major stuff :p)

Related

Looping over 3D array in parallel.for

I have a 3D array with arbitrary X, Y and Z lengths
I want to iterate over it in a parallel.for loop, which can't be nested without wasting tasks afaik
Instead, the single loop's length is ArrayLengthX * ArrayLengthY * ArrayLengthZ
Can I mathematically get the current 3D array element from the current iteration + the X, Y and Z length of the array? if so how?
edit : Example below, hope this is enough to understand what's going on
DimensionSettings dimensionSettings = dimension.Settings;
Vector3Int DimSize = dimensionSettings.GetDimensionSize();
TaskProgressMutex.WaitOne();
CurrentProgress = 0;
TotalProgress = DimSize.x * DimSize.y * DimSize.z;
TaskProgressMutex.ReleaseMutex();
int ChunkAmount = DimSize.x * DimSize.y * DimSize.z;
GD.Print("Chunks to generate : " + ChunkAmount);
ParallelLoopResult result = Parallel.For(0, ChunkAmount, (int i) =>
{
GD.Print(i);
int xcoords = ???;
int ycoords = ???;
int zcoords = ???;
Vector3Int ChunkCoords = new Vector3Int(xcoords, ycoords, zcoords);
GD.Print("Current Chunk : " + xcoords + " " + ycoords + " " + zcoords);
GenerateChunk(ChunkCoords, seed);
TaskProgressMutex.WaitOne();
CurrentProgress += 1;
//GD.Print("Chunk " + xcoords + " " + ycoords + " " + zcoords + " finished generating. Current Progress : " + CurrentProgress);
TaskProgressMutex.ReleaseMutex();
});
My suggestion is to parallelize only the outer loop (the X dimension), and do normal (non-parallel) inner loops for the Y and Z dimensions:
ParallelOptions options = new()
{
MaxDegreeOfParallelism = Environment.ProcessorCount
};
Parallel.For(0, dimSize.X, options, (int x) =>
{
for (int y = 0; y < dimSize.Y; y++)
{
for (int z = 0; z < dimSize.Z; z++)
{
Vector3Int chunkCoords = new (x, y, z);
GenerateChunk(chunkCoords, seed);
}
}
});
The idea is to increase the chunkiness of the parallel work. In general the more chunky is the workload, the less is the overall overhead of the parallelization. At the other extreme, if each unit of work is too chunky, the partitioning of the work may become imbalanced.
Also when you use the Parallel.For/Parallel.ForEach/Parallel.Invoke methods I am suggesting to specify always the MaxDegreeOfParallelism, although this suggestion deviates from the general advice offered in the official documentation.

How to put multiple lines in NetTelegramBot KeybrardMarkup?

I'm making a telegram bot with c#.
I want to read a number of names (not more than 20 tough thy could be less) and give them to the user as keyboardMarkup. With a one dimensional array they go all in one line and it's unreadable. I wanted to make 4 line with 5 names so i tried a 4x5 array. But i get this error
Error CS0029 Cannot implicitly convert type 'NetTelegramBotApi.Types.KeyboardButton[,]' to 'NetTelegramBotApi.Types.KeyboardButton[][]'
if (text == "/lista")
{
// Read a text file line by line.
listapz = System.IO.File.ReadAllLines("listapz.txt");
string selezione = "Seleziona il paziente:";
int i = 0;
int x = 0;
int y = 0;
var arrays = new KeyboardButton[4,5];
for (i = 0; i < listapz.Length; i++)
{
y = i / 5;
x = i - (y * 5);
arrays[y,x] = new KeyboardButton("$" + (i + 1) + " " + listapz[i]);
selezione += "\n$" + (i + 1) + " " + listapz[i] + "";
}
var keyb = new ReplyKeyboardMarkup()
{
Keyboard = arrays,
OneTimeKeyboard = true,
ResizeKeyboard = true
};
var reqAction = new SendMessage(update.Message.Chat.Id, selezione) { ReplyMarkup = keyb };
bot.MakeRequestAsync(reqAction).Wait();
Console.WriteLine(reqAction);
continue;
}
any solution?
You can create new one dimensional array for every line
Then
keyb.row(first_array) //you need get only values in python it will like keyb.row(*array)
keyb.row(second_array) //and so on
and add all keyboards in one reply_markup=keyb

Creating a grid like structure based on the area of an room

so in unity im creating randomly generating rooms. inside of these rooms i will "randomly" place objects, enemy,objects,items etc. based on nodes. nodes are transform objects that are separated from each other by 1 unit. the idea is that i can now pick a node and instantiate something at that node. The code works great when the room is 10x10(x,z since its a 3d game) i get a nice grid pattern it also works as expected when x is any multiple of 2. however when z changes from 10 it doesn't create the grid properly. there is also a problem if the room changes locations other then 0,0.
floor is a child object of the room.
void RoomSetup()
{
bool first = true;
int collCount = -1;
GameObject placeHolder = new GameObject("temp");
float colls;
float offX, offZ;
colls = floor.transform.localScale.x - 1;
print(colls);
for (int i = 0; i < ((floor.transform.localScale.x-1)
*(floor.transform.localScale.z-1)); i++)
{
//creating a for loop that stops when its greater then the area of the rectangle, subtract one from x,z so theres a one unit of padding from the walls.
offX = floor.transform.lossyPosition.x;
offZ = floor.transform.lossyPosition.z;
//getting the offset of the room in world space this is where i believe the issues arise
collCount++;
GameObject temp = new GameObject(i + " Node");
temp.transform.SetParent(floor.transform);
temp.AddComponent<BoxCollider>();
temp.GetComponent<BoxCollider>().isTrigger = true;
if(!first)
{
temp.transform.position = new Vector3((placeHolder.transform.position.x + 1), 6, placeHolder.transform.position.z);
placeHolder = temp;
if (collCount >= colls)
{
print("new line on " + temp.name + " coll " + collCount);
collCount = 0;
placeHolder.transform.position = new Vector3((-(floor.transform.localScale.x / 2) + 1)+offX, 6, (placeHolder.transform.position.z - 1)-offZ);
}
}
if (first)
{
// print(colls);
temp.transform.position = new Vector3((-(floor.transform.localScale.x / 2) + 1) + offX, 6, floor.transform.localScale.z - offZ);
placeHolder = temp;
first = false;
}
nodes.Add(temp);
}
}
Here are some pictures to help illustrate the issue
the first image is when the room is at 0,0 and it creates a nice grid pattern
when the room is offest it creates the grid still at 0,0
i figured it out, it happend to do with with the local and world scale/pos of the floor and the room
void RoomSetup()
{
bool first = true;
int collCount = -1;
GameObject placeHolder = new GameObject("temp");
float colls;
colls = floor.transform.localScale.x - 1;
offX = floor.transform.localScale.x;
offZ = floor.transform.localScale.z;
offX = (offX / 2) - offX + 1;
offZ = (offZ / 2) - 1;
offX = offX + floor.transform.position.x;
offZ = (offZ + floor.transform.position.z);
print(colls);
for (int i = 0; i < ((floor.transform.localScale.x-1) * (floor.transform.localScale.z-1)); i++)
{
collCount++;
//print(collCount);
GameObject temp = new GameObject(i + " Node");
temp.transform.SetParent(floor.transform);
temp.AddComponent<BoxCollider>();
temp.GetComponent<BoxCollider>().isTrigger = true;
if(!first)
{
temp.transform.position = new Vector3((placeHolder.transform.position.x + 1), 6, placeHolder.transform.position.z);
placeHolder = temp;
if (collCount >= colls)
{
print("new line on " + temp.name + " coll " + collCount);
collCount = 0;
temp.transform.position = new Vector3(floor.transform.localPosition.x + offX, 6, placeHolder.transform.position.z - 1);
placeHolder = temp;
}
}
if (first)
{
// print(colls);
temp.transform.position = new Vector3(floor.transform.localPosition.x+offX, 6, floor.transform.localPosition.z+offZ);
placeHolder = temp;
first = false;
}
nodes.Add(temp);
}
}
works as intended, creates a grid of nodes on the floor of anyroom square room

C# for skipping some

I am asking a question today because I look is skipping certain items and I think it is because its running too fast and doing too much, is there a way to fix this without manually putting a thread.sleep of like 10ms after each loop element?
Is this a known issue? any help would be appreciated! The for loop I am talking about is the 3rd one, the one after the two nested set of for's
There is about 104 items in squares after the first 2 foreach's are ran, there could be up to 1000, what is the best way to stop it skipping?
If I don't put a thread.sleep there, only the first occurence works, the rest of the items in the foreach DONT work
If I do 10ms, 3-4 miss
If I do 15ms they all work
List<string> squares = new List<string>();
var minX = 1;
var minY = 1;
var maxX = room.Model.MapSizeX;
var maxY = room.Model.MapSizeY;
for (var currentX = minX; currentX <= maxX; ++currentX)
{
for (var currentY = minY; currentY <= maxY; ++currentY)
{
if (!room.GetGameMap().ItemCanBePlacedHere(currentX, currentY))
{
continue;
}
squares.Add(currentX + "," + currentY);
}
}
foreach (string tileString in squares)
{
var x = Convert.ToInt32(tileString.Split(',')[0]);
var y = Convert.ToInt32(tileString.Split(',')[1]);
session.SendWhisper("Attempting to place an item in X" + x + " and Y" + y);
if (!room.GetGameMap().ItemCanBePlacedHere(x, y))
{
session.SendWhisper("Can't place an item in X" + x + " Y" + y);
continue;
}
var newItem = new Item(new Random().Next(), room.RoomId, 1536, "", x, y, 0, 0, session.GetPlayerData().Id, 0, 0, 0, "", room);
newItem.ExtraData = "1";
newItem.UpdateState();
room.SendMessage(new ObjectAddComposer(newItem, room));
room.GetGameMap().AddToMap(newItem);
// I only put this here because it skips
// This slows it down a little and doesnt
// Make it skip 3-5 of the items
System.Threading.Thread.Sleep(15);
}

Dealing with imprecise, jittery gps signal

My goal is to use GPS to measure the distance that I moved with my phone. My problem is, that the results are imprecise. I've used the following code to calculate the distance:
public double getDistance(GeoCoordinate p1, GeoCoordinate p2)
{
double d = p1.Latitude * 0.017453292519943295;
double num3 = p1.Longitude * 0.017453292519943295;
double num4 = p2.Latitude * 0.017453292519943295;
double num5 = p2.Longitude * 0.017453292519943295;
double num6 = num5 - num3;
double num7 = num4 - d;
double num8 = Math.Pow(Math.Sin(num7 / 2.0), 2.0) + ((Math.Cos(d) * Math.Cos(num4)) * Math.Pow(Math.Sin(num6 / 2.0), 2.0));
double num9 = 2.0 * Math.Atan2(Math.Sqrt(num8), Math.Sqrt(1.0 - num8));
return (6376500.0 * num9);
}
This is my OnLocationChanged implementation:
bool begin = true;
public void OnLocationChanged(Location location)
{
_aktuellerOrt = location;
//aktuellerOrt.Speed is always 0, so I cannot use that.
if (_aktuellerOrt == null)
{
//message
}
else
{
if (_aktuellerOrt.Accuracy > 70) //I found values around 130 to be more or less good
{
_locationText.Text = String.Format("{0}, {1}", _aktuellerOrt.Latitude, _aktuellerOrt.Longitude);
GeoJetzt = new GeoCoordinate();
GeoJetzt.Latitude = _aktuellerOrt.Latitude;
GeoJetzt.Longitude = _aktuellerOrt.Longitude;
if (beginn)
{
GeoVorher = new GeoCoordinate();
GeoVorher.Latitude = _aktuellerOrt.Latitude;
GeoVorher.Longitude = _aktuellerOrt.Longitude;
beginn = false;
}
else
{
double abstand = getDistance(GeoVorher, GeoJetzt);
weg += abstand;
if (weg >= 1)
_distanzText.Text = weg + " kilometers";
else
_distanzText.Text = (weg * 1000) + " meters";
_distanzText.Text += " (" + abstand + ", " + _aktuellerOrt.Accuracy + ")";
GeoVorher = new GeoCoordinate();
GeoVorher.Latitude = _aktuellerOrt.Latitude;
GeoVorher.Longitude = _aktuellerOrt.Longitude;
}
}
else
_locationText.Text = "Too coarse, now " + _aktuellerOrt.Accuracy + ".";
}
}
The problem is, I get values for abstand within the kilometer range while not moving the phone.
What are best practices for imprecise signals? My goal is to measure the distance while jogging or running, so 10 - 16 km/h.

Categories