after profiling a lot I found out that this method takes up most of the % of calculation time. I don't really see a way to optimize, since it is a horrible function. (it is...) Maybe someone can show me some nice idea or so?
public static double perceivedLoudness(double L_G, double L_ETQ, double a0) {
double t1 = 1d + 1 / 4d * Math.pow(10d, 0.1d * (L_G - a0 - L_ETQ));
double t2 = Math.pow(t1, 0.25);
return 0.064d * Math.pow(10, 0.025 * L_ETQ) * (t2 - 1);
}
Here is the improved version:
public static double perceivedLoudness(double L_G, double L_ETQ, double a0) {
double x = L_G - a0 - L_ETQ;
double t1 = 0.25 * Math.exp(0.230259 * x) + 1;
double t2 = Math.sqrt(Math.sqrt(t1));
return ltqFactors[(int)L_ETQ] * (t2 - 1);
}
The lookup for ltqFactors goes this way. ltqValues hold 20 points from the given ltq function, that approx should be sufficiant.
for( int i = 0; i < etqValues.length; ++i) {
ltqFactors[(int)etqValues[i]] = 0.064d * Math.exp(etqValues[i] * 0.05756462732485114210d);
}
Edit: After more test runs with more files, I come up to a ~100% speed up:
Thank you so far!
Edit2: I don't know which answer to accept. :( With some other improvements (mostly lookup tables) the processing time for 9000 sound files went down from 4:30min to 3:28min.
I will keep this question open to see if there are other ideas, but then accept one answer.
Edit: I'm kind of frustrated now. I use a JFace treeviewer to let the user browse the results, and it need more time to update than the calculations itself. :/
Mathematically speaking, optimization is the minimization or maximization of a function subject to constraints on its variables.
Your function seems to be analytic, I would suggest replacing it entirely with an interpolation method. This way, you reduce the expensive calls to Math.Pow
to a few arithmetical operations.
The best in this case should be rational function approximation. Your function is likely to have poles in the complex plane, this usually defeats polynomial interpolation.
Note that you have two variables: L_G - a0 - L_ETQ
and L_ETQ
. Interpolation should be performed in one variable only.
I'd go for rational function approximation of t2
as a function of L_G - a0 - L_ETQ
. Take a look at Numerical Recipes for implementation techniques.
Also, for the last part, replace
Math.pow(10, 0.025 * L_ETQ);
by
Math.exp(L_ETQ * 0.05756462732485114210d)
(which is exp(L_ETQ * 0.025 * log(10))
).
So you should be fine with a handful of arithmetical operations and one exponential.
EDIT:
See a graph of t2
as a function of L_G - a0 - L_ETQ
.
EDIT: Replace
double t1 = 1d + 1 / 4d * Math.pow(10d, 0.1d * (L_G - a0 - L_ETQ));
double t2 = Math.pow(t1, 0.25);
by
double x = L_G - a0 - L_ETQ;
double t1 = 0.25 * Math.exp(0.230259 * x) + 1;
double t2 = Math.sqrt(Math.sqrt(t1));
and you should gain some more %. At this point, rational approximation may be overengineering: you have two exp, and two sqrt.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With