i have a text file with 10.000 lines and this content:
16500000000 -11.6560625775
16600000000 -11.99428283515
16700000000 -12.06410749998
16800000000 -11.81220239236
I want to create a function in c# where i pass the filename, and a number of the first column. Then the output is the value of the second column. In case that the number is not found in column1, it should interpolate the value.
Means, when i enter 16600000000 then function returns -11.99428283515.
When i enter 16650000000 then function should interpolate the value between 166.. and 167...
Currently i have this code, but without interpolation.
How can this be done better with interpolation(and fast):
public static int GetPw(string filePath, double Freq, out double power, out string errMsg)
{
power = Double.MinValue;
errMsg = "No error";
try
{
string[] lines = File.ReadAllLines(filePath);
var filteredLines = lines.Where(line => !line.Contains("#") && !line.Contains("!") && !line.Contains("IND"));
var splitLines = filteredLines.Select(line => line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries));
var validLines = splitLines.Where(parts => parts.Length >= 2);
var sortedLines = validLines.OrderBy(parts => Math.Abs(float.Parse(parts[0]) - targetFrequency));
string closestPower = sortedLines.Select(parts => parts[1]).FirstOrDefault();
if (!Double.TryParse(closestPower, CultureInfo.InvariantCulture, out power))
{
power = Double.MinValue;
throw new InvalidCastException($"{power} is not a valid power value");
}
}
catch (Exception e)
{
errMsg=e.Message;
return -1;
}
return 0;
}
If you have read data into a ordered collection, say List<(double x, double y)>
var data = new List<(double x, double y)> {
(1, 123),
(2, 234),
(3, 345),
};
and you are looing for linear interpolation, you can try binary search, i.e.
private static double Interpolate(List<(double x, double y)> list, double x) {
if (list is null || list.Count == 0)
return double.NaN; // or throw exception
if (list.Count == 1)
return list[0].y;
var index = list.BinarySearch((x, 0),
Comparer<(double x, double y)>.Create((left, right) => left.x.CompareTo(right.x)));
if (index >= 0)
return list[index].y;
int leftIndex = ~index - 1;
if (leftIndex < 0)
leftIndex = 0;
int rightIndex = leftIndex + 1;
if (rightIndex == list.Count) {
leftIndex -= 1;
rightIndex -= 1;
}
double xa = list[leftIndex].x;
double ya = list[leftIndex].y;
double xb = list[rightIndex].x;
double yb = list[rightIndex].y;
return ya + (x - xa) / (xb - xa) * (yb - ya);
}
Let's have a look:
var y = Interpolate(data, 1.5);
// 178.5
Console.WriteLine(y);