2011-01-06 35 views
18

Tôi có cảm biến 3D đo các dữ liệu v (x, y, z). Tôi chỉ sử dụng dữ liệu x và y. Chỉ làm mịn x và y là đủ.Làm mịn dữ liệu từ cảm biến

Nếu tôi sử dụng nhật ký để hiển thị dữ liệu, nó hiển thị cho tôi nội dung như sau: (thời gian) 0,1 ... (Nhật ký dữ liệu) x = 1.1234566667 (thời gian) 0,2 ... (Nhật ký dữ liệu) x = 1.1245655666 (thời gian) 0,3 ... (nhật ký dữ liệu) x = 1.2344445555

Dữ liệu chính xác hơn, nhưng tôi muốn làm mịn giữa giá trị 1.1234 và giá trị 1.2344, bởi vì đối với tôi cũng vậy, tôi có thể sử dụng số nguyên, chỉ hiển thị "x = 1" nhưng tôi cũng cần số thập phân, sau đó, tôi cần hiển thị một loại giá trị "được làm mịn" ở đây.

Bất kỳ ai cũng có ý tưởng gì? Tôi đang lập trình trong C# nhưng không phải tất cả các chức năng đều hoạt động, vì vậy tôi cần xây dựng chức năng của riêng mình.

Trả lời

56

Cách đơn giản nhất là làm trung bình di chuyển dữ liệu của bạn. Đó là, để giữ một mảng các dữ liệu cảm biến đọc và trung bình chúng. Nội dung như thế này (mã giả):

data_X = [0,0,0,0,0]; 

    function read_X() { 
     data_X.delete_first_element(); 
     data_X.push(get_sensor_data_X()); 
     return average(data_X); 
    } 

Có sự cân bằng khi thực hiện việc này. Càng lớn mảng bạn sử dụng, kết quả mượt mà hơn sẽ là độ trễ lớn hơn giữa kết quả và đọc thực tế. Ví dụ:

      /\_/\ 
         /\/  \_/\ 
    Sensor reading: __/\/   \/\ 
             \/\ _/\___________ 
              \/ 
           _ 
          __/ \_ 
         ___/  \__ 
    Small array:  ___/    \_/\_  _ 
             \ __/ \________ 
              \_/ 

           ____ 
           __/ \__ 
          __/   \__ 
    Large array:  _______/     \__  __ 
               \_ /\__ 
               \_/ 


(forgive my ASCII-ART but I'm hoping it's good enough for illustration). 

Nếu bạn muốn trả lời nhanh nhưng vẫn làm mịn thì bạn sẽ sử dụng mức trung bình trọng số của mảng. Đây là cơ bản xử lý tín hiệu kỹ thuật số (với vốn DSP) mà trái với tên của nó là chặt chẽ hơn liên quan đến thiết kế tương tự. Đây là một bài viết wikipedia ngắn về nó (với các liên kết bên ngoài tốt mà bạn nên đọc nếu bạn muốn đi xuống con đường này): http://en.wikipedia.org/wiki/Digital_filter

Đây là một số mã từ SO về bộ lọc thông thấp có thể phù hợp với nhu cầu của bạn: Low pass filter software?. Lưu ý rằng trong mã trong câu trả lời đó, anh ta sử dụng một mảng có kích thước 4 (hoặc thứ tự 4 trong thuật ngữ xử lý tín hiệu vì bộ lọc này được gọi là bộ lọc thứ tư, nó thực sự có thể được mô hình hóa theo phương trình đa thức bậc 4: ax^4 + bx^3 + cx^2 + dx).

+0

Thank you very much !!! Điều này thực sự giúp tôi, tôi đang thực hiện mã ngay bây giờ, từ bây giờ tôi sẽ giúp mọi người giống như bạn, tốt, nếu tôi có thể tất nhiên. Thax !! – Mworks

+3

Bộ lọc trung bình di chuyển là trường hợp đặc biệt của bộ lọc thông thấp là bộ lọc khá đẹp (về hiệu suất). Một bộ lọc thông thấp thứ tự đầu tiên thường (thường là?) Tốt hơn so với trung bình di chuyển về phản ứng tần số và tải tính toán và độ phức tạp của chương trình. Đối với nhiều ứng dụng, bạn có thể bỏ qua các chi tiết này, ví dụ như màn hình la bàn có thể phản ứng chậm, trung bình di chuyển sẽ tuyệt vời. Nếu bạn có một trò chơi mà bạn muốn phản ứng nhanh bằng cách sử dụng cảm biến ồn ào, trung bình di chuyển sẽ là một giải pháp kém vì sự chậm trễ mà nó phải chịu cho một lượng lọc nhất định. – Hucker

+12

Câu trả lời hay được tạo bởi nghệ thuật ASCII – Spaceghost

21

Vì vậy, tôi đến đây tìm cách để giải quyết cùng một vấn đề (đầu vào cảm biến làm mịn trong Android) và đây là những gì tôi đã đưa ra:

/* 
* time smoothing constant for low-pass filter 
* 0 ≤ α ≤ 1 ; a smaller value basically means more smoothing 
* See: http://en.wikipedia.org/wiki/Low-pass_filter#Discrete-time_realization 
*/ 
static final float ALPHA = 0.2f; 

protected float[] accelVals; 

public void onSensorChanged(SensorEvent event) { 
    if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) 
     accelVals = lowPass(event.values, accelVals); 

    // use smoothed accelVals here; see this link for a simple compass example: 
    // http://www.codingforandroid.com/2011/01/using-orientation-sensors-simple.html 
} 

/** 
* @see http://en.wikipedia.org/wiki/Low-pass_filter#Algorithmic_implementation 
* @see http://en.wikipedia.org/wiki/Low-pass_filter#Simple_infinite_impulse_response_filter 
*/ 
protected float[] lowPass(float[] input, float[] output) { 
    if (output == null) return input; 

    for (int i=0; i<input.length; i++) { 
     output[i] = output[i] + ALPHA * (input[i] - output[i]); 
    } 
    return output; 
} 

Cảm ơn bạn @slebetman đã chỉ cho tôi hướng tới liên kết Wikipedia, mà sau một chút đọc đã thu hút tôi vào thuật toán trên bài viết bộ lọc Low-pass wikipedia. Tôi sẽ không thề tôi có thuật toán tốt nhất (hoặc thậm chí đúng!) Nhưng bằng chứng giai thoại dường như chỉ ra rằng nó đang làm thủ thuật.

+1

chỉ muốn nói rằng nếu bạn sử dụng mã này trên android, trả về input.copy() ban đầu thay vì mảng đó. Cảm biến của tôi ghi vào cùng một mảng, tức là đầu vào và đầu ra là cùng một mảng và làm mịn sẽ không hoạt động. –

0

Tra một câu hỏi cũ ở đây, nhưng nếu bạn đang ở trong đất .NET, bạn có thể sử dụng RX để làm điều này cho bạn.

Ví dụ, sử dụng RX kết hợp với WebClient.DownloadFileAsync để tính toán một "vuốt" tốc độ download:

double interval = 2.0; // 2 seconds 
long bytesReceivedSplit = 0; 

WebClient wc = new WebClient(); 
var downloadProgress = Observable.FromEventPattern< 
    DownloadProgressChangedEventHandler, DownloadProgressChangedEventArgs>(
    h => wc.DownloadProgressChanged += h, 
    h => wc.DownloadProgressChanged -= h) 
    .Select(x => x.EventArgs); 

downloadProgress.Sample(TimeSpan.FromSeconds(interval)).Subscribe(x => 
    { 
     Console.WriteLine((x.BytesReceived - bytesReceivedSplit)/interval); 
     bytesReceivedSplit = x.BytesReceived; 
    }); 

Uri source = new Uri("http://someaddress.com/somefile.zip"); 
wc.DownloadFileAsync(source, @"C:\temp\somefile.zip"); 

Rõ ràng là còn là khoảng thời gian, càng làm mịn sẽ được, mà còn các bạn còn sẽ phải chờ đọc ban đầu.

1

Dưới đây là ví dụ dựa trên logic trong phần MotionEvents của Event Handling guide dành cho iOS.

float ALPHA = 0.1; 

protected float[] lowPass(float[] input, float[] output) { 
    if (output == null) return input; 

    for (int i=0; i<input.length; i++) { 
     output[i] = (input[i] * ALPHA) + (ouptut[i] * (1.0 - ALPHA)); 
    } 
    return output; 
} 
3

Có nhiều cách để làm mịn dữ liệu cảm biến phụ thuộc vào loại cảm biến và loại tương tự sẽ phù hợp. Tôi đã sử dụng các thuật toán này trong các dự án của mình:

  1. Bộ lọc thông cao [HPF] và Bộ lọc thông thấp [LPF] - như được thể hiện trong câu trả lời đã chọn.
  2. Moving Average Algorithm -MAA
  3. Gaely của Algorithmm [phiên bản tốt hơn cho MAA]
  4. Fast Fourier Transform -FFT

Code:

HPF-High Pass Lọc

private float[] highPass(float x, float y, float z) { 
    float[] filteredValues = new float[3]; 
    gravity[0] = ALPHA * gravity[0] + (1 – ALPHA) * x; 
    gravity[1] = ALPHA * gravity[1] + (1 – ALPHA) * y; 
    gravity[2] = ALPHA * gravity[2] + (1 – ALPHA) * z; 
    filteredValues[0] = x – gravity[0]; 
    filteredValues[1] = y – gravity[1]; 
    filteredValues[2] = z – gravity[2]; 
    return filteredValues; 
    } 

Bộ lọc LPF-Low Pass

private float[] lowPass(float x, float y, float z) { 
    float[] filteredValues = new float[3]; 
    filteredValues[0] = x * a + filteredValues[0] * (1.0f – a); 
    filteredValues[1] = y * a + filteredValues[1] * (1.0f – a); 
    filteredValues[2] = z * a + filteredValues[2] * (1.0f – a); 
    return filteredValues; 
    } 

MAA-Moving Average

 private final int SMOOTH_FACTOR_MAA = 2;//increase for better results but hits cpu bad 

    public ArrayList<Float> processWithMovingAverageGravity(ArrayList<Float> list, ArrayList<Float> gList) { 
      int listSize = list.size();//input list 
      int iterations = listSize/SMOOTH_FACTOR_MAA; 
      if (!AppUtility.isNullOrEmpty(gList)) { 
       gList.clear(); 
      } 
      for (int i = 0, node = 0; i < iterations; i++) { 
       float num = 0; 
       for (int k = node; k < node + SMOOTH_FACTOR_MAA; k++) { 
        num = num + list.get(k); 
       } 
       node = node + SMOOTH_FACTOR_MAA; 
       num = num/SMOOTH_FACTOR_MAA; 
       gList.add(num);//out put list 
      } 
      return gList; 
     } 
Các vấn đề liên quan