X-axis scaling from number value to time in C# - c#

I have a line graph where my x-axis shows ticks every 3000 data points. The frequency that I am working with is 10 Hz meaning 3000 data points translates to 3000/10 (300 seconds). Ultimately I would want to show it in minutes, so it should show 300/60 (5 minutes), 10, 15, 20, 25, and so on. Right now I am trying to find it on the properties of the chart but can't find it.

Do this:
var ticks = 3000;
var seconds = ticks / 10;
var minutes = TimeSpan.FromSeconds(seconds).TotalMinutes;

Related

Rounding datetime in c# - why does this solution work?

I want to round datetime objects in C# to the nearest minute. So if the datetime object has 1 minute, 29 seconds and 999 miliseconds it should be rounded to 1 minute. If it has 1 minute, 30 seconds and 0 miliseconds, it should be rounded to 2 minutes.
I implemented this solution which I found from internet:
var timespan = new TimeSpan(0, 0, 1, 0);
//timespan has a value of 1 minute because I want to round to the nearest minute
return new DateTime(((dateTime.Ticks + timespan.Ticks/2)/ timespan.Ticks)* timespan.Ticks);
I'm not sure about the last line. Why do we divide by 2? Why do we divide with timespan.Ticks and then multiply?
It's a lot used method of rounding to add half of desired precision and then cut the decimals. Examples:
Desired precision: 0.1 ( / 2 -> add 0.05 )
1.44 + 0.05 = 1.49 -> cut last -> 1.4
1.46 + 0.05 = 1.51 -> cut last -> 1.5
Desired precision: 0.01 ( / 2 -> add 0.005 )
1.443 + 0.005 = 1.448 -> cut last -> 1.44
1.465 + 0.005 = 1.470 -> cut last -> 1.47
Desired precision: 1minute -> add 0.5min or 30s or 30000 ticks* (assumed 1s = 1000 ticks). Unit doesn't matter as long as you keep units the same in all calculations.
1min 25s + 30s = 1min 55s -> cut -> 1min
1min 35s + 30s = 2min 05s -> cut -> 2min
So with datetime it's the same. In order to round by minute, you may add half a minute and then cut the rest away.
Ticks are one way of representing time. So just take the tick-count of a minute (new TimeSpan(0, 0, 1, 0)), divide it by two to get the half way and then add it to your time.
Now all you need to do is to cut the rest away and you can do it by diving your time with the precision (tick count of 1 minute). When you divide by 1 minute, everything that's smaller than a minute will be in decimals. Tick is an integer so it "forgets" all the decimals, thus cutting them away. Now all you need to do is make the value valid again by multiplying it with the same value you divided it with. Decimals are already lost at this point, so... TADAA: Rounded by minute.

how to calculate proportional ratio

First of all pardon me to raise this question here (not sure). Not good in maths so need help from others to understand how to calculate.
I have to calculate proportional ratio score. For doing that i am taking two input values
ValueA = 3
ValueB = 344.
To find the percentage of the proportional ratio ((ValueB-ValueA)/ValueA )*100)
that formula gives me the score 11366.6.
Now i have to match with proportional percentage against with following table,
no idea how to match with percentage
for example the score comes around 43.12 % then i will pick the value 5 (>40 -50)
% Ratio Score
0 0
≤10 1
>10 – 20 2
>20 – 30 3
>30 – 40 4
>40 – 50 5
>50 – 60 6
>60 – 70 7
>70 – 80 8
>80 – 90 9
>90 – 100 10
your formula is of (as you can see by the 11366.6 percentage) - it should be
100.0*(ValueB-ValueA)/(double)ValueB
this will give you values in between 0 and 100 percent if ValueB is always bigger than ValueA (if not use):
100.0*Math.Abs(ValueB - ValueA)/(double)Math.Max(ValueA, ValueB)
based on the table your score should than be simply:
var score = (int)Math.Ceiling(percentage / 10.0)
You should swap value a and value b of you get percentages bigger than 100. By the way, finding the proportional value is not unique and the formula you have provided is one way to do that. I guess Valuea/valueb is also a possibility for example.

Group users by age for a range

I have some data which i need to make some statistics. I need to group the users by age.
var byAge = displayResult.GroupBy(x => x.Age);
Which i can do as above. However, this gives me ages like 19, 20, 21 etc. what I want is grouping age by 10 years, such as
users between 10-20 yearsold, 20-30 years old, 30-40 years old etc.
How can i get that?
You can truncate the trailing digit by dividing by ten using integer division, and then multiplying back by ten.
var byAge = displayResult.GroupBy(x => 10*(x.Age/10));
Everyone between 0, inclusive, and 10, exclusive, will be in the bucket 0.
from 10 to 20 will be under the key 10, from 20 to 30 - under the key 20, and so on.

NAudio frequency band intensity

I have an audio player using NAudio and I would like to display a real time intensity for each frequency band.
I have an event triggered for each block of 1024 samples:
public void Update(Complex[] fftResults)
{
// ??
}
What i would like to have is an array of numbers indicating the intensity of each frequency band. Lets say I would like to divide the window into 16 bands.
For example when there are more bass frequencies it could look like this:
░░░░░░░░░░░░░░░░
▓▓▓░░░░░░░░░░░░░
▓▓▓░░░░░░░░░░░░░
▓▓▓▓░░░░░░░░░░░░
▓▓▓▓▓░░░░░░░░░░░
▓▓▓▓▓▓▓▓░░░▓░░▓░
What should I put into that event handler if this is possible with that data?
Data coming (Complex[]) has already been transformed with the FFT.
It is a stereo stream.
First try:
double[] bandIntensity = new double[16] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
public void Update(Complex[] fftResults)
{
// using half fftResults because the others are just mirrored
int band = 0;
for (int n = 0; n < fftResults.Length/2; n++)
{
band = (int)(.5 * n / fftResults.Length * bandIntensity.Length);
bandIntensity[band] += Math.Sqrt(fftResults[n].X * fftResults[n].X + fftResults[n].Y * fftResults[n].Y);
bandIntensity[band] /= 2;
}
}
The above is doing something but I think too much goes into the first two bands, and I'm playing shakira which does not have that much bass.
Thanks!
There are two separate issues that you probably want to address here:
(1) Window Function
You need to apply a window function to your data prior to the FFT, otherwise you will get spectral leakage which will results in a very smeared spectrum. One unpleasant side effect of spectral leakage is that if you have any kind of significant DC (0 Hz) component then this will result in the kind of 1/f shape that you are seeing on your bar graph.
(2) Log amplitude/frequency axes
Human hearing is essentially logarithmic in both the intensity and frequency axes. Not only that, but speech and music tend to have more energy in the lower frequency part of the spectrum. To get a more pleasing and meaningful display of intensity versus frequency we usually make both the magnitude and frequency axes logarithmic. In the case of the magnitude axis this is normally taken care of by plotting dB re full scale, i.e.
magnitude_dB = 10 * log10(magnitude);
In the case of the frequency axis you will probably want to group your bins into bands, which might each be an octave (2:1 frequency range), or more commonly for higher resolution, third octave. So if you just want 10 "bars" then you might use the following octave bands:
25 - 50 Hz
50 - 100 Hz
100 - 200 Hz
200 - 400 Hz
400 - 800 Hz
800 - 1600 Hz
1600 - 3200 Hz
3200 - 6400 Hz
6400 - 12800 Hz
12800 - 20000 Hz
(assuming you have a 44.1 kHz sample rate and an upper limit on your audio input hardware of 20 kHz).
Note that while having a magnitude (dB) intensity scale is pretty much mandatory for this kind of application, the log frequency axis is less critical, so you could try with your existing linear binning for now, and just see what effect you get from applying a window function in the time domain (assuming you don't already have one) and converting the magnitude scale to dB.

Increment, decrement by percentage

I'll try to explain this problem the best way i can with code:
double power = 5000;
//picked up 5 power ups, now need to increase power by 10% per powerup
power += 5 * (power * .10);
//later on...ran into 5 power downs need to decrease power back to initial hp
power -= 5 * (power * .10);//7500 - 3750 -- doesn't work
So what i need is a scaleable solution that gets back to the original value using only the count. Any ideas?
The best way to do this is using a function. It doesn't have to look exactly like this, but:
class Whatever
{
private double basePower = 5000;
public int numPowerUps = 5;
public double GetActualPower()
{
return basePower + (numPowerUps * basePower * 0.1);
}
}
Just change numPowerUps back to 0 when they run out. This way, it looks a whole lot neater.
An aside:
The reason it's not working is because of the fact that adding and then subtracting percentages doesn't work. For instance:
1. What is 10% of 100? --> 10
2. Add that to the 100 --> 110
3. What is 10% of 110? --> 11
4. Subtract that from 110 --> 99
You'll always end up with 99% of your original value. If you really want to take a shortcut, you could instead do this:
1. What is 10% of 100? --> 10
2. Add that to the 100 --> 110
3. What is (100/11) = 9.09090909...% of 110? --> 10
4. Subtract that from 110 --> 100
But then you're potentially susceptible to floating point errors. The function way of doing it is not only neater and clearer, but potentially less error-prone.
To reverse a %age increase, you must divide by the original %age, not subtract.
i.e.:
100 + 5% = 100 * 1.05 = 105
to reverse it:
105 / 1.05 = 100
The more usual '5% off' formula would instead give you:
105 - 5% = (105 * 0.95) = 99.75
To power up:
power <- power * (1 + count * percent);
eg: 5000 * (1 + 5 * 0.1)
5000 * 1.5
7500
To power back down:
power <- power / (1 + count * percent)
eg: 7500 / (1 + 5 * 0.1)
7500 / 1.5
5000
Let's take a more complicated example, 17 power ups, each giving 3% to an intial 1234 power:
1234 * (1 + 17 * 0.3)
= 1234 * (1 + 5.1)
= 1234 * 6.1
= 7527.4
7527.4 / (1 + 17 * 0.3)
= 7527.4 / (1 + 5.1)
= 7527.4 / 6.1
= 1234
It actually looks pretty simple when you write it out like that.
This doesn't work because the two percentages are not taken from the same number. They're taken from the same variable, but not the same number.
The first time, power * 0.10 is 500, and 5*500=2500 so the power will be 5000+2500=7500. Now, the power is 7500, so power * 0.10 is 750. 5*750 = 3750 and 7500-3750=3750 and not 5000 like you started out with.
So apparently, what you want is not really to in/decrease by a percentage of the current power. Perhaps it would be better to set a base power (let's say 5000) and an actual power. Then when you in/decrease, you use actualPower = actualPower + 5*0.1*basePower; or something. Or you just accept that five power downs after five power ups does not get you back to initial hp.
I'm going to suspect that what you mean by "doesn't work" is that the value for power does not end up to be exactly 3750.
This is due to floating-point rounding errors, as floating point values such as double and float are not able to be represented exact values.
If exact values are needed, then using decimal or int would be a better solution, as they are designed to handle exact values.
Edit The actual issue here is not a floating-point rounding error, but an issue noted in Smashery's answer.

Categories

Resources