2012-12-18 9 views
10

Ich habe eine Frage bezüglich der Mathematik, die Apple in seinem speak here example verwendet.Die Mathematik hinter Apples Speak here Beispiel

Ein kleiner Hintergrund: Ich weiß, dass die durchschnittliche Leistung und Spitzenleistung von AVAudioRecorder und AVAudioPlayer in dB ist. Ich verstehe auch, warum die RMS-Leistung in dB ist und dass sie unter Verwendung von pow(10, (0.5 * avgPower)) in einen Verstärker umgewandelt werden muss.

Meine Frage Wesen:

Apple verwendet diese Formel ist es „Meter Table“

MeterTable::MeterTable(float inMinDecibels, size_t inTableSize, float inRoot) 
    : mMinDecibels(inMinDecibels), 
    mDecibelResolution(mMinDecibels/(inTableSize - 1)), 
    mScaleFactor(1./mDecibelResolution) 
{ 
    if (inMinDecibels >= 0.) 
    { 
     printf("MeterTable inMinDecibels must be negative"); 
     return; 
    } 

    mTable = (float*)malloc(inTableSize*sizeof(float)); 

    double minAmp = DbToAmp(inMinDecibels); 
    double ampRange = 1. - minAmp; 
    double invAmpRange = 1./ampRange; 

    double rroot = 1./inRoot; 
    for (size_t i = 0; i < inTableSize; ++i) { 
     double decibels = i * mDecibelResolution; 
     double amp = DbToAmp(decibels); 
     double adjAmp = (amp - minAmp) * invAmpRange; 
     mTable[i] = pow(adjAmp, rroot); 
    } 
} 

Was die Berechnungen sind alle zu schaffen - oder besser gesagt, was jeder dieser Schritte tun? Ich denke, dass mDecibelResolution und mScaleFactor verwendet werden, um 80dB Bereich über 400 Werte zu plotten (wenn ich mich nicht irre). Was ist jedoch die Bedeutung von , ampRange, invAmpRange und adjAmp? Warum ist der i-te Eintrag in der Zähler-Tabelle "mTable[i] = pow(adjAmp, rroot);"?

Jede Hilfe wird sehr geschätzt! :)

Vielen Dank im Voraus und Prost!

Antwort

8

Es ist ein Monat her, seit ich diese Frage gestellt habe, und danke, Geebs, für Ihre Antwort! :)

Also, das ist mit einem Projekt verbunden, an dem ich gearbeitet habe, und die Funktion, die darauf basiert, wurde etwa 2 Tage nach dem Stellen dieser Frage implementiert. Klar, ich habe nachgedacht eine abschließende Antwort zu posten (tut mir leid). Ich habe am 7. Januar auch einen Kommentar gepostet, aber ich kreise zurück, es scheint, als hätte ich eine Verwirrung mit var Namen. > _ <. Ich dachte, ich würde eine vollständige, zeilenweise Antwort auf diese Frage geben (mit Bildern).:)

So, hier geht:

//mDecibelResolution is the "weight" factor of each of the values in the meterTable. 
//Here, the table is of size 400, and we're looking at values 0 to 399. 
//Thus, the "weight" factor of each value is minValue/399. 


MeterTable::MeterTable(float inMinDecibels, size_t inTableSize, float inRoot) 
    : mMinDecibels(inMinDecibels), 
    mDecibelResolution(mMinDecibels/(inTableSize - 1)), 
    mScaleFactor(1./mDecibelResolution) 
{ 
    if (inMinDecibels >= 0.) 
    { 
     printf("MeterTable inMinDecibels must be negative"); 
     return; 
    } 

    //Allocate a table to store the 400 values 
    mTable = (float*)malloc(inTableSize*sizeof(float)); 

    //Remember, "dB" is a logarithmic scale. 
    //If we have a range of -160dB to 0dB, -80dB is NOT 50% power!!! 
    //We need to convert it to a linear scale. Thus, we do pow(10, (0.05 * dbValue)), as stated in my question. 

    double minAmp = DbToAmp(inMinDecibels); 

    //For the next couple of steps, you need to know linear interpolation. 
    //Again, remember that all calculations are on a LINEAR scale. 
    //Attached is an image of the basic linear interpolation formula, and some simple equation solving. 

Linear Interpolation Equation

//As per the image, and the following line, (y1 - y0) is the ampRange - 
    //where y1 = maxAmp and y0 = minAmp. 
    //In this case, maxAmp = 1amp, as our maxDB is 0dB - FYI: 0dB = 1amp. 
    //Thus, ampRange = (maxAmp - minAmp) = 1. - minAmp 
    double ampRange = 1. - minAmp; 

    //As you can see, invAmpRange is the extreme right hand side fraction on our image's "Step 3" 
    double invAmpRange = 1./ampRange; 

    //Now, if we were looking for different values of x0, x1, y0 or y1, simply substitute it in that equation and you're good to go. :) 
    //The only reason we were able to get rid of x0 was because our minInterpolatedValue was 0. 

    //I'll come to this later. 
    double rroot = 1./inRoot; 

    for (size_t i = 0; i < inTableSize; ++i) { 
     //Thus, for each entry in the table, multiply that entry with it's "weight" factor. 
     double decibels = i * mDecibelResolution; 

     //Convert the "weighted" value to amplitude using pow(10, (0.05 * decibelValue)); 
     double amp = DbToAmp(decibels); 

     //This is linear interpolation - based on our image, this is the same as "Step 3" of the image. 
     double adjAmp = (amp - minAmp) * invAmpRange; 

     //This is where inRoot and rroot come into picture. 
     //Linear interpolation gives you a "straight line" between 2 end-points. 
     //rroot = 0.5 
     //If I raise a variable, say myValue by 0.5, it is essentially taking the square root of myValue. 
     //So, instead of getting a "straight line" response, by storing the square root of the value, 
     //we get a curved response that is similar to the one drawn in the image (note: not to scale). 
     mTable[i] = pow(adjAmp, rroot); 
    } 
} 

Reaktionskurve Bild: Wie Sie sehen können, die "Linear-Kurve" ist nicht gerade eine Kurve. > _ < Square root response image

Hoffe das hilft der Gemeinde in irgendeiner Weise. :)

2

kein Experte, aber basierend auf Physik und Mathematik:

Angenommen, die maximale Amplitude 1 ist und mindestens 0,0001 [entsprechend -80 dB, was was min db Wert ist im Beispiel Apfel eingestellt ist: #define kMinDBvalue -80.0 in AQLevelMeter.h]

minAmp ist die minimale Amplitude = 0,0001 für dieses Beispiel

nun alles, was getan wird, um die Amplituden in Vielfachen der Auflösung Dezibel gegen die minimale Amplitude eingestellt werden:
eingestellte Amplitude = (Amp-Minamp)/(1-Minamp)
Dies macht den Bereich der eingestellten Amplitude = 0 zu 1 statt 0,0001 zu 1 (wenn das gewünscht wurde).

InRoot ist hier auf 2 gesetzt. Rroot = 1/2 - Anheben zur Macht 1/2 ist Quadratwurzel. aus der Apple-Datei:
// inRoot - dies steuert die Krümmung der Antwort. 2.0 ist Quadratwurzel, 3.0 ist Kubikwurzel. Aber inRoot muss nicht ganzzahlig sein, es könnte 1,8 oder 2,5 usw. sein.
Gibt im Wesentlichen eine Antwort zwischen 0 und 1 wieder, und die Krümmung davon hängt davon ab, welchen Wert Sie für inRoot setzen.

+0

Danke für Ihre Antwort! Also, wenn ich das richtig verstehe, ist adjAmp im Wesentlichen der linear interpolierte Wert für -80 bis 0, der auf einer Skala von 0 bis 1 gezeichnet wird, um sicherzustellen, dass wir nur 400 Werte (in diesem Beispiel) auftragen? Und dann macht Rroot es im Grunde "nicht linear", aber eher eine gekrümmte Antwort? Vielen Dank! – codeBearer

+0

Es ist falsch, eingestellte linear interpolierte Werte für -80db auf 0 zu setzen. Die linear interpolierten Werte sind für die Amplituden, die den Dezibelwerten entsprechen (mit einem Minimum bei -80). Die Umwandlung von Db zu Amp ist nicht linear (exponentiell). Die Amp-to-Adjusted Amp-Konvertierung ist eine lineare Interpolation. – Geebs

+0

Hallo. Nochmals vielen Dank für Ihre Antwort. Ja, ich verstehe die logarithmische v/s lineare Skala und warum es wichtig ist, auf linear zu zeichnen. Was ich bestätigen wollte, war die "Antwortkurve" und die Anpassung, aber es scheint, als ob ich mich zu sehr auf die "Bedeutung der Var-Namen" konzentriert hätte. > _ <. Aber, nochmals vielen Dank für Ihre Antwort. :) – codeBearer