# \[ANN\] MDDatasets.jl: Multi-dimensional datasets & continuous x-variable interpolation

**URL:** https://discourse.julialang.org/t/ann-mddatasets-jl-multi-dimensional-datasets-continuous-x-variable-interpolation/27354
**Category:** Package Announcements
**Created:** [August 9, 2019, 4:41pm UTC](https://discourse.julialang.org/t/ann-mddatasets-jl-multi-dimensional-datasets-continuous-x-variable-interpolation/27354 "2019-08-09T16:41:01Z")
**Posts on this page:** 2
**Page:** 1

<div class="post-metadata">

### Author: ![MA\_Laforge](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ma_laforge/32/385_2.png) [@MA\_Laforge](https://discourse.julialang.org/u/MA_Laforge)
#### Post date: [August 9, 2019, 4:41pm UTC](https://discourse.julialang.org/t/ann-mddatasets-jl-multi-dimensional-datasets-continuous-x-variable-interpolation/27354/1 "2019-08-09T16:41:01Z")

</div>

The MDDatasets.jl module provides tools to simplify manipulation of multi-dimensional datasets.  
 → [GitHub - ma-laforge/MDDatasets.jl: Multi-Dimensional Datasets for Parametric Analysis](https://github.com/ma-laforge/MDDatasets.jl)

Insallation:

```julia-auto
] add MDDatasets

```

### Grouping (x,y) vectors

MDDatasets also provides a means to group `(x,y)` data in a single data structure to simplify calculations (`DataF1` structure). For example, we can take the derivative of a dataset (wrt `x`) very simply using:

_**(Using MDDatasets.jl:)**_

```julia-auto
#Assuming f1 has time-domain data y=f(x=t):
slope = deriv(f1)

```

Note that internally, `f1` contains _ **both** _ `y` values, and `x` values (which represent time, `t`). This is much more straightforward than the typical way to do differentiation:

_**(WITHOUT the help of MDDatasets.jl:)**_

```julia-auto
#Assuming we have f1_x & f1_y data:
deltax = f1_x[2:end] .- f1_x[1:end-1]
deltay = f1_y[2:end] .- f1_y[1:end-1]
slope = deltay ./ deltax

```

### AUTOMATIC INTERPOLATION

Note that operations on `DataF1` objects will _ **automatically interpolate** _ intermediate values if the `x` sample points don’t match. This is particularly useful if you wish to perform operations on results collected from multiple simulations that have different/non-uniform time steps (or whatever the x-values might represent).

### Multi-Dimensional Data & “Parametric Analysis”

`MDDatasets.jl` is designed to store values from a “Parametric Analysis”. Basically, you re-run the same experiments with different conditions by “sweeping” the values of different control variables in order to see how they affect results.

For example, you might want to simulate circuit behaviour by “sweeping” the following parameters:

```julia-auto
for vSupply in [0.9V, 1V, 1.1V]
	for temp in [-40, 0, 100, 125]
		for trise in 10e-12:10e-12:100e-12
			#Read in data & compute characteristics that might be insighful
		end
	end
end

```

With MDDatasets.jl, the procedure is a bit more straightforward…

### Step 1: Collect Data in Multi-Dimensional Dataset using `DataRS`

To build a multi-dimensional dataset, you would “fill” a `DataRS` structure:

```julia-auto
signal1 = fill(DataRS, PSweep("tbit", [1, 3, 9] * 1e-9)) do tbit
	fill(DataRS, PSweep("VDD", 0.9 * [0.9, 1, 1.1])) do vdd

		#Inner-most sweep: need to specify element type (DataF1):
		fill(DataRS{DataF1}, PSweep("trise", [0.1, 0.15, 0.2] * tbit)) do trise
			y = get_ydata(tbit, vdd, trise) #Read in y values
			x = get_xdata(tbit, vdd, trise) #Read in x values
			return DataF1(x, y) #"Leaf" elements of DataRS structure are DataF1 containers.
		end
	end
end

```

This assumes `get_xdata()` & `get_ydata()` functions retrieve simulation data at certain values of `tbit`, `vdd`, & `trise`.

_**Indeed, this DOES seem like alot, but you only have to read in data once. Once data is read in, performing the actual calculations becomes much more straightforward and easy to read/write (see below).**_

### Step 2: Run Calculations

Assuming `vin` & `vout` are `DataRS` structures storing the input & output voltages of a closed-loop op-amp time-domain simulation, one could easily compute the gain error over all of the simulated time:

```julia-auto
gainideal = 6 #Desired gain of op-amp

#Compute error in gain value, over time:
error = 100 * ((vout/vin) - gainideal) / gainideal

```

_ **NOTE:** _

- There is no need for explicit `for` loops. MDDatasets.jl automatically broadcasts operations over all “swept” parameters.
- There is no need for the “dot” notation (`.+`, `.*`, …). Unlike with `Array` objects, `DataRS` structures are not meant to natively support matrix operations (matrix multiplication, etc). Consequently, there is no confusion between element-by-element & matrix operations.

### Sample Usage

More advanced uses of the `MDDatasets.jl` module can be found in the (not-yet-registered) `SignalProcessing.jl` module:

→ [https://github.com/ma-laforge/SignalProcessing.jl](https://github.com/ma-laforge/SignalProcessing.jl)

---

<div class="post-metadata">

### Author: ![MA\_Laforge](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ma_laforge/32/385_2.png) [@MA\_Laforge](https://discourse.julialang.org/u/MA_Laforge)
#### Post date: [August 10, 2019, 1:28am UTC](https://discourse.julialang.org/t/ann-mddatasets-jl-multi-dimensional-datasets-continuous-x-variable-interpolation/27354/2 "2019-08-10T01:28:23Z")

</div>

# Concrete Example

```julia-auto
using MDDatasets

```

Create (x,y) container pair, and call it “x”:

```julia-auto
x = DataF1(0:.1:20)
#NOTE: Both x & y coordinates of "x" object initialized as y = x = [supplied range]

```

“Extract” maximum x-value from data:

```julia-auto
xmax = maximum(x)

```

Construct a “normalized” ramp dataset, `unity_ramp`:

```julia-auto
unity_ramp = x/xmax

```

### Observe `x` and `unity_ramp`

(Note how `unity_ramp` is normalized such that the maximum value is 1)

 ![image](https://global.discourse-cdn.com/julialang/original/3X/6/f/6f1d25b5999eef271a7b83f8b898979885d08848.png)

Compute `sin(x)`

```julia-auto
sinx = sin(x)

```

Compute ramps with different slopes using `unity_ramp` (previously computed):

```julia-auto
#NOTE: for Inner-most sweep, we need to specify leaf element type (DataF1 here):
ramp = fill(DataRS{DataF1}, PSweep("slope", [0, 0.5, 1, 1.5, 2])) do slope
	return unity_ramp * slope
end

```

NOTE: the above expression constructs a multi-dimensional `DataRS` structure, and fills it with `(x,y)` values for each of the desired parameter values (the slope).

### Observe `sinx` and `ramp`

 ![image](https://global.discourse-cdn.com/julialang/original/3X/3/5/358b02fcd34f301b62631254b80976db8922a1c3.png)

Merge two datasets with different # of sweeps (`sinx` & `ramp`):

```julia-auto
r_sin = sinx+ramp

```

### Observe newly constructed `r_sin` dataset:

 ![image](https://global.discourse-cdn.com/julialang/original/3X/1/b/1ba60ec335f6705da9cd510ae65fa9aac0a54ef5.png)

Shift all ramped `sin(x)` waveforms to make them centered at their mid-points:

```julia-auto
midval = (minimum(ramp) + maximum(ramp)) / 2
c_sin = r_sin - midval #Shift by midval (different for each swept slope of "ramp")

```

### Observe newly constructed `c_sin` dataset:

 ![image](https://global.discourse-cdn.com/julialang/original/3X/9/5/9543cad89475105821e6e779c1ed8568dfb0c1e4.png)
