Пример #1
0
        /// <summary>
        /// Create synthetic USB data frames.
        /// </summary>
        /// <param name="neuralSynthData">Neural waveforms.</param>
        /// <param name="EMGSynthData">EMG waveforms.</param>
        /// <param name="rawFrameBlock">Array for raw USB data.</param>
        /// <param name="dataRate">Data rate (High, Medium, or Low).</param>
        /// <param name="hammingDecoder">Hamming decoder object.</param>
        /// <param name="BER">Bit error rate (set to zero to disable).</param>
        private void USBDataFrameCreate(double[,] neuralSynthData, double[,] EMGSynthData, UInt16[] rawFrameBlock, DataRate dataRate, HammingDecoder hammingDecoder, double BER)
        {
            int    frame, i, channel, index, indexNeural;
            int    dataWord;
            Random myRand = new Random(unchecked ((int)DateTime.Now.Ticks));

            index       = 0;
            indexNeural = 0;
            for (frame = 0; frame < Constant.FramesPerBlock; frame++)
            {
                for (i = 0; i < Constant.NeuralSamplesPerFrame; i++)
                {
                    for (channel = Constant.MinNeuralChannel(dataRate); channel <= Constant.MaxNeuralChannel(dataRate); channel++)
                    {
                        dataWord = (int)((neuralSynthData[channel, indexNeural] / Constant.ADCStepNeural) + Constant.ADCOffset);
                        rawFrameBlock[index++] = hammingDecoder.EncodeData(dataWord, myRand, BER);
                    }
                    indexNeural++;
                }
                for (channel = 0; channel < Constant.TotalEMGChannels; channel++)
                {
                    dataWord = (int)((EMGSynthData[channel, frame] / Constant.ADCStepEMG) + Constant.ADCOffset);
                    rawFrameBlock[index++] = hammingDecoder.EncodeData(dataWord, myRand, BER);
                }
                dataWord = 0;   // AUX 1
                rawFrameBlock[index++] = hammingDecoder.EncodeData(dataWord, myRand, BER);

                dataWord = (int)(((1.8 + 0.1 * gaussian(myRand)) / Constant.ADCStepAux) + Constant.ADCOffset);
                rawFrameBlock[index++] = hammingDecoder.EncodeData(dataWord, myRand, BER);

                dataWord = 1536;   // Chip ID
                rawFrameBlock[index++] = hammingDecoder.EncodeData(dataWord, myRand, BER);

                dataWord = chipCounter;   // Chip Counter
                rawFrameBlock[index++] = hammingDecoder.EncodeData(dataWord, myRand, BER);

                dataWord = frameCounterLow;   // Frame Counter Low
                rawFrameBlock[index++] = hammingDecoder.EncodeData(dataWord, myRand, 0.0);

                dataWord = frameCounterHigh;   // Frame Counter High
                rawFrameBlock[index++] = hammingDecoder.EncodeData(dataWord, myRand, 0.0);

                dataWord = 960;   // Frame Timer Low (= 960)
                rawFrameBlock[index++] = hammingDecoder.EncodeData(dataWord, myRand, 0.0);

                dataWord = 0;   // Frame Timer High (= 960)
                rawFrameBlock[index++] = hammingDecoder.EncodeData(dataWord, myRand, 0.0);

                dataWord = 0;   // TTL Inputs
                rawFrameBlock[index++] = hammingDecoder.EncodeData(dataWord, myRand, 0.0);

                dataWord = 144;   // Frame Marker Correlation
                rawFrameBlock[index++] = hammingDecoder.EncodeData(dataWord, myRand, 0.0);

                if (dataRate == DataRate.Medium || dataRate == DataRate.Low)
                {
                    dataWord = 0;
                    rawFrameBlock[index++] = hammingDecoder.EncodeData(dataWord, myRand, 0.0);
                    rawFrameBlock[index++] = hammingDecoder.EncodeData(dataWord, myRand, 0.0);
                }

                chipCounter++;
                if (chipCounter > 2047)
                {
                    chipCounter = 0;
                }

                frameCounterLow++;
                if (frameCounterLow > 2047)
                {
                    frameCounterLow = 0;
                    frameCounterHigh++;
                    if (frameCounterHigh > 2047)
                    {
                        frameCounterHigh = 0;
                    }
                }
            }
        }
Пример #2
0
        /// <summary>
        /// USBData constructor.
        /// </summary>
        /// <param name="rawFrameBlock">Data block from USB interface.</param>
        /// <param name="dataRate">Data rate (Low, Medium, or High).</param>
        /// <param name="hammingDecoder">Hamming code decoder object.</param>
        public USBData(UInt16[] rawFrameBlock, DataRate dataRate, bool rawDataMode, HammingDecoder hammingDecoder)
        {
            int frame, channel, index, indexNeural, i;
            int numBitErrors;
            int bitErrorCount  = 0;
            int wordErrorCount = 0;

            int minNeuralChannel = Constant.MinNeuralChannel(dataRate);
            int maxNeuralChannel = Constant.MaxNeuralChannel(dataRate);
            int frameSize        = Constant.FrameSize(dataRate, rawDataMode);

            const double expectedFrameTimer = Constant.FPGAClockFreq * Constant.FramePeriod / 32.0; // = 960
            const int    maxFrameTimer      = (int)(expectedFrameTimer * 1.01);
            const int    minFrameTimer      = (int)(expectedFrameTimer / 1.01);

            missingFrameCount = 0;
            falseFrameCount   = 0;

            timeStampNanos = MainForm.GetAbsTimeNS();

            for (i = 0; i < frameSize * Constant.FramesPerBlock; i++)
            {
                rawData[i] = rawFrameBlock[i];
            }

            index       = 0;
            indexNeural = 0;
            double vOut;

            for (frame = 0; frame < Constant.FramesPerBlock; frame++)
            {
                for (i = 0; i < Constant.NeuralSamplesPerFrame; i++)
                {
                    for (channel = minNeuralChannel; channel <= maxNeuralChannel; channel++)
                    {
                        neuralData[channel, indexNeural + i] =
                            Constant.ADCStepNeural * ((neuralData16[channel, indexNeural + i] = hammingDecoder.DecodeDataCountErrors(rawFrameBlock[index], out numBitErrors, ref bitErrorCount, ref wordErrorCount)) - Constant.ADCOffset);
                        if (numBitErrors == 2 && (indexNeural + i) > 0)
                        {
                            neuralData[channel, indexNeural + i]   = neuralData[channel, indexNeural + i - 1];
                            neuralData16[channel, indexNeural + i] = neuralData16[channel, indexNeural + i - 1];
                        }
                        index++;
                    }
                    for (channel = 0; channel < minNeuralChannel; channel++)
                    {
                        neuralData[channel, indexNeural + i]   = 0.0;
                        neuralData16[channel, indexNeural + i] = (UInt16)Constant.ADCOffset;
                    }
                    for (channel = maxNeuralChannel + 1; channel < Constant.TotalNeuralChannels; channel++)
                    {
                        neuralData[channel, indexNeural + i]   = 0.0;
                        neuralData16[channel, indexNeural + i] = (UInt16)Constant.ADCOffset;
                    }
                }
                indexNeural += Constant.NeuralSamplesPerFrame;

                for (channel = 0; channel < Constant.TotalEMGChannels; channel++)
                {
                    EMGData[channel, frame] =
                        Constant.ADCStepEMG * ((EMGData16[channel, frame] = hammingDecoder.DecodeDataCountErrors(rawFrameBlock[index], out numBitErrors, ref bitErrorCount, ref wordErrorCount)) - Constant.ADCOffset);
                    if (numBitErrors == 2 && frame > 0)
                    {
                        EMGData[channel, frame]   = EMGData[channel, frame - 1];
                        EMGData16[channel, frame] = EMGData16[channel, frame - 1];
                    }
                    index++;
                }

                for (channel = 0; channel < Constant.TotalAuxChannels; channel++)
                {
                    vOut = Constant.ADCStep * (hammingDecoder.DecodeDataCountErrors(rawFrameBlock[index], out numBitErrors, ref bitErrorCount, ref wordErrorCount) - Constant.ADCOffset);

                    // Empirical equation modeling nonlinearity of auxiliary amplifier (see testing data, 6/25/11)
                    auxData[channel, frame] = 4.343 * vOut + 0.1 * Math.Exp(12.0 * (vOut - 0.82)) + 0.2 * Math.Exp(130.0 * (vOut - 1.0));

                    // Limit result to between 0 and 6.0 V
                    if (auxData[channel, frame] > 6.0)
                    {
                        auxData[channel, frame] = 6.0;
                    }
                    else if (auxData[channel, frame] < 0.0)
                    {
                        auxData[channel, frame] = 0.0;
                    }

                    if (numBitErrors == 2 && frame > 0)
                    {
                        auxData[channel, frame] = auxData[channel, frame - 1];
                    }

                    auxData16[channel, frame] = (UInt16)(auxData[channel, frame] / Constant.ADCStep + Constant.ADCOffset);

                    index++;
                }

                chipID[frame] = hammingDecoder.DecodeDataCountErrors(rawFrameBlock[index], out numBitErrors, ref bitErrorCount, ref wordErrorCount);
                index++;

                chipFrameCounter[frame] = hammingDecoder.DecodeDataCountErrors(rawFrameBlock[index], out numBitErrors, ref bitErrorCount, ref wordErrorCount);
                index++;

                boardFrameCounter[frame]      = hammingDecoder.DecodeData(rawFrameBlock[index++]) + 2048 * hammingDecoder.DecodeData(rawFrameBlock[index++]);
                boardFrameTimer[frame]        = hammingDecoder.DecodeData(rawFrameBlock[index++]) + 2048 * hammingDecoder.DecodeData(rawFrameBlock[index++]);
                TTLInputs[frame]              = hammingDecoder.DecodeData(rawFrameBlock[index++]);
                frameMarkerCorrelation[frame] = hammingDecoder.DecodeData(rawFrameBlock[index++]);

                if (dataRate == DataRate.Low || dataRate == DataRate.Medium)
                {
                    index += 2;
                }

                if (boardFrameTimer[frame] > maxFrameTimer)
                {
                    missingFrameCount++;
                }
                else if (boardFrameTimer[frame] < minFrameTimer)
                {
                    falseFrameCount++;
                }
            }

            BER = ((double)bitErrorCount) / ((double)(Constant.FramesPerBlock * Constant.BitsPerWord * (Constant.NeuralSamplesPerFrame * (maxNeuralChannel - minNeuralChannel + 1) + (Constant.TotalEMGChannels + Constant.TotalAuxChannels + 2))));
            WER = ((double)wordErrorCount) / ((double)(Constant.FramesPerBlock * (Constant.NeuralSamplesPerFrame * (maxNeuralChannel - minNeuralChannel + 1) + (Constant.TotalEMGChannels + Constant.TotalAuxChannels + 2))));
        }
Пример #3
0
        /// <summary>
        /// Check to see if there is at least 25 msec worth of data (40 frames) in the USB read buffer.
        /// </summary>
        /// <param name="plotQueue">Queue used for plotting data to screen.</param>
        /// <param name="saveQueue">Queue used for saving data to disk.</param>
        /// <param name="dataRate">Data rate (High, Medium, or Low).</param>
        /// <param name="hammingDecoder">Hamming decoder object.</param>
        /// <returns>Number of pages remaining in FPGA board RAM buffer.</returns>
        public int CheckForUSBData(Queue <USBData> plotQueue, Queue <USBData> saveQueue, DataRate dataRate, bool rawDataMode, HammingDecoder hammingDecoder)
        {
            bool haveEnoughData = false;
            int  i, numPagesInRAM, numPagesLeftInRAM, numBytesToRead, numBytesRead, indexUSB, indexFrame;
            int  word1, word2, word3, word4;
            int  pageThreshold = 20;

            numPagesLeftInRAM = 0;

            if (rawDataMode)
            {
                pageThreshold = 24;
            }
            else
            {
                switch (dataRate)
                {
                case DataRate.High:
                    pageThreshold = 20;
                    break;

                case DataRate.Medium:
                    pageThreshold = 11;
                    break;

                case DataRate.Low:
                    pageThreshold = 6;
                    break;
                }
            }

            if (synthDataMode)
            {
                if (newSynthDataReady)
                {
                    //HACK XXX TODO FIXME TESTING -- comment-in the following conditional to test the "no data from USB condition"
                    //long sec = System.DateTime.Now.Second;
                    //if ((sec / 4) % 2 == 0)
                    //{
                    haveEnoughData    = true;
                    newSynthDataReady = false;
                    //}
                }
            }
            else
            {
                myXEM.UpdateWireOuts();
                numPagesInRAM = (int)myXEM.GetWireOutValue(wireOutNumPages);
                //Debug.WriteLine("numPagesInRAM = " + numPagesInRAM);
                if (numPagesInRAM > pageThreshold)
                {
                    haveEnoughData = true;
                }
            }

            if (haveEnoughData)
            {
                USBData USBDataBlock;
                long    tsNow = MainForm.GetAbsTimeNS();

                if (synthDataMode)
                {
                    int    channel, j;
                    Random myRand = new Random(unchecked ((int)DateTime.Now.Ticks));

                    for (channel = 0; channel < Constant.TotalNeuralChannels; channel++)
                    {
                        for (i = 0; i < Constant.NeuralSamplesPerFrame * Constant.FramesPerBlock; i++)
                        {
                            neuralSynthData[channel, i] = synthSpikeOffset[channel] + 5.7 * gaussian(myRand);  // create realistic offset and background of 5.7 uV rms noise
                        }
                        i = 0;
                        while (i < Constant.NeuralSamplesPerFrame * Constant.FramesPerBlock - 52)   // 52 samples = 2 msec (refractory period)
                        {
                            if (myRand.NextDouble() < 0.01)
                            {
                                for (j = 0; j < synthSpikeWidth1[channel]; j++)
                                {
                                    neuralSynthData[channel, i + j] += (synthSpikeAmp1[channel] * Math.Exp(-1 * (double)j / 12.5) * Math.Sin(6.28 * (double)j / synthSpikeWidth1[channel]));
                                }
                                i += 40 + 52;    // advance by 2 msec (refractory period)
                            }
                            else if (myRand.NextDouble() < 0.02)
                            {
                                for (j = 0; j < synthSpikeWidth2[channel]; j++)
                                {
                                    neuralSynthData[channel, i + j] += (synthSpikeAmp2[channel] * Math.Exp(-1 * (double)j / 12.5) * Math.Sin(6.28 * (double)j / synthSpikeWidth2[channel]));
                                }
                                i += 40 + 52;    // advance by 2 msec (refractory period)
                            }
                            else
                            {
                                i += 26;    // advance by 1 msec
                            }
                        }
                    }

                    for (channel = 0; channel < Constant.TotalEMGChannels; channel++)
                    {
                        for (i = 0; i < Constant.FramesPerBlock; i++)
                        {
                            EMGSynthData[channel, i] = synthEMGOffset[channel] + 0.043 * gaussian(myRand);  // create realistic offset and background of 43 uV rms noise
                        }
                        i = 0;
                        while (i < Constant.FramesPerBlock - 10)   // 10 = max 'spike' width
                        {
                            if (myRand.NextDouble() < 0.004)
                            {
                                for (j = 0; j < synthEMGWidth1[channel]; j++)
                                {
                                    EMGSynthData[channel, i + j] += (synthEMGAmp1[channel] * Math.Exp(-1 * (double)j / 12.5) * Math.Sin(6.28 * (double)j / synthEMGWidth1[channel]));
                                }
                                i += 10 + 3;    // advance by 2 msec (refractory period)
                            }
                            else if (myRand.NextDouble() < 0.008)
                            {
                                for (j = 0; j < synthEMGWidth2[channel]; j++)
                                {
                                    EMGSynthData[channel, i + j] += (synthEMGAmp2[channel] * Math.Exp(-1 * (double)j / 12.5) * Math.Sin(6.28 * (double)j / synthEMGWidth2[channel]));
                                }
                                i += 10 + 3;    // advance by 2 msec (refractory period)
                            }
                            else
                            {
                                i += 2;    // advance by 1 msec
                            }
                        }
                    }

                    // USBDataBlock = new USBData(neuralSynthData, EMGSynthData);

                    USBDataFrameCreate(neuralSynthData, EMGSynthData, rawFrameBlock, dataRate, hammingDecoder, 0.001);
                    USBDataBlock      = new USBData(rawFrameBlock, dataRate, rawDataMode, hammingDecoder);
                    numPagesLeftInRAM = 1;
                }
                else
                {
                    numBytesToRead = (4 * Constant.FrameSize(dataRate, rawDataMode) / 3) * Constant.BytesPerWord * Constant.FramesPerBlock;
                    numBytesRead   = myXEM.ReadFromPipeOut(pipeOutData, numBytesToRead, USBBuf);

                    if (numBytesRead != numBytesToRead)
                    {
                        UsbException e = new UsbException("USB read error; not enough bytes read");
                        throw e;
                    }

                    if ((USBBuf[1] & 0xe0) != 0xe0) // USBBuf[1] = high byte of first word; should have the form 111xxxxx if we are in sync
                    {
                        Debug.WriteLine("Resync");

                        // Reset FIFOs
                        myXEM.SetWireInValue(wireInResetReadWrite, 0x04);
                        myXEM.UpdateWireIns();
                        myXEM.SetWireInValue(wireInResetReadWrite, 0x00);
                        myXEM.UpdateWireIns();

                        // Enable data transfers
                        myXEM.SetWireInValue(wireInResetReadWrite, 0x03); // read and write
                        myXEM.UpdateWireIns();

                        return(0);     // abandon corrupted frame; get out of here

                        // UsbException e = new UsbException("USB sync error");
                        // throw e;
                    }

                    indexUSB   = 0;
                    indexFrame = 0;
                    for (i = 0; i < (Constant.FrameSize(dataRate, rawDataMode) / 3) * Constant.FramesPerBlock; i++)
                    {
                        word1     = 256 * Convert.ToInt32(USBBuf[indexUSB + 1]) + Convert.ToInt32(USBBuf[indexUSB]);
                        indexUSB += 2;
                        word2     = 256 * Convert.ToInt32(USBBuf[indexUSB + 1]) + Convert.ToInt32(USBBuf[indexUSB]);
                        indexUSB += 2;
                        word3     = 256 * Convert.ToInt32(USBBuf[indexUSB + 1]) + Convert.ToInt32(USBBuf[indexUSB]);
                        indexUSB += 2;
                        word4     = 256 * Convert.ToInt32(USBBuf[indexUSB + 1]) + Convert.ToInt32(USBBuf[indexUSB]);
                        indexUSB += 2;

                        rawFrameBlock[indexFrame++] = Convert.ToUInt16(((word1 & 0x0f00) << 4) + (word2 & 0x0fff));
                        rawFrameBlock[indexFrame++] = Convert.ToUInt16(((word1 & 0x00f0) << 8) + (word3 & 0x0fff));
                        rawFrameBlock[indexFrame++] = Convert.ToUInt16(((word1 & 0x000f) << 12) + (word4 & 0x0fff));
                    }

                    USBDataBlock = new USBData(rawFrameBlock, dataRate, rawDataMode, hammingDecoder);

                    myXEM.UpdateWireOuts();
                    numPagesLeftInRAM = (int)myXEM.GetWireOutValue(wireOutNumPages);
                }

                if (dataJustStarted)
                {
                    USBDataBlock.InitNeuralFilterState(neuralState, neuralDelay1, neuralDelay2, neuralNotchDelay1, neuralNotchDelay2);
                    USBDataBlock.InitEMGFilterState(EMGState, EMGDelay1, EMGDelay2, EMGNotchDelay1, EMGNotchDelay2);
                    dataJustStarted = false;
                }

                if (enableHPF)
                {
                    USBDataBlock.NeuralFilterHPF(neuralState, fHPF, Constant.NeuralSampleRate);
                    USBDataBlock.EMGFilterHPF(EMGState, fHPF, Constant.EMGSampleRate);
                }

                if (enableNotch)
                {
                    USBDataBlock.NeuralFilterNotch(neuralDelay1, neuralDelay2, neuralNotchDelay1, neuralNotchDelay2, fNotch, Constant.NeuralSampleRate);
                    USBDataBlock.EMGFilterNotch(EMGDelay1, EMGDelay2, EMGNotchDelay1, EMGNotchDelay2, fNotch, Constant.EMGSampleRate);
                }

                USBDataBlock.timeStampNanos = tsNow;

                plotQueue.Enqueue(USBDataBlock);
                saveQueue.Enqueue(USBDataBlock);
            }

            return(numPagesLeftInRAM);
        }