ngscopeclient v0.2.1
Loading...
Searching...
No Matches
Filter.h
Go to the documentation of this file.
1/***********************************************************************************************************************
2* *
3* libscopehal *
4* *
5* Copyright (c) 2012-2026 Andrew D. Zonenberg and contributors *
6* All rights reserved. *
7* *
8* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the *
9* following conditions are met: *
10* *
11* * Redistributions of source code must retain the above copyright notice, this list of conditions, and the *
12* following disclaimer. *
13* *
14* * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the *
15* following disclaimer in the documentation and/or other materials provided with the distribution. *
16* *
17* * Neither the name of the author nor the names of any contributors may be used to endorse or promote products *
18* derived from this software without specific prior written permission. *
19* *
20* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
21* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL *
22* THE AUTHORS BE HELD LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
23* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR *
24* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
25* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE *
26* POSSIBILITY OF SUCH DAMAGE. *
27* *
28***********************************************************************************************************************/
29
37#ifndef Filter_h
38#define Filter_h
39
40#include "OscilloscopeChannel.h"
41#include "FlowGraphNode.h"
42#include "KahanSummation.h"
43
44class QueueHandle;
45
47{
48public:
49 uint32_t size;
50 uint32_t bins;
51 float nmin;
52 float nmax;
53};
54
62{
63public:
64
67 : m_wfm(nullptr)
68 , m_rev(0)
69 {}
70
77 : m_wfm(wfm)
78 , m_rev(wfm->m_revision)
79 {}
80
81 bool operator==(WaveformBase* wfm)
82 { return (m_wfm == wfm) && (m_rev == wfm->m_revision); }
83
84 bool operator==(WaveformCacheKey wfm)
85 { return (m_wfm == wfm.m_wfm) && (m_rev == wfm.m_rev); }
86
87 bool operator!=(WaveformBase* wfm)
88 { return (m_wfm != wfm) || (m_rev != wfm->m_revision); }
89
90 bool operator!=(WaveformCacheKey wfm)
91 { return (m_wfm != wfm.m_wfm) || (m_rev != wfm.m_rev); }
92
95
98};
99
105{
106public:
107
109 // Construction and enumeration
110
118 {
119 CAT_ANALYSIS, //Signal integrity analysis
120 CAT_BUS, //Buses
121 CAT_CLOCK, //Clock stuff
122 CAT_MATH, //Basic math functions
123 CAT_MEASUREMENT, //Measurement functions
124 CAT_MEMORY, //Memory buses
125 CAT_SERIAL, //Serial communications
126 CAT_MISC, //anything not otherwise categorized
127 CAT_POWER, //Power analysis
128 CAT_RF, //Frequency domain analysis (FFT etc) and other RF stuff
129 CAT_GENERATION, //Waveform generation and synthesis
130 CAT_EXPORT, //Waveform export
131 CAT_OPTICAL, //Optics
132
133 CAT_COUNT //current max number of categories (will increase over time as more are added)
134 };
135
136 Filter(
137 const std::string& color,
139 Unit xunit = Unit::UNIT_FS);
140 virtual ~Filter();
141
143 static const std::set<Filter*>& GetAllInstances()
144 { return m_filters; }
145
147 static size_t GetNumInstances()
148 { return m_filters.size(); }
149
157 {
158 m_filters.erase(this);
159 m_instanceCount[GetProtocolDisplayName()] --;
160 }
161
162 virtual void ClearStreams() override;
163 virtual size_t AddStream(
164 Unit yunit,
165 const std::string& name,
166 Stream::StreamType stype,
167 uint8_t flags = 0) override;
168
174 void AddProtocolStream(const std::string& name)
175 { AddStream(Unit(Unit::UNIT_COUNTS), name, Stream::STREAM_TYPE_PROTOCOL); }
176
182 void AddDigitalStream(const std::string& name)
183 { AddStream(Unit(Unit::UNIT_COUNTS), name, Stream::STREAM_TYPE_DIGITAL); }
184
186 // Name generation
187
188 virtual void SetDefaultName();
189
196 {
198 if(use)
200 }
201
204 { return m_usingDefault; }
205
207 // Reference counting
208
209 virtual void AddRef() override;
210 virtual void Release() override;
211
213 // Accessors
214
217 { return m_category; }
218
222 virtual std::string GetProtocolDisplayName() =0;
223
224public:
230 virtual void ClearSweeps();
231
233 // Vertical scaling
234
235 virtual void AutoscaleVertical(size_t stream);
236
237 virtual float GetVoltageRange(size_t stream) override;
238 virtual void SetVoltageRange(float range, size_t stream) override;
239
240 virtual float GetOffset(size_t stream) override;
241 virtual void SetOffset(float offset, size_t stream) override;
242
243protected:
244
246 std::vector<float> m_ranges;
247
249 std::vector<float> m_offsets;
250
251public:
253 // Serialization
254
255 virtual YAML::Node SerializeConfiguration(IDTable& table) override;
256
257 virtual void LoadParameters(const YAML::Node& node, IDTable& table) override;
258 virtual void LoadInputs(const YAML::Node& node, IDTable& table) override;
259
260 virtual bool ShouldPersistWaveform() override;
261
262protected:
263
266
269
270 bool VerifyAllInputsOK(bool allowEmpty = false);
271 bool VerifyInputOK(size_t i, bool allowEmpty = false);
276
277public:
280
286 {
287 if(swfm)
288 return GetNextEventTimestamp(swfm, i, len, timestamp);
289 else
290 return GetNextEventTimestamp(uwfm, i, len, timestamp);
291 }
292
293 static void AdvanceToTimestamp(SparseWaveformBase* wfm, size_t& i, size_t len, int64_t timestamp);
294 static void AdvanceToTimestamp(UniformWaveformBase* wfm, size_t& i, size_t len, int64_t timestamp);
295
296 static void AdvanceToTimestamp(
298 {
299 if(swfm)
301 else
303 }
304
307 static void AdvanceToTimestampScaled(SparseWaveformBase* wfm, size_t& i, size_t len, int64_t timestamp);
308 static void AdvanceToTimestampScaled(UniformWaveformBase* wfm, size_t& i, size_t len, int64_t timestamp);
309
310 static void AdvanceToTimestampScaled(
312 {
313 if(swfm)
315 else
317 }
318
321 {
322 if(swfm)
324 else
326 }
327
328protected:
335
347 template<class T>
348 T* SetupEmptyWaveform(WaveformBase* din, size_t stream, bool clear = true)
349 {
350 //Create the waveform, but only if necessary
351 auto cap = dynamic_cast<T*>(GetData(stream));
352 if(cap == nullptr)
353 {
354 cap = new T;
356 }
357
358 //Copy configuration
359 if(din != nullptr)
360 {
361 cap->m_startTimestamp = din->m_startTimestamp;
362 cap->m_startFemtoseconds = din->m_startFemtoseconds;
363 cap->m_triggerPhase = din->m_triggerPhase;
364 cap->m_timescale = din->m_timescale;
365 }
366
367 //Bump rev number
368 cap->m_revision ++;
369
370 //Clear output
371 if(clear)
372 cap->clear();
373
374 return cap;
375 }
376
377public:
378 //Helpers for sub-sample interpolation
379
389 template<class T>
391 static float InterpolateTime(T* cap, size_t a, float voltage)
392 {
393 AssertTypeIsAnalogWaveform(cap);
394
395 //If the voltage isn't between the two points, abort
396 float fa = cap->m_samples[a];
397 float fb = cap->m_samples[a+1];
398 bool ag = (fa > voltage);
399 bool bg = (fb > voltage);
400 if( (ag && bg) || (!ag && !bg) )
401 return 0;
402
403 //no need to divide by time, sample spacing is normalized to 1 timebase unit
404 float slope = (fb - fa);
405 float delta = voltage - fa;
406 return delta / slope;
407 }
408
409 static float InterpolateTime(SparseAnalogWaveform* s, UniformAnalogWaveform* u, size_t a, float voltage)
410 {
411 if(s)
412 return InterpolateTime(s, a, voltage);
413 else
414 return InterpolateTime(u, a, voltage);
415 }
416
417 static float InterpolateTime(UniformAnalogWaveform* p, UniformAnalogWaveform* n, size_t a, float voltage);
418 static float InterpolateTime(SparseAnalogWaveform* p, SparseAnalogWaveform* n, size_t a, float voltage);
419
420 static float InterpolateTime(
425 size_t a, float voltage)
426 {
427 if(sp)
428 return InterpolateTime(sp, sn, a, voltage);
429 else
430 return InterpolateTime(up, un, a, voltage);
431 }
432
433 static float InterpolateValue(SparseAnalogWaveform* cap, size_t index, float frac_ticks);
434 static float InterpolateValue(UniformAnalogWaveform* cap, size_t index, float frac_ticks);
435
436 //Helpers for more complex measurements
437 //TODO: create some process for caching this so we don't waste CPU time
438
442 template<class T>
444 static void GetMinMaxVoltage(T* cap, float& vmin, float& vmax)
445 {
446 AssertTypeIsAnalogWaveform(cap);
447
448 vmin = FLT_MAX;
449 vmax = FLT_MIN;
450 for(float f : cap->m_samples)
451 {
452 if(f < vmin)
453 vmin = f;
454 if(f > vmax)
455 vmax = f;
456 }
457 }
458
462 template<class T>
464 static void GetMinMaxVoltage(
465 vk::raii::CommandBuffer& cmdBuf,
466 std::shared_ptr<QueueHandle> queue,
470 T* cap,
471 float& vmin,
472 float& vmax
473 )
474 {
475 AssertTypeIsAnalogWaveform(cap);
476
477 //GPU side min/max
478 const uint32_t nthreads = 4096;
479 const uint32_t threadsPerBlock = 64;
480 scratchMin.resize(nthreads);
481 scratchMax.resize(nthreads);
482
483 cmdBuf.begin({});
484 minmaxPipeline.BindBufferNonblocking(0, cap->m_samples, cmdBuf);
485 minmaxPipeline.BindBufferNonblocking(1, scratchMin, cmdBuf);
486 minmaxPipeline.BindBufferNonblocking(2, scratchMax, cmdBuf);
487 minmaxPipeline.Dispatch(cmdBuf, (uint32_t)cap->size(), nthreads / threadsPerBlock);
488
489 scratchMin.MarkModifiedFromGpu();
490 scratchMax.MarkModifiedFromGpu();
491
492 scratchMin.PrepareForCpuAccessNonblocking(cmdBuf);
493 scratchMax.PrepareForCpuAccessNonblocking(cmdBuf);
494
495 cmdBuf.end();
496 queue->SubmitAndBlock(cmdBuf);
497
498 //Final reduction on CPU (TODO: faster to do second shader invocation and read one value??)
499 vmin = scratchMin[0];
500 vmax = scratchMax[0];
501 for(uint32_t i=1; i<nthreads; i++)
502 {
503 vmin = std::min(vmin, scratchMin[i]);
504 vmax = std::max(vmax, scratchMax[i]);
505 }
506 }
507
511 template<class T>
513 static float GetMinVoltage(T* cap)
514 {
515 AssertTypeIsAnalogWaveform(cap);
516
517 //Loop over samples and find the minimum
518 float tmp = FLT_MAX;
519 for(float f : cap->m_samples)
520 {
521 if(f < tmp)
522 tmp = f;
523 }
524 return tmp;
525 }
526
531 {
532 if(s)
533 return GetMinVoltage(s);
534 else
535 return GetMinVoltage(u);
536 }
537
541 template<class T>
543 static float GetMaxVoltage(T* cap)
544 {
545 AssertTypeIsAnalogWaveform(cap);
546
547 //Loop over samples and find the maximum
548 float tmp = -FLT_MAX;
549 for(float f : cap->m_samples)
550 {
551 if(f > tmp)
552 tmp = f;
553 }
554 return tmp;
555 }
556
561 {
562 if(s)
563 return GetMaxVoltage(s);
564 else
565 return GetMaxVoltage(u);
566 }
567
585 vk::raii::CommandBuffer& cmdBuf,
586 std::shared_ptr<QueueHandle> queue,
588 std::shared_ptr<ComputePipeline>& histogramPipeline,
594 float& base,
595 float& top)
596 {
597 if(swfm)
598 {
600 cmdBuf,
601 queue,
606 hist,
607 swfm,
608 base,
609 top);
610 }
611 else if(uwfm)
612 {
614 cmdBuf,
615 queue,
620 hist,
621 uwfm,
622 base,
623 top);
624 }
625 else
626 {
627 LogError("Filter::GetBaseAndTopVoltage called with both waveforms null\n");
628 base = 0;
629 top = 0;
630 }
631 }
632
636 template<class T>
638 static void GetBaseAndTopVoltage(
639 vk::raii::CommandBuffer& cmdBuf,
640 std::shared_ptr<QueueHandle> queue,
642 std::shared_ptr<ComputePipeline>& histogramPipeline,
646
647 T* cap, float& base, float& top)
648 {
649 AssertTypeIsAnalogWaveform(cap);
650
651 //GPU side min/max calculation
652 float vmin;
653 float vmax;
654 GetMinMaxVoltage(cmdBuf, queue, minmaxPipeline, scratchMin, scratchMax, cap, vmin, vmax);
655
656 //Do the histogram calculation on the GPU if possible
657 float delta = vmax - vmin;
658 const int nbins = 100;
660 {
661 MakeHistogram(cmdBuf, queue, *histogramPipeline, cap, hist, vmin, vmax, nbins);
662 hist.PrepareForCpuAccess();
663 }
664 else
665 {
666 //CPU fallback
667 hist.resize(nbins);
668 hist.PrepareForCpuAccess();
669
670 auto tmp = MakeHistogram(cap, vmin, vmax, nbins);
671 for(int i=0; i<nbins; i++)
672 hist[i] = tmp[i];
673
674 hist.MarkModifiedFromCpu();
675 }
676
677 //Find the highest peak in the first quarter of the histogram
678 size_t binval = 0;
679 int idx = 0;
680 for(int i=0; i<(nbins/4); i++)
681 {
682 if(hist[i] > binval)
683 {
684 binval = hist[i];
685 idx = i;
686 }
687 }
688
689 float fbin = (idx + 0.5f)/nbins;
690 base = fbin*delta + vmin;
691
692 //Find the highest peak in the third quarter of the histogram
693 binval = 0;
694 idx = 0;
695 for(int i=(nbins*3)/4; i<nbins; i++)
696 {
697 if(hist[i] > binval)
698 {
699 binval = hist[i];
700 idx = i;
701 }
702 }
703
704 fbin = (idx + 0.5f)/nbins;
705 top = fbin*delta + vmin;
706 }
707
711 template<class T>
713 static float GetBaseVoltage(T* cap)
714 {
715 AssertTypeIsAnalogWaveform(cap);
716
717 float vmin;
718 float vmax;
719 GetMinMaxVoltage(cap, vmin, vmax);
720
721 float delta = vmax - vmin;
722 const int nbins = 100;
723 auto hist = MakeHistogram(cap, vmin, vmax, nbins);
724
725 //Find the highest peak in the first quarter of the histogram
726 size_t binval = 0;
727 int idx = 0;
728 for(int i=0; i<(nbins/4); i++)
729 {
730 if(hist[i] > binval)
731 {
732 binval = hist[i];
733 idx = i;
734 }
735 }
736
737 float fbin = (idx + 0.5f)/nbins;
738 return fbin*delta + vmin;
739 }
740
745 {
746 if(swfm)
747 return GetBaseVoltage(swfm);
748 else
749 return GetBaseVoltage(uwfm);
750 }
751
755 template<class T>
757 static float GetTopVoltage(T* cap)
758 {
759 AssertTypeIsAnalogWaveform(cap);
760
761 float vmin;
762 float vmax;
763 GetMinMaxVoltage(cap, vmin, vmax);
764
765 float delta = vmax - vmin;
766 const int nbins = 100;
767 auto hist = MakeHistogram(cap, vmin, vmax, nbins);
768
769 //Find the highest peak in the third quarter of the histogram
770 size_t binval = 0;
771 int idx = 0;
772 for(int i=(nbins*3)/4; i<nbins; i++)
773 {
774 if(hist[i] > binval)
775 {
776 binval = hist[i];
777 idx = i;
778 }
779 }
780
781 float fbin = (idx + 0.5f)/nbins;
782 return fbin*delta + vmin;
783 }
784
789 {
790 if(swfm)
791 return GetTopVoltage(swfm);
792 else
793 return GetTopVoltage(uwfm);
794 }
795
799 template<class T>
801 static float GetAvgVoltage(T* cap)
802 {
803 AssertTypeIsAnalogWaveform(cap);
804
805 //Loop over samples and find the average
807 for(float f : cap->m_samples)
808 ksum += f;
809 return ksum.GetSum() / cap->m_samples.size();
810 }
811
816 {
817 if(swfm)
818 return GetAvgVoltage(swfm);
819 else
820 return GetAvgVoltage(uwfm);
821 }
822
832 template<class T>
834 static std::vector<size_t> MakeHistogram(T* cap, float low, float high, size_t bins)
835 {
836 AssertTypeIsAnalogWaveform(cap);
837
838 std::vector<size_t> ret;
839 for(size_t i=0; i<bins; i++)
840 ret.push_back(0);
841
842 //Early out if we have zero span
843 if(bins == 0)
844 return ret;
845
846 float delta = high-low;
847
848 for(float v : cap->m_samples)
849 {
850 float fbin = (v-low) / delta;
851 size_t bin = floor(fbin * bins);
852 if(fbin < 0)
853 bin = 0;
854 else
855 bin = std::min(bin, bins-1);
856 ret[bin] ++;
857 }
858
859 return ret;
860 }
861
871 static std::vector<size_t> MakeHistogram(
872 SparseAnalogWaveform* s, UniformAnalogWaveform* u, float low, float high, size_t bins)
873 {
874 if(s)
875 return MakeHistogram(s, low, high, bins);
876 else
877 return MakeHistogram(u, low, high, bins);
878 }
879
891 template<class T>
893 static void MakeHistogram(
894 vk::raii::CommandBuffer& cmdBuf,
895 std::shared_ptr<QueueHandle> queue,
897 T* cap,
899 float low,
900 float high,
901 size_t bins)
902 {
903 AssertTypeIsAnalogWaveform(cap);
904
905 //Early out if we have zero span
906 if(bins == 0)
907 return;
908
909 const uint32_t nthreads = 4096;
910 const uint32_t threadsPerBlock = 8;
911
912 //Fill the input histogram with zeroes CPU side for now
913 //TODO: GPU side fill
914 hist.resize(bins);
915 hist.PrepareForCpuAccess();
916 memset(hist.GetCpuPointer(), 0, bins*sizeof(int64_t));
917 hist.MarkModifiedFromCpu();
918
919 //Push constants
921 cfg.size = cap->size();
922 cfg.bins = bins;
923 cfg.nmin = low;
924 cfg.nmax = high;
925
926 cmdBuf.begin({});
927 histogramPipeline.BindBufferNonblocking(0, cap->m_samples, cmdBuf);
928 histogramPipeline.BindBufferNonblocking(1, hist, cmdBuf);
929 histogramPipeline.Dispatch(cmdBuf, cfg, nthreads / threadsPerBlock);
930
931 hist.MarkModifiedFromGpu();
932
933 cmdBuf.end();
934 queue->SubmitAndBlock(cmdBuf);
935 }
936
946 template<class T>
948 static std::vector<size_t> MakeHistogramClipped(T* cap, float low, float high, size_t bins)
949 {
950 AssertTypeIsAnalogWaveform(cap);
951
952 std::vector<size_t> ret;
953 for(size_t i=0; i<bins; i++)
954 ret.push_back(0);
955
956 //Early out if we have zero span
957 if(bins == 0)
958 return ret;
959
960 float delta = high-low;
961
962 for(float v : cap->m_samples)
963 {
964 float fbin = (v-low) / delta;
965 // must cast through a signed int type to avoid UB (e.g. saturates to 0 on arm64) [conv.fpint]
966 size_t bin = static_cast<ssize_t>(floor(fbin * bins));
967 if(bin >= bins) //negative values wrap to huge positive and get caught here
968 continue;
969 ret[bin] ++;
970 }
971
972 return ret;
973 }
974
988 template<class T, class R, class S>
990 static void SampleOnAnyEdges(T* data, R* clock, SparseWaveform<S>& samples, bool cpuOnly = true)
991 {
992 //Compile-time check to make sure inputs are correct types
993 AssertTypeIsDigitalWaveform(clock);
994 AssertSampleTypesAreSame(data, &samples);
995
996 samples.clear();
997 if(cpuOnly)
998 samples.SetGpuAccessHint(AcceleratorBuffer<S>::HINT_NEVER); //assume we're being used as part of a CPU-side filter
999 clock->PrepareForCpuAccess();
1000 data->PrepareForCpuAccess();
1001 samples.PrepareForCpuAccess();
1002
1003 //TODO: split up into blocks and multithread?
1004 //TODO: AVX vcompress?
1005 size_t len = clock->size();
1006 size_t dlen = data->size();
1007
1008 //If the clock is sparse, assume it probably has edges on every sample and allocate that much buffer to start
1009 //(we might overallocate here but it'll be a lot faster)
1010 if(dynamic_cast<SparseDigitalWaveform*>(clock) != nullptr)
1011 {
1012 //Allocate exactly enough space
1013 samples.Resize(clock->size());
1014
1015 size_t ndata = 0;
1016 size_t nout = 0;
1017 for(size_t i=1; i<len; i++)
1018 {
1019 //Throw away clock samples until we find an edge
1020 if(clock->m_samples[i] == clock->m_samples[i-1])
1021 continue;
1022
1023 //Throw away data samples until the data is synced with us
1025 while( (ndata+1 < dlen) && (GetOffsetScaled(data, ndata+1) < clkstart) )
1026 ndata ++;
1027 if(ndata >= dlen)
1028 break;
1029
1030 //Add the new sample
1031 samples.m_offsets[nout] = clkstart;
1032 samples.m_samples[nout] = data->m_samples[ndata];
1033 nout ++;
1034 }
1035 samples.Resize(nout);
1036 }
1037 else
1038 {
1039 samples.Reserve(1 * 1024 * 1024); //preallocate 1 MB sample buffer to avoid lots of reallocation when small
1040 //if it's smaller than this, we won't waste a lot of memory
1041
1042 size_t ndata = 0;
1043 for(size_t i=1; i<len; i++)
1044 {
1045 //Throw away clock samples until we find an edge
1046 if(clock->m_samples[i] == clock->m_samples[i-1])
1047 continue;
1048
1049 //Throw away data samples until the data is synced with us
1051 while( (ndata+1 < dlen) && (GetOffsetScaled(data, ndata+1) < clkstart) )
1052 ndata ++;
1053 if(ndata >= dlen)
1054 break;
1055
1056 //Add the new sample
1057 samples.m_offsets.push_back(clkstart);
1058 samples.m_samples.push_back(data->m_samples[ndata]);
1059 }
1060 }
1061 samples.MarkModifiedFromCpu();
1062
1063 //Compute sample durations
1064 #ifdef __x86_64__
1065 if(g_hasAvx2)
1066 FillDurationsAVX2(samples);
1067 else
1068 #endif
1069 FillDurationsGeneric(samples);
1070
1071 samples.MarkModifiedFromCpu();
1072 }
1073
1086 template<class T>
1089 {
1090 data->PrepareForCpuAccess();
1091 clock->PrepareForCpuAccess();
1092 samples.PrepareForCpuAccess();
1093
1094 auto udata = dynamic_cast<UniformWaveform<T>*>(data);
1095 auto sdata = dynamic_cast<SparseWaveform<T>*>(data);
1096
1097 auto uclock = dynamic_cast<UniformDigitalWaveform*>(clock);
1098 auto sclock = dynamic_cast<SparseDigitalWaveform*>(clock);
1099
1100 if(udata && uclock)
1101 SampleOnAnyEdges(udata, uclock, samples);
1102 else if(udata && sclock)
1103 SampleOnAnyEdges(udata, sclock, samples);
1104 else if(sdata && sclock)
1105 SampleOnAnyEdges(sdata, sclock, samples);
1106 else if(sdata && uclock)
1107 SampleOnAnyEdges(sdata, uclock, samples);
1108 }
1109
1122 template<class T, class R, class S>
1124 static void SampleOnRisingEdges(T* data, R* clock, SparseWaveform<S>& samples)
1125 {
1126 //Compile-time check to make sure inputs are correct types
1127 AssertTypeIsDigitalWaveform(clock);
1128 AssertTypeIsSparseWaveform(&samples);
1129 AssertSampleTypesAreSame(data, &samples);
1130
1131 samples.clear();
1132 samples.SetGpuAccessHint(AcceleratorBuffer<S>::HINT_NEVER); //assume we're being used as part of a CPU-side filter
1133 samples.Reserve(1 * 1024 * 1024); //preallocate 1 MB sample buffer to avoid lots of reallocation when small
1134 //if it's smaller than this, we won't waste a lot of memory
1135
1136 //TODO: split up into blocks and multithread?
1137 //TODO: AVX vcompress?
1138
1139 size_t len = clock->size();
1140 size_t dlen = data->size();
1141
1142 size_t ndata = 0;
1143 for(size_t i=1; i<len; i++)
1144 {
1145 //Throw away clock samples until we find a rising edge
1146 if(!(clock->m_samples[i] && !clock->m_samples[i-1]))
1147 continue;
1148
1149 //Throw away data samples until the data is synced with us
1151 while( (ndata+1 < dlen) && (GetOffsetScaled(data, ndata+1) < clkstart) )
1152 ndata ++;
1153 if(ndata >= dlen)
1154 break;
1155
1156 //Add the new sample
1157 samples.m_offsets.push_back(clkstart);
1158 samples.m_samples.push_back(data->m_samples[ndata]);
1159 }
1160
1161 //Compute sample durations
1162 #ifdef __x86_64__
1163 if(g_hasAvx2)
1164 FillDurationsAVX2(samples);
1165 else
1166 #endif
1167 FillDurationsGeneric(samples);
1168
1169 samples.MarkModifiedFromCpu();
1170 }
1171
1184 template<class T>
1187 {
1188 data->PrepareForCpuAccess();
1189 clock->PrepareForCpuAccess();
1190 samples.PrepareForCpuAccess();
1191
1192 auto udata = dynamic_cast<UniformWaveform<T>*>(data);
1193 auto sdata = dynamic_cast<SparseWaveform<T>*>(data);
1194
1195 auto uclock = dynamic_cast<UniformDigitalWaveform*>(clock);
1196 auto sclock = dynamic_cast<SparseDigitalWaveform*>(clock);
1197
1198 if(udata && uclock)
1199 SampleOnRisingEdges(udata, uclock, samples);
1200 else if(udata && sclock)
1201 SampleOnRisingEdges(udata, sclock, samples);
1202 else if(sdata && sclock)
1203 SampleOnRisingEdges(sdata, sclock, samples);
1204 else if(sdata && uclock)
1205 SampleOnRisingEdges(sdata, uclock, samples);
1206 }
1207
1220 template<class T, class R, class S>
1222 static void SampleOnFallingEdges(T* data, R* clock, SparseWaveform<S>& samples)
1223 {
1224 //Compile-time check to make sure inputs are correct types
1225 AssertTypeIsDigitalWaveform(clock);
1226 AssertTypeIsSparseWaveform(&samples);
1227 AssertSampleTypesAreSame(data, &samples);
1228
1229 samples.clear();
1230 samples.SetGpuAccessHint(AcceleratorBuffer<S>::HINT_NEVER); //assume we're being used as part of a CPU-side filter
1231 samples.Reserve(1 * 1024 * 1024); //preallocate 1 MB sample buffer to avoid lots of reallocation when small
1232 //if it's smaller than this, we won't waste a lot of memory
1233
1234 //TODO: split up into blocks and multithread?
1235 //TODO: AVX vcompress?
1236
1237 size_t len = clock->size();
1238 size_t dlen = data->size();
1239
1240 size_t ndata = 0;
1241 for(size_t i=1; i<len; i++)
1242 {
1243 //Throw away clock samples until we find a falling edge
1244 if(!(!clock->m_samples[i] && clock->m_samples[i-1]))
1245 continue;
1246
1247 //Throw away data samples until the data is synced with us
1249 while( (ndata+1 < dlen) && (GetOffsetScaled(data, ndata+1) < clkstart) )
1250 ndata ++;
1251 if(ndata >= dlen)
1252 break;
1253
1254 //Add the new sample
1255 samples.m_offsets.push_back(clkstart);
1256 samples.m_samples.push_back(data->m_samples[ndata]);
1257 }
1258
1259 //Compute sample durations
1260 #ifdef __x86_64__
1261 if(g_hasAvx2)
1262 FillDurationsAVX2(samples);
1263 else
1264 #endif
1265 FillDurationsGeneric(samples);
1266
1267 samples.MarkModifiedFromCpu();
1268 }
1269
1281 template<class T, class R>
1283 static void SampleOnAnyEdgesWithInterpolation(T* data, R* clock, SparseAnalogWaveform& samples)
1284 {
1285 //Compile-time check to make sure inputs are correct types
1286 AssertTypeIsAnalogWaveform(data);
1287 AssertTypeIsDigitalWaveform(clock);
1288
1289 samples.clear();
1290 samples.SetGpuAccessHint(AcceleratorBuffer<float>::HINT_NEVER); //assume we're being used as part of a CPU-side filter
1291 samples.Reserve(1 * 1024 * 1024); //preallocate 1 MB sample buffer to avoid lots of reallocation when small
1292 //if it's smaller than this, we won't waste a lot of memory
1293
1294 //TODO: split up into blocks and multithread?
1295 //TODO: AVX vcompress
1296
1297 size_t len = clock->size();
1298 size_t dlen = data->size();
1299
1300 size_t ndata = 0;
1301 for(size_t i=1; i<len; i++)
1302 {
1303 //Throw away clock samples until we find an edge
1304 if(clock->m_samples[i] == clock->m_samples[i-1])
1305 continue;
1306
1307 //Throw away data samples until the data is synced with us
1309 while( (ndata+1 < dlen) && (GetOffsetScaled(data, ndata+1) < clkstart) )
1310 ndata ++;
1311 if(ndata >= dlen)
1312 break;
1313
1314 //Find the fractional position of the clock edge
1316 int64_t delta = clkstart - tsample;
1317 float frac = delta * 1.0 / data->m_timescale;
1318
1319 //Add the new sample
1320 samples.m_offsets.push_back(clkstart);
1321 samples.m_samples.push_back(InterpolateValue(data, ndata, frac));
1322 }
1323
1324 //Compute sample durations
1325 #ifdef __x86_64__
1326 if(g_hasAvx2)
1327 FillDurationsAVX2(samples);
1328 else
1329 #endif
1330 FillDurationsGeneric(samples);
1331
1332 samples.MarkModifiedFromCpu();
1333 }
1334
1347 template<class T>
1350 {
1351 data->PrepareForCpuAccess();
1352 clock->PrepareForCpuAccess();
1353 samples.PrepareForCpuAccess();
1354
1355 auto udata = dynamic_cast<UniformWaveform<T>*>(data);
1356 auto sdata = dynamic_cast<SparseWaveform<T>*>(data);
1357
1358 auto uclock = dynamic_cast<UniformDigitalWaveform*>(clock);
1359 auto sclock = dynamic_cast<SparseDigitalWaveform*>(clock);
1360
1361 if(udata && uclock)
1362 SampleOnAnyEdgesWithInterpolation(udata, uclock, samples);
1363 else if(udata && sclock)
1364 SampleOnAnyEdgesWithInterpolation(udata, sclock, samples);
1365 else if(sdata && sclock)
1366 SampleOnAnyEdgesWithInterpolation(sdata, sclock, samples);
1367 else if(sdata && uclock)
1368 SampleOnAnyEdgesWithInterpolation(sdata, uclock, samples);
1369 }
1370
1374 template<class T>
1376 {
1377 if(s)
1378 s->PrepareForCpuAccess();
1379 else
1380 u->PrepareForCpuAccess();
1381 }
1382
1386 template<class T>
1388 {
1389 if(s)
1390 s->PrepareForGpuAccess();
1391 else
1392 u->PrepareForGpuAccess();
1393 }
1394
1395 static void FindRisingEdges(UniformAnalogWaveform* data, float threshold, std::vector<int64_t>& edges);
1396 static void FindRisingEdges(SparseAnalogWaveform* data, float threshold, std::vector<int64_t>& edges);
1397 static void FindZeroCrossings(SparseAnalogWaveform* data, float threshold, std::vector<int64_t>& edges);
1398 static void FindZeroCrossings(UniformAnalogWaveform* data, float threshold, std::vector<int64_t>& edges);
1399 static void FindZeroCrossings(UniformDigitalWaveform* data, std::vector<int64_t>& edges);
1400 static void FindZeroCrossings(SparseDigitalWaveform* data, std::vector<int64_t>& edges);
1401 static void FindRisingEdges(UniformDigitalWaveform* data, std::vector<int64_t>& edges);
1402 static void FindRisingEdges(SparseDigitalWaveform* data, std::vector<int64_t>& edges);
1403 static void FindFallingEdges(UniformDigitalWaveform* data, std::vector<int64_t>& edges);
1404 static void FindFallingEdges(SparseDigitalWaveform* data, std::vector<int64_t>& edges);
1405 static void FindPeaks(UniformAnalogWaveform* data, float peak_threshold, std::vector<int64_t>& peak_indices);
1406 static void FindPeaks(SparseAnalogWaveform* data, float peak_threshold, std::vector<int64_t>& peak_indices);
1407
1408 static void FindZeroCrossingsBase(WaveformBase* data, float threshold, std::vector<int64_t>& edges)
1409 {
1410 auto udata = dynamic_cast<UniformAnalogWaveform*>(data);
1411 auto sdata = dynamic_cast<SparseAnalogWaveform*>(data);
1412
1413 if(udata)
1414 FindZeroCrossings(udata, threshold, edges);
1415 else
1416 FindZeroCrossings(sdata, threshold, edges);
1417 }
1418
1419 static void FindRisingEdges(
1420 SparseDigitalWaveform* sdata, UniformDigitalWaveform* udata, std::vector<int64_t>& edges)
1421 {
1422 if(sdata)
1423 FindRisingEdges(sdata, edges);
1424 else
1425 FindRisingEdges(udata, edges);
1426 }
1427
1428 static void FindFallingEdges(
1429 SparseDigitalWaveform* sdata, UniformDigitalWaveform* udata, std::vector<int64_t>& edges)
1430 {
1431 if(sdata)
1432 FindFallingEdges(sdata, edges);
1433 else
1434 FindFallingEdges(udata, edges);
1435 }
1436
1437 static void FindPeaks(
1438 SparseAnalogWaveform* sdata, UniformAnalogWaveform* udata, float peak_threshold, std::vector<int64_t>& peak_indices)
1439 {
1440 if(sdata)
1441 FindPeaks(sdata, peak_threshold, peak_indices);
1442 else
1443 FindPeaks(udata, peak_threshold, peak_indices);
1444 }
1445
1446 static void FindZeroCrossings(
1447 SparseAnalogWaveform* sdata, UniformAnalogWaveform* udata, float threshold, std::vector<int64_t>& edges)
1448 {
1449 if(sdata)
1450 FindZeroCrossings(sdata, threshold, edges);
1451 else
1452 FindZeroCrossings(udata, threshold, edges);
1453 }
1454
1455 static void FindZeroCrossings(
1456 SparseDigitalWaveform* sdata, UniformDigitalWaveform* udata, std::vector<int64_t>& edges)
1457 {
1458 if(sdata)
1459 FindZeroCrossings(sdata, edges);
1460 else
1461 FindZeroCrossings(udata, edges);
1462 }
1463
1464 static void ClearAnalysisCache();
1465
1466 enum FIRFilterType
1467 {
1468 FILTER_TYPE_LOWPASS,
1469 FILTER_TYPE_HIGHPASS,
1470 FILTER_TYPE_BANDPASS,
1471 FILTER_TYPE_NOTCH
1472 };
1473
1474 static void CalculateFIRCoefficients(
1475 float fa,
1476 float fb,
1477 float stopbandAtten,
1478 FIRFilterType type,
1480 static float Bessel(float x);
1481
1482protected:
1483 //Helpers for sparse waveforms
1484 static void FillDurationsGeneric(SparseWaveformBase& wfm);
1485#ifdef __x86_64__
1487#endif
1488
1489public:
1490 sigc::signal<void()> signal_outputsChanged()
1491 { return m_outputsChangedSignal; }
1492
1493protected:
1496
1502 unsigned int m_instanceNum;
1503
1504public:
1505 typedef Filter* (*CreateProcType)(const std::string&);
1506 static void DoAddDecoderClass(const std::string& name, CreateProcType proc);
1507
1508 static void EnumProtocols(std::vector<std::string>& names);
1509 static Filter* CreateFilter(const std::string& protocol, const std::string& color = "#ffffff");
1510
1511protected:
1512 //Class enumeration
1513 typedef std::map< std::string, CreateProcType > CreateMapType;
1514 static CreateMapType m_createprocs;
1515
1516 //Object enumeration
1517 static std::set<Filter*> m_filters;
1518
1519 //Instance naming
1520 static std::map<std::string, unsigned int> m_instanceCount;
1521
1522 //Caching
1523 static std::mutex m_cacheMutex;
1524 static std::map<std::pair<WaveformBase*, float>, std::vector<int64_t> > m_zeroCrossingCache;
1525};
1526
1527#define PROTOCOL_DECODER_INITPROC(T) \
1528 static Filter* CreateInstance(const std::string& color) \
1529 { \
1530 return new T(color); \
1531 } \
1532 virtual std::string GetProtocolDisplayName() override \
1533 { return GetProtocolName(); }
1534
1535#define AddDecoderClass(T) Filter::DoAddDecoderClass(T::GetProtocolName(), T::CreateInstance)
1536
1537#endif
Declaration of FlowGraphNode.
Declaration of OscilloscopeChannel.
Definition AcceleratorBuffer.h:204
A buffer of memory which may be used by GPU acceleration.
Definition AcceleratorBuffer.h:343
Encapsulates a Vulkan compute pipeline and all necessary resources to use it.
Definition ComputePipeline.h:55
Abstract base class for all filter graph blocks which are not physical instrument channels.
Definition Filter.h:105
void AddDigitalStream(const std::string &name)
Helper method for constructors that adds a new STREAM_TYPE_DIGITAL output stream.
Definition Filter.h:182
static void GetBaseAndTopVoltage(vk::raii::CommandBuffer &cmdBuf, std::shared_ptr< QueueHandle > queue, ComputePipeline &minmaxPipeline, std::shared_ptr< ComputePipeline > &histogramPipeline, AcceleratorBuffer< float > &scratchMin, AcceleratorBuffer< float > &scratchMax, AcceleratorBuffer< uint64_t > &hist, SparseAnalogWaveform *swfm, UniformAnalogWaveform *uwfm, float &base, float &top)
Gets the base and top voltage of a waveform which may be sparse or uniform.
Definition Filter.h:584
static float GetMaxVoltage(SparseAnalogWaveform *s, UniformAnalogWaveform *u)
Gets the lowest voltage of a waveform.
Definition Filter.h:560
virtual size_t AddStream(Unit yunit, const std::string &name, Stream::StreamType stype, uint8_t flags=0) override
Adds a new data stream to the channel.
Definition Filter.cpp:1491
__attribute__((noinline)) static void MakeHistogram(vk
Makes a histogram from a waveform with the specified number of bins.
Definition Filter.h:892
void UseDefaultName(bool use)
Specifies whether we're using an auto-generated name or not.
Definition Filter.h:195
bool VerifyAllInputsOKAndSparseOrUniformDigital()
Returns true if every input to the filter is non-NULL and has a non-empty, digital waveform present.
Definition Filter.cpp:247
SparseDigitalWaveform * SetupEmptySparseDigitalOutputWaveform(WaveformBase *din, size_t stream)
Sets up an digital output waveform and copies basic metadata from the input.
Definition Filter.cpp:1164
__attribute__((noinline)) static float GetAvgVoltage(T *cap)
Gets the average voltage of a waveform.
Definition Filter.h:800
static void FindRisingEdges(UniformAnalogWaveform *data, float threshold, std::vector< int64_t > &edges)
Find rising edges in a waveform, interpolating to sub-sample resolution as necessary.
Definition Filter.cpp:326
virtual bool ShouldPersistWaveform() override
Determine whether the channel's waveform(s) should be persisted to a session file.
Definition Filter.cpp:932
bool VerifyInputOK(size_t i, bool allowEmpty=false)
Returns true if a given input to the filter is non-NULL (and, optionally has a non-empty waveform pre...
Definition Filter.cpp:130
static int64_t GetNextEventTimestamp(SparseWaveformBase *wfm, size_t i, size_t len, int64_t timestamp)
Gets the timestamp of the next event (if any) on a waveform.
Definition Filter.cpp:1283
T * SetupEmptyWaveform(WaveformBase *din, size_t stream, bool clear=true)
Sets up an empty output waveform and copies basic metadata from the input.
Definition Filter.h:348
static void PrepareForCpuAccess(SparseWaveform< T > *s, UniformWaveform< T > *u)
Prepares a sparse or uniform analog waveform for CPU access.
Definition Filter.h:1375
__attribute__((noinline)) static void SampleOnAnyEdges(T *data
Samples a waveform on all edges of a clock.
static std::vector< size_t > MakeHistogram(SparseAnalogWaveform *s, UniformAnalogWaveform *u, float low, float high, size_t bins)
Makes a histogram from a waveform with the specified number of bins.
Definition Filter.h:871
virtual void ClearStreams() override
Clears out any existing streams.
Definition Filter.cpp:1484
static void AdvanceToTimestamp(SparseWaveformBase *wfm, size_t &i, size_t len, int64_t timestamp)
Advance the waveform to a given timestamp.
Definition Filter.cpp:1309
UniformAnalogWaveform * SetupEmptyUniformAnalogOutputWaveform(WaveformBase *din, size_t stream, bool clear=true)
Sets up an analog output waveform and copies basic metadata from the input.
Definition Filter.cpp:1050
__attribute__((noinline)) static void SampleOnAnyEdgesWithInterpolation(T *data
Samples an analog waveform on all edges of a clock, interpolating linearly to get sub-sample accuracy...
virtual void ClearSweeps()
Clears any integrated data from past triggers (e.g. eye patterns).
Definition Filter.cpp:80
static size_t GetNumInstances()
Get all currently existing filters.
Definition Filter.h:147
__attribute__((noinline)) static void SampleOnRisingEdgesBase(WaveformBase *data
Samples a waveform on rising edges of a clock.
static float GetMinVoltage(SparseAnalogWaveform *s, UniformAnalogWaveform *u)
Gets the lowest voltage of a waveform.
Definition Filter.h:530
SparseAnalogWaveform * SetupEmptySparseAnalogOutputWaveform(WaveformBase *din, size_t stream, bool clear=true)
Sets up an analog output waveform and copies basic metadata from the input.
Definition Filter.cpp:1090
Category m_category
Category this filter should be displayed under.
Definition Filter.h:265
static void PrepareForGpuAccess(SparseWaveform< T > *s, UniformWaveform< T > *u)
Prepares a sparse or uniform analog waveform for GPU access.
Definition Filter.h:1387
bool VerifyAllInputsOKAndSparseDigital()
Returns true if every input to the filter is non-NULL and has a non-empty, sparsely sampled digital w...
Definition Filter.cpp:221
virtual void SetDefaultName()
Sets the name of a filter based on its inputs.
Definition Filter.cpp:1464
std::vector< float > m_ranges
Y axis range of each output stream.
Definition Filter.h:246
void HideFromList()
Removes this filter from the global list.
Definition Filter.h:156
unsigned int m_instanceNum
Instance number (for auto naming)
Definition Filter.h:1502
__attribute__((noinline)) static float GetMinVoltage(T *cap)
Gets the lowest voltage of a waveform.
Definition Filter.h:512
static float Bessel(float x)
0th order Bessel function
Definition Filter.cpp:1441
static int64_t GetNextEventTimestampScaled(SparseWaveformBase *wfm, size_t i, size_t len, int64_t timestamp)
Gets the timestamp of the next event (if any) on a waveform.
Definition Filter.cpp:1330
UniformDigitalWaveform * SetupEmptyUniformDigitalOutputWaveform(WaveformBase *din, size_t stream)
Sets up an digital output waveform and copies basic metadata from the input.
Definition Filter.cpp:1129
std::vector< float > m_offsets
Y axis offset of each output stream.
Definition Filter.h:249
bool m_usingDefault
If true, we're using an auto-generated name.
Definition Filter.h:268
static int64_t GetNextEventTimestamp(SparseWaveformBase *swfm, UniformWaveformBase *uwfm, size_t i, size_t len, int64_t timestamp)
Gets the timestamp of the next sample in a waveform, which may be sparse or uniform.
Definition Filter.h:284
static void AdvanceToTimestampScaled(SparseWaveformBase *wfm, size_t &i, size_t len, int64_t timestamp)
Advance the waveform to a given timestamp.
Definition Filter.cpp:1356
__attribute__((noinline)) static std
Makes a histogram from a waveform with the specified number of bins.
Definition Filter.h:833
static float GetTopVoltage(SparseAnalogWaveform *swfm, UniformAnalogWaveform *uwfm)
Gets the top voltage of a waveform which may be sparse or uniform.
Definition Filter.h:788
bool IsUsingDefaultName()
Return true if we're using an autogenerated name, false if customized.
Definition Filter.h:203
Category GetCategory()
Returns the category for displaying this filter in the browser.
Definition Filter.h:216
__attribute__((noinline)) static void GetMinMaxVoltage(vk
Gets the min and max voltage of a waveform on the GPU.
Definition Filter.h:463
__attribute__((noinline)) static float GetBaseVoltage(T *cap)
Gets the most probable "0" level for a digital waveform.
Definition Filter.h:712
Category
Category the filter should be displayed under in the GUI.
Definition Filter.h:118
__attribute__((noinline)) static float GetTopVoltage(T *cap)
Gets the most probable "1" level for a digital waveform.
Definition Filter.h:756
SparseDigitalWaveform * SetupSparseDigitalOutputWaveform(SparseWaveformBase *din, size_t stream, size_t skipstart, size_t skipend)
Sets up a digital output waveform and copies timebase configuration from the input.
Definition Filter.cpp:1236
__attribute__((noinline)) static float GetMaxVoltage(T *cap)
Gets the highest voltage of a waveform.
Definition Filter.h:542
static float InterpolateValue(SparseAnalogWaveform *cap, size_t index, float frac_ticks)
Interpolates the actual value of a point between two samples.
Definition Filter.cpp:997
virtual void LoadParameters(const YAML::Node &node, IDTable &table) override
Load configuration from a save file.
Definition Filter.cpp:871
sigc::signal< void()> m_outputsChangedSignal
Signal emitted when the set of output streams changes.
Definition Filter.h:1495
__attribute__((noinline)) static void GetMinMaxVoltage(T *cap
Gets the lowest and highest voltage of a waveform.
__attribute__((noinline)) static void SampleOnAnyEdgesBaseWithInterpolation(WaveformBase *data
Samples an analog waveform on all edges of a clock, interpolating linearly to get sub-sample accuracy...
static float GetAvgVoltage(SparseAnalogWaveform *swfm, UniformAnalogWaveform *uwfm)
Gets the average voltage of a waveform which may be sparse or uniform.
Definition Filter.h:815
SparseAnalogWaveform * SetupSparseOutputWaveform(SparseWaveformBase *din, size_t stream, size_t skipstart, size_t skipend)
Sets up an analog output waveform and copies timebase configuration from the input.
Definition Filter.cpp:1202
virtual std::string GetProtocolDisplayName()=0
Gets the display name of this protocol (for use in menus, save files, etc). Must be unique.
__attribute__((noinline)) static void GetBaseAndTopVoltage(vk
Gets the most probable "0" and "1" level for a digital waveform.
Definition Filter.h:637
virtual void AutoscaleVertical(size_t stream)
Adjusts gain and offset such that the active waveform occupies the entire vertical area of the plot.
Definition Filter.cpp:1501
static float GetBaseVoltage(SparseAnalogWaveform *swfm, UniformAnalogWaveform *uwfm)
Gets the base voltage of a waveform which may be sparse or uniform.
Definition Filter.h:744
bool VerifyAllInputsOKAndUniformAnalog()
Returns true if every input to the filter is non-NULL and has a non-empty, uniformly sampled analog w...
Definition Filter.cpp:169
__attribute__((noinline)) static void SampleOnFallingEdges(T *data
Samples a waveform on the falling edges of a clock.
virtual YAML::Node SerializeConfiguration(IDTable &table) override
Serializes this trigger's configuration to a YAML string.
Definition Filter.cpp:831
__attribute__((noinline)) static float InterpolateTime(T *cap
Interpolates the actual time of a threshold crossing between two samples.
static const std::set< Filter * > & GetAllInstances()
Get all currently existing filters.
Definition Filter.h:143
bool VerifyAllInputsOKAndSparseAnalog()
Returns true if every input to the filter is non-NULL and has a non-empty, sparsely sampled analog wa...
Definition Filter.cpp:195
bool VerifyAllInputsOK(bool allowEmpty=false)
Returns true if every input to the filter is non-NULL (and, optionally has a non-empty waveform prese...
Definition Filter.cpp:155
void AddProtocolStream(const std::string &name)
Helper method for constructors that adds a new STREAM_TYPE_PROTOCOL output stream.
Definition Filter.h:174
static void CalculateFIRCoefficients(float fa, float fb, float stopbandAtten, FIRFilterType type, AcceleratorBuffer< float > &coefficients)
Calculates FIR coefficients.
Definition Filter.cpp:1393
Definition Filter.h:47
Bidirectional table mapping integer IDs in scopesession files to object pointers.
Definition IDTable.h:49
void SetData(WaveformBase *pNew, size_t stream)
Sets the waveform data for a given stream, replacing any previous waveform.
Definition InstrumentChannel.cpp:144
WaveformBase * GetData(size_t stream)
Get the contents of a data stream.
Definition InstrumentChannel.h:189
Helper class for performing a Kahan summation on a large number of floating point numbers.
Definition KahanSummation.h:37
A single channel on an oscilloscope.
Definition OscilloscopeChannel.h:49
Wrapper around a Vulkan Queue object.
Definition QueueHandle.h:65
Base class for waveforms with nonuniform sample rate.
Definition Waveform.h:293
AcceleratorBuffer< int64_t > m_offsets
Start timestamps of each sample, in multiples of m_timescale.
Definition Waveform.h:328
virtual void MarkModifiedFromCpu() override
Indicates that this waveform's sample data and timestamps have been modified on the CPU and the GPU-s...
Definition Waveform.h:358
A waveform sampled at irregular intervals.
Definition Waveform.h:514
virtual void Reserve(size_t size) override
Preallocates buffers without changing the usable size of the waveform.
Definition Waveform.h:608
virtual void clear() override
Remove all samples from this waveform.
Definition Waveform.h:624
AcceleratorBuffer< S > m_samples
Sample data.
Definition Waveform.h:589
void SetGpuAccessHint(enum AcceleratorBuffer< S >::UsageHint hint)
Passes a hint to the memory allocator about where our sample data is expected to be used.
Definition Waveform.h:670
StreamType
General data type stored in a stream.
Definition Stream.h:57
Base class for waveforms with data sampled at uniform intervals.
Definition Waveform.h:376
A waveform sampled at uniform intervals.
Definition Waveform.h:404
A unit of measurement, plus conversion to pretty-printed output.
Definition Unit.h:59
Base class for all Waveform specializations.
Definition Waveform.h:59
virtual void PrepareForCpuAccess()=0
Indicates that this waveform is going to be used by the CPU in the near future.
Describes a particular revision of a waveform.
Definition Filter.h:62
WaveformCacheKey()
Create an empty cache key for a null waveform.
Definition Filter.h:66
WaveformBase * m_wfm
Pointer to the waveform object.
Definition Filter.h:94
WaveformCacheKey(WaveformBase *wfm)
Create a cache key for a waveform.
Definition Filter.h:76
uint64_t m_rev
Definition Filter.h:97
int64_t GetOffsetScaled(T *wfm, size_t i)
Returns the offset of a sample from the start of the waveform, in X axis units.
Definition Waveform.h:841
bool g_hasShaderInt64
Indicates whether the int64 type is available for use in shaders and SSBOs.
Definition VulkanInit.cpp:171
bool g_hasShaderAtomicInt64
Indicates whether atomic operations on the int64 type are available in shaders.
Definition VulkanInit.cpp:195