2014-11-11 9 views
2

Я никогда не использовал указатели раньше, и теперь мне нужно, и хотя я их прочитал, я до сих пор не знаю, как их использовать! Я использую сторонний продукт (Mitov Signal Lab), и я использую элемент управления, в котором есть событие, которое позволит мне перехватить данные. Когда я вхожу в событие, у меня есть доступ к «args», и один из операторов возвращает указатель. Теперь это указывает на буфер из 4096 двойных значений (один - действительное число, а следующее - воображаемое число и т. Д.). Так что это код:C# указатели на указатели

private void genericComplex1_ProcessData(object Sender, Mitov.SignalLab.ProcessComplexNotifyArgs Args) 
    { 
     unsafe 
     { 
     IntPtr pointer = Args.InBuffer.Read(); 

     // now what???? I want to get each double value, do some calculations on them 
     // and return them to the buffer. 
     } 
     args.sendOutPutData = true; 
    } 

Я предполагаю, что мне нужно присвоить указатель на Args.InBuffer.Read() Но я попробовал несколько примеров, я видел, и я просто получаю ошибки. Я использую visual studio 2010, и я компилирую с/unsafe. Вот обновление. Существуют дополнительные методы, такие как Args.Inbuffer.Write() и Args.Inbuffer.Modify(), но я до сих пор не могу понять, как обращаться к отдельным компонентам буфера.

Хорошо, вот подробности. Я использовал Marshall.copy. Вот код:

private void genericComplex1_ProcessData(object Sender, Mitov.SignalLab.ProcessComplexNotifyArgs Args) 
    { 
     //used to generate a phase corrected Q signal 
     //equations: 
     // real = real 
     // imaginary = (1 + amplitudeimbalance)(real*cos(phaseImbalance) + imaginary*sin(phaseImbalance) 
     //but amplitude imbalance is already corrected therefore 

     //imaginary = real * cos(phaseCorrection) + imaginary*sin(phaseCorrection) 

     double real; 
     double imaginary; 
     double newImaginary; 

     var bufferSize = Convert.ToInt32(Args.InBuffer.GetSize()); 

     Mitov.SignalLab.ComplexBuffer ComplexDataBuffer = new Mitov.SignalLab.ComplexBuffer(bufferSize); 
     ComplexDataBuffer.Zero(); 

     IntPtr pointer = Args.InBuffer.Read(); 
     IntPtr pointer2 = ComplexDataBuffer.Write(); 

     var data = new double[8192]; 

     Marshal.Copy(pointer, data, 0, 8192); 

     for (int i = 0; i < 8192; i+=2) 
     { 
      data[i] = data[i]; 
      data[i + 1] = data[i] * Math.Cos(phaseCorrection) + data[i+1] * Math.Sin(phaseCorrection); 
     } 

     Marshal.Copy(data, 0, pointer2, 8192); 

     Args.SendOutputData = false; 
     genericComplex1.SendData(ComplexDataBuffer); 

    } 

Теперь это не работает. Причина в том, что это занимает слишком много времени. Я отбираю звук со звуковой карты со скоростью 192 000 выборок в секунду. Событие выше срабатывает каждый раз, когда имеется доступный буфер 4096. Таким образом, каждые 20 миллисекунд поступает новый буфер. Затем этот буфер отправляется в процедуру быстрого преобразования Фурье, которая создает график силы сигнала по частоте. Мнимые данные фактически совпадают с реальными данными, но сдвинуты по фазе на 90 градусов. Так оно и есть в совершенном мире. Однако фаза никогда не бывает на 90 градусов из-за дисбаланса в сигнале, разных электронных дорожек, разного кода и т. Д. Таким образом, необходим поправочный коэффициент, и это то, что делают уравнения. Теперь, если я заменю

data[i] = data[i]; 
data[i + 1] = data[i] * Math.Cos(phaseCorrection) + data[i+1] * Math.Sin(phaseCorrection); 

с

data[i] = data[i]; 
data[i+1] = data[i+1]; 

он работает нормально.
Так что мне понадобятся указатели. Но будет ли это значительно быстрее или функции sin и cosine просто затянутся слишком долго? Cn Я отправляю данные непосредственно на процессор (теперь это становится небезопасным!).

+3

Этот метод 'Read' действительно возвращает' IntPtr' или указатель, потому что это не одно и то же? – jmcilhinney

+0

Привет, Да, это IntPtr – Tom

+0

@ Посмотрите мой обновленный ответ на аспекты производительности. –

ответ

2

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

using System.Runtime.InteropServices; 
// ... 

var data = new double[4096]; 
Marshal.Copy(pointer, data, 0, 4096); 
// process data here 

И насколько я понимаю, unsafe контекста не требуется для эта часть кода.

Что касается записи данных обратно на самом деле это совсем то же самое, но заказать внимание параметры:

// finished processing, copying data back 
Marshal.Copy(data, 0, pointer, 4096); 

Что касается ваших последних заметок на perfprmance. Как я уже упоминал, переместите var data = new double[8192]; в член класса data и инициализируйте его в конструкторе класса, поэтому он не выделяется каждый раз (и распределение выполняется довольно медленно). Вы можете сделать Math.Cos(phaseCorrection) вне цикла с phaseCorrection не изменилось, то же самое для Math.Sin(phaseCorrection) конечно. Что-то вроде этого:

Marshal.Copy(pointer, this.data, 0, 8192); 

var cosCache = Math.Cos(phaseCorrection); 
var sinCache = Math.Sin(phaseCorrection); 
for (int i = 0; i < 8192; i+=2) 
{ 
    data[i] = data[i]; 
    data[i + 1] = data[i] * cosCache + data[i+1] * sinCache; 
} 

Marshal.Copy(this.data, 0, pointer2, 8192); 

Все это должно значительно ускорить работу.

+0

Привет, Хорошо, что работает, чтобы получить данные, но как же вернуть их в исходный буфер? – Tom

+0

«Вы не можете получить доступ к неуправляемым данным напрямую». Это совсем не так. Вы можете поместить в память все, что вам нравится, в «небезопасном» контексте. –

+0

@JimMischel Согласен. Я сделал редактирование, поэтому ясно, что это ограничение безопасного контекста. –

1

Если у вас есть , вы можете получить указатель.Используя ваш пример:

unsafe 
    { 
    IntPtr pointer = Args.InBuffer.Read(); 

    // create a pointer to a double 
    double* pd = (double*)pointer.ToPointer(); 

    // Now you can access *pd 
    double firstDouble = *pd; 
    pd++; // moves to the next double in the memory block 
    double secondDouble = *pd; 

    // etc. 
    } 

Теперь, если вы хотите поместить данные обратно в массив, это то же самое:

double* pd = (double*)pointer.ToPointer(); 
*pd = 3.14; 
++pd; 
*pd = 42.424242; 

Вы должны прочитать и понять Unsafe Code and Pointers. Будьте очень осторожны с этим; вы программируете без защитной сетки.

+0

спасибо, я знаю, как это сделать. Как оказалось, это не нужно. Я в безопасности! – Tom

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