سؤال

كتبت برنامج صغير موالفة لفون.
إلى مزيد من ضبط الأداء لا يقاس طلبي مع القرش وجدت أنني فقدان الكثير من الوقت في تعويم/SInt16 التحويلات.
لذا أعاد كتابة بعض أجزاء للالتفاف على التحويلات من خلال ما قبل حساب جداول البحث أن عودة "جاهزة للاستخدام" SInt16 العينات.هذا يعمل بشكل جيد حتى الآن.
حاليا أنا أحاول كتابة بعض الفلاتر و ADSR المغلف تنفيذ استخدام صحيح فقط الحساب ولكن يمكن استخدام بعض نصائح لمحبي كيفية أداء الضرب/الشعب دون يطفو.
أنا تستهدف في اي فون الكنسي شكل:

  • LPCM
  • 16-بت عدد صحيح عينات

ما هي الطرق الجيدة لتطبيق السعة إلى العينة النهائية دون استخدام تعويم ؟

تحرير:
الشيء الوحيد الذي اكتشفت حتى الآن هو أنني يمكن أن القسمة صلاحيات 2 من تحول بلدي العينة الحالية.

inBuffer[frame] = wavetable[i % cycleLengthInSamples] >> 4;

ولكن لا أستطيع التفكير في أي طريقة أنيقة لخلق سلس ADSR المغلف مع ذلك.

Edit2: شكرا على كل ما تبذلونه من إجابات كبيرة!
بلدي النهج الحالي:

  • جلب كل ADSR المغلف القيم إلى الإيجابية SInt16 مجموعة
  • تتضاعف مع القيمة الحالية من wavetable (تخزين وسيطة كما SInt32)
  • تحويل النتيجة من 16 إلى اليمين

يبدو أن هذا العمل :)

هل كانت مفيدة؟

المحلول

نقطة ثابتة جيدة ، لأنه في هذه الحالة أنت باستخدام 16 بت.أبسط طريقة هي ضرب من قبل قوة من 10 حسب الدقة التي تحتاج إليها.إذا كان يمكنك استخدام 32 بت رجات كمادة وسيطة ، يجب أن تكون قادرة على الحصول على كريمة الدقة.في نهاية يمكنك تحويل مرة أخرى إلى 16 بت الباحث التقريب أو اقتطاع كما كنت تفضل.

تحرير:تريد التحول إلى اليسار, إلى جعل القيم أكبر.متجر نتيجة التحول في نوع مع مزيد من الدقة (32 أو 64 بت اعتمادا على ما تحتاج إليه). بسيطة التحول لن تعمل إذا كنت تستخدم وقعت أنواع

احترس إذا كنت ضرب أو تقسيم اثنين من نقطة ثابتة الأرقام.ضرب الرياح حتى يتم (a*n) * (بن) و سوف تصل الرياح معبن^2 بدلا منبن.شعبة (أن) / (بن) وهو (a/b) بدلا من ((أn)/ب).لهذا السبب اقترحت استخدام صلاحيات 10, يجعل من السهل العثور على الأخطاء الخاصة بك إذا كنت لم تكن مألوفة مع نقطة ثابتة.

عند الانتهاء من الحسابات الخاصة بك ، يمكنك العودة إلى الحق في الحصول على العودة إلى 16 بت الباحث.إذا كنت ترغب في الحصول على الهوى ، يمكنك أيضا القيام التقريب قبل التحول.

أقترح عليك القيام ببعض القراءة إذا كنت مهتما حقا في تنفيذ كفاءة نقطة ثابتة. http://www.digitalsignallabs.com/fp.pdf

نصائح أخرى

إجابات هذا السؤال هي شاملة جدا من حيث التنفيذ.وهنا قليلا تفسير أكثر من رأيت هناك:

نهج واحد هو قوة جميع الأرقام الخاصة بك إلى مجموعة ، ويقول [-1.0,1.0).ثم تعيين هذه الأرقام في مجموعة [-2^15,(2^15)-1].فعلى سبيل المثال ،

Half = round(0.5*32768); //16384
Third = round((1.0/3.0)*32768); //10923

عندما ضرب هذين الرقمين تحصل

Temp = Half*Third; //178962432
Result = Temp/32768; //5461 = round(1.0/6.0)*32768

قسمة 32768 في السطر الأخير هو نقطة Patros حول يضاعف الحاجة إضافية زيادة الخطوة.هذا أكثر منطقية إذا كنت أكتب 2^ن القياس صراحة:

x1 = x1Float*(2^15);
x2 = x2Float*(2^15);
Temp = x1Float*x2Float*(2^15)*(2^15);
Result = Temp/(2^15); //get back to 2^N scaling

لذلك هذا هو الحساب.لتنفيذ, علما بأن ضرب اثنين من 16 بت الصحيحه يحتاج 32 بت نتيجة لذلك درجة الحرارة يجب أن تكون 32 بت.أيضا ، 32768 ليس قابل للتمثيل في 16-بت متغير, حتى يكون على بينة من أن المترجم جعل 32 بت immediates.و كما كنت قد لاحظت بالفعل ، يمكنك التحول إلى ضرب/قسمة القوى من 2 حتى تتمكن من كتابة

N = 15;
SInt16 x1 = round(x1Float * (1 << N));
SInt16 x2 = round(x2Float * (1 << N));
SInt32 Temp = x1*x2;
Result = (SInt16)(Temp >> N);
FloatResult = ((double)Result)/(1 << N);

ولكن لنفترض [-1,1) ليس الصحيح ؟ إذا كنت تفضل الحد من الأرقام الخاصة بك إلى [-4.0,4.0) ، يمكنك استخدام N = 13.ثم لديك 1 علامة بت, بت اثنين قبل ثنائي نقطة و 13 بعد.وتسمى هذه 1.15 3.13 نقطة ثابتة أنواع كسور على التوالي.يمكنك التجارة الدقة في الكسر على الإرتفاع.

جمع وطرح كسور أنواع يعمل بشكل جيد طالما كنت ابحث عن التشبع.من أجل تقسيم ، Patros قال: التوسع في الواقع يلغي.لذلك ما عليك القيام به

Quotient = (x1/x2) << N;

أو الحفاظ على الدقة

Quotient = (SInt16)(((SInt32)x1 << N)/x2); //x1 << N needs wide storage

ضرب و قسمة الأعداد الصحيحة يعمل بشكل طبيعي.على سبيل المثال, القسمة على 6 يمكنك ببساطة كتابة

Quotient = x1/6; //equivalent to x1Float*(2^15)/6, stays scaled

وفي حالة قسمة قوة 2 ،

Quotient = x1 >> 3; //divides by 8, can't do x1 << -3 as Patros pointed out

جمع وطرح الأعداد الصحيحة ، على الرغم من لا يعمل بسذاجة.يجب أن نرى أولا إذا كان العدد مناسب في x.نوع y ، وجعل ما يعادل نوع كسور و المضي قدما.

آمل أن يساعد هذا مع فكرة تبدو في المدونة في مسألة أخرى نظيفة تطبيقات.

إلقاء نظرة على هذه الصفحة التي توضح سريع الضرب الخوارزميات.

http://www.newton.dep.anl.gov/askasci/math99/math99199.htm

عموما أقول لك استخدام وقعت 16.16 نقطة ثابتة التمثيل.بحيث 32bit صحيح سوف وقعت 16bit جزء صحيح و 16bit جزء كسري.ثم أنا لا أعرف ما هي اللغة المستخدمة في اي فون التنمية (الهدف-C ربما؟), ولكن هذا المثال هو في C:

#include <stdint.h>

typedef fixed16q16_t int32_t ;
#define FIXED16Q16_SCALE 1 << 16 ;

fixed16q16_t mult16q16( fixed16q16_t a, fixed16q16_t b )
{
    return (a * b) / FIXED16Q16_SCALE ;
}

fixed16q16_t div16q16( fixed16q16_t a, fixed16q16_t b )
{
    return (a * FIXED16Q16_SCALE) / b ;
}

علما أن ما ورد أعلاه هو التبسيط التنفيذ ، و لا يوفر الحماية من تجاوز الحساب.على سبيل المثال في div16q16() لقد متعددة قبل تقسيم للحفاظ على الدقة ، ولكن اعتمادا على المعاملات العملية قد تجاوز.قد تستخدم 64 بت المتوسطة للتغلب على هذا.أيضا تقسيم دائما جولات أسفل لأنه يستخدم قسمة عدد صحيح.وهذا يعطي أفضل أداء ، ولكن قد تؤثر على دقة الحسابات التكرارية.إصلاحات بسيطة ولكن إضافة إلى النفقات العامة.

لاحظ أنه عند ضرب أو قسمة قوة ثابتة من اثنين ، معظم المجمعين بقعة تافهة الأمثل واستخدام التحول.ومع ذلك ج لا تحدد سلوك حق التحول من السلبية صحيح وقعت لذا يجب تركه مترجم إلى العمل من أجل السلامة وقابلية.YMV أيا كانت اللغة التي تستخدمها.

في OO اللغة ، fixed16q16_t الطبيعي أن يكون مرشحا عن فئة مع عامل الحمولة الزائدة بحيث يمكنك استخدامه مثل العادي والحساب نوع.

قد تجد أنه من المفيد تحويل بين أنواع:

double fixed16q16_to_double( fixed16q16_t fix )
{
    return (double)fix / FIXED16Q16_SCALE ;
}

int fixed16q16_to_int( fixed16q16_t fix )
{
    // Note this rounds to nearest rather than truncates
    return ((fix + FIXED16Q16_SCALE/2)) / FIXED16Q16_SCALE ;
}

fixed16q16_t int_to_fixed16q16( int i )
{
    return i * FIXED16Q16_SCALE ;
}

fixed16q16_t double_to_fixed16q16( double d )
{
    return (int)(d * FIXED16Q16_SCALE) ;
}

تلك هي الأساسيات ، فإنه من الممكن الحصول على أكثر تطورا إضافة حساب المثلثات وغيرها من وظائف الرياضيات.

ثابت الجمع والطرح يعمل مع المدمج في + و - مشغلي ومتغيراتها.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top