//FIXME: we really shouldn't be needing the freqcomp mode in here
        internal SmartScopeHeader(byte[] data)
        {
            int headerSize = SmartScope.AcquisitionRegisters.Length + SmartScope.DumpRegisters.Length + (int)Math.Ceiling(SmartScope.AcquisitionStrobes.Length / 8.0);
            raw = new byte[headerSize];
            if (data[0] != 'L' || data[1] != 'N')
                throw new Exception("Invalid magic number, can't parse header");

            int headerOffset = data[2];
            Array.Copy(data, headerOffset, raw, 0, headerSize);

            BytesPerBurst = data[3];
            NumberOfPayloadBursts = data[4] + (data[5] << 8);

            PackageOffset = (short)(data[6] + (data[7] << 8));

            ViewportLength = (int)(BytesPerBurst / Channels) << GetRegister(REG.VIEW_BURSTS);

            AcquisitionDepth = (uint)(2048 << GetRegister(REG.ACQUISITION_DEPTH));
            Samples = NumberOfPayloadBursts * BytesPerBurst / Channels;
            Acquiring       = Utils.IsBitSet(data[10], 0);
            OverviewBuffer  = Utils.IsBitSet(data[10], 1);
            LastAcquisition = Utils.IsBitSet(data[10], 2);
            Rolling         = Utils.IsBitSet(data[10], 3);
            TimedOut        = Utils.IsBitSet(data[10], 4);
            AwaitingTrigger = Utils.IsBitSet(data[10], 5);
            Armed           = Utils.IsBitSet(data[10], 6);
            FullAcquisitionDump = Utils.IsBitSet(data[10], 7);

            AnalogTrigger = new AnalogTriggerValue()
            {
                channel = AnalogChannel.List.First(x => x.Value ==  ((GetRegister(REG.TRIGGER_MODE) >> 2) & 0x03)),
                direction = (TriggerDirection)((GetRegister(REG.TRIGGER_MODE) >> 4) & 0x03),
            };
            ChannelSacrificedForLogicAnalyser = GetStrobe(STR.LA_CHANNEL) ? AnalogChannel.ChB : AnalogChannel.ChA;
            LogicAnalyserEnabled = GetStrobe(STR.LA_ENABLE);

            AcquisitionId = data[11];
            SamplePeriod = SmartScope.BASE_SAMPLE_PERIOD * Math.Pow(2, GetRegister(REG.INPUT_DECIMATION));
            ViewportSamplePeriod = SmartScope.BASE_SAMPLE_PERIOD * Math.Pow(2, GetRegister(REG.INPUT_DECIMATION) + GetRegister(REG.VIEW_DECIMATION));

            ViewportOffset = SamplePeriod * (
                GetRegister(REG.VIEW_OFFSET_B0) +
                (GetRegister(REG.VIEW_OFFSET_B1) << 8) +
                (GetRegister(REG.VIEW_OFFSET_B2) << 16)
                );

            int viewportExcessiveSamples = GetRegister(REG.VIEW_EXCESS_B0) + (GetRegister(REG.VIEW_EXCESS_B1) << 8);
            ViewportExcess = viewportExcessiveSamples * SamplePeriod;

            Int64 holdoffSamples = GetRegister(REG.TRIGGERHOLDOFF_B0) +
                                    (GetRegister(REG.TRIGGERHOLDOFF_B1) << 8) +
                                    (GetRegister(REG.TRIGGERHOLDOFF_B2) << 16) +
                                    (GetRegister(REG.TRIGGERHOLDOFF_B3) << 24) - SmartScope.TriggerDelay(TriggerMode, GetRegister(REG.TRIGGER_WIDTH), GetRegister(REG.INPUT_DECIMATION));
            TriggerHoldoff = holdoffSamples * (SmartScope.BASE_SAMPLE_PERIOD * Math.Pow(2, GetRegister(REG.INPUT_DECIMATION)));
        }
Example #2
0
        private static bool DoTriggerAnalog(float [] wave, AnalogTriggerValue trigger, int holdoff, float threshold, uint width, uint outputWaveLength, out int triggerIndex)
        {
            //Hold off:
            // - if positive, start looking for trigger at that index, so we are sure to have that many samples before the trigger
            // - if negative, start looking at index 0
            triggerIndex = 0;
            float invertor             = (trigger.direction == TriggerDirection.RISING) ? 1f : -1f;
            uint  halfWidth            = width / 2;
            uint  preconditionCounter  = 0;
            uint  postconditionCounter = 0;

            for (int i = Math.Max(0, holdoff); i < wave.Length - width - outputWaveLength; i++)
            {
                bool preconditionMet = preconditionCounter == halfWidth;
                if (preconditionMet)
                {
                    if (invertor * wave[i] >= invertor * trigger.level + threshold)
                    {
                        postconditionCounter++;
                    }
                }
                else
                {
                    if (invertor * wave[i] < invertor * trigger.level)
                    {
                        preconditionCounter++;
                    }
                }
                if (preconditionMet && postconditionCounter == halfWidth)
                {
                    int triggerIndexTmp = (int)(i + width / 2);
                    if (triggerIndexTmp - holdoff + outputWaveLength <= wave.Length)
                    {
                        triggerIndex = triggerIndexTmp;
                        return(true);
                    }
                }
            }
            return(false);
        }
        //FIXME: we really shouldn't be needing the freqcomp mode in here
        internal SmartScopeHeader(byte[] data)
        {
            int headerSize = SmartScope.AcquisitionRegisters.Length + SmartScope.DumpRegisters.Length + (int)Math.Ceiling(SmartScope.AcquisitionStrobes.Length / 8.0);

            raw = new byte[headerSize];
            if (data[0] != 'L' || data[1] != 'N')
            {
                throw new Exception("Invalid magic number, can't parse header");
            }

            int headerOffset = data[2];

            Array.Copy(data, headerOffset, raw, 0, headerSize);

            BytesPerBurst         = data[3];
            NumberOfPayloadBursts = data[4] + (data[5] << 8);

            PackageOffset = (short)(data[6] + (data[7] << 8));

            ViewportLength = (int)(BytesPerBurst / Channels) << GetRegister(REG.VIEW_BURSTS);

            AcquisitionDepth    = (uint)(2048 << GetRegister(REG.ACQUISITION_DEPTH));
            Samples             = NumberOfPayloadBursts * BytesPerBurst / Channels;
            Acquiring           = Utils.IsBitSet(data[10], 0);
            OverviewBuffer      = Utils.IsBitSet(data[10], 1);
            LastAcquisition     = Utils.IsBitSet(data[10], 2);
            Rolling             = Utils.IsBitSet(data[10], 3);
            TimedOut            = Utils.IsBitSet(data[10], 4);
            AwaitingTrigger     = Utils.IsBitSet(data[10], 5);
            Armed               = Utils.IsBitSet(data[10], 6);
            FullAcquisitionDump = Utils.IsBitSet(data[10], 7);

            AnalogTrigger = new AnalogTriggerValue()
            {
                channel   = AnalogChannel.List.First(x => x.Value == ((GetRegister(REG.TRIGGER_MODE) >> 2) & 0x03)),
                direction = (TriggerDirection)((GetRegister(REG.TRIGGER_MODE) >> 4) & 0x03),
            };
            ChannelSacrificedForLogicAnalyser = GetStrobe(STR.LA_CHANNEL) ? AnalogChannel.ChB : AnalogChannel.ChA;
            LogicAnalyserEnabled = GetStrobe(STR.LA_ENABLE);

            AcquisitionId        = data[11];
            SamplePeriod         = SmartScope.BASE_SAMPLE_PERIOD * Math.Pow(2, GetRegister(REG.INPUT_DECIMATION));
            ViewportSamplePeriod = SmartScope.BASE_SAMPLE_PERIOD * Math.Pow(2, GetRegister(REG.INPUT_DECIMATION) + GetRegister(REG.VIEW_DECIMATION));

            ViewportOffset = SamplePeriod * (
                GetRegister(REG.VIEW_OFFSET_B0) +
                (GetRegister(REG.VIEW_OFFSET_B1) << 8) +
                (GetRegister(REG.VIEW_OFFSET_B2) << 16)
                );

            int viewportExcessiveSamples = GetRegister(REG.VIEW_EXCESS_B0) + (GetRegister(REG.VIEW_EXCESS_B1) << 8);

            ViewportExcess = viewportExcessiveSamples * SamplePeriod;

            Int64 holdoffSamples = GetRegister(REG.TRIGGERHOLDOFF_B0) +
                                   (GetRegister(REG.TRIGGERHOLDOFF_B1) << 8) +
                                   (GetRegister(REG.TRIGGERHOLDOFF_B2) << 16) +
                                   (GetRegister(REG.TRIGGERHOLDOFF_B3) << 24) - SmartScope.TriggerDelay(TriggerMode, GetRegister(REG.TRIGGER_WIDTH), GetRegister(REG.INPUT_DECIMATION));

            TriggerHoldoff = holdoffSamples * (SmartScope.BASE_SAMPLE_PERIOD * Math.Pow(2, GetRegister(REG.INPUT_DECIMATION)));
        }
Example #4
0
        public static Dictionary<AnalogChannel, AnalogWaveProperties> MeasureAutoArrangeSettings(IScope scope, AnalogChannel aciveChannel, Action<float> progressReport)
        {
            float progress = 0f;
            progressReport(progress);

            //stop scope streaming
            scope.DataSourceScope.Stop();

            //Prepare scope for test
            if (scope is SmartScope)
                (scope as SmartScope).SetDisableVoltageConversion(false);

            //set to timerange wide enough to capture 50Hz, but slightly off so smallest chance of aliasing
            const float initialTimeRange = 0.0277f;
            scope.AcquisitionMode = AcquisitionMode.AUTO;
            scope.AcquisitionLength = initialTimeRange;
            scope.SetViewPort(0, scope.AcquisitionLength);
            //s.AcquisitionDepth = 4096;
            scope.TriggerHoldOff = 0;
            scope.SendOverviewBuffer = false;

            AnalogTriggerValue atv = new AnalogTriggerValue();
            atv.channel = AnalogChannel.ChA;
            atv.direction = TriggerDirection.RISING;
            atv.level = 5000;
            scope.TriggerAnalog = atv;

            foreach (AnalogChannel ch in AnalogChannel.List)
                scope.SetCoupling(ch, Coupling.DC);

            scope.CommitSettings();
            progress += .1f;
            progressReport(progress);
            ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            // VERTICAL == VOLTAGE

            //set to largest input range
            float maxRange = 1.2f / 1f * 36f;
            foreach (AnalogChannel ch in AnalogChannel.List)
                scope.SetVerticalRange(ch, -maxRange / 2f, maxRange / 2f);

            float[] minValues = new float[] { float.MaxValue, float.MaxValue };
            float[] maxValues = new float[] { float.MinValue, float.MinValue };
            //measure min and max voltage over 3 full ranges
            for (int i = -1; i < 2; i++)
            {
                progress += .1f;
                progressReport(progress);

                foreach (AnalogChannel ch in AnalogChannel.List)
                    scope.SetYOffset(ch, (float)i * maxRange);
                scope.CommitSettings();

                System.Threading.Thread.Sleep(100);
                scope.ForceTrigger();

                //fetch data
                DataPackageScope p = FetchLastFrame(scope);
                p = FetchLastFrame(scope); //needs this second fetch as well to get voltage conversion on ChanB right?!?

                if (p == null)
                {
                    Logger.Error("Didn't receive data from scope, aborting");
                    return null;
                }

                //check if min or max need to be updated (only in case this measurement was not saturated)
                float[] dataA = (float[])p.GetData(DataSourceType.Viewport, AnalogChannel.ChA).array;
                float[] dataB = (float[])p.GetData(DataSourceType.Viewport, AnalogChannel.ChB).array;
                float minA = dataA.Min();
                float maxA = dataA.Max();
                float minB = dataB.Min();
                float maxB = dataB.Max();

                if (minA != p.SaturationLowValue[AnalogChannel.ChA] && minA != p.SaturationHighValue[AnalogChannel.ChA] && minValues[0] > minA) minValues[0] = minA;
                if (minB != p.SaturationLowValue[AnalogChannel.ChB] && minB != p.SaturationHighValue[AnalogChannel.ChB] && minValues[1] > minB) minValues[1] = minB;
                if (maxA != p.SaturationLowValue[AnalogChannel.ChA] && maxA != p.SaturationHighValue[AnalogChannel.ChA] && maxValues[0] < maxA) maxValues[0] = maxA;
                if (maxB != p.SaturationLowValue[AnalogChannel.ChB] && maxB != p.SaturationHighValue[AnalogChannel.ChB] && maxValues[1] < maxB) maxValues[1] = maxB;
            }

            //calc ideal voltage range and offset
            float sizer = 3; //meaning 3 waves would fill entire view
            float[] coarseAmplitudes = new float[2];
            coarseAmplitudes[0] = maxValues[0] - minValues[0];
            coarseAmplitudes[1] = maxValues[1] - minValues[1];
            float[] desiredOffsets = new float[2];
            desiredOffsets[0] = (maxValues[0] + minValues[0]) / 2f;
            desiredOffsets[1] = (maxValues[1] + minValues[1]) / 2f;
            float[] desiredRanges = new float[2];
            desiredRanges[0] = coarseAmplitudes[0] * sizer;
            desiredRanges[1] = coarseAmplitudes[1] * sizer;

            //intervene in case the offset is out of range for this range
            if (desiredRanges[0] < Math.Abs(desiredOffsets[0]))
                desiredRanges[0] = Math.Abs(desiredOffsets[0]);
            if (desiredRanges[1] < Math.Abs(desiredOffsets[1]))
                desiredRanges[1] = Math.Abs(desiredOffsets[1]);

            //set fine voltage range and offset
            scope.SetVerticalRange(AnalogChannel.ChA, -desiredRanges[0] / 2f, desiredRanges[0] / 2f);
            scope.SetYOffset(AnalogChannel.ChA, -desiredOffsets[0]);
            scope.SetVerticalRange(AnalogChannel.ChB, -desiredRanges[1] / 2f, desiredRanges[1] / 2f);
            scope.SetYOffset(AnalogChannel.ChB, -desiredOffsets[1]);
            scope.CommitSettings();

            //now get data in order to find accurate lowHigh levels (as in coarse mode this was not accurate)
            DataPackageScope pFine = FetchLastFrame(scope);
            pFine = FetchLastFrame(scope); //needs this second fetch as well to get voltage conversion on ChanB right?!?

            Dictionary<AnalogChannel, float[]> dataFine = new Dictionary<AnalogChannel, float[]>();
            dataFine.Add(AnalogChannel.ChA, (float[])pFine.GetData(DataSourceType.Viewport, AnalogChannel.ChA).array);
            dataFine.Add(AnalogChannel.ChB, (float[])pFine.GetData(DataSourceType.Viewport, AnalogChannel.ChB).array);

            Dictionary<AnalogChannel, float> minimumValues = new Dictionary<AnalogChannel, float>();
            Dictionary<AnalogChannel, float> maximumValues = new Dictionary<AnalogChannel, float>();
            Dictionary<AnalogChannel, float> amplitudes = new Dictionary<AnalogChannel, float>();
            Dictionary<AnalogChannel, float> offsets = new Dictionary<AnalogChannel, float>();
            Dictionary<AnalogChannel, bool> isFlatline = new Dictionary<AnalogChannel, bool>();
            foreach (var kvp in dataFine)
            {
                minimumValues.Add(kvp.Key, kvp.Value.Min());
                maximumValues.Add(kvp.Key, kvp.Value.Max());
                amplitudes.Add(kvp.Key, kvp.Value.Max() - kvp.Value.Min());
                offsets.Add(kvp.Key, (kvp.Value.Max() + kvp.Value.Min())/2f);
                isFlatline.Add(kvp.Key, amplitudes[kvp.Key] < 0.01f);
            }

            ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            // HORIZONTAL == FREQUENCY

            const float minTimeRange = 500f * 0.00000001f;//500 samples over full hor span
            const float maxTimeRange = 1f;

            double frequency, frequencyError, dutyCycle, dutyCycleError;
            Dictionary<AnalogChannel, double> finalFrequencies = new Dictionary<AnalogChannel, double>();
            finalFrequencies.Add(AnalogChannel.ChA, double.MaxValue);
            finalFrequencies.Add(AnalogChannel.ChB, double.MaxValue);
            int iterationCounter = 0;   //only for performance testing
            float currTimeRange = minTimeRange;
            bool continueLooping = true;
            if (isFlatline.Where(x => x.Value).ToList().Count == isFlatline.Count) //no need to find frequency in case of 2 DC signals
                continueLooping = false;
            while (continueLooping)
            {
                progress += .04f;
                progressReport(progress);

                iterationCounter++;     //only for performance testing

                scope.AcquisitionLength = currTimeRange;
                scope.SetViewPort(0, scope.AcquisitionLength);
                scope.CommitSettings();

                DataPackageScope pHor = FetchLastFrame(scope);
                pHor = FetchLastFrame(scope);
                Dictionary<AnalogChannel, float[]> timeData = new Dictionary<AnalogChannel, float[]>();
                timeData.Add(AnalogChannel.ChA, (float[])pHor.GetData(DataSourceType.Viewport, AnalogChannel.ChA).array);
                timeData.Add(AnalogChannel.ChB, (float[])pHor.GetData(DataSourceType.Viewport, AnalogChannel.ChB).array);

                foreach (var kvp in timeData)
                {
                    //make sure entire amplitude is in view
                    float currMinVal = kvp.Value.Min();
                    float currMaxVal = kvp.Value.Max();
                    float lowMarginValue = minimumValues[kvp.Key] + amplitudes[kvp.Key] * 0.1f;
                    float highMarginValue = maximumValues[kvp.Key] - amplitudes[kvp.Key] * 0.1f;
                    if (currMinVal > lowMarginValue) break;
                    if (currMaxVal < highMarginValue) break;

                    ComputeFrequencyDutyCycle(pHor.GetData(DataSourceType.Viewport, kvp.Key), out frequency, out frequencyError, out dutyCycle, out dutyCycleError);
                    if (!double.IsNaN(frequency) && (finalFrequencies[kvp.Key] == double.MaxValue))
                        finalFrequencies[kvp.Key] = frequency;
                }

                //update and check whether we've found what we were looking for
                currTimeRange *= 100f;
                bool freqFoundForAllActiveWaves = true;
                foreach (var kvp in timeData)
                    if (!isFlatline[kvp.Key] && finalFrequencies[kvp.Key] == double.MaxValue)
                        freqFoundForAllActiveWaves = false;
                continueLooping = !freqFoundForAllActiveWaves;
                if (currTimeRange > maxTimeRange)
                    continueLooping = false;
            }

            //in case of flatline or very low freq, initial value will not have changed
            foreach (AnalogChannel ch in finalFrequencies.Keys.ToList())
                if (finalFrequencies[ch] == double.MaxValue)
                    finalFrequencies[ch] = 0;

            Dictionary<AnalogChannel, AnalogWaveProperties> waveProperties = new Dictionary<AnalogChannel, AnalogWaveProperties>();
            foreach (var kvp in isFlatline)
                waveProperties.Add(kvp.Key, new AnalogWaveProperties(minimumValues[kvp.Key], maximumValues[kvp.Key], amplitudes[kvp.Key], offsets[kvp.Key], isFlatline[kvp.Key], finalFrequencies[kvp.Key]));

            return waveProperties;
        }