patternjavaMinor
Performance of speech enhancement code for Android app
Viewed 0 times
speechandroidappenhancementforperformancecode
Problem
I wrote a speech enhancement code for an Android App. The algorithm runs on 256 size frames of voice samples. On my PC the code runs per about 5ms per frame, while on my Nexsus 5 it more like 50ms per frame, making the speech enhancement on a 30sec long recording run for over two minutes. On my PC, enhancing the whole audio file takes under a minute. I am looking to improve run time anywhere I can. I am attaching the code that runs per frame which is where I see biggest increase in run time.
```
for(int j = 0; j < Consts.NUM_OF_CLUSTERS; j++)
{
tmp_log_h=0;
for(int k = 0; k < Consts.SIZE_OF_SEMPELS_IN_CHUNCK; k++)
{
f_X = (1/FastMath.sqrt(2FastMath.PIsigmaSqr.get(j).get(k)))FastMath.exp(-(FastMath.pow(NoisySignal[k] - mue.get(j).get(k),2))/(2sigmaSqr.get(j).get(k)));// equation (3)
F_X=(0.500 + 0.5Erf.erf((NoisySignal[k] - mue.get(j).get(k))/(FastMath.sqrt(2sigmaSqr.get(j).get(k)))));// equation (6)
if(j==0)
{
g_pdf_Y[k]=1/FastMath.sqrt(2FastMath.PINoise_sigmaSqr.get(k))FastMath.exp(-(FastMath.pow(NoisySignal[k] - Noise_mu.get(k),2))/(2Noise_sigmaSqr.get(k)));// equation (4)
G_cdf_Y[k]=(0.500 + 0.5Erf.erf((NoisySignal[k] - Noise_mu.get(k))/(FastMath.sqrt(2Noise_sigmaSqr.get(k)))));// equation (5)
}
tmp_R_samples = (f_X/F_X);// equation (12.5)
if(j==0)
{
R_noise[k]=g_pdf_Y[k]/G_cdf_Y[k]; // equation (12.5)
}
Roe[j][k] = 1/(1 + (R_noise[k]/tmp_R_samples));
X_hat[j][k] = NoisySignal[k]Roe[j][k]+ (mue.get(j).get(k))(1 - Roe[j][k]) - (sigmaSqr.get(j).get(k))((f_XR_noise[k])/(f_X + F_X*R_noise[k]));
tmp_h_first=(f_XG_cdf_Y[k] + F_Xg_pdf_Y[k]);// equation (7.5)
tmp_log_h += FastMath.log(tmp_h_first); // equation (7.5)
}
Log_h_second[j]=tmp_log_h;
Log_h_final_vecotr[j]=FastMath.log(c.get(j)) + Log_h_second[j];
}
Double maxVi = MathHelpers.findMax(Log_h_final_vecotr);
double
```
for(int j = 0; j < Consts.NUM_OF_CLUSTERS; j++)
{
tmp_log_h=0;
for(int k = 0; k < Consts.SIZE_OF_SEMPELS_IN_CHUNCK; k++)
{
f_X = (1/FastMath.sqrt(2FastMath.PIsigmaSqr.get(j).get(k)))FastMath.exp(-(FastMath.pow(NoisySignal[k] - mue.get(j).get(k),2))/(2sigmaSqr.get(j).get(k)));// equation (3)
F_X=(0.500 + 0.5Erf.erf((NoisySignal[k] - mue.get(j).get(k))/(FastMath.sqrt(2sigmaSqr.get(j).get(k)))));// equation (6)
if(j==0)
{
g_pdf_Y[k]=1/FastMath.sqrt(2FastMath.PINoise_sigmaSqr.get(k))FastMath.exp(-(FastMath.pow(NoisySignal[k] - Noise_mu.get(k),2))/(2Noise_sigmaSqr.get(k)));// equation (4)
G_cdf_Y[k]=(0.500 + 0.5Erf.erf((NoisySignal[k] - Noise_mu.get(k))/(FastMath.sqrt(2Noise_sigmaSqr.get(k)))));// equation (5)
}
tmp_R_samples = (f_X/F_X);// equation (12.5)
if(j==0)
{
R_noise[k]=g_pdf_Y[k]/G_cdf_Y[k]; // equation (12.5)
}
Roe[j][k] = 1/(1 + (R_noise[k]/tmp_R_samples));
X_hat[j][k] = NoisySignal[k]Roe[j][k]+ (mue.get(j).get(k))(1 - Roe[j][k]) - (sigmaSqr.get(j).get(k))((f_XR_noise[k])/(f_X + F_X*R_noise[k]));
tmp_h_first=(f_XG_cdf_Y[k] + F_Xg_pdf_Y[k]);// equation (7.5)
tmp_log_h += FastMath.log(tmp_h_first); // equation (7.5)
}
Log_h_second[j]=tmp_log_h;
Log_h_final_vecotr[j]=FastMath.log(c.get(j)) + Log_h_second[j];
}
Double maxVi = MathHelpers.findMax(Log_h_final_vecotr);
double
Solution
Performance
I cannot offer any mayor improvements, just some small things:
You should save results of a calculation or action instead of doing them over and over.
For example:
You could also move the calculation of
It will save you running through the loop once, you can profile it to see if it is worth the loss in readability.
Readability
Code Structure
I would probably pull out the
Function calls do cause an overhead, but I would still consider extracting some of the code to separate functions (this would make profiling the code easier).
Additional variables also cause a slight overhead, but some of your expressions are quite long and hard to grasp. You might consider adding intermediate variables with an expressive name saving a temporary state of the calculation. An alternative would be to use newlines to present the expressions in a better way.
Variable Names
I don't think that your variable names are very expressive. I'm not that deep into the topic, but I would guess that at least some of them can be improved upon.
Also, just using case to differentiate names is quite confusing (
Comments
I'm guessing that you have some kind of documentation to which your current comments refer. But without it, they are not that useful. It might be helpful to add this documentation (or a short excerpt) to the top.
Style
Please follow general style guidelines.
Misc
I cannot offer any mayor improvements, just some small things:
You should save results of a calculation or action instead of doing them over and over.
For example:
2FastMath.PI: this is not dependent on the loop variables, just save it in a variable (same goes for2sigmaSqr.get(j).get(k)which you are doing three times for every loop; andNoisySignal[k] - mue.get(j).get(k)which you are doing twice). These duplicate calculations are quite hard to catch in your code. If you write the equations on paper, it becomes easier to spot.
mue.get(j).get(k): you are doing this three times. I don't know whatmueis, but depending on the kind of list, it may be expensive (same goes forsigmaSqr.get(j).get(k))
You could also move the calculation of
X_estimate inside the previous j loop: for(int j = 0; j < Consts.NUM_OF_CLUSTERS; j++)
{
Log_q[j]=FastMath.log(c.get(j)) + Log_h_second[j] - Log_h_final;
q[j]=(FastMath.exp(Log_q[j]));// equation (10)
Double temp_X_estimate = 0.0;
for(int k = 0; k < Consts.SIZE_OF_SEMPELS_IN_CHUNCK; k++)
{
temp_X_estimate += (X_hat[j][k]*q[j]);
}
X_estimate[k]=temp_X_estimate;// equation (9)
}It will save you running through the loop once, you can profile it to see if it is worth the loss in readability.
Readability
Code Structure
I would probably pull out the
j==0 case in front of the loop. Keeping it in the loop is confusing and seems unnecessary.Function calls do cause an overhead, but I would still consider extracting some of the code to separate functions (this would make profiling the code easier).
Additional variables also cause a slight overhead, but some of your expressions are quite long and hard to grasp. You might consider adding intermediate variables with an expressive name saving a temporary state of the calculation. An alternative would be to use newlines to present the expressions in a better way.
Variable Names
I don't think that your variable names are very expressive. I'm not that deep into the topic, but I would guess that at least some of them can be improved upon.
Also, just using case to differentiate names is quite confusing (
f_X vs F_X).Comments
I'm guessing that you have some kind of documentation to which your current comments refer. But without it, they are not that useful. It might be helpful to add this documentation (or a short excerpt) to the top.
Style
Please follow general style guidelines.
- variable names start with a lowercase letter (this lets a reader easily see that it is a variable, not a class)
- declare variables where they are used (
tmp_log_hfor example is declared outside the loop, even though it is not needed there)
- use more spaces (for example, before and after
==,=,/,*, etc)
- in Java, camelCase is usually used instead of underscores (you do this sometimes (eg
maxViorsumExp, but mostly you use underscores)
Misc
- get rid of unnecessary brackets (for example
(X_hat[j][k]*q[j]),tmp_R_samples = (f_X/F_X), orf_X = (...); especially in the last example, the expression already has enough parentheses without the extra once :) )
Code Snippets
for(int j = 0; j < Consts.NUM_OF_CLUSTERS; j++)
{
Log_q[j]=FastMath.log(c.get(j)) + Log_h_second[j] - Log_h_final;
q[j]=(FastMath.exp(Log_q[j]));// equation (10)
Double temp_X_estimate = 0.0;
for(int k = 0; k < Consts.SIZE_OF_SEMPELS_IN_CHUNCK; k++)
{
temp_X_estimate += (X_hat[j][k]*q[j]);
}
X_estimate[k]=temp_X_estimate;// equation (9)
}Context
StackExchange Code Review Q#63181, answer score: 5
Revisions (0)
No revisions yet.