Get RMS from FFT - c#

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;
}

Related

Unusual StackOverflowException in ListDictionaryInternal

I have class library with a bunch of static methods. While trying to call one of them, I experience unhandled StackOverflowException somewhere in the ListDictionaryInternal class.
I tried enabling .Net Framework (v 4.5.2) stepping, surrounding call with try/catch block, and executing it step by step. When I place continue statement after Appendix A comment, then comment it while debugging, method works as expected. Otherwise I cannot even hit breakpoint at the start at the method. I also tried to call method with all parameters set to null, but it did not help either.
public static List<CalcSector> Split(List<CalcSector> calibration, List<ProfilePoint> profile, List<MeasurementPoint> additionalPoints)
{
double lengthCorridor = 10d;
double lengthEpsilon = 1d;
if (!(calibration?.Any() ?? false)) throw new ArgumentNullException(nameof(calibration), "Empty calibration table");
if (!(profile?.Any() ?? false)) throw new ArgumentNullException(nameof(profile), "Empty profile points collection");
for (int i = 0; i < calibration.Count - 1; i++)
if (Math.Abs(calibration[i].EndDistance - calibration[i + 1].StartDistance) > lengthEpsilon)
throw new ArgumentException($"calibration[{i}]", "Calibration table integrity is compromised");
List<CalcSector> result = new List<CalcSector>();
List<ProfilePoint> SummitPoints = new List<ProfilePoint>();
calibration.ForEach(x => result.Add(x));
profiles = profile.OrderBy(x => x.Distance).ToList();
//
if (additionalPoints?.Any() ?? false)
foreach (MeasurementPoint mp in additionalPoints.Where(x => x.Id != int.MinValue && x.Id != int.MaxValue))
for (int i = 0; i < result.Count; i++)
if (Math.Abs(mp.Distance - result[i].StartDistance) > lengthEpsilon && Math.Abs(mp.Distance - result[i].EndDistance) > lengthEpsilon && mp.Distance > result[i].StartDistance && mp.Distance < result[i].EndDistance)
{
CalcSector c = new CalcSector()
{
StartDistance = mp.Distance,
StartHeight = BinaryHeightSearch(mp.Distance),
StartPointId = mp.Id,
EndDistance = result[i].EndDistance,
EndHeight = result[i].EndHeight,
Length = result[i].EndDistance - mp.Distance,
Thickness = result[i].Thickness,
};
result[i].EndDistance = mp.Distance;
result[i].EndHeight = c.StartHeight;
result[i].EndPointId = mp.Id;
c.Volume = result[i].Volume / result[i].Length * c.Length;
result[i].Length -= c.Length;
result[i].Volume -= c.Volume;
result.Insert(i + 1, c);
break;
}
else if (Math.Abs(mp.Distance - result[i].StartDistance) < lengthEpsilon)
result[i].StartPointId = mp.Id;
else if (Math.Abs(mp.Distance - result[i].EndDistance) < lengthEpsilon)
result[i].EndPointId = mp.Id;
int start = 0;
int end = 0;
bool hasSpikes = true;
while (hasSpikes)
{
hasSpikes = false;
//Appendix A
for (int j = 0; j < result.Count; j++)
{
result[j].z = -1d * (result[j].StartHeight - result[j].EndHeight) / (result[j].EndDistance - result[j].StartDistance);
result[j].sI = start = BinaryProfileSearch(result[j].StartDistance);
result[j].eI = end = BinaryProfileSearch(result[j].EndDistance);
for (int i = start + 1; i < end; i++)
if (Math.Abs(result[j].z * (profiles[i].Distance - result[j].StartDistance) + result[j].StartHeight - profiles[i].Height) > lengthCorridor)
{
int maxIndex = -1;
double maxH = double.MinValue;
int minIndex = -1;
double minH = double.MaxValue;
for (; start < end; start++)
{
if (Math.Abs(result[j].z * (profiles[start].Distance - result[j].StartDistance) + result[j].StartHeight - profiles[start].Height) <= lengthCorridor)
continue;
if (result[j].z * (profiles[i].Distance - result[j].StartDistance) + result[j].StartHeight - profiles[i].Height > maxH)
{
maxH = profiles[start].Height;
maxIndex = start;
}
if (result[j].z * (profiles[i].Distance - result[j].StartDistance) + result[j].StartHeight - profiles[i].Height < minH)
{
minH = profiles[start].Height;
minIndex = start;
}
}
int target = Math.Min(maxIndex, minIndex);
CalcSector c = new CalcSector()
{
StartDistance = profiles[target].Distance,
StartHeight = profiles[target].Height,
sI = target,
EndDistance = result[j].EndDistance,
EndHeight = result[j].EndHeight,
EndPointId = result[j].EndPointId,
eI = result[j].eI,
Length = result[j].EndDistance - profiles[target].Distance,
Thickness = result[j].Thickness,
};
result[j].EndDistance = c.StartDistance;
result[j].EndHeight = c.StartHeight;
result[j].EndPointId = null;
result[j].eI = target;
result[j].z = -1d * (result[j].StartHeight - result[j].EndHeight) / (result[j].EndDistance - result[j].StartDistance);
c.Volume = result[j].Volume / result[j].Length * c.Length;
result[j].Length -= c.Length;
result[j].Volume -= c.Volume;
result.Insert(j + 1, c);
hasSpikes = true;
break;
}
}
}
for (int j = 0; j < result.Count; j++)
{
result[j].Diameter = 1000d * Math.Sqrt(4d * result[j].Volume / Constants["PI"] / result[j].Length);
result[j].OrdNum = j;
}
result.First().StartPointId = int.MinValue;
result.Last().EndPointId = int.MaxValue;
for (int i = 1; i < profiles.Count - 1; i++)
if (profiles[i - 1].Height < profiles[i].Height && profiles[i].Height > profiles[i + 1].Height)
SummitPoints.Add(profiles[i]);
return result;
}
public class CalcSector
{
public int OrdNum;
public double StartDistance;
public double StartHeight;
public int? StartPointId;
public double EndDistance;
public double EndHeight;
public int? EndPointId;
public double Length;
public double Volume;
public double Diameter;
public double Thickness;
public int sI;
public int eI;
public double z;
}
public class ProfilePoint
{
public double Distance;
public double Height;
}
public class MeasurementPoint
{
public int Id;
public double Distance;
}
I expect this method to split some of the original CalcSectors into smaller ones, but all I have is this unhandled fatal exception.
Added:
private static int BinaryProfileSearch(double distance)
{
if (profiles == null || profiles.Count == 0)
return -1;
//assuming that profile points are already ordered by distance
if (distance <= profiles.First().Distance)
return 0;
if (distance >= profiles.Last().Distance)
return profiles.Count - 1;
int first = 0;
int last = profiles.Count - 1;
while (first + 1 < last)
{
int mid = (first + last) / 2;
if (distance <= profiles[mid].Distance)
last = mid;
else
first = mid + 1;
}
if (distance - profiles[first].Distance > profiles[last].Distance - distance)
return last;
else
return first;
}
The solution came quite unexpected: invalid value of 8087 control word. Next line changes it back.
_controlfp(0x9001F, 0xFFFFF);

Matrix Multiplication returning wrong value

I am calculating values by using weights and bias from MATLAB trained ANN. trying to code a sigmoid simulation equation, but for some reason C# calculations vary too much than that of MATLAB. i.e. error is too high. I tried to check each step of the equation and found out the specific part that is creating the problem (Emphasized part), but I don't know how to solve this issue, if someone could help, would be a huge favour.
1+(purelin(net.LW{2}×(tansig(net.IW{1}×(1-(abs(2×([inputs]-1)))))+net.b{1}))+net.b{2}))/2
//Normalization of Data
public double Normalization(double x, double xMAx, double xMin)
{
double xNorm = 0.0;
xNorm = (x - xMin) / (xMAx - xMin);
if (xNorm < 0)
xNorm = 0;
if (xNorm > 1)
xNorm = 1;
xNorm = Math.Round(xNorm, 4);
return xNorm;
}
// Equation to calculate ANN based Output Values
public double MetrixCalc(double[] Pn, double[,] W1, double[] W2, double[] b1, double b2, double maxValue, double minValue)
{
double FinalValue = 0;
double[] PnCalc1 = new double[Pn.Length];
double[] PnCalc2 = new double[W1.Length / Pn.Length];
for (int i = 0; i < Pn.Length; i++)
{
PnCalc1[i] = 1 - Math.Abs(2 * (Pn[i] - 1));
}
for (int i = 0; i < (W1.Length / Pn.Length); i++)
{
double PnCalc = 0.0;
for (int j = 0; j < Pn.Length; j++)
{
PnCalc = PnCalc + (W1[i, j] * PnCalc1[j]);
}
PnCalc2[i] = PnCalc;
}
for (int i = 0; i < PnCalc2.Length; i++)
{
//PnCalc2[i] = Math.Tanh(PnCalc2[i] + b1[i]);
PnCalc2[i] = PnCalc2[i] + b1[i];
PnCalc2[i] = 2.0 / (1 + Math.Exp(-2 * (PnCalc2[i]))) - 1;
PnCalc2[i] = Math.Round(PnCalc2[i], 4);
}
double FinalCalc = 0.0;
for (int i = 0; i < PnCalc2.Length; i++)
{
*FinalCalc = FinalCalc + (W2[i] * (PnCalc2[i]));*
//FinalValue = FinalCalc;
}
FinalValue = FinalCalc + b2;
FinalValue = 1 + FinalValue;
FinalValue = (1 + FinalValue) / 2.0;
FinalValue = (FinalValue * (maxValue - minValue)) + minValue;
FinalValue = Math.Round(FinalValue, 4);
FinalValue = Math.Abs(FinalValue);
return FinalValue;
}
Problem is solved.
Problem was with the weights matrix copied from MATLAB. debugging mode saved my life. :)

Neural Net - Feed Forward, Matrix Multiplication in C#

I'm attempting to make a Neural Network in C#, I based the design in a python code I made a while back. But somehow the end result is not the same.
I'm new to C# and I'm using it in Unity, so I have limitation to library uses.
In python numpy can do matrix multiplications with the numpy.dot() method. I Haven't found something similar in C#, especially in Unity. So I had to do it by hand.
The Python code:
import numpy as np
class NN:
def __init__(self, n_input, n_hidden_layers, n_hidden_nodes, n_output):
self.weights_hidden = []
for n in range(n_hidden_layers + 1):
if n == 0:
size = n_input, n_hidden_nodes
elif n == n_hidden_layers:
size = n_hidden_nodes, n_output
else:
size = n_hidden_nodes, n_hidden_nodes
self.weights_hidden.append(
np.random.random(size)
)
#staticmethod
def activation(x):
return np.tanh(x)
def feed_forward(self, ip):
input_values = (ip - np.mean(ip, axis=0)) / np.std(ip, axis=0)
for w, weights in enumerate(self.weights_hidden):
if w == 0:
result = input_values
result = np.array(
map(self.activation, result.dot(weights))
)
return result
ANN = NN(n_input=5, n_hidden_layers=2, n_hidden_nodes=3, n_output=1)
print ANN.feed_forward([1, 2, 3, 4, 5])
My attempt to convert it to C#.
using UnityEngine;
using System.Collections;
public class neural_net : MonoBehaviour {
int n_inputs;
int n_hidden_layers;
int n_hidden_nodes;
int n_outputs;
float[] inputs;
ArrayList hidden_weights;
ArrayList hidden_results;
float[] output_results;
public void init(int n_inputs, int n_hidden_layers, int n_hidden_nodes, int n_outputs){
this.n_inputs = n_inputs;
this.n_hidden_layers = n_hidden_layers;
this.n_hidden_nodes = n_hidden_nodes;
this.n_outputs = n_outputs;
this.hidden_weights = new ArrayList ();
this.hidden_results = new ArrayList ();
this.output_results = new float[n_outputs];
int rows;
int columns;
for (int h = 0; h < n_hidden_layers + 2; h++) {
if (h == 0){
// input -> hidden
rows = n_inputs;
columns = n_hidden_nodes;
}
else if(h == n_hidden_layers + 1){
// hidden -> output
rows = n_hidden_nodes;
columns = n_outputs;
}
else {
// hidden -> hidden
rows = n_hidden_nodes;
columns = n_hidden_nodes;
}
float[] hidden_result = new float[rows*columns];
hidden_results.Add(hidden_results);
float[,] target = new float[rows,columns];
string test = "";
for(int r = 0; r < rows; r++){
for(int c = 0; c < columns; c++){
target[r,c] = Random.Range(0.0f, 1.0f);
test += target[r,c] + ", ";
}
}
hidden_weights.Add(target);
}
}
float activation(float x){
// tanh(x);
return (1 - Mathf.Exp (-2 * x)) / (1 + Mathf.Exp (-2 * x));
}
float[] _dot_matrix(float[] results, float[,] weights){
float[] new_matrix = new float[weights.GetLength(1)];
string t0 = "";
for (int r = 0; r < weights.GetLength(1); r++){
float res = 0;
for (int c = 0; c < weights.GetLength(0); c++) {
res += results[c] * weights[c,r];
}
new_matrix[r] = res;
}
return new_matrix;
}
float[] _map_activation(float[] pre_results){
float[] results = new float[pre_results.Length];
for (int i = 0; i < results.Length; i++) {
results[i] = activation(pre_results[i]);
}
return results;
}
float[] feed_forward(){
int h;
for (h = 0; h < n_hidden_layers + 2; h++) {
float[] dot_matrix_result;
if(h == 0){
dot_matrix_result = _dot_matrix(inputs, (float[,])hidden_weights[h]);
}
else if (h == n_hidden_layers +1){
dot_matrix_result = _dot_matrix((float[])hidden_results[h-1], (float[,])hidden_weights[h]);
output_results = _map_activation(dot_matrix_result);
break;
}
else {
dot_matrix_result = _dot_matrix((float[])hidden_results[h-1], (float[,])hidden_weights[h]);
}
float[] result = _map_activation(dot_matrix_result);
hidden_results[h] = _map_activation(result);
}
return output_results;
}
float[] normalize_input(float[] inputs){
float sum = 0.0f;
for (int i = 0; i < inputs.Length; i++) {
sum += inputs[i] ;
}
float average = sum / inputs.Length;
float[] deviations = new float[inputs.Length];
for (int i = 0; i < inputs.Length; i++) {
deviations[i] = Mathf.Pow(inputs[i] - average,2);
}
float sum_deviation = 0;
for (int i = 0; i < deviations.Length; i++) {
sum_deviation += deviations[i];
}
float variance = sum_deviation / deviations.Length;
float std = Mathf.Sqrt (variance);
for (int i = 0; i < inputs.Length; i++) {
inputs[i] = (inputs[i] - average)/std;
}
return inputs;
}
public void start_net(float[] inputs){
this.inputs = normalize_input(inputs);
feed_forward ();
}
}
I run the net from other script using the init method and then the start_net() method.
I made a test with not random weights and fixed input data, but it didn't came to the same result as the python code.
What's wrong with the C# code?

Calculating exponential growth equation from data points c#

I am trying to analyse some data using a C# app and need to calculate trend lines. I am aware that there are multiple types of trend line but for now I am trying to calculate exponential growth; I am going to be using it to predict future values. The equation I have been working off is
x(t) = x(0) * ((1+r)^t)
And this is the code that I have written to try and replicate the graph:
public void ExponentialBestFit(List<DateTime> xvalues, List<double> yvalues)
{
//Find the first value of y (The start value) and the first value of x (The start date)
xzero = Convert.ToDouble(xvalues[0].ToOADate());
yzero = yvalues[0];
if (yzero == 0)
yzero += 0.1;
//For every value of x (exluding the 1st value) find the r value
//
// | y | Where t = the time sinse the start time (time period)
//Equation for r = t root|-------| - 1 Where y = the current y value
// | y[0] | Where y[0] = the first y value #IMPROVMENT - Average 1st y value in range
//
double r = 0;
//c is a count of how many r values are added; it is not equal to the count of all the values
int c = 0;
for (int i = 1; i < xvalues.Count; i++)
{
r += Math.Pow(yvalues[i]/yzero, 1/(Convert.ToDouble(xvalues[i].ToOADate()) - xzero)) - 1;
c++;
}
r = r / c;
}
The data I am passing in is over a period of time however the increments in which the time increases are not the same. When I created a chart in excel they use a different formula
x(t) = x(0)*(e^kt)
I think however I have no idea where the k value is being generated from. The two lists that I am passing in are Date and Value and each row in each list corresponds to the same row in the other list. The question is - Is there a better way of creating the equation and variables and are the variables I am getting the most accurate it can be for my data?
This is the c# version of the javascript provided.
// Calculate Exponential Trendline / Growth
IEnumerable<double> Growth(IList<double> knownY, IList<double> knownX, IList<double> newX, bool useConst)
{
// Credits: Ilmari Karonen
// Default values for optional parameters:
if (knownY == null) return null;
if (knownX == null)
{
knownX = new List<double>();
for (var i = 0; i<=knownY.Count; i++)
knownX.Add(i);
}
if (newX == null)
{
newX = new List<double>();
for (var i = 0; i <= knownY.Count; i++)
newX.Add(i);
}
int n = knownY.Count;
double avg_x = 0.0;
double avg_y = 0.0;
double avg_xy = 0.0;
double avg_xx = 0.0;
double beta = 0.0;
double alpha = 0.0;
for (var i = 0; i < n; i++)
{
var x = knownX[i];
var y = Math.Log(knownY[i]);
avg_x += x;
avg_y += y;
avg_xy += x * y;
avg_xx += x * x;
}
avg_x /= n;
avg_y /= n;
avg_xy /= n;
avg_xx /= n;
// Compute linear regression coefficients:
if (useConst)
{
beta = (avg_xy - avg_x * avg_y) / (avg_xx - avg_x * avg_x);
alpha = avg_y - beta * avg_x;
}
else
{
beta = avg_xy / avg_xx;
alpha = 0.0;
}
// Compute and return result array:
return newX.Select(t => Math.Exp(alpha + beta*t)).ToList();
}
The following JavaScript code should help. I used it to implement Excel's GROWTH function. It's written in JavaScript, but porting it to C# should be very easy. Please note that most of it was written by someone else (credits in the code).
function GROWTH(known_y, known_x, new_x, use_const) {
// Credits: Ilmari Karonen
// Default values for optional parameters:
if (typeof(known_x) == 'undefined') {
known_x = [];
for (var i = 1; i <= known_y.length; i++) known_x.push(i);
}
if (typeof(new_x) == 'undefined') {
new_x = [];
for (var i = 1; i <= known_y.length; i++) new_x.push(i);
}
if (typeof(use_const) == 'undefined') use_const = true;
// Calculate sums over the data:
var n = known_y.length;
var avg_x = 0;
var avg_y = 0;
var avg_xy = 0;
var avg_xx = 0;
for (var i = 0; i < n; i++) {
var x = known_x[i];
var y = Math.log(known_y[i]);
avg_x += x;
avg_y += y;
avg_xy += x*y;
avg_xx += x*x;
}
avg_x /= n;
avg_y /= n;
avg_xy /= n;
avg_xx /= n;
// Compute linear regression coefficients:
if (use_const) {
var beta = (avg_xy - avg_x*avg_y) / (avg_xx - avg_x*avg_x);
var alpha = avg_y - beta*avg_x;
} else {
var beta = avg_xy / avg_xx;
var alpha = 0;
}
// Compute and return result array:
var new_y = [];
for (var i = 0; i < new_x.length; i++) {
new_y.push(Math.exp(alpha + beta * new_x[i]));
}
return new_y;
}
Since x(t)=x(0)*e^{kt}, we can take logarithms to get ln x(t)=ln x(0) + kt. This means that to find ln x(0) and k, you can find the least squares fit for the data {(t,ln x(t))}. This will tell you that ln x(t) = b + at, so that k=a and x(0)=e^b.

Out of memory and overflow exceptions creating small array

I am new to C# and XNA. Have just managed to write a class that generates a triangular grid.
But there is one problem. I can get maximum 27 nodes length triangle.
At 28 it throws Out of memory exception and at 31 -overFlow exception.
I don't understand how it overflows or out of memory... Tried to
calculate all those memory values but they look very tiny.
It is only array of nodes affected by variable. Node class is not very big:
float x; 4 B
float y; 4 B
float z; 4 B
int[] con; int[6] 4*6=24 B
byte pass; 1 B
Color col; 32 b= 4 B
Total: 41B
sequence sum of nodes needed to create triangle is n(n+1)/2
out of memory at 28
28*29/2=406 nodes
total memory:
41*406 = 16646 B = 16.26 kB
Overflows at 31: 496 nodes is 19.9 kB
I did read articles about "out of memory exceptions", that structures size is bigger than it seems and that out of memory happens at sizes of 500MB... there is no way my small triangle would reach such huge size.
This is my whole class:
class TriMatrix
{
int len;
int Lenght;
Node[] node;
VertexPositionColor[] vertex;
public class Node
{
public float x;
public float y;
public float z;
public int[] con;
public byte pass;
public Color col;
public Node(byte passable)
{
pass = passable;
if (pass > 0)
{ col = Color.Green; }
else
{ col = Color.DarkRed; }
x = 0;
z = 0;
con = new int[6];
}
}
public TriMatrix(int lenght)
{
len = lenght;
Lenght = 0;
byte pass;
Random rnd = new Random();
for (int i = 0; i <= len; i++)
{
Lenght += Lenght + 1;
}
node = new Node[Lenght];
int num = 0;
for (int i = 0; i < len; i++)
{
for (int j = 0; j <= i; j++)
{
if (rnd.Next(0, 5) > 0) { pass = 1; } else { pass = 0; }
node[num] = new Node(pass);
node[num].x = (float)i - (float)j / 2.0f;
node[num].y = 0;
node[num].z = (float)j * 0.6f;
if (i < len - 1) { node[num].con[0] = num + i; } else { node[num].con[0] = -1; node[num].col = Color.Violet; }
if (i < len - 1) { node[num].con[1] = num + i + 1; } else { node[num].con[1] = -1; }
if (j < i) { node[num].con[2] = num + 1; } else { node[num].con[2] = -1; node[num].col = Color.Violet; }
if (j < i) { node[num].con[3] = num - i; } else { node[num].con[3] = -1; }
if (i > 0) { node[num].con[4] = num - i - 1; } else { node[num].con[4] = -1; }
if (i > 0) { node[num].con[5] = num - 1; } else { node[num].con[5] = -1; }
if (j == 0) { node[num].col = Color.Violet; }
num++;
}
}
}
public void Draw(Effect effect, GraphicsDevice graphics)
{
VertexPositionColor[] verts = new VertexPositionColor[3];
int num = 0;
for (int i = 0; i < len-1; i++)
{
for (int j = 0; j <= i; j++)
{
foreach (EffectPass pass in effect.CurrentTechnique.Passes)
{
pass.Apply();
verts[0] = new VertexPositionColor(new Vector3(node[num].x, node[num].y, node[num].z), node[num].col);
verts[1] = new VertexPositionColor(new Vector3(node[num + i + 1].x, node[num + i + 1].y, node[num + i + 1].z), node[num + i + 1].col);
verts[2] = new VertexPositionColor(new Vector3(node[num + i + 2].x, node[num + i + 2].y, node[num + i + 2].z), node[num + i + 2].col);
graphics.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.TriangleStrip, verts, 0, 1);
if ( j < i)
{
verts[0] = new VertexPositionColor(new Vector3(node[num].x, node[num].y, node[num].z), node[num].col);
verts[1] = new VertexPositionColor(new Vector3(node[num + i + 2].x, node[num + i + 2].y, node[num + i + 2].z), node[num + i + 2].col);
verts[2] = new VertexPositionColor(new Vector3(node[num + 1].x, node[num + 1].y, node[num + 1].z), node[num + 1].col);
graphics.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.TriangleStrip, verts, 0, 1);
}
}
num++;
}
}
}
}// endclass
I assume that your bug lies in this loop (taking the liberty to correct your spelling):
for (int i = 0; i <= len; i++)
{
Length += Length + 1;
}
Within the loop, you are incrementing the value of Length by itself plus one. This effectively means that you are doubling the value of Length for each iteration, resulting in exponential growth.
During the first few iterations, the values of Length will be: 1, 3, 7, 15, 31, 63, …. We can generalize this sequence such that, at iteration i, the value of Length will be 2i+1−1. At iteration 28, this would be 536,870,911. At iteration 31, this would be 4,294,967,295.
Edit: As you mentioned in the comment below, the correct fix for computing the number of elements in a triangular grid of length len would be:
for (int i = 1; i <= len; i++)
{
Length += i;
}
This is equivalent to the summation 1 + 2 + 3 + … + len, which computes what is known as the triangular number. It may be succinctly computed using the formula:
Length = len * (len + 1) / 2;
The reason that this number grows so large is that it is a square relation; for a side of length n, you need an area of approximately half of n².

Categories