2009-05-30 56 views
4

我是一名機械工程研究生,我的顧問剛要我爲我們的一個傳感器項目編寫數據可視化工具。由於是夏天,他希望我可以有一些樂趣,所以我認爲現在是學習科學計算語言的好時機,所以我繼續前進,並且投入到F#中。你如何在F#中解決這個問題? (高頻傳感器數據)

由於我是新的函數式編程範例,我在構建我的程序時遇到了一些困難,尤其是考慮到可以輕鬆地將FO中的OO/FP結合起來。我的任務如下:

  1. 我們有幾十個傳感器不斷報告數據(每隔幾秒鐘一次)。
  2. 我需要同時連接所有傳感器,創建每個傳感器輸出的內存時間序列,然後實時計算這些時間序列的各種統計數據。
  3. 每隔幾個小時,我需要將數據刷新到二進制文件中以用於日誌記錄。

我應該如何設計我的應用程序?我想過這樣的事情: 1.我打算連接到每個傳感器以開始接收數據,然後將這些數據轉儲到消息隊列中。 2.我會有一個事件驅動的處理函數接收隊列中的數據。當收到數據時,會確定數據來自哪個傳感器,然後將數據放入相應傳感器的時間序列對象中。 3.每當傳感器數據時間序列對象被添加時,我都可以觸發事件並讓我的統計功能爲傳感器收集新數據。

顯然我需要在這個應用程序中保持某種狀態。所以我會添加下面的可變數據結構。我會使用一個通用的.NET可調整大小的List來存儲我的時間序列數據,並實現一個新的派生方法來觸發數據添加事件。我可以在一個Dictionary中存儲sensorid和實際時間序列容器之間的映射(當數據從隊列中彈出時,我可以讀取sensorid字段,獲取該sensorid的時間序列容器,然後輕鬆添加新數據)。我還可以有第二個字典來存儲sensorid和各個時間序列之間的映射,這些時間序列包含感應時間序列的統計信息)。當添加主傳感器時間序列時,它會觸發一個事件來調用所有統計函數,以便在新數據上自行運行,並將其信息存儲在該傳感器ID的適當字典中。

我還沒有想過如何保存數據,但我想我可以用數據寫出二進制文件。

任何意見,想法或參考表示讚賞。

謝謝:)

+0

傳感器陣列的接口是什麼樣的?你會收到一個輸入的傳感器事件流,還是來自每個傳感器的流?我認爲這是即時的(例如顯示最後一分鐘或某些類似的滑動窗口移動平均值),所以您需要不斷更新計算的統計數據? – Brian 2009-05-30 00:19:23

+0

傳感器時間序列對象(可調整大小的數組) - 它只是帶有onadd事件的List。不,我從每個傳感器獲取流,這就是爲什麼我要說我需要彙總這些數據並將其放在隊列中以便於消耗/處理。是的,可視化是實時的,計算的統計數據也需要實時更新。 – 2009-05-30 00:35:02

回答

2

我對此可能完全錯誤,並且它不是您的問題的答案,所以請將意見投給我,但是我對F#感興趣的一年就是沒有那種感覺在科學/技術環境(我知道oneexception)中有很多使用F#的經驗的人(或'在這裏')有很多人。

這可能是因爲微軟把他們的努力集中在了金融界的F#外展上 - 相當不幸回顧的時機!

這並不意味着你不會爲你的具體問題得到很好的答案,你只是不可能得到「哦,是的,我上週做了類似的事情,注意到這個問題」等等...

撇開,你知道units of measure in F#?非常有趣的功能與任何技術相關。

5

我建議對執行F#中的新項目,直到你的語言得到了更好的處理,否則你會剛剛結束了在F#的語法編寫C#代碼。至少在工作中的項目中,最好使用你知道的工具而不是使用公司的資金來試驗新技術。

但是,既然您問了,我會使用mailbox processor作爲所有傳感器輸入的線程安全消息處理隊列。消息隊列可以重新計算收到的每條消息的統計信息。關於我的頭頂,我正在考慮這樣的設置:

type SensorMsg<'a, 'b> = 
    | Fetch of 'a AsyncReplyChannel 
    | Post of 'b 
    | Die 

type SensorMessageQueue<'a, 'b>(emptyStats : 'a, compute : 'a -> 'b -> 'a) = 
    let queue = MailboxProcessor.Start(fun inbox -> 
      let rec loop stats = 
       async { 
        let! msg = inbox.Receive() 
        match msg with 
        | Die -> return() 
        | Post(x) -> return! loop (compute stats x) 
        | Fetch(x) -> x.Reply(stats); return! loop stats 
       } 
      loop emptyStats 
     ) 

    member this.Post(x) = queue.Post(Post(x)) 
    member this.Fetch() = queue.PostAndReply(fun replyChannel -> Fetch(replyChannel)) 
    member this.Die() = queue.Post(Die) 

類似這樣的東西可以保存傳感器的實時運行統計信息。例如,可以說,我想後的東西,將舉行一個正在運行的平均值:

let averager = 
    SensorMessageQueue(
      (0, 0), (* initial state of sum, total *) 
      (fun (sum, total) input -> sum + input, total + 1) 
     ) 

averager.Post(75) 
averager.Post(90) 
averager.Post(80) 
let x = averager.Fetch() (* returns (245, 3) *) 
averager.Post(100) 
let y = averager.Fetch() (* returns (345, 4) *) 

像這樣的設置是比較容易的工作,線程安全的,並且不使用可變的狀態(全「狀態」的存在在封閉的論點中)。如果你仔細想想,這基本上是一個榮耀的seq.unfold,只有使用郵箱處理器才能實現。這可能是矯枉過正,可能是正確的,或者可能正是你的項目所需要的,這取決於你的要求。