Ammeter interface

by cisterni 5. September 2011 20:39

We are using VSLab as a console to coordinate experiments for measuring energy absorbed by algorithms. We have developed a methodology that allows us to get complexity behavior from the current absorbed by a computer on the AC power. Here is the source of a "virtual" ammeter based on phidgets sensors that allows us to decide the sampling frequency and wether use a buffer or not to accumulate samples. It is a nice application of unit of measure of F#, and shows also a pitfall of the language: "open" is a keyword but also the method name of the Phidgets .NET library, thus we resorted to reflection for invocation.

open Phidgets
 
let ifkit = new InterfaceKit()
let openPhidgets() = typeof<InterfaceKit>.GetMethod("open", [| |]).Invoke(ifkit, [| |]) |> ignore
 
[<Measure>] type V // Volt unit measure
[<Measure>] type A // Ampére unit measure
[<Measure>] type Hz // Hertz
[<Measure>] type s // Seconds
[<Measure>] type ms // Seconds
 
type AmmeterSensor(id:int, kit:InterfaceKit) =
  let k = 0.04204<A>
  let mutable buffered = false
  let sensor = kit.sensors.[id]
  let mutable lastv = 0.
  let mutable samplingRate = 10.<Hz>
  let mutable accumulator = 0.
  let mutable samplescount = 0.
  let mutable maxsz = 0 // Infinite
 
  let interval() = float(1. / samplingRate) * 1000.<ms>
  let mutable startInterval = System.DateTime.Now
 
  let buffer = new System.Collections.Generic.Queue<float<A>>()
 
  do
    sensor.Sensitivity <- 1
    kit.SensorChange.Add(fun v ->
      if v.Index = id && buffered then
        let dt = interval()
        let t = System.DateTime.Now
        if (t - startInterval).TotalMilliseconds > float(dt) then
          lastv <- (accumulator / samplescount)
          if maxsz > 0 && buffer.Count = maxsz then buffer.Dequeue() |> ignore
          buffer.Enqueue(lastv * k)
          startInterval <- t
          samplescount <- 0.
          accumulator <- 0.
        accumulator <- float(v.Value) + accumulator
        samplescount <- samplescount + 1.
    )
 
  member x.Buffered
    with get() = buffered
    and set(v) = buffered <- v
 
  member x.SamplingRate
    with get() = samplingRate
    and set(v) = samplingRate <- v
 
  /// <summary>
  /// NUmber of buffered samples. 0 means no bouds, please beware out of memory!
  /// </summary>
  member x.BufferSize
    with get() = maxsz
    and set(v) = maxsz <- v
 
  member x.nextValue() =
    if not buffered then
      Some(float(sensor.Value) * k)
    else
      if buffer.Count = 0 then
        let dt = interval()
        let t = System.DateTime.Now
        if (t - startInterval).TotalMilliseconds > float(dt) then
          startInterval <- t
          samplescount <- 0.
          accumulator <- 0.
          Some(float(sensor.Value) * k)
        else
          None
      else
        Some(buffer.Dequeue())
 
  member x.ToSequence () =
    seq {
      while kit.Attached do
        if buffered then
          let t = System.DateTime.Now
          let dt = float(interval())
          let elapsed = (t - startInterval).TotalMilliseconds
          if elapsed <= dt then
            System.Threading.Thread.Sleep(int(dt - elapsed) + 1)
        yield x.nextValue()
    }
 
 
 
 
openPhidgets()
 
let sens0 = new AmmeterSensor(3, ifkit)
 
sens0.Buffered <- true
 
sens0.ToSequence() |> Seq.take 1000 |> Seq.map (fun v -> match v with Some x -> float(x) | _ -> 0.)  |> Seq.toList |> Chart.Line
 
 
let sensors = [| 0 .. 2 |] |> Array.map (fun id -> new AmmeterSensor(id, ifkit))
sensors |> Array.iter (fun s -> s.Buffered <- true)
 
let values(amount) =
  seq {
    while true do
      let e = sensors |> Array.fold (fun v s -> v + s.nextValue().Value) 0.<A>
      System.Threading.Thread.Sleep(110)
      yield e
  } |> Seq.take amount
 
 
 
open System.IO
 
let out = File.CreateText(@"enclosure-5-pwr-100.xml")
out.WriteLine(@"<? xml version=""1.1"" encoding=""utf-8"" ?>")
out.WriteLine(@"<AmmeterSamples Description=""Enclosure with 5 blade pwr 100%"" SampleRate=""10Hz"">")
 
values(1200) |> Seq.iter (fun v -> out.WriteLine(sprintf "  <Sample>%f</Sample>" (float(v))))
 
out.WriteLine(@"</AmmeterSamples>")
out.Close()
printfn "Done."
 
 
sens0.nextValue()
 
let inp0 = ifkit.sensors.[0]
 
inp0.Sensitivity <- 1
 
inp0.Value
  ifkit.close()

Currently rated 2.5 by 10 people

  • Currently 2.5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Design | General | F# Interactive

Powered by BlogEngine.NET 1.4.0.0
Theme by Mads Kristensen

VSLab blog

VSLab is a Visual Studio extension designed to support Visual Studio interaction from F# interactive. It is a Microsoft product developed at University of Pisa, by a team lead by Antonio Cisternino.

Resources

Recent comments

Comment RSS

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in  anyway.

© Copyright 2008