2016年9月5日 星期一

AirView 新增資料存檔功能



說明

1.      AirView 新增資料存檔功能,紅字為修改部分,可套用未來版本
2.      目前AirView程式雖有記錄time tag,但尚未使用,且林所長只看最高最低點,資料亦已被壓縮,因processing未支援秒以下的小數點,為避免資料存檔的時間混淆,將Arduino端的程式改成1000ms2筆。
3.     套用時請將原本的 rootDir="D:\\Earthquake Research\\SampledData\\" 改成自己欲存檔的目錄


Processing程式(新增的修改碼用紅字標示)
// AirView
// Plot the graph of the air voltage from Arduino
// to predict earthquakes.
// Dyson Lin dysonlin@gmail.com
// 2016-07-30 05:58 UTC+8 V1.0
// 2016-08-10 15:42 UTC+8 V2.1.3 20x data compression. Change background to Black.
// 2016-08-16 21:56 UTC+8 V2.1.9 Plot select range area.
// 2016-08-16 22:17 UTC+8 V2.2.0 Adjust text sizes.
// 2016-08-17 23:43 UTC+8 V2.2.1 Use noLoop() and redraw() to plot graph only after reading new data.
// 2016-08-19 18:40 UTC+8 V2.2.2 10K-Ohom-R Voltage!
// 2016-08-19 19:14 UTC+8 V2.2.3 Water Voltage!
// 2016-08-20 21:04 UTC+8 V2.2.4 220-Ohom-R Voltage!
// 2016-08-24 04:25 UTC+8 V2.2.5 Air Voltage.
// 2016-08-26 17:10 UTC+8 V2.2.6 Fix the minData and maxData bug.
// 2016-08-27 03:53 UTC+8 V2.2.7 Modify plotData(), plotSelectRange().
// 2016-08-29 01:31 UTC+8 V2.2.8 Comment out noLoop() and redraw().
// 2016-08-29 02:23 UTC+8 V2.2.9 Make the window resizable.
// 2016-09-05 22:39 UTC+8 V2.2.9g Save sampled data to file for analysis, modified by ghosty

import processing.serial.*;

int startTime = 0;
int currentTime = 0;

String timeStringStart = null;
String dateStringStart = null;
String timeStringNow = null;
String dateStringNow = null;

int graphLeft = 0;
int graphRight = 0;
int graphTop = 0;
int graphBottom = 0;

int selectRangeLeft = 0;
int selectRangeRight = 0;
int selectRangeTop = 0;
int selectRangeBottom = 0;

int isFirstRead = 1;

int maxData = 0;
int minData = 0;
int maxTime = 0;
int minTime = 0;

final int compressionRatio = 20;
final int bufferLimit = 2 * compressionRatio; // compression ratio = bufferLimit/2. So bufferLimit must be even.
int [] buffer = new int[bufferLimit];
int [] bufferTime = new int[bufferLimit];
int bufferNumber = 0;

int dataLimit = 1000000;
int[] data = new int[dataLimit];
int[] dataTime = new int[dataLimit];
int dataNumber = 0;

boolean mouseInZoomArea(int x, int y)
{
  boolean inZoomArea = false;
  int zoomAreaLength = 10;
  int zoomLeft = width - zoomAreaLength;;
  int zoomRight = width;
  int zoomBottom = height;
  int zoomTop = height - zoomAreaLength;

  if ((x >= zoomLeft) && (x <= zoomRight) && (y <= zoomBottom) && (y >= zoomTop))
  {
    inZoomArea = true;
  }

  return inZoomArea;
}


//void mouseDragged()
//{
//  if (mouseInZoomArea(mouseX, mouseY))
//  {
//    int newWidth = width + (mouseX - pmouseX);
//    int newHeight = height + (mouseY - pmouseY);

//    surface.setSize(newWidth, newHeight);
//  }
//}

void setup()
{
  size(1300, 720);
  surface.setResizable(true);

  openSerialPort();
  setStartTimeStamp();
}

void openSerialPort()
{
  int lf = 10;    // Linefeed in ASCII
  Serial myPort;  // The serial port

  // List all the available serial ports
  print("Available serial ports: ");
  printArray(Serial.list());

  myPort = new Serial(this, "COM5", 9600);
  myPort.clear(); // Clear buffer
  myPort.bufferUntil(lf); // Trigger serialEvent() only after linefeed is read.
}

void setStartTimeStamp()
{
  startTime = millis();
  timeStringStart = nf(hour(), 2) + ":" + nf(minute(), 2) + ":" + nf(second(), 2);
  dateStringStart = year() + "-" + nf(month(), 2) + "-" + nf(day(), 2);
}

void setTimeStamp()
{
  currentTime = millis();
  timeStringNow = nf(hour(), 2) + ":" + nf(minute(), 2) + ":" + nf(second(), 2);
  dateStringNow = year() + "-" + nf(month(), 2) + "-" + nf(day(), 2);
}

void draw()
{
  //background(204); // gray background
  background(0);  // black background
  stroke(255);
  fill(255);

  // Set the location of graph
  graphLeft = 50;
  graphRight = width - 50;
  graphTop = 50;
  graphBottom = height - 100;
  maxTime = graphRight - graphLeft;

  background(0);
  setTimeStamp();
  plotSelectRange();
  plotAxes();
  //plotData();
  plotData(graphLeft+3, graphRight, graphBottom-3, graphTop);
}

void plotData(int leftBorder, int rightBorder, int bottomBorder, int topBorder) {
  float x1 = 0;
  float y1 = 0;
  float x2 = 0;
  float y2 = 0;

  if (dataNumber < 2) {
    return;
  }

  stroke(255);

  // set first point
  //x1 = graphLeft+3;
  //y1 = map(data[0], minData, maxData, graphBottom-3, graphTop);
  x1 = leftBorder;
  y1 = map(data[0], minData, maxData, bottomBorder, topBorder);

  // plot lines
  for (int i=1; i<dataNumber; i++)
  {
    //x2 = map(i, 0, dataNumber-1, graphLeft+3, graphRight); // auto range
    //y2 = map(data[i], minData, maxData, graphBottom-3, graphTop); // auto range
    x2 = map(i, 0, dataNumber-1, leftBorder, rightBorder); // auto range
    y2 = map(data[i], minData, maxData, bottomBorder, topBorder); // auto range
    line(x1, y1, x2, y2);
    x1 = x2;
    y1 = y2;
  }
}

void plotSelectRange()
{
  // Set the location of graph
  selectRangeLeft = 100;
  selectRangeRight = width - 100;
  selectRangeBottom = height - 15;
  selectRangeTop = height - 48;

  int textSize = 12;
  textSize(textSize);

  stroke(0, 128, 0, 128);
  fill(0, 128, 0, 128);
  rect(selectRangeLeft, selectRangeTop, selectRangeRight - selectRangeLeft, selectRangeBottom - selectRangeTop);

  stroke(255);
  fill(255);

  textAlign(CENTER);
  text(timeStringStart, graphLeft, selectRangeTop + textSize*1);
  text(dateStringStart, graphLeft, selectRangeTop + textSize*2.5);

  textAlign(CENTER);
  text(timeStringNow, graphRight, selectRangeTop + textSize*1);
  text(dateStringNow, graphRight, selectRangeTop + textSize*2.5);

  plotData(selectRangeLeft, selectRangeRight, selectRangeBottom, selectRangeTop);
}

void plotAxes() {
  int textSize = 12;
  float minVoltage = 0;
  float maxVoltage = 0;

  textAlign(CENTER);
  textSize = 24;
  textSize(textSize);
  text("Air Voltage", (graphLeft+graphRight)/2, graphTop - textSize);

  textSize = 16;
  textSize(textSize);
  text("Time", (graphRight + graphLeft)/2, graphBottom + textSize * 3);
  text("V (mV)", graphLeft, graphTop - textSize);

  // plot x-axis
  textSize = 12;
  textSize(textSize);

  stroke(0, 128, 0);
  line(graphLeft, graphBottom, graphLeft, graphTop);
  textAlign(RIGHT);
  minVoltage = map(minData, -1023, 1023, -5000, 5000);
  text(round(minVoltage), graphLeft - textSize/2, graphBottom);

  maxVoltage = map(maxData, -1023, 1023, -5000, 5000);
  text(round(maxVoltage), graphLeft - textSize/2, graphTop + textSize);

  textAlign(CENTER);
  text(timeStringStart, graphLeft, graphBottom + textSize*1.5);
  text(dateStringStart, graphLeft, graphBottom + textSize*2.5);

  textAlign(CENTER);
  text(timeStringNow, graphRight, graphBottom + textSize*1.5);
  text(dateStringNow, graphRight, graphBottom + textSize*2.5);

  // plot y-axis
  line(graphLeft, graphBottom, graphRight, graphBottom);
  textAlign(CENTER);

  textSize = 16;
  textSize(textSize);
  textAlign(CENTER);
  text("Time", (graphRight + graphLeft)/2, graphBottom + textSize * 3);
  text("V (mV)", graphLeft, graphTop - textSize);
}

void serialEvent(Serial whichPort) {
  int lf = 10;    // Linefeed in ASCII
  String inString = null;  // Input string from serial port
  int voltage = 0;

  inString = whichPort.readStringUntil(lf);
  if (inString == null)
  { 
    return;
  }

  inString = trim(inString);
  voltage = int(inString);
  saveData(voltage); //modified by ghosty

  if (isFirstRead == 1)
  {
    print("Discard first read: ");
    println(inString);
    isFirstRead = 0;
    return;
  }

  buffer[bufferNumber] = voltage;
  bufferTime[bufferNumber] = millis();

  if (bufferNumber < bufferLimit-1)
  {
    bufferNumber++;
  } else
  {
    // bufferNumber == bufferLimit-1
    // That means buffer is full
    // Compress data:
    // keep the max and min
    // also keep their order
    int xMax = 0;
    int yMax = 0;
    int xMin = 0;
    int yMin = 0;
    int i = 0;
    String s = null;

    yMax = buffer[0];
    xMax = 0;
    yMin = buffer[0];
    xMin = 0;

    for (i=1; i<bufferLimit; i++)
    {
      if (buffer[i] > yMax)
      {
        yMax = buffer[i];
        xMax = i;
      }

      if (buffer[i] < yMin)
      {
        yMin = buffer[i];
        xMin = i;
      }
    }

    bufferNumber = 0;

    if (dataNumber == 0)
    {
      maxData = yMax;
      minData = yMin;
    } else {
      if (yMax > maxData)
      {
        maxData = yMax;
      }

      if (yMin < minData)
      {
        minData = yMin;
      }
    }

    if (xMin < xMax)
    {
      data[dataNumber] = yMin;
      s = "data[" + dataNumber + "] = " + data[dataNumber] + "  Max: " + maxData + "  Min: " + minData;
      println(s);
      dataNumber++;

      data[dataNumber] = yMax;
      s = "data[" + dataNumber + "] = " + data[dataNumber] + "  Max: " + maxData + "  Min: " + minData;
      println(s);
      dataNumber++;
    } else
    {
      data[dataNumber] = yMax;
      s = "data[" + dataNumber + "] = " + data[dataNumber] + "  Max: " + maxData + "  Min: " + minData;
      println(s);
      dataNumber++;

      data[dataNumber] = yMin;
      s = "data[" + dataNumber + "] = " + data[dataNumber] + "  Max: " + maxData + "  Min: " + minData;
      println(s);
      dataNumber++;
    }
  }
}

/*
   modified by ghosty : save data to file
*/
import java.io.*;
String rootDir="D:\\Earthquake Research\\SampledData\\";
void saveData(int voltage)
{
  BufferedWriter output = null;
  try {
    String fileName = rootDir+String.format("air%04d-%02d-%02d.txt", year(), month(), day());
    output = new BufferedWriter(new FileWriter(fileName, true)); //the true will append the new data
    output.write(String.format("%04d-%02d-%02d %02d:%02d:%02d, %d", year(), month(), day(), hour(), minute(), second(), voltage));
    output.newLine();
  }
  catch (IOException e) {
    println("It Broke");
    e.printStackTrace();
  }
  finally {
    if (output != null) {
      try {
        output.close();
      } catch (IOException e) {
        println("Error while closing the writer");
      }
    }
  }
}

Arduino程式
// 測量A0A1的空氣電壓
// 修改自地震預測研究所所長 林湧森 2016-07-28 04:29 UTC+8
// 修改者:ghostyguo
// 使用最快取樣速度, 每隔400ms送出最大與最小值
// 2016-08-20 22:30 UTC+8 by

int sampleCount;
int maxValue, minValue; //keep extreme value
int whoIsLast = 0; //-1=min, 1=max, 0=undefined;
int sampleCountLimit;

void setup()
{
    Serial.begin(9600);
    SetupRunningParameters();
    startNewCycle();
}

void SetupRunningParameters()
{
    // find sampleCountLimit in 1000ms
    unsigned long startMicros=micros();
    startNewCycle();
    while (micros()-startMicros<1000000L) {  //原本為400000L, 400ms
        sampling();
    }
    sampleCountLimit = sampleCount;
    // uncomment the following lines to see the sampleCountLimit
    // Serial.print("#");
    // Serial.println(sampleCountLimit);
}

void startNewCycle()
{
    maxValue = -10000; //12bit ADC < -1024
    minValue = 10000;  //12bit ADC > 1024
    whoIsLast = 0;
    sampleCount = 0;
}

void loop()
{
    sampling();
    if (sampleCount>sampleCountLimit) {
        if (whoIsLast == -1) {
            Serial.println(maxValue);
            Serial.println(minValue);    
        } else if (whoIsLast == 1) {
            Serial.println(minValue);
            Serial.println(maxValue);     
        } else {
            Serial.println("Extreme Value Error");   
        }
        startNewCycle();
    }
}
void sampling()
{
    int sampleValue = analogRead(A1) - analogRead(A0);
    if (minValue > sampleValue) {
        minValue = sampleValue;
        whoIsLast = -1;
    }
    if (maxValue < sampleValue) {
        maxValue = sampleValue;
        whoIsLast = 1;
    }
    ++sampleCount;
}

沒有留言:

張貼留言