2012-12-18 42 views
10

Tôi có một câu hỏi liên quan đến phép toán mà Apple đang sử dụng ở đây là speak here example.Toán học đằng sau ví dụ của Apple Nói ở đây, ví dụ

Một nền tảng nhỏ: Tôi biết rằng công suất trung bình và công suất đỉnh được trả về bởi AVAudioRecorder và AVAudioPlayer bằng dB. Tôi cũng hiểu tại sao điện RMS bằng dB và nó cần phải được chuyển đổi thành amp sử dụng pow(10, (0.5 * avgPower)).

tôi câu hỏi hạnh phúc:

Apple sử dụng công thức này để tạo ra nó "Meter Bảng"

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

gì được tất cả các tính toán - hay đúng hơn, điều gì làm từng bước làm gì? Tôi nghĩ rằng mDecibelResolutionmScaleFactor được sử dụng để vẽ phạm vi 80dB trên 400 giá trị (trừ khi tôi bị nhầm lẫn). Tuy nhiên, ý nghĩa của inRoot, ampRange, invAmpRangeadjAmp là gì? Ngoài ra, tại sao mục nhập thứ i trong bảng đồng hồ "mTable[i] = pow(adjAmp, rroot);"?

Bất kỳ trợ giúp nào được đánh giá cao! :)

Cảm ơn trước và chúc mừng!

Trả lời

8

Đã một tháng kể từ khi tôi hỏi câu hỏi này và cảm ơn, Geebs, về câu trả lời của bạn! :)

Vì vậy, điều này liên quan đến một dự án mà tôi đã làm việc và tính năng dựa trên điều này đã được triển khai khoảng 2 ngày sau khi đặt câu hỏi đó. Rõ ràng, tôi đã giảm đi khi đăng một câu trả lời cuối cùng (xin lỗi về điều đó). Tôi cũng đã đăng một bình luận vào ngày 7 tháng 1, nhưng quay lại, có vẻ như tôi đã nhầm lẫn với các tên var. > _ <. Nghĩ rằng tôi sẽ trả lời đầy đủ, từng dòng một cho câu hỏi này (với hình ảnh).:)

Vì vậy, ở đây đi:

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

đáp ứng hình ảnh Curve: Như bạn có thể thấy, "đường cong tuyến tính" là không chính xác một đường cong. > _ < Square root response image

Hy vọng điều này sẽ giúp cộng đồng theo một cách nào đó. :)

2

Không chuyên gia, nhưng dựa trên vật lý và toán học:

Giả sử biên độ tối đa là 1 và tối thiểu là 0,0001 [tương ứng với -80db, đó là những gì tối thiểu giá trị db được thiết lập để trong ví dụ táo: #define kMinDBvalue -80,0 trong AQLevelMeter.h]

minAmp là biên độ tối thiểu = 0,0001 ví dụ này

Bây giờ, tất cả những gì đang được thực hiện là biên độ trong bội số của độ phân giải decibel đang được điều chỉnh so với biên độ tối thiểu:
biên độ được điều chỉnh = (amp-minamp)/(1-minamp)
Điều này làm cho phạm vi biên độ được điều chỉnh = 0 đến 1 thay vì 0,0001 đến 1 (nếu điều đó là mong muốn).

inRoot được đặt thành 2 tại đây. rroot = 1/2 - nâng lên 1/2 là căn bậc hai. từ tệp của apple:
// inRoot - điều khiển độ cong của phản hồi. 2.0 là căn bậc hai, 3.0 là gốc khối. Nhưng inRoot không phải là số nguyên có giá trị, nó có thể là 1,8 hoặc 2,5, v.v.
Về cơ bản cung cấp cho bạn phản hồi từ 0 đến 1, và độ cong thay đổi dựa trên giá trị bạn đặt cho inRoot.

+0

Cảm ơn bạn đã phản hồi! Vì vậy, nếu tôi hiểu điều này một cách chính xác, là adjAmp về cơ bản giá trị nội suy tuyến tính cho -80 đến 0 được vẽ trên thang tỷ lệ 0 đến 1, đảm bảo rằng chúng ta chỉ vẽ 400 giá trị (trong ví dụ này)? Và sau đó rroot về cơ bản làm cho nó "phi tuyến tính", nhưng nhiều hơn một phản ứng cong? Cảm ơn! – codeBearer

+0

Việc gọi các giá trị nội suy tuyến tính được điều chỉnh bằng amp là -80db đến 0. Các giá trị nội suy tuyến tính là cho các biên độ tương ứng với các giá trị decibel (với tối thiểu là -80). db để chuyển đổi amp không phải là tuyến tính (nó là theo cấp số nhân). amp để điều chỉnh amp chuyển đổi là nội suy tuyến tính. – Geebs

+0

Xin chào. Cảm ơn một lần nữa cho phản ứng của bạn. Vâng, tôi hiểu về thang log v/s tuyến tính, và tại sao nó cần thiết để vẽ trên tuyến tính. Những gì tôi muốn xác nhận, là "đường cong phản ứng" và điều chỉnh, nhưng có vẻ như tôi đã tập trung nhiều vào "ý nghĩa của tên var". > _ <. Nhưng, cảm ơn một lần nữa vì phản ứng của bạn. :) – codeBearer