How do I calculate LINEST in C# with a zero intercept? - c#

The normal Linest is easy, but I don't know how to "b is set equal to 0 and the m-values are adjusted to fit y = mx."
static class Program
{
static void Main(string[] args)
{
var yValues = new double[] { 1, 9, 5, 7 };
var xValues = new double[] { 0, 4, 2, 3 };
var noConst = Linest(yValues, xValues);
Console.WriteLine("m = {0}, b = {1}", noConst.Slope, noConst.Intercept);
}
public static LineSpec Linest(IList<double> yValues, IList<double> xValues)
{
var yAvg = yValues.Sum() / yValues.Count;
var xAvg = xValues.Sum() / xValues.Count;
double upperSum = 0;
double lowerSum = 0;
for (var i = 0; i < yValues.Count; i++)
{
upperSum += (xValues[i] - xAvg) * (yValues[i] - yAvg);
lowerSum += (xValues[i] - xAvg) * (xValues[i] - xAvg);
}
var m = upperSum / lowerSum;
var b = yAvg - m * xAvg;
return new LineSpec() { Slope = m, Intercept = b };
}
}
struct LineSpec
{
public double Slope { get; set; }
public double Intercept { get; set; }
}

This is a math question, not a coding question. Use linear regression without the intercept term.
public static LineSpec LinestConst(IList<double> yValues, IList<double> xValues)
{
var yAvg = yValues.Sum() / yValues.Count;
var xAvg = xValues.Sum() / xValues.Count;
double upperSum = 0;
double lowerSum = 0;
for (var i = 0; i < yValues.Count; i++)
{
upperSum += (xValues[i] * yValues[i] );
lowerSum += (xValues[i] * xValues[i] );
}
var m = upperSum / lowerSum;
var b = 0;
return new LineSpec() { Slope = m, Intercept = b };
}

Related

How to get Tensorflow PoseNet working with Xamarin forms/Xam.Android

I've tried with java/Kotlin android and then using it as a .jar but cant get it to work. I have this code in Java, and i need to try to replicate it using C# for Xamarin/Xamarin.Android
JAVA METHOD
fun estimateSinglePose(bitmap: Bitmap): Person {
var t1: Long = SystemClock.elapsedRealtimeNanos()
val inputArray = arrayOf(initInputArray(bitmap))
var t2: Long = SystemClock.elapsedRealtimeNanos()
Log.i("posenet", String.format("Scaling to [-1,1] took %.2f ms", 1.0f *
(t2 - t1) / 1_000_000))
val outputMap = initOutputMap(interpreter!!)
t1 = SystemClock.elapsedRealtimeNanos()
interpreter!!.runForMultipleInputsOutputs(inputArray, outputMap)
t2 = SystemClock.elapsedRealtimeNanos()
Log.i("posenet", String.format("Interpreter took %.2f ms", 1.0f * (t2 - t1) / 1_000_000))
val heatmaps = outputMap[0] as Array<Array<Array<FloatArray>>>
val offsets = outputMap[1] as Array<Array<Array<FloatArray>>>
val height = heatmaps[0].size
val width = heatmaps[0][0].size
val numKeypoints = heatmaps[0][0][0].size
// Finds the (row, col) locations of where the keypoints are most likely to be.
val keypointPositions = Array(numKeypoints) { Pair(0, 0) }
for (keypoint in 0 until numKeypoints) {
var maxVal = heatmaps[0][0][0][keypoint]
var maxRow = 0
var maxCol = 0
for (row in 0 until height) {
for (col in 0 until width) {
heatmaps[0][row][col][keypoint] = sigmoid(heatmaps[0][row][col][keypoint])
if (heatmaps[0][row][col][keypoint] > maxVal) {
maxVal = heatmaps[0][row][col][keypoint]
maxRow = row
maxCol = col
}
}
}
keypointPositions[keypoint] = Pair(maxRow, maxCol)
}
// Calculating the x and y coordinates of the keypoints with offset adjustment.
val xCoords = IntArray(numKeypoints)
val yCoords = IntArray(numKeypoints)
val confidenceScores = FloatArray(numKeypoints)
keypointPositions.forEachIndexed { idx, position ->
val positionY = keypointPositions[idx].first
val positionX = keypointPositions[idx].second
yCoords[idx] = (
position.first / (height - 1).toFloat() * bitmap.height +
offsets[0][positionY][positionX][idx]
).toInt()
xCoords[idx] = (
position.second / (width - 1).toFloat() * bitmap.width +
offsets[0][positionY]
[positionX][idx + numKeypoints]
).toInt()
confidenceScores[idx] = heatmaps[0][positionY][positionX][idx]
}
val person = Person()
val keypointList = Array(numKeypoints) { KeyPoint() }
var totalScore = 0.0f
enumValues<BodyPart>().forEachIndexed { idx, it ->
keypointList[idx].bodyPart = it
keypointList[idx].position.x = xCoords[idx]
keypointList[idx].position.y = yCoords[idx]
keypointList[idx].score = confidenceScores[idx]
totalScore += confidenceScores[idx]
}
person.keyPoints = keypointList.toList()
person.score = totalScore / numKeypoints
return person
}
I have got the PoseNet model running in a C# method but this method is written for object detection and not returning Keypoints, i don't know how to adapt it to get the keypoints
C# Method
public void Recognize(int[] colors)
{
if (!initialized)
{
throw new Exception("Initialize TensorflowLiteService first");
}
MessagingCenter.Instance.Send(this, nameof(AR.InputTensorMessage), new InputTensorMessage()
{
Colors = colors,
});
using (var op = new BuildinOpResolver())
{
using (var interpreter = new Interpreter(model, op))
{
InvokeInterpreter(colors, interpreter);
}
}
}
private void InvokeInterpreter(int[] colors, Interpreter interpreter)
{
if (useNumThreads)
{
interpreter.SetNumThreads(Environment.ProcessorCount);
}
var allocateTensorStatus = interpreter.AllocateTensors();
if (allocateTensorStatus == Status.Error)
{
throw new Exception("Failed to allocate tensor");
}
var input = interpreter.GetInput();
using (var inputTensor = interpreter.GetTensor(input[0]))
{
CopyColorsToTensor(inputTensor.DataPointer, colors);
var watchInvoke = Stopwatch.StartNew();
interpreter.Invoke();
watchInvoke.Stop();
Console.WriteLine($"InterpreterInvoke: {watchInvoke.ElapsedMilliseconds}ms");
}
var output = interpreter.GetOutput();
var outputIndex = output[0];
var outputTensors = new Tensor[output.Length];
for (var i = 0; i < output.Length; i++)
{
outputTensors[i] = interpreter.GetTensor(outputIndex + i);
}
var detection_boxes_out = outputTensors[0].GetData() as float[];
var detection_classes_out = outputTensors[1].GetData() as float[];
var detection_scores_out = outputTensors[2].GetData() as float[];
var num_detections_out = outputTensors[3].GetData() as float[];
var numDetections = num_detections_out[0];
LogDetectionResults(detection_classes_out, detection_scores_out, detection_boxes_out, (int)numDetections);
}

Get RMS from FFT

I got an array of data voltages and I want to get the RMS value from the FFT that has been applied before to that data. I've seen that RMS in time domain should be equal to RMS(fft) / sqrt(nFFT) from Parseval's Theorem, but gives me different results. I'm using these functions:
1)FFT
public static VectorDPoint FFT(double[] trama, double samplingFreq)
{
double fs = samplingFreq; // Sampling frequency
double t1 = 1 / fs; // Sample time
int l = trama.Length; // Length of signal
// Time vector
//Vector t = Normal(0, l, 1) * t1;
//// Values vector
//Vector y = new Vector(trama);
// We just use half of the data as the other half is simetric. The middle is found in NFFT/2 + 1
int nFFT = (int)Math.Pow(2, NextPow2(l));
if (nFFT > 655600)
{ }
// Create complex array for FFT transformation. Use 0s for imaginary part
Complex[] samples = new Complex[nFFT];
for (int i = 0; i < nFFT; i++)
{
if (i >= trama.Length)
{
samples[i] = new MathNet.Numerics.Complex(0, 0);
}
else
{
samples[i] = new MathNet.Numerics.Complex(trama[i], 0);
}
}
ComplexFourierTransformation fft = new ComplexFourierTransformation(TransformationConvention.Matlab);
fft.TransformForward(samples);
ComplexVector s = new ComplexVector(samples);
s = s / l;
Vector f = (fs / 2.0) * Linspace(0, 1, (nFFT / 2) + 1);
VectorDPoint result = new VectorDPoint();
for (int i = 0; i < (nFFT / 2) + 1; i++)
{
result.Add(new DPoint(f[i], 2 * s[i].Modulus));
}
s = null;
f = null;
samples = null;
return result;
2) RMS
public static double RMSCalculate(double[] channelValues, int samplesNumber, double sampleRate, DateTime currentDate)
{
double[] times = new double[channelValues.Length];
double sampleTime = 0.0;
double period = 0;
times[0] = currentDate.Second + currentDate.Millisecond / 1000.0;
sampleTime = 1 / sampleRate; //s
// Limited samples
for (int i = 1; i < channelValues.Length; i++)
{
times[i] = times[i - 1] + sampleTime;
}
DPoint RMSValues = new DPoint();
RMSValues.Y = 0;
if (channelValues.Length == 1)
{
double x = channelValues[0];
double y = channelValues[0];
RMSValues = new DPoint(x, Math.Abs(y));
}
else
{
for (int i = 0; i < times.Length - 1; i++)
{
period = 0;
if (i + 1 < times.Length)
{
RMSValues.Y += channelValues[i + 1] * channelValues[i + 1] * (times[i + 1] - times[i]);
}
}
period = times[times.Length - 1] - times[0];
RMSValues.Y = RMSValues.Y / period;
RMSValues.Y = Math.Sqrt(RMSValues.Y);
}
return RMSValues.Y;
}

Neural Network, Getting output less then 1

I am trying to create a neural network for the function y=e^(-(x-u)^2)/(2*o^2)) where u = 50 and o = 15.
I must train my neural network so I can find the 2 x's for each y. I have created the folling code, it seems to learn it nicely, but once I test the outputs go I only get numbers around 0.99 to 1 where I should get 25 and 75 and I just can't see why. My best guess is that my error correction is wrong, but can't find the error. The neural network uses back-propagation.
The test code and training set
class Program
{
static void Main(string[] args)
{
args = new string[] {
"c:\\testTrain.csv",
"c:\\testValues.csv"
};
// Output File
string fileTrainPath = null;
string fileValuesPath = null;
if (args.Length > 0)
{
fileTrainPath = args[0];
if (File.Exists(fileTrainPath))
File.Delete(fileTrainPath);
fileValuesPath = args[1];
if (File.Exists(fileValuesPath))
File.Delete(fileValuesPath);
}
double learningRate = 0.1;
double u = 50;
double o = 15;
Random rand = new Random();
Network net = new Network(1, 8, 4, 2);
NetworkTrainer netTrainer = new NetworkTrainer(learningRate, net);
List<TrainerSet> TrainerSets = new List<TrainerSet>();
for(int i = 0; i <= 20; i++)
{
double random = rand.NextDouble();
TrainerSets.Add(new TrainerSet(){
Inputs = new double[] { random },
Outputs = getX(random, u, o)
});
}
// Train Network
string fileTrainValue = String.Empty;
for (int i = 0; i <= 10000; i++)
{
if (i == 5000)
{ }
double error = netTrainer.RunEpoch(TrainerSets);
Console.WriteLine("Epoch " + i + ": Error = " + error);
if(fileTrainPath != null)
fileTrainValue += i + "," + learningRate + "," + error + "\n";
}
if (fileTrainPath != null)
File.WriteAllText(fileTrainPath, fileTrainValue);
// Test Network
string fileValuesValue = String.Empty;
for (int i = 0; i <= 100; i++)
{
double y = rand.NextDouble();
double[] dOutput = getX(y, u, o);
double[] Output = net.Compute(new double[] { y });
if (fileValuesPath != null)
fileValuesValue += i + "," + y + "," + dOutput[0] + "," + dOutput[1] + "," + Output[0] + "," + Output[1] + "\n";
}
if (fileValuesPath != null)
File.WriteAllText(fileValuesPath, fileValuesValue);
}
public static double getResult(int x, double u, double o)
{
return Math.Exp(-Math.Pow(x-u,2)/(2*Math.Pow(o,2)));
}
public static double[] getX(double y, double u, double o)
{
return new double[] {
u + Math.Sqrt(2 * Math.Pow(o, 2) * Math.Log(1/y)),
u - Math.Sqrt(2 * Math.Pow(o, 2) * Math.Log(1/y)),
};
}
}
The code behind the network
public class Network
{
protected int inputsCount;
protected int layersCount;
protected NetworkLayer[] layers;
protected double[] output;
public int Count
{
get
{
return layers.Count();
}
}
public NetworkLayer this[int index]
{
get { return layers[index]; }
}
public Network(int inputsCount, params int[] neuronsCount)
{
this.inputsCount = Math.Max(1, inputsCount);
this.layersCount = Math.Max(1, neuronsCount.Length);
layers = new NetworkLayer[neuronsCount.Length];
for (int i = 0; i < layersCount; i++)
layers[i] = new NetworkLayer(neuronsCount[i],
(i == 0) ? inputsCount : neuronsCount[i - 1]);
}
public virtual double[] Compute(double[] input)
{
output = input;
foreach (NetworkLayer layer in layers)
output = layer.Compute(output);
return output;
}
}
public class NetworkLayer
{
protected int inputsCount = 0;
protected int neuronsCount = 0;
protected Neuron[] neurons;
protected double[] output;
public Neuron this[int index]
{
get { return neurons[index]; }
}
public int Count
{
get { return neurons.Length; }
}
public int Inputs
{
get { return inputsCount; }
}
public double[] Output
{
get { return output; }
}
public NetworkLayer(int neuronsCount, int inputsCount)
{
this.inputsCount = Math.Max( 1, inputsCount );
this.neuronsCount = Math.Max( 1, neuronsCount );
neurons = new Neuron[this.neuronsCount];
output = new double[this.neuronsCount];
// create each neuron
for (int i = 0; i < neuronsCount; i++)
neurons[i] = new Neuron(inputsCount);
}
public virtual double[] Compute(double[] input)
{
// compute each neuron
for (int i = 0; i < neuronsCount; i++)
output[i] = neurons[i].Compute(input);
return output;
}
}
public class Neuron
{
protected static Random rand = new Random((int)DateTime.Now.Ticks);
public int Inputs;
public double[] Input;
public double[] Weights;
public double Output = 0;
public double Threshold;
public double Error;
public Neuron(int inputs)
{
this.Inputs = inputs;
Weights = new double[inputs];
for (int i = 0; i < inputs; i++)
Weights[i] = rand.NextDouble() * 0.5;
}
public double Compute(double[] inputs)
{
Input = inputs;
double e = 0.0;
for (int i = 0; i < inputs.Length; i++)
e += Weights[i] * inputs[i];
e -= Threshold;
return (Output = sigmoid(e));
}
private double sigmoid(double value)
{
return (1 / (1 + Math.Exp(-1 * value)));
//return 1 / (1 + Math.Exp(-value));
}
}
My Trainer
public class NetworkTrainer
{
private Network network;
private double learningRate = 0.1;
public NetworkTrainer(double a, Network network)
{
this.network = network;
this.learningRate = a;
}
public double Run(double[] input, double[] output)
{
network.Compute(input);
return CorrectErrors(output);
}
public double RunEpoch(List<TrainerSet> sets)
{
double error = 0.0;
for (int i = 0, n = sets.Count; i < n; i++)
error += Run(sets[i].Inputs, sets[i].Outputs);
// return summary error
return error;
}
private double CorrectErrors(double[] desiredOutput)
{
double[] errorLast = new double[desiredOutput.Length];
NetworkLayer lastLayer = network[network.Count - 1];
for (int i = 0; i < desiredOutput.Length; i++)
{
// S(p)=y(p)*[1-y(p)]*(yd(p)-y(p))
lastLayer[i].Error = lastLayer[i].Output * (1-lastLayer[i].Output)*(desiredOutput[i] - lastLayer[i].Output);
errorLast[i] = lastLayer[i].Error;
}
// Calculate errors
for (int l = network.Count - 2; l >= 0; l--)
{
for (int n = 0; n < network[l].Count; n++)
{
double newError = 0;
for (int np = 0; np < network[l + 1].Count; np++)
{
newError += network[l + 1][np].Weights[n] * network[l + 1][np].Error;
}
network[l][n].Error = newError;
}
}
// Update Weights
// w = w + (a * input * error)
for (int l = network.Count - 1; l >= 0; l--)
{
for (int n = 0; n < network[l].Count; n++)
{
for (int i = 0; i < network[l][n].Inputs; i++)
{
// deltaW = a * y(p) * s(p)
double deltaW = learningRate * network[l][n].Output * network[l][n].Error;
network[l][n].Weights[i] += deltaW;
}
}
}
double returnError = 0;
foreach (double e in errorLast)
returnError += e;
return returnError;
}
}
For regression problems your output layer should have the identity (or at least a linear) activation function. This way you don't have to scale your output. The derivative of the identity function is 1 and thus the derivative dE/da_i for the output layer is y-t (lastLayer[i].Output - desiredOutput[i]).

reading a barcode with a webcam

Hey,
I'm trying to read a EAN-13 barcode from my webcam.
I already wrote a class to do that work.
I'm taking a picture from my webcam, trimming it to show ONLY the barcode,
and reading the barcode with the code tables from wikipedia.
For some reason, the barcode gets trimmed, but the output is always "0-1-1-1-1-1-1-1-1-1-1-1-1".
I wonder if i did any stupid mistake or misunderstood something?
I do not want to use ANY third-party programs!
this is my code for now:
public class BarcodeDecoder
{
static string[] ligerade = new string[] { "0100111", "0110011", "0011011", "0100001", "0011101", "0000101", "0010001", "0001001", "0010111" };
static string[] rechtsgerade = new string[ligerade.Length];
static string[] liungerade = new string[ligerade.Length];
static string[] GeradeUG = new string[] { "UUUUUU", "UUGUGG", "UUGGUG", "UUGGGU", "UGUUGG", "UGGUUG", "UGGGUU", "UGUGUG", "UGUGGU", "UGGUGU" };
static int[] links;
static int[] rechts;
static string result;
public static string Decode(Bitmap b)
{
result = "";
Bitmap bb = CutOutOf(b, b.Height / 2);
bb = trimBitmap(bb);
int[] lgs = GetNumberOutOf(bb);
int[][] rr = trimArray(lgs);
links = rr[0];
rechts = rr[1];
FillArrays();
BearbeiteLinks();
BearbeiteRechts();
return result;
}
static void BearbeiteLinks()
{
string GU = "";
string[] zahlen = new string[6];
zahlen[0] = OutOfArray(links, 0, 7);
zahlen[1] = OutOfArray(links, 7, 7);
zahlen[2] = OutOfArray(links, 14, 7);
zahlen[3] = OutOfArray(links, 21, 7);
zahlen[4] = OutOfArray(links, 28, 7);
zahlen[5] = OutOfArray(links, 35, 7);
foreach (string pq in zahlen)
{
bool gerade = ligerade.ToList().IndexOf(pq) > -1;
if (gerade)
{
result += ligerade.ToList().IndexOf(pq).ToString();
GU += "G";
}
else
{
result += liungerade.ToList().IndexOf(pq).ToString();
GU += "U";
}
}
result = GeradeUG.ToList().IndexOf(GU).ToString() + result;
}
static void BearbeiteRechts()
{
string[] zahlen = new string[6];
zahlen[0] = OutOfArray(rechts, 0, 7);
zahlen[1] = OutOfArray(rechts, 7, 7);
zahlen[2] = OutOfArray(rechts, 14, 7);
zahlen[3] = OutOfArray(rechts, 21, 7);
zahlen[4] = OutOfArray(rechts, 28, 7);
zahlen[5] = OutOfArray(rechts, 35, 7);
foreach (string pq in zahlen)
{
result += rechtsgerade.ToList().IndexOf(pq).ToString();
}
}
static string OutOfArray(int[] ar, int startindex, int length)
{
int[] gar = new int[length];
Array.Copy(ar, startindex, gar, 0, length);
StringBuilder bilder = new StringBuilder();
for (int i = 0; i < gar.Length; i++)
{
bilder.Append(gar[i].ToString());
}
return bilder.ToString();
}
static Bitmap trimBitmap(Bitmap b)
{
bool alreadyBlack = false;
int firstblack = 0;
for (int i = 0; i < b.Width; i++)
{
Color gp = b.GetPixel(i, 0);
if ((gp.R + gp.G + gp.B) / 3 < 128)
{
if (!alreadyBlack)
{
alreadyBlack = true;
firstblack = i;
}
}
}
bool alreadyblack = false;
int lastblack = 0;
for (int i = b.Width -1; i > 0; i--)
{
Color gpp = b.GetPixel(i, 0);
if ((gpp.R + gpp.G + gpp.B) / 3 < 128)
{
if (!alreadyblack)
{
alreadyblack = true;
lastblack = i;
}
}
}
Bitmap result = new Bitmap(lastblack - firstblack, 1);
for (int i = firstblack; i < lastblack; i++)
{
Color c = b.GetPixel(i, 0);
result.SetPixel(i - firstblack, 0, c);
}
result.Save("C:\\result.bmp", System.Drawing.Imaging.ImageFormat.Bmp);
return result;
}
static int[][] trimArray(int[] ar)
{
int[][] res = new int[2][];
int[] resl = new int[6 * 7];
int[] resr = new int[6 * 7];
Array.Copy(ar, 2, resl, 0, 6 * 7);
Array.Copy(ar, 2 + 6 * 7 + 5, resr, 0, 6 * 7);
res[0] = resl;
res[1] = resr;
return res;
}
static void FillArrays()
{
for (int i = 0; i < ligerade.Length; i++)
{
rechtsgerade[i] = string.Concat(ligerade[i].Reverse());
}
for (int x = 0; x < liungerade.Length; x++)
{
liungerade[x] = Invert(rechtsgerade[x]);
}
}
static string Invert(string xx)
{
string xs = "";
for (int y = 0; y < xx.Length; y++)
{
int fd = int.Parse(xx[y].ToString());
if (fd == 0)
fd = 1;
else
fd = 0;
xs += fd.ToString();
}
return xs;
}
static Bitmap CutOutOf(Bitmap b, int y)
{
Bitmap res = new Bitmap(b.Width, 1);
for (int i = 0; i < b.Width; i++)
{
Color c = b.GetPixel(i, y);
res.SetPixel(i, 0, c);
}
return res;
}
static int[] GetNumberOutOf(Bitmap bb)
{
List<int> intlst = new List<int>();
float f = (float)bb.Width / 95.0f;
float wd = f / 2.0f;
for (float i = wd; i < bb.Width; i+=f)
{
Color c = bb.GetPixel((int)Math.Round(i,0), 0);
intlst.Add(GetOutOfColor(c));
}
return intlst.ToArray();
}
static int GetOutOfColor(Color c)
{
if (c.A + c.B + c.R > 128 * 3)
{
return 0;
}
return 1;
}
}
Sorry for german names in the code!
I see two problems:
1) You only scan the top most pixel row of your image (see the second parameter of GetPixel). Your barcode is probably in the middle of the image and not at the top.
Color c = bb.GetPixel((int)Math.Round(i,0), 0);
2) Instead of the green component, you take the alpha component to convert the colored pixel into a binary value. Since the alpha component is probably always 255, you always get 0 unless you have a very dark pixel.
if (c.A + c.B + c.R > 128 * 3)

Implementation of FIR filter in C#

at the moment im trying to implement a FIR lowpass filter on a wave file. The FIR coefficients where obtained using MATLAB using a 40 order. Now i need to implement the FIR algorithm in C# and im finding it difficult to implement it.
Any help?
Thanks
How about this:
private static double[] FIR(double[] b, double[] x)
{
int M = b.Length;
int n = x.Length;
//y[n]=b0x[n]+b1x[n-1]+....bmx[n-M]
var y = new double[n];
for (int yi = 0; yi < n; yi++)
{
double t = 0.0;
for (int bi = M-1; bi >=0; bi--)
{
if (yi - bi < 0) continue;
t += b[bi] * x[yi - bi];
}
y[yi] = t;
}
return y;
}
Try this. Does it help?
static void Main()
{
var bb = new List<double> { 1, 2, 3, 4 };
var xx = new List<double> { 3, 3, 4, 5 };
var yy = func_FIR(bb, xx);
for (int i = 0; i < yy.Count; i++)
{
Console.WriteLine("y[{0}] = {1}",i,yy[i]);
}
}
public static List<double> func_FIR(List<double> b, List<double> x)
{
//y[n]=b0x[n]+b1x[n-1]+....bmx[n-M]
var y = new List<double>();
int M = b.Count;
int n = x.Count;
double t = 0.0;
for (int j = 0; j < n; j++)
{
for (int i = 0; i < M; i++)
{
t += b[i] * x[n - i-1];
}
y.Add(t);
}
return y;
}

Categories