Awesome Open Source
Awesome Open Source

FSharp.Data.Tdms FSharp.Data

FSharp.Data.Tdms provides support for TDMS 2.0 files[1] from F# and C# on .NET 6.0. From F# it allows you to access these in a type-safe manner through a generative type provider, while plain old functions and methods are available to both F# and C#. FSharp.Data.Tdms reads raw channel data from TDMS 2.0 files as arrays.

Missing features

  • Reading DAQmx raw data

  • Defragmenting TDMS files

  • Writing TDMS files

License

FSharp.Data.Tdms is licensed under an MIT License. Please refer to LICENSE for its full text.

Usage

From F#

Using the generative type provider, given a TDMS file Experiment.tdms with a channel containing floating-point values named Channel1 within a group named Group1:

#r "nuget: FSharp.Data.Tdms"

open FSharp.Data

[<Literal>]
let Path = "Experiment.tdms"

type Experiment = TdmsProvider<Path, WriteIndex = true>

let experiment = Experiment(Path)

experiment.Group1.Channel1.Data |> Array.iter (printfn "%f")

Alternatively, use the functions in the FSharp.Data.Tdms namespace, mainly those in the File module:

#r "nuget: FSharp.Data.Tdms"

open FSharp.Data.Tdms

File.read "Experiment.tdms" true
|> File.tryRawData<float> "Group1" "Channel1"
|> Option.defaultValue [||]
|> Array.iter (printfn "%f")

These functions have asynchronous equivalents:

#r "nuget: FSharp.Data.Tdms"

open FSharp.Control.Tasks.NonAffine
open FSharp.Data.Tdms

task {
    let! file = File.readAsync "Experiment.tdms" true
    let! data = File.tryRawDataAsync<float> "Group1" "Channel1"

    Option.defaultValue data
    |> Array.iter (printfn "%f")
}
|> Async.AwaitTask
|> Async.RunSynchronously

From C#

When using FSharp.Data.Tdms from C#, prefer the API for idiomatic C#:

using System;
using FSharp.Data.Tdms;

class Program
{
    static void Main(string[] args)
    {
        File.Read("Experiment.tdms", true).TryGetRawData("Group1", "Channel1", out double[] data);

        foreach (double sample in data)
        {
            Console.WriteLine(sample);
        }
    }
}

Or asynchronously:

using System;
using FSharp.Data.Tdms;

class Program
{
    static async Task Main(string[] args)
    {
        var file = await File.ReadAsync("Experiment.tdms", true);
        var data = await file.TryGetRawDataAsync("Group1", "Channel1");

        foreach (double sample in data)
        {
            Console.WriteLine(sample);
        }
    }
}

Property and raw data types

Most TDMS 2.0 data types directly map to .NET 5.0 data types. The first exception is tdsTypeTimeStamp, which you can read as either FSharp.Data.Tdms.Timestamp (this data type corresponds to the NI LabVIEW timestamp), System.DateTime, System.DateTimeOffset, or System.TimeSpan. In case of System.TimeSpan, FSharp.Data.Tdms returns the time elapsed since 01/01/1904 00:00:00.00 UTC, as per this support document from NI.

The second exception is tdsTypeExtendedFloat. Since .NET 5.0 does not support 80-bit extended precision floating point numbers, FSharp.Data.Tdms reads these as FSharp.Data.Tdms.Extended values.

Table 1. Mapping from TDMS 2.0 to .NET 5.0 data types in FSharp.Data.Tdms

Name

TDMS 2.0 data type

.NET 5.0 data type

F# alias

C# alias

Void

tdsTypeVoid

FSharp.Core.Unit

unit

None

8-bit signed integer

tdsTypeI8

System.SByte

int8

sbyte

16-bit signed integer

tdsTypeI16

System.Int16

int16

short

32-bit signed integer

tdsTypeI32

System.Int32

int

int

64-bit signed integer

tdsTypeI64

System.Int64

int64

long

8-bit unsigned integer

tdsTypeU8

System.Byte

uint8

byte

16-bit unsigned integer

tdsTypeU16

System.UInt16

uint16

ushort

32-bit unsigned integer

tdsTypeU32

System.UInt32

uint

uint

64-bit unsigned integer

tdsTypeU64

System.UInt64

uint64

ulong

32-bit single-precision floating point

  • tdsTypeSingleFloat

  • tdsTypeSingleFloatWithUnit

System.Single

float32

float

64-bit double-precision floating point

  • tdsTypeDoubleFloat

  • tdsTypeDoubleFloatWithUnit

System.Double

float

double

80-bit extended-precision floating point

  • tdsTypeExtendedFloat

  • tdsTypeExtendedFloatWithUnit

FSharp.Data.Tdms.Extended

float80

None

Character string

tdsTypeString

System.String

string

string

Boolean

tdsTypeBoolean

System.Boolean

bool

bool

Timestamp

tdsTypeTimeStamp

None

None

32-bit single-precision floating point complex

tdsTypeComplexSingleFloat

System.ValueTuple<System.Single, System.Single>

struct (float32 * float32)

(float, float)

64-bit double-precision floating point complex

tdsTypeComplexDoubleFloat

System.Numerics.Complex

None

None

Performance

The BenchmarkDotNet benchmarks in this section give an idea of the performance of FSharp.Data.Tdms when compared to TDMSReader, the only other TDMS 2.0 implementation which works on .NET 5.0. Since TDMSReader does not support reading TDMS index files, the benchmark disables this feature for FSharp.Data.Tdms as well, for a fair comparison. This means that FSharp.Data.Tdms may perform better in practice for TDMS files with many raw data segments.

Small file

This benchmark reads 30,489 double-precision floating points from a segmented 3.1 MB TDMS 2.0 file.

BenchmarkDotNet=v0.12.1, OS=macOS 11.1 (20C69) [Darwin 20.2.0]
Intel Core i9-9980HK CPU 2.40GHz, 1 CPU, 16 logical and 8 physical cores
.NET Core SDK=5.0.101
  [Host]        : .NET Core 5.0.1 (CoreCLR 5.0.120.57516, CoreFX 5.0.120.57516), X64 RyuJIT DEBUG
  .NET Core 5.0 : .NET Core 5.0.1 (CoreCLR 5.0.120.57516, CoreFX 5.0.120.57516), X64 RyuJIT

Job=.NET Core 5.0  Runtime=.NET Core 5.0

Method

Mean

Error

StdDev

Ratio

RatioSD

TDMSReader

5.531 ms

0.1049 ms

0.0930 ms

1.00

0.00

FSharp.Data.Tdms synchronously

1.962 ms

0.0378 ms

0.0435 ms

0.35

0.01

FSharp.Data.Tdms asynchronously

5.061 ms

0.0503 ms

0.0471 ms

0.91

0.02

Medium-sized file

This benchmark reads a channel of 43,200 strings from a segmented 138.1 MB TDMS 2.0 file.

BenchmarkDotNet=v0.12.1, OS=macOS 11.1 (20C69) [Darwin 20.2.0]
Intel Core i9-9980HK CPU 2.40GHz, 1 CPU, 16 logical and 8 physical cores
.NET Core SDK=5.0.101
  [Host]        : .NET Core 5.0.1 (CoreCLR 5.0.120.57516, CoreFX 5.0.120.57516), X64 RyuJIT DEBUG
  .NET Core 5.0 : .NET Core 5.0.1 (CoreCLR 5.0.120.57516, CoreFX 5.0.120.57516), X64 RyuJIT

Job=.NET Core 5.0  Runtime=.NET Core 5.0

Method

Mean

Error

StdDev

Ratio

TDMSReader

12.334 s

0.2287 s

0.2139 s

1.00

FSharp.Data.Tdms synchronously

4.400 s

0.0370 s

0.0328 s

0.36

FSharp.Data.Tdms asynchronously

6.797 s

0.0981 s

0.0918 s

0.55

Large file

This benchmark reads a channel of 779,297 double-precision floating points from a segmented 1.54 GB TDMS 2.0 file.

BenchmarkDotNet=v0.12.1, OS=macOS 11.1 (20C69) [Darwin 20.2.0]
Intel Core i9-9980HK CPU 2.40GHz, 1 CPU, 16 logical and 8 physical cores
.NET Core SDK=5.0.101
  [Host]        : .NET Core 5.0.1 (CoreCLR 5.0.120.57516, CoreFX 5.0.120.57516), X64 RyuJIT DEBUG
  .NET Core 5.0 : .NET Core 5.0.1 (CoreCLR 5.0.120.57516, CoreFX 5.0.120.57516), X64 RyuJIT

Job=.NET Core 5.0  Runtime=.NET Core 5.0

Method

Mean

Error

StdDev

Ratio

TDMSReader

2.145 s

0.0242 s

0.0214 s

1.00

FSharp.Data.Tdms synchronously

1.103 s

0.0123 s

0.0103 s

0.52

FSharp.Data.Tdms asynchronously

1.953 s

0.0167 s

0.0157 s

0.91

How to contribute

Imposter syndrome disclaimer: I want your help. No really, I do.

There might be a little voice inside that tells you you’re not ready; that you need to do one more tutorial, or learn another framework, or write a few more blog posts before you can help me with this project.

I assure you, that’s not the case.

And you don’t just have to write code. You can help out by writing documentation, tests, or even by giving feedback about this work. (And yes, that includes giving feedback about the contribution guidelines.)

Thank you for contributing!

References

[1] National Instruments. 2019. The NI TDMS File Format. (January 2019). Retrieved January 12, 2019 from http://www.ni.com/white-paper/3727/en/.

Related Awesome Lists
Top Programming Languages
Top Projects

Get A Weekly Email With Trending Projects For These Topics
No Spam. Unsubscribe easily at any time.
C Sharp (163,944
Fsharp (4,086
Typeprovider (25
Tdm (25