ngscopeclient v0.1
Filter.h
Go to the documentation of this file.
1/***********************************************************************************************************************
2* *
3* libscopehal *
4* *
5* Copyright (c) 2012-2025 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
43class QueueHandle;
44
52{
53public:
54
57 : m_wfm(nullptr)
58 , m_rev(0)
59 {}
60
67 : m_wfm(wfm)
68 , m_rev(wfm->m_revision)
69 {}
70
71 bool operator==(WaveformBase* wfm)
72 { return (m_wfm == wfm) && (m_rev == wfm->m_revision); }
73
74 bool operator==(WaveformCacheKey wfm)
75 { return (m_wfm == wfm.m_wfm) && (m_rev == wfm.m_rev); }
76
77 bool operator!=(WaveformBase* wfm)
78 { return (m_wfm != wfm) || (m_rev != wfm->m_revision); }
79
80 bool operator!=(WaveformCacheKey wfm)
81 { return (m_wfm != wfm.m_wfm) || (m_rev != wfm.m_rev); }
82
85
87 uint64_t m_rev;
88};
89
95{
96public:
97
99 // Construction and enumeration
100
108 {
109 CAT_ANALYSIS, //Signal integrity analysis
110 CAT_BUS, //Buses
111 CAT_CLOCK, //Clock stuff
112 CAT_MATH, //Basic math functions
113 CAT_MEASUREMENT, //Measurement functions
114 CAT_MEMORY, //Memory buses
115 CAT_SERIAL, //Serial communications
116 CAT_MISC, //anything not otherwise categorized
117 CAT_POWER, //Power analysis
118 CAT_RF, //Frequency domain analysis (FFT etc) and other RF stuff
119 CAT_GENERATION, //Waveform generation and synthesis
120 CAT_EXPORT, //Waveform export
121 CAT_OPTICAL, //Optics
122
123 CAT_COUNT //current max number of categories (will increase over time as more are added)
124 };
125
126 Filter(
127 const std::string& color,
128 Category cat,
129 Unit xunit = Unit::UNIT_FS);
130 virtual ~Filter();
131
133 static std::set<Filter*> GetAllInstances()
134 { return m_filters; }
135
137 static size_t GetNumInstances()
138 { return m_filters.size(); }
139
147 {
148 m_filters.erase(this);
149 m_instanceCount[GetProtocolDisplayName()] --;
150 }
151
152 virtual void ClearStreams() override;
153 virtual size_t AddStream(
154 Unit yunit,
155 const std::string& name,
156 Stream::StreamType stype,
157 uint8_t flags = 0) override;
158
164 void AddProtocolStream(const std::string& name)
165 { AddStream(Unit(Unit::UNIT_COUNTS), name, Stream::STREAM_TYPE_PROTOCOL); }
166
172 void AddDigitalStream(const std::string& name)
173 { AddStream(Unit(Unit::UNIT_COUNTS), name, Stream::STREAM_TYPE_DIGITAL); }
174
176 // Name generation
177
178 virtual void SetDefaultName();
179
185 void UseDefaultName(bool use)
186 {
187 m_usingDefault = use;
188 if(use)
190 }
191
194 { return m_usingDefault; }
195
197 // Reference counting
198
199 virtual void AddRef() override;
200 virtual void Release() override;
201
203 size_t GetRefCount()
204 { return m_refcount; }
205
207 // Accessors
208
211 { return m_category; }
212
213 virtual bool NeedsConfig();
214
218 virtual std::string GetProtocolDisplayName() =0;
219
220public:
226 virtual void ClearSweeps();
227
228 [[deprecated]]
229 virtual void Refresh() override;
230
231 //GPU accelerated refresh method
232 virtual void Refresh(vk::raii::CommandBuffer& cmdBuf, std::shared_ptr<QueueHandle> queue) override;
233
235 // Vertical scaling
236
237 virtual void AutoscaleVertical(size_t stream);
238
239 virtual float GetVoltageRange(size_t stream) override;
240 virtual void SetVoltageRange(float range, size_t stream) override;
241
242 virtual float GetOffset(size_t stream) override;
243 virtual void SetOffset(float offset, size_t stream) override;
244
245protected:
246
248 std::vector<float> m_ranges;
249
251 std::vector<float> m_offsets;
252
253public:
255 // Serialization
256
257 virtual YAML::Node SerializeConfiguration(IDTable& table) override;
258
259 virtual void LoadParameters(const YAML::Node& node, IDTable& table) override;
260 virtual void LoadInputs(const YAML::Node& node, IDTable& table) override;
261
262 virtual bool ShouldPersistWaveform() override;
263
264protected:
265
268
271
272 bool VerifyAllInputsOK(bool allowEmpty = false);
273 bool VerifyInputOK(size_t i, bool allowEmpty = false);
278
279public:
280 static int64_t GetNextEventTimestamp(SparseWaveformBase* wfm, size_t i, size_t len, int64_t timestamp);
281 static int64_t GetNextEventTimestamp(UniformWaveformBase* wfm, size_t i, size_t len, int64_t timestamp);
282
286 static int64_t GetNextEventTimestamp(
287 SparseWaveformBase* swfm, UniformWaveformBase* uwfm, size_t i, size_t len, int64_t timestamp)
288 {
289 if(swfm)
290 return GetNextEventTimestamp(swfm, i, len, timestamp);
291 else
292 return GetNextEventTimestamp(uwfm, i, len, timestamp);
293 }
294
295 static void AdvanceToTimestamp(SparseWaveformBase* wfm, size_t& i, size_t len, int64_t timestamp);
296 static void AdvanceToTimestamp(UniformWaveformBase* wfm, size_t& i, size_t len, int64_t timestamp);
297
298 static void AdvanceToTimestamp(
299 SparseWaveformBase* swfm, UniformWaveformBase* uwfm, size_t& i, size_t len, int64_t timestamp)
300 {
301 if(swfm)
302 AdvanceToTimestamp(swfm, i, len, timestamp);
303 else
304 AdvanceToTimestamp(uwfm, i, len, timestamp);
305 }
306
307 static int64_t GetNextEventTimestampScaled(SparseWaveformBase* wfm, size_t i, size_t len, int64_t timestamp);
308 static int64_t GetNextEventTimestampScaled(UniformWaveformBase* wfm, size_t i, size_t len, int64_t timestamp);
309 static void AdvanceToTimestampScaled(SparseWaveformBase* wfm, size_t& i, size_t len, int64_t timestamp);
310 static void AdvanceToTimestampScaled(UniformWaveformBase* wfm, size_t& i, size_t len, int64_t timestamp);
311
312 static void AdvanceToTimestampScaled(
313 SparseWaveformBase* swfm, UniformWaveformBase* uwfm, size_t& i, size_t len, int64_t timestamp)
314 {
315 if(swfm)
316 AdvanceToTimestampScaled(swfm, i, len, timestamp);
317 else
318 AdvanceToTimestampScaled(uwfm, i, len, timestamp);
319 }
320
321 static int64_t GetNextEventTimestampScaled(
322 SparseWaveformBase* swfm, UniformWaveformBase* uwfm, size_t i, size_t len, int64_t timestamp)
323 {
324 if(swfm)
325 return GetNextEventTimestampScaled(swfm, i, len, timestamp);
326 else
327 return GetNextEventTimestampScaled(uwfm, i, len, timestamp);
328 }
329
330protected:
331 UniformAnalogWaveform* SetupEmptyUniformAnalogOutputWaveform(WaveformBase* din, size_t stream, bool clear=true);
332 SparseAnalogWaveform* SetupEmptySparseAnalogOutputWaveform(WaveformBase* din, size_t stream, bool clear=true);
335 SparseAnalogWaveform* SetupSparseOutputWaveform(SparseWaveformBase* din, size_t stream, size_t skipstart, size_t skipend);
336 SparseDigitalWaveform* SetupSparseDigitalOutputWaveform(SparseWaveformBase* din, size_t stream, size_t skipstart, size_t skipend);
337
349 template<class T>
350 T* SetupEmptyWaveform(WaveformBase* din, size_t stream, bool clear = true)
351 {
352 //Create the waveform, but only if necessary
353 auto cap = dynamic_cast<T*>(GetData(stream));
354 if(cap == NULL)
355 {
356 cap = new T;
357 SetData(cap, stream);
358 }
359
360 //Copy configuration
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 //Bump rev number
367 cap->m_revision ++;
368
369 //Clear output
370 if(clear)
371 cap->clear();
372
373 return cap;
374 }
375
376public:
377 //Helpers for sub-sample interpolation
378
388 template<class T>
389 __attribute__((noinline))
390 static float InterpolateTime(T* cap, size_t a, float voltage)
391 {
392 AssertTypeIsAnalogWaveform(cap);
393
394 //If the voltage isn't between the two points, abort
395 float fa = cap->m_samples[a];
396 float fb = cap->m_samples[a+1];
397 bool ag = (fa > voltage);
398 bool bg = (fb > voltage);
399 if( (ag && bg) || (!ag && !bg) )
400 return 0;
401
402 //no need to divide by time, sample spacing is normalized to 1 timebase unit
403 float slope = (fb - fa);
404 float delta = voltage - fa;
405 return delta / slope;
406 }
407
408 static float InterpolateTime(SparseAnalogWaveform* s, UniformAnalogWaveform* u, size_t a, float voltage)
409 {
410 if(s)
411 return InterpolateTime(s, a, voltage);
412 else
413 return InterpolateTime(u, a, voltage);
414 }
415
416 static float InterpolateTime(UniformAnalogWaveform* p, UniformAnalogWaveform* n, size_t a, float voltage);
417 static float InterpolateTime(SparseAnalogWaveform* p, SparseAnalogWaveform* n, size_t a, float voltage);
418
419 static float InterpolateTime(
424 size_t a, float voltage)
425 {
426 if(sp)
427 return InterpolateTime(sp, sn, a, voltage);
428 else
429 return InterpolateTime(up, un, a, voltage);
430 }
431
432 static float InterpolateValue(SparseAnalogWaveform* cap, size_t index, float frac_ticks);
433 static float InterpolateValue(UniformAnalogWaveform* cap, size_t index, float frac_ticks);
434
435 //Helpers for more complex measurements
436 //TODO: create some process for caching this so we don't waste CPU time
437
441 template<class T>
442 __attribute__((noinline))
443 static void GetMinMaxVoltage(T* cap, float& vmin, float& vmax)
444 {
445 AssertTypeIsAnalogWaveform(cap);
446
447 vmin = FLT_MAX;
448 vmax = FLT_MIN;
449 for(float f : cap->m_samples)
450 {
451 if(f < vmin)
452 vmin = f;
453 if(f > vmax)
454 vmax = f;
455 }
456 }
457
461 template<class T>
462 __attribute__((noinline))
463 static float GetMinVoltage(T* cap)
464 {
465 AssertTypeIsAnalogWaveform(cap);
466
467 //Loop over samples and find the minimum
468 float tmp = FLT_MAX;
469 for(float f : cap->m_samples)
470 {
471 if(f < tmp)
472 tmp = f;
473 }
474 return tmp;
475 }
476
481 {
482 if(s)
483 return GetMinVoltage(s);
484 else
485 return GetMinVoltage(u);
486 }
487
491 template<class T>
492 __attribute__((noinline))
493 static float GetMaxVoltage(T* cap)
494 {
495 AssertTypeIsAnalogWaveform(cap);
496
497 //Loop over samples and find the maximum
498 float tmp = -FLT_MAX;
499 for(float f : cap->m_samples)
500 {
501 if(f > tmp)
502 tmp = f;
503 }
504 return tmp;
505 }
506
511 {
512 if(s)
513 return GetMaxVoltage(s);
514 else
515 return GetMaxVoltage(u);
516 }
517
521 template<class T>
522 __attribute__((noinline))
523 static float GetBaseVoltage(T* cap)
524 {
525 AssertTypeIsAnalogWaveform(cap);
526
527 float vmin = GetMinVoltage(cap);
528 float vmax = GetMaxVoltage(cap);
529 float delta = vmax - vmin;
530 const int nbins = 100;
531 auto hist = MakeHistogram(cap, vmin, vmax, nbins);
532
533 //Find the highest peak in the first quarter of the histogram
534 size_t binval = 0;
535 int idx = 0;
536 for(int i=0; i<(nbins/4); i++)
537 {
538 if(hist[i] > binval)
539 {
540 binval = hist[i];
541 idx = i;
542 }
543 }
544
545 float fbin = (idx + 0.5f)/nbins;
546 return fbin*delta + vmin;
547 }
548
553 {
554 if(swfm)
555 return GetBaseVoltage(swfm);
556 else
557 return GetBaseVoltage(uwfm);
558 }
559
563 template<class T>
564 __attribute__((noinline))
565 static float GetTopVoltage(T* cap)
566 {
567 AssertTypeIsAnalogWaveform(cap);
568
569 float vmin = GetMinVoltage(cap);
570 float vmax = GetMaxVoltage(cap);
571 float delta = vmax - vmin;
572 const int nbins = 100;
573 auto hist = MakeHistogram(cap, vmin, vmax, nbins);
574
575 //Find the highest peak in the third quarter of the histogram
576 size_t binval = 0;
577 int idx = 0;
578 for(int i=(nbins*3)/4; i<nbins; i++)
579 {
580 if(hist[i] > binval)
581 {
582 binval = hist[i];
583 idx = i;
584 }
585 }
586
587 float fbin = (idx + 0.5f)/nbins;
588 return fbin*delta + vmin;
589 }
590
595 {
596 if(swfm)
597 return GetTopVoltage(swfm);
598 else
599 return GetTopVoltage(uwfm);
600 }
601
605 template<class T>
606 __attribute__((noinline))
607 static float GetAvgVoltage(T* cap)
608 {
609 AssertTypeIsAnalogWaveform(cap);
610
611 //Loop over samples and find the average
612 //TODO: more numerically stable summation algorithm for deep captures
613 double sum = 0;
614 for(float f : cap->m_samples)
615 sum += f;
616 return sum / cap->m_samples.size();
617 }
618
623 {
624 if(swfm)
625 return GetAvgVoltage(swfm);
626 else
627 return GetAvgVoltage(uwfm);
628 }
629
639 template<class T>
640 __attribute__((noinline))
641 static std::vector<size_t> MakeHistogram(T* cap, float low, float high, size_t bins)
642 {
643 AssertTypeIsAnalogWaveform(cap);
644
645 std::vector<size_t> ret;
646 for(size_t i=0; i<bins; i++)
647 ret.push_back(0);
648
649 //Early out if we have zero span
650 if(bins == 0)
651 return ret;
652
653 float delta = high-low;
654
655 for(float v : cap->m_samples)
656 {
657 float fbin = (v-low) / delta;
658 size_t bin = floor(fbin * bins);
659 if(fbin < 0)
660 bin = 0;
661 else
662 bin = std::min(bin, bins-1);
663 ret[bin] ++;
664 }
665
666 return ret;
667 }
668
678 static std::vector<size_t> MakeHistogram(
679 SparseAnalogWaveform* s, UniformAnalogWaveform* u, float low, float high, size_t bins)
680 {
681 if(s)
682 return MakeHistogram(s, low, high, bins);
683 else
684 return MakeHistogram(u, low, high, bins);
685 }
686
696 template<class T>
697 __attribute__((noinline))
698 static std::vector<size_t> MakeHistogramClipped(T* cap, float low, float high, size_t bins)
699 {
700 AssertTypeIsAnalogWaveform(cap);
701
702 std::vector<size_t> ret;
703 for(size_t i=0; i<bins; i++)
704 ret.push_back(0);
705
706 //Early out if we have zero span
707 if(bins == 0)
708 return ret;
709
710 float delta = high-low;
711
712 for(float v : cap->m_samples)
713 {
714 float fbin = (v-low) / delta;
715 // must cast through a signed int type to avoid UB (e.g. saturates to 0 on arm64) [conv.fpint]
716 size_t bin = static_cast<ssize_t>(floor(fbin * bins));
717 if(bin >= bins) //negative values wrap to huge positive and get caught here
718 continue;
719 ret[bin] ++;
720 }
721
722 return ret;
723 }
724
737 template<class T, class R, class S>
738 __attribute__((noinline))
739 static void SampleOnAnyEdges(T* data, R* clock, SparseWaveform<S>& samples)
740 {
741 //Compile-time check to make sure inputs are correct types
742 AssertTypeIsDigitalWaveform(clock);
743 AssertSampleTypesAreSame(data, &samples);
744
745 samples.clear();
746 samples.SetGpuAccessHint(AcceleratorBuffer<S>::HINT_NEVER); //assume we're being used as part of a CPU-side filter
747
748 //TODO: split up into blocks and multithread?
749 //TODO: AVX vcompress?
750 size_t len = clock->size();
751 size_t dlen = data->size();
752
753 //If the clock is sparse, assume it probably has edges on every sample and allocate that much buffer to start
754 //(we might overallocate here but it'll be a lot faster)
755 if(dynamic_cast<SparseDigitalWaveform*>(clock) != nullptr)
756 {
757 //Allocate exactly enough space
758 samples.Resize(clock->size());
759 samples.PrepareForCpuAccess();
760
761 size_t ndata = 0;
762 size_t nout = 0;
763 for(size_t i=1; i<len; i++)
764 {
765 //Throw away clock samples until we find an edge
766 if(clock->m_samples[i] == clock->m_samples[i-1])
767 continue;
768
769 //Throw away data samples until the data is synced with us
770 int64_t clkstart = GetOffsetScaled(clock, i);
771 while( (ndata+1 < dlen) && (GetOffsetScaled(data, ndata+1) < clkstart) )
772 ndata ++;
773 if(ndata >= dlen)
774 break;
775
776 //Add the new sample
777 samples.m_offsets[nout] = clkstart;
778 samples.m_samples[nout] = data->m_samples[ndata];
779 nout ++;
780 }
781 samples.Resize(nout);
782 samples.MarkModifiedFromCpu();
783 }
784 else
785 {
786 samples.Reserve(1 * 1024 * 1024); //preallocate 1 MB sample buffer to avoid lots of reallocation when small
787 //if it's smaller than this, we won't waste a lot of memory
788 samples.PrepareForCpuAccess();
789
790 size_t ndata = 0;
791 for(size_t i=1; i<len; i++)
792 {
793 //Throw away clock samples until we find an edge
794 if(clock->m_samples[i] == clock->m_samples[i-1])
795 continue;
796
797 //Throw away data samples until the data is synced with us
798 int64_t clkstart = GetOffsetScaled(clock, i);
799 while( (ndata+1 < dlen) && (GetOffsetScaled(data, ndata+1) < clkstart) )
800 ndata ++;
801 if(ndata >= dlen)
802 break;
803
804 //Add the new sample
805 samples.m_offsets.push_back(clkstart);
806 samples.m_samples.push_back(data->m_samples[ndata]);
807 }
808 }
809
810 //Compute sample durations
811 #ifdef __x86_64__
812 if(g_hasAvx2)
813 FillDurationsAVX2(samples);
814 else
815 #endif
816 FillDurationsGeneric(samples);
817
818 samples.MarkModifiedFromCpu();
819 }
820
833 template<class T>
834 __attribute__((noinline))
835 static void SampleOnAnyEdgesBase(WaveformBase* data, WaveformBase* clock, SparseWaveform<T>& samples)
836 {
837 data->PrepareForCpuAccess();
838 clock->PrepareForCpuAccess();
839 samples.PrepareForCpuAccess();
840
841 auto udata = dynamic_cast<UniformWaveform<T>*>(data);
842 auto sdata = dynamic_cast<SparseWaveform<T>*>(data);
843
844 auto uclock = dynamic_cast<UniformDigitalWaveform*>(clock);
845 auto sclock = dynamic_cast<SparseDigitalWaveform*>(clock);
846
847 if(udata && uclock)
848 SampleOnAnyEdges(udata, uclock, samples);
849 else if(udata && sclock)
850 SampleOnAnyEdges(udata, sclock, samples);
851 else if(sdata && sclock)
852 SampleOnAnyEdges(sdata, sclock, samples);
853 else if(sdata && uclock)
854 SampleOnAnyEdges(sdata, uclock, samples);
855 }
856
869 template<class T, class R, class S>
870 __attribute__((noinline))
871 static void SampleOnRisingEdges(T* data, R* clock, SparseWaveform<S>& samples)
872 {
873 //Compile-time check to make sure inputs are correct types
874 AssertTypeIsDigitalWaveform(clock);
875 AssertTypeIsSparseWaveform(&samples);
876 AssertSampleTypesAreSame(data, &samples);
877
878 samples.clear();
879 samples.SetGpuAccessHint(AcceleratorBuffer<S>::HINT_NEVER); //assume we're being used as part of a CPU-side filter
880 samples.Reserve(1 * 1024 * 1024); //preallocate 1 MB sample buffer to avoid lots of reallocation when small
881 //if it's smaller than this, we won't waste a lot of memory
882
883 //TODO: split up into blocks and multithread?
884 //TODO: AVX vcompress?
885
886 size_t len = clock->size();
887 size_t dlen = data->size();
888
889 size_t ndata = 0;
890 for(size_t i=1; i<len; i++)
891 {
892 //Throw away clock samples until we find a rising edge
893 if(!(clock->m_samples[i] && !clock->m_samples[i-1]))
894 continue;
895
896 //Throw away data samples until the data is synced with us
897 int64_t clkstart = GetOffsetScaled(clock, i);
898 while( (ndata+1 < dlen) && (GetOffsetScaled(data, ndata+1) < clkstart) )
899 ndata ++;
900 if(ndata >= dlen)
901 break;
902
903 //Add the new sample
904 samples.m_offsets.push_back(clkstart);
905 samples.m_samples.push_back(data->m_samples[ndata]);
906 }
907
908 //Compute sample durations
909 #ifdef __x86_64__
910 if(g_hasAvx2)
911 FillDurationsAVX2(samples);
912 else
913 #endif
914 FillDurationsGeneric(samples);
915
916 samples.MarkModifiedFromCpu();
917 }
918
931 template<class T>
932 __attribute__((noinline))
933 static void SampleOnRisingEdgesBase(WaveformBase* data, WaveformBase* clock, SparseWaveform<T>& samples)
934 {
935 data->PrepareForCpuAccess();
936 clock->PrepareForCpuAccess();
937 samples.PrepareForCpuAccess();
938
939 auto udata = dynamic_cast<UniformWaveform<T>*>(data);
940 auto sdata = dynamic_cast<SparseWaveform<T>*>(data);
941
942 auto uclock = dynamic_cast<UniformDigitalWaveform*>(clock);
943 auto sclock = dynamic_cast<SparseDigitalWaveform*>(clock);
944
945 if(udata && uclock)
946 SampleOnRisingEdges(udata, uclock, samples);
947 else if(udata && sclock)
948 SampleOnRisingEdges(udata, sclock, samples);
949 else if(sdata && sclock)
950 SampleOnRisingEdges(sdata, sclock, samples);
951 else if(sdata && uclock)
952 SampleOnRisingEdges(sdata, uclock, samples);
953 }
954
967 template<class T, class R, class S>
968 __attribute__((noinline))
969 static void SampleOnFallingEdges(T* data, R* clock, SparseWaveform<S>& samples)
970 {
971 //Compile-time check to make sure inputs are correct types
972 AssertTypeIsDigitalWaveform(clock);
973 AssertTypeIsSparseWaveform(&samples);
974 AssertSampleTypesAreSame(data, &samples);
975
976 samples.clear();
977 samples.SetGpuAccessHint(AcceleratorBuffer<S>::HINT_NEVER); //assume we're being used as part of a CPU-side filter
978 samples.Reserve(1 * 1024 * 1024); //preallocate 1 MB sample buffer to avoid lots of reallocation when small
979 //if it's smaller than this, we won't waste a lot of memory
980
981 //TODO: split up into blocks and multithread?
982 //TODO: AVX vcompress?
983
984 size_t len = clock->size();
985 size_t dlen = data->size();
986
987 size_t ndata = 0;
988 for(size_t i=1; i<len; i++)
989 {
990 //Throw away clock samples until we find a falling edge
991 if(!(!clock->m_samples[i] && clock->m_samples[i-1]))
992 continue;
993
994 //Throw away data samples until the data is synced with us
995 int64_t clkstart = GetOffsetScaled(clock, i);
996 while( (ndata+1 < dlen) && (GetOffsetScaled(data, ndata+1) < clkstart) )
997 ndata ++;
998 if(ndata >= dlen)
999 break;
1000
1001 //Add the new sample
1002 samples.m_offsets.push_back(clkstart);
1003 samples.m_samples.push_back(data->m_samples[ndata]);
1004 }
1005
1006 //Compute sample durations
1007 #ifdef __x86_64__
1008 if(g_hasAvx2)
1009 FillDurationsAVX2(samples);
1010 else
1011 #endif
1012 FillDurationsGeneric(samples);
1013
1014 samples.MarkModifiedFromCpu();
1015 }
1016
1028 template<class T, class R>
1029 __attribute__((noinline))
1030 static void SampleOnAnyEdgesWithInterpolation(T* data, R* clock, SparseAnalogWaveform& samples)
1031 {
1032 //Compile-time check to make sure inputs are correct types
1033 AssertTypeIsAnalogWaveform(data);
1034 AssertTypeIsDigitalWaveform(clock);
1035
1036 samples.clear();
1037 samples.SetGpuAccessHint(AcceleratorBuffer<float>::HINT_NEVER); //assume we're being used as part of a CPU-side filter
1038 samples.Reserve(1 * 1024 * 1024); //preallocate 1 MB sample buffer to avoid lots of reallocation when small
1039 //if it's smaller than this, we won't waste a lot of memory
1040
1041 //TODO: split up into blocks and multithread?
1042 //TODO: AVX vcompress
1043
1044 size_t len = clock->size();
1045 size_t dlen = data->size();
1046
1047 size_t ndata = 0;
1048 for(size_t i=1; i<len; i++)
1049 {
1050 //Throw away clock samples until we find an edge
1051 if(clock->m_samples[i] == clock->m_samples[i-1])
1052 continue;
1053
1054 //Throw away data samples until the data is synced with us
1055 int64_t clkstart = GetOffsetScaled(clock, i);
1056 while( (ndata+1 < dlen) && (GetOffsetScaled(data, ndata+1) < clkstart) )
1057 ndata ++;
1058 if(ndata >= dlen)
1059 break;
1060
1061 //Find the fractional position of the clock edge
1062 int64_t tsample = GetOffsetScaled(data, ndata);
1063 int64_t delta = clkstart - tsample;
1064 float frac = delta * 1.0 / data->m_timescale;
1065
1066 //Add the new sample
1067 samples.m_offsets.push_back(clkstart);
1068 samples.m_samples.push_back(InterpolateValue(data, ndata, frac));
1069 }
1070
1071 //Compute sample durations
1072 #ifdef __x86_64__
1073 if(g_hasAvx2)
1074 FillDurationsAVX2(samples);
1075 else
1076 #endif
1077 FillDurationsGeneric(samples);
1078
1079 samples.MarkModifiedFromCpu();
1080 }
1081
1094 template<class T>
1095 __attribute__((noinline))
1096 static void SampleOnAnyEdgesBaseWithInterpolation(WaveformBase* data, WaveformBase* clock, SparseWaveform<T>& samples)
1097 {
1098 data->PrepareForCpuAccess();
1099 clock->PrepareForCpuAccess();
1100 samples.PrepareForCpuAccess();
1101
1102 auto udata = dynamic_cast<UniformWaveform<T>*>(data);
1103 auto sdata = dynamic_cast<SparseWaveform<T>*>(data);
1104
1105 auto uclock = dynamic_cast<UniformDigitalWaveform*>(clock);
1106 auto sclock = dynamic_cast<SparseDigitalWaveform*>(clock);
1107
1108 if(udata && uclock)
1109 SampleOnAnyEdgesWithInterpolation(udata, uclock, samples);
1110 else if(udata && sclock)
1111 SampleOnAnyEdgesWithInterpolation(udata, sclock, samples);
1112 else if(sdata && sclock)
1113 SampleOnAnyEdgesWithInterpolation(sdata, sclock, samples);
1114 else if(sdata && uclock)
1115 SampleOnAnyEdgesWithInterpolation(sdata, uclock, samples);
1116 }
1117
1121 template<class T>
1123 {
1124 if(s)
1126 else
1128 }
1129
1133 template<class T>
1135 {
1136 if(s)
1138 else
1140 }
1141
1142 static void FindRisingEdges(UniformAnalogWaveform* data, float threshold, std::vector<int64_t>& edges);
1143 static void FindRisingEdges(SparseAnalogWaveform* data, float threshold, std::vector<int64_t>& edges);
1144 static void FindZeroCrossings(SparseAnalogWaveform* data, float threshold, std::vector<int64_t>& edges);
1145 static void FindZeroCrossings(UniformAnalogWaveform* data, float threshold, std::vector<int64_t>& edges);
1146 static void FindZeroCrossings(UniformDigitalWaveform* data, std::vector<int64_t>& edges);
1147 static void FindZeroCrossings(SparseDigitalWaveform* data, std::vector<int64_t>& edges);
1148 static void FindRisingEdges(UniformDigitalWaveform* data, std::vector<int64_t>& edges);
1149 static void FindRisingEdges(SparseDigitalWaveform* data, std::vector<int64_t>& edges);
1150 static void FindFallingEdges(UniformDigitalWaveform* data, std::vector<int64_t>& edges);
1151 static void FindFallingEdges(SparseDigitalWaveform* data, std::vector<int64_t>& edges);
1152 static void FindPeaks(UniformAnalogWaveform* data, float peak_threshold, std::vector<int64_t>& peak_indices);
1153 static void FindPeaks(SparseAnalogWaveform* data, float peak_threshold, std::vector<int64_t>& peak_indices);
1154
1155 static void FindZeroCrossingsBase(WaveformBase* data, float threshold, std::vector<int64_t>& edges)
1156 {
1157 auto udata = dynamic_cast<UniformAnalogWaveform*>(data);
1158 auto sdata = dynamic_cast<SparseAnalogWaveform*>(data);
1159
1160 if(udata)
1161 FindZeroCrossings(udata, threshold, edges);
1162 else
1163 FindZeroCrossings(sdata, threshold, edges);
1164 }
1165
1166 static void FindRisingEdges(
1167 SparseDigitalWaveform* sdata, UniformDigitalWaveform* udata, std::vector<int64_t>& edges)
1168 {
1169 if(sdata)
1170 FindRisingEdges(sdata, edges);
1171 else
1172 FindRisingEdges(udata, edges);
1173 }
1174
1175 static void FindFallingEdges(
1176 SparseDigitalWaveform* sdata, UniformDigitalWaveform* udata, std::vector<int64_t>& edges)
1177 {
1178 if(sdata)
1179 FindFallingEdges(sdata, edges);
1180 else
1181 FindFallingEdges(udata, edges);
1182 }
1183
1184 static void FindPeaks(
1185 SparseAnalogWaveform* sdata, UniformAnalogWaveform* udata, float peak_threshold, std::vector<int64_t>& peak_indices)
1186 {
1187 if(sdata)
1188 FindPeaks(sdata, peak_threshold, peak_indices);
1189 else
1190 FindPeaks(udata, peak_threshold, peak_indices);
1191 }
1192
1193 static void FindZeroCrossings(
1194 SparseAnalogWaveform* sdata, UniformAnalogWaveform* udata, float threshold, std::vector<int64_t>& edges)
1195 {
1196 if(sdata)
1197 FindZeroCrossings(sdata, threshold, edges);
1198 else
1199 FindZeroCrossings(udata, threshold, edges);
1200 }
1201
1202 static void FindZeroCrossings(
1203 SparseDigitalWaveform* sdata, UniformDigitalWaveform* udata, std::vector<int64_t>& edges)
1204 {
1205 if(sdata)
1206 FindZeroCrossings(sdata, edges);
1207 else
1208 FindZeroCrossings(udata, edges);
1209 }
1210
1211 static void ClearAnalysisCache();
1212
1213 enum FIRFilterType
1214 {
1215 FILTER_TYPE_LOWPASS,
1216 FILTER_TYPE_HIGHPASS,
1217 FILTER_TYPE_BANDPASS,
1218 FILTER_TYPE_NOTCH
1219 };
1220
1221 static void CalculateFIRCoefficients(
1222 float fa,
1223 float fb,
1224 float stopbandAtten,
1225 FIRFilterType type,
1226 AcceleratorBuffer<float>& coefficients);
1227 static float Bessel(float x);
1228
1229protected:
1230 //Helpers for sparse waveforms
1231 static void FillDurationsGeneric(SparseWaveformBase& wfm);
1232#ifdef __x86_64__
1233 static void FillDurationsAVX2(SparseWaveformBase& wfm);
1234#endif
1235
1236public:
1237 sigc::signal<void()> signal_outputsChanged()
1238 { return m_outputsChangedSignal; }
1239
1240protected:
1242 sigc::signal<void()> m_outputsChangedSignal;
1243
1249 unsigned int m_instanceNum;
1250
1251public:
1252 typedef Filter* (*CreateProcType)(const std::string&);
1253 static void DoAddDecoderClass(const std::string& name, CreateProcType proc);
1254
1255 static void EnumProtocols(std::vector<std::string>& names);
1256 static Filter* CreateFilter(const std::string& protocol, const std::string& color = "#ffffff");
1257
1258protected:
1259 //Class enumeration
1260 typedef std::map< std::string, CreateProcType > CreateMapType;
1261 static CreateMapType m_createprocs;
1262
1263 //Object enumeration
1264 static std::set<Filter*> m_filters;
1265
1266 //Instance naming
1267 static std::map<std::string, unsigned int> m_instanceCount;
1268
1269 //Caching
1270 static std::mutex m_cacheMutex;
1271 static std::map<std::pair<WaveformBase*, float>, std::vector<int64_t> > m_zeroCrossingCache;
1272};
1273
1274#define PROTOCOL_DECODER_INITPROC(T) \
1275 static Filter* CreateInstance(const std::string& color) \
1276 { \
1277 return new T(color); \
1278 } \
1279 virtual std::string GetProtocolDisplayName() override \
1280 { return GetProtocolName(); }
1281
1282#define AddDecoderClass(T) Filter::DoAddDecoderClass(T::GetProtocolName(), T::CreateInstance)
1283
1284#endif
Declaration of FlowGraphNode.
Declaration of OscilloscopeChannel.
A buffer of memory which may be used by GPU acceleration.
Definition: AcceleratorBuffer.h:158
void push_back(const T &value)
Adds a new element to the end of the container, allocating space if needed.
Definition: AcceleratorBuffer.h:752
Abstract base class for all filter graph blocks which are not physical instrument channels.
Definition: Filter.h:95
void AddDigitalStream(const std::string &name)
Helper method for constructors that adds a new STREAM_TYPE_DIGITAL output stream.
Definition: Filter.h:172
static float GetMaxVoltage(SparseAnalogWaveform *s, UniformAnalogWaveform *u)
Gets the lowest voltage of a waveform.
Definition: Filter.h:510
virtual void Refresh() override
Evaluates a filter graph node.
Definition: Filter.cpp:823
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:1598
void UseDefaultName(bool use)
Specifies whether we're using an auto-generated name or not.
Definition: Filter.h:185
bool VerifyAllInputsOKAndSparseOrUniformDigital()
Returns true if every input to the filter is non-NULL and has a non-empty, digital waveform present.
Definition: Filter.cpp:241
SparseDigitalWaveform * SetupEmptySparseDigitalOutputWaveform(WaveformBase *din, size_t stream)
Sets up an digital output waveform and copies basic metadata from the input.
Definition: Filter.cpp:1170
__attribute__((noinline)) static float GetAvgVoltage(T *cap)
Gets the average voltage of a waveform.
Definition: Filter.h:606
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:318
virtual bool ShouldPersistWaveform() override
Determine whether the channel's waveform(s) should be persisted to a session file.
Definition: Filter.cpp:944
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:1278
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:350
static void PrepareForCpuAccess(SparseWaveform< T > *s, UniformWaveform< T > *u)
Prepares a sparse or uniform analog waveform for CPU access.
Definition: Filter.h:1122
__attribute__((noinline)) static void SampleOnRisingEdges(T *data
Samples a waveform on the rising edges of a clock.
__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:678
virtual void ClearStreams() override
Clears out any existing streams.
Definition: Filter.cpp:1591
static void AdvanceToTimestamp(SparseWaveformBase *wfm, size_t &i, size_t len, int64_t timestamp)
Advance the waveform to a given timestamp.
Definition: Filter.cpp:1304
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:1062
__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:137
__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:480
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:1099
Category m_category
Category this filter should be displayed under.
Definition: Filter.h:267
static void PrepareForGpuAccess(SparseWaveform< T > *s, UniformWaveform< T > *u)
Prepares a sparse or uniform analog waveform for GPU access.
Definition: Filter.h:1134
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:217
virtual void SetDefaultName()
Sets the name of a filter based on its inputs.
Definition: Filter.cpp:1459
std::vector< float > m_ranges
Y axis range of each output stream.
Definition: Filter.h:248
void HideFromList()
Removes this filter from the global list.
Definition: Filter.h:146
static std::set< Filter * > GetAllInstances()
Get all currently existing filters.
Definition: Filter.h:133
unsigned int m_instanceNum
Instance number (for auto naming)
Definition: Filter.h:1249
__attribute__((noinline)) static float GetMinVoltage(T *cap)
Gets the lowest voltage of a waveform.
Definition: Filter.h:462
static float Bessel(float x)
0th order Bessel function
Definition: Filter.cpp:1436
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:1325
UniformDigitalWaveform * SetupEmptyUniformDigitalOutputWaveform(WaveformBase *din, size_t stream)
Sets up an digital output waveform and copies basic metadata from the input.
Definition: Filter.cpp:1135
std::vector< float > m_offsets
Y axis offset of each output stream.
Definition: Filter.h:251
bool m_usingDefault
If true, we're using an auto-generated name.
Definition: Filter.h:270
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:286
static void AdvanceToTimestampScaled(SparseWaveformBase *wfm, size_t &i, size_t len, int64_t timestamp)
Advance the waveform to a given timestamp.
Definition: Filter.cpp:1351
__attribute__((noinline)) static std
Makes a histogram from a waveform with the specified number of bins.
Definition: Filter.h:640
static float GetTopVoltage(SparseAnalogWaveform *swfm, UniformAnalogWaveform *uwfm)
Gets the top voltage of a waveform which may be sparse or uniform.
Definition: Filter.h:594
bool IsUsingDefaultName()
Return true if we're using an autogenerated name, false if customized.
Definition: Filter.h:193
Category GetCategory()
Returns the category for displaying this filter in the browser.
Definition: Filter.h:210
__attribute__((noinline)) static float GetBaseVoltage(T *cap)
Gets the most probable "0" level for a digital waveform.
Definition: Filter.h:522
Category
Category the filter should be displayed under in the GUI.
Definition: Filter.h:108
__attribute__((noinline)) static float GetTopVoltage(T *cap)
Gets the most probable "1" level for a digital waveform.
Definition: Filter.h:564
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:1242
__attribute__((noinline)) static void SampleOnAnyEdgesBase(WaveformBase *data
Samples a waveform on all edges of a clock.
__attribute__((noinline)) static float GetMaxVoltage(T *cap)
Gets the highest voltage of a waveform.
Definition: Filter.h:492
static float InterpolateValue(SparseAnalogWaveform *cap, size_t index, float frac_ticks)
Interpolates the actual value of a point between two samples.
Definition: Filter.cpp:1009
virtual void LoadParameters(const YAML::Node &node, IDTable &table) override
Load configuration from a save file.
Definition: Filter.cpp:883
sigc::signal< void()> m_outputsChangedSignal
Signal emitted when the set of output streams changes.
Definition: Filter.h:1242
__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:622
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:1208
virtual std::string GetProtocolDisplayName()=0
Gets the display name of this protocol (for use in menus, save files, etc). Must be unique.
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:1608
static float GetBaseVoltage(SparseAnalogWaveform *swfm, UniformAnalogWaveform *uwfm)
Gets the base voltage of a waveform which may be sparse or uniform.
Definition: Filter.h:552
size_t GetRefCount()
Returns the current reference count.
Definition: Filter.h:203
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:843
__attribute__((noinline)) static float InterpolateTime(T *cap
Interpolates the actual time of a threshold crossing between two samples.
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:193
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:164
static void CalculateFIRCoefficients(float fa, float fb, float stopbandAtten, FIRFilterType type, AcceleratorBuffer< float > &coefficients)
Calculates FIR coefficients.
Definition: Filter.cpp:1388
virtual bool NeedsConfig()
Determines if we need to display the configuration / setup dialog.
Definition: Filter.cpp:1579
Bidirectional table mapping integer IDs in scopesession files to object pointers.
Definition: IDTable.h:51
void SetData(WaveformBase *pNew, size_t stream)
Sets the waveform data for a given stream, replacing any previous waveform.
Definition: InstrumentChannel.cpp:139
WaveformBase * GetData(size_t stream)
Get the contents of a data stream.
Definition: InstrumentChannel.h:184
A single channel on an oscilloscope.
Definition: OscilloscopeChannel.h:49
size_t m_refcount
Number of references (channel is disabled when last ref is released)
Definition: OscilloscopeChannel.h:165
Wrapper around a Vulkan Queue, protected by mutex for thread safety.
Definition: QueueManager.h:53
Base class for waveforms with nonuniform sample rate.
Definition: Waveform.h:272
AcceleratorBuffer< int64_t > m_offsets
Start timestamps of each sample, in multiples of m_timescale.
Definition: Waveform.h:307
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:337
A waveform sampled at irregular intervals.
Definition: Waveform.h:481
virtual void Reserve(size_t size) override
Preallocates buffers without changing the usable size of the waveform.
Definition: Waveform.h:575
virtual void PrepareForCpuAccess() override
Indicates that this waveform is going to be used by the CPU in the near future.
Definition: Waveform.h:592
virtual void clear() override
Remove all samples from this waveform.
Definition: Waveform.h:585
AcceleratorBuffer< S > m_samples
Sample data.
Definition: Waveform.h:556
virtual void PrepareForGpuAccess() override
Indicates that this waveform is going to be used by the CPU in the near future.
Definition: Waveform.h:599
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:617
virtual void Resize(size_t size) override
Reallocates buffers so the waveform contains the specified number of samples.
Definition: Waveform.h:568
StreamType
General data type stored in a stream.
Definition: Stream.h:58
Base class for waveforms with data sampled at uniform intervals.
Definition: Waveform.h:355
A waveform sampled at uniform intervals.
Definition: Waveform.h:383
virtual void PrepareForCpuAccess() override
Indicates that this waveform is going to be used by the CPU in the near future.
Definition: Waveform.h:448
virtual void PrepareForGpuAccess() override
Indicates that this waveform is going to be used by the CPU in the near future.
Definition: Waveform.h:451
A unit of measurement, plus conversion to pretty-printed output.
Definition: Unit.h:57
Base class for all Waveform specializations.
Definition: Waveform.h:59
uint64_t m_revision
Revision number.
Definition: Waveform.h:139
time_t m_startTimestamp
Start time of the acquisition, integer part.
Definition: Waveform.h:109
virtual void PrepareForCpuAccess()=0
Indicates that this waveform is going to be used by the CPU in the near future.
int64_t m_startFemtoseconds
Start time of the acquisition, fractional part (femtoseconds since since the UTC second)
Definition: Waveform.h:112
int64_t m_triggerPhase
Offset, in X axis units (usually femtoseconds), from the trigger to the sampling clock.
Definition: Waveform.h:125
int64_t m_timescale
The time scale, in X axis units (usually femtoseconds) per timestep, used by this channel.
Definition: Waveform.h:106
Describes a particular revision of a waveform.
Definition: Filter.h:52
WaveformCacheKey()
Create an empty cache key for a null waveform.
Definition: Filter.h:56
WaveformBase * m_wfm
Pointer to the waveform object.
Definition: Filter.h:84
WaveformCacheKey(WaveformBase *wfm)
Create a cache key for a waveform.
Definition: Filter.h:66
uint64_t m_rev
Definition: Filter.h:87
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:741