2016-10-28 1 views
0

Я пишу метод измерения частоты выборочной синусоидальной волны. Он занимает несколько большую 1D-матрицу (порядка 10^3 до 10^4 порядка порядка) и возвращает double. Вспомогательные методы также называются внутри тела метода, который проверяет, пересекает ли волна ноль. Вот пример того, что я написал:Есть ли более быстрый способ петли над массивом в безопасном режиме

public static double Hertz(float[] v, int n) { 
    int nZCros = 0 
    for (int i = 1; i < n; i++) { 
     if (IsZeroCrossing(v.Skip(i - 1).ToArray())) { 
      ++nZCros; 
     } 
    } 
    return (double)nZCros/2.0; 
} 
private static bool IsZeroCrossing(float[] v) { 
    bool cross; 
    //checks if the first two elements of the array are opposite sign or not 
    return cross; 
} 

Моя проблема заключается в том, что для запуска требуется 200-300 мс. Поэтому я решил попробовать использовать unsafe и указатели, как это,

public unsafe static double Hertz(float* v, int n) { 
    int nZCros = 0 
    for (int i = 1; i < n; i++) { 
     if (IsZeroCrossing(&v[i - 1])) { 
      ++nZCros; 
     } 
    } 
    return (double)nZCros/2.0; 
} 
private unsafe static bool IsZeroCrossing(float* v) { 
    bool cross; 
    //checks if the first two elements of the array are opposite sign or not 
    return cross; 
} 

, который работает в течение 2-4 мс.

Тем не менее, мне не очень удобно разбираться за пределами рекомендуемых границ. Есть ли способ достичь такой же скорости в безопасном контексте? И если этого не происходит, это лишает цель использования C#? Должен ли я действительно использовать C# для таких приложений обработки сигналов и научных реализаций?

Это всего лишь один из многих методов DSP, которые я пишу, которые принимают большой массив образцов в качестве входных данных. Но мне удалось понять, что есть проблема, потому что я случайно положил 48000 образцов вместо 4800, когда я тестировал этот метод, и потребовалось 20 секунд, чтобы вернуть значение.

спасибо.

ОБНОВЛЕНИЕ: Я попытался добавить Take(2) после Skip(i - 1) в прежнем фрагменте. Это снизило его до 90-100 мс, но вопрос все еще стоит.

+1

Я сильно подозреваю, что это не безопасное решение против небезопасности, которое меняет здесь; это 'v.Skip (i - 1) .ToArray()'. – adv12

+0

Я подозревал это. Итак, LINQ является виновником? – skwear

+0

Я бы сказал, что злоупотребление LINQ является виновником. Определенно, преобразование перечислимого в массив на каждой итерации будет намного дороже, чем просто передать массив со смещением. – adv12

ответ

3

Вам не нужно передавать копию элементов массива в IsZeroCrossing().

Вместо этого, просто передать эти два элемента, вы заинтересованы в:

private static bool IsZeroCrossing(float elem1, float elem2) 
{ 
    return elem1*elem2 < 0.0f; // Quick way to check if signs differ. 
} 

И называют это так:

if (IsZeroCrossing(v[i-1], v[i]) { 

Вполне возможно, что такой простой метод будет встраиваемыми для сборки релиза , делая его как можно быстрее.

+0

+1 Это хороший ответ, но он не доходит до самой большой проблемы, о которой я говорил. У меня есть другие методы, которые занимают остальную часть массива от смещения, а не только от первых двух элементов. – skwear

+3

@skwear, тогда в этих случаях передайте массив и смещение, как это предлагается в комментариях. – adv12

+0

Спасибо @ adv12. У меня есть довольно много рефакторинга. – skwear

Смежные вопросы