Waveform Characterization

I am developing a library for basic waveform characterization. Linked WaveformAnalysis.jl

I have a few of the functions done pretty well done in the most efficient way I can think of. I am getting hung up right now with my “pulses” function which will simultaneously measure all of the pulse widths for the given polarity. I am trying to have a more finessed way of handling all the edge cases for a captured waveform. The simplest case (to me) is to count all the positive and negative crosses in the waveform, then subtract either the positives from the negatives for looking for negative pulses or subtracting the positive crosses from the negative crosses to get the positive pulses.

The trouble comes when there are not an equal number of detected edges. I have the incomplete function pasted below: (incomplete because it is missing code to handle negative pulses)

Edit: I think I came up with a good solution, pasted below

function detectcrosses(x::Vector{T}, thresh::T, edge::Edge) where {T <: Real}
    events = (edge == Rising ? x .>= thresh : x .<= thresh)
    findall(events .& (.~events >> 1))

pulses(x::Vector{T}, thresh::T, pol::Polarity) where T <: Real = 
    measurepulses(detectcrosses(x, thresh, Rising), detectcrosses(x, thresh, Falling), pol)

function measurepulses(poscrosses::Vector{T}, negcrosses::Vector{T}, pol::Polarity) where T <: Int64
    if !isempty(poscrosses) && !isempty(negcrosses)
        if pol == ActiveHigh
            alignedges!(poscrosses, negcrosses)
            negcrosses .- poscrosses
            alignedges!(negcrosses, poscrosses)
            poscrosses .- negcrosses

for more context, please take a look at my code in src/WaveformAnalysis.jl. Any additional feedback is welcome for my code not pertaining to my exact question as I am a relatively new Julia coder.

Thanks in advance!

It is unclear what you are asking for. Please clarify the actual question, and create a minimal self-contained example.

Thank you for the tips. I am also pretty new at posting to forums in general. The actual question is, is there a more elegant way to align my detected positive and negative edges, then perform the proper subtraction to get either positive pulse width or negative pulse widths. More elegant than brute forcing every conceivable case other than the simplest.

Nice vectorized code. Very Matlab-ish… bet maybe even more SKILL/OCEAN-like in my opinion.


Your solution looks pretty good. If I understood correctly, after detecting the crosses, you then run those through alignedges! to strip off leading edges if they are in the wrong direction.

I myself would have instead detected the first rising edge, then would have run my algorithm from that point on (or vice-versa when looking for negative pulses).

…but that’s not really that important: because at least alignedges! only runs on the “crosses” data (which is much more sparse than the original x-vector).

Julian solution

Although I find creating vecorized code is very elegant in its own way, I personally prefer writing these “base” algorithms with for loops. Julia does not get performance enhancements by using vectorized code. In fact, you are probably adding redundant operations when writing code in this “macroscopic fashion”

Though ok for getting a quick-and-dirty first cut, I would personally re-write these “crosses” functions with for loops, and let users of the functions use them in their own quick-and-dirty, one-off algorithms.

Of course, feel free to ignore this suggestion - especially if the performance you get is sufficient for the problems you are trying to solve.

Alternative (existing) solution

FYI: If I understand what you are trying to do, I think you would be very interested in my CData.jl module:

It is simply a dummy module that pulls in other (not-yet-registered) modules that make data processing of simulation & measurement results much easier to handle. CData.jl includes such things as:

  • MDDatasets.jl: Handles multi-dimensional data sets & operations on them (Particularly effective when analyzing results from large parametric sweeps of Voltage, Temperature, datarate, etc).
  • SignalProcessing.jl: Step/pulse responses, Fourier transform/series, PRBS sequences, …:
  • CircuitAnalysis.jl: Basic circuit analysis tools.
  • NetwAnalysis.jl: S/Z/Y/H/G/ABCD parameters, …
  • InspectDR.jl: Efficient/interactive Julia/Gtk plots (Great for bode plots & Smith charts)
  • SpiceData.jl: Pure-Julia SPICE data file reader
  • LibPSF.jl: Pure-Julia implementation of 3rd party .psf reader
  • PSFWrite.jl: Pure-Julia .psf writer

There are examples of things similar to what you are doing in the SignalProcessing.jl sample/ subdirectory.

In particular, I make use of xcross, ycross, delay measurement functions, etc.

You can check out some of the plots it can generate:

PS: CData.jl solutions support arbitrary time steps by keeping (t, v(t)) values together in a single data structure (called DataF1). That way, you can directly deal with outputs from modern circuit simulators.