실시간 애플리케이션을위한 신호의 평균 및 표준 편차를 찾는 이상적인 방법은 무엇입니까? 신호가 특정 시간 동안 평균에서 3 표준 편차 이상일 때 컨트롤러를 트리거 할 수 있기를 원합니다.
전용 DSP가이 작업을 매우 쉽게 수행한다고 가정하지만 너무 복잡한 것이 필요하지 않은 "바로 가기"가 있습니까?
실시간 애플리케이션을위한 신호의 평균 및 표준 편차를 찾는 이상적인 방법은 무엇입니까? 신호가 특정 시간 동안 평균에서 3 표준 편차 이상일 때 컨트롤러를 트리거 할 수 있기를 원합니다.
전용 DSP가이 작업을 매우 쉽게 수행한다고 가정하지만 너무 복잡한 것이 필요하지 않은 "바로 가기"가 있습니까?
답변:
Jason R의 답변에 결함이 있습니다.이 내용은 Knuth의 "Art of Computer Programming"vol. 2. 표준 편차가 평균의 작은 부분 인 경우 문제가 발생합니다. E (x ^ 2)-(E (x) ^ 2)의 계산은 부동 소수점 반올림 오류에 대한 민감도가 높습니다.
파이썬 스크립트에서 직접 시도해 볼 수도 있습니다.
ofs = 1e9
A = [ofs+x for x in [1,-1,2,3,0,4.02,5]]
A2 = [x*x for x in A]
(sum(A2)/len(A))-(sum(A)/len(A))**2
수학은 결과가 음이 아니어야한다고 예측하기 때문에 -128.0을 답으로 얻습니다.이 계산은 분명히 유효하지 않습니다.
Knuth는 다음과 같은 진행 평균 및 표준 편차를 계산하는 접근법 (발명가의 이름을 기억하지 못합니다)을 인용합니다.
initialize:
m = 0;
S = 0;
n = 0;
for each incoming sample x:
prev_mean = m;
n = n + 1;
m = m + (x-m)/n;
S = S + (x-m)*(x-prev_mean);
그런 다음 각 단계 후의 값은 m
평균이며 표준 편차는 표준 편차 에 대한 선호도 정의에 따라 sqrt(S/n)
또는 표준 편차 sqrt(S/n-1)
에 따라 계산 될 수 있습니다 .
위에서 쓴 방정식은 Knuth의 방정식과 약간 다르지만 계산적으로 동일합니다.
몇 분 더 있으면 파이썬에서 위의 수식을 코딩하고 음수가 아닌 대답을 얻습니다 (바람직한 값에 가깝습니다).
업데이트 : 여기 있습니다.
test1.py :
import math
def stats(x):
n = 0
S = 0.0
m = 0.0
for x_i in x:
n = n + 1
m_prev = m
m = m + (x_i - m) / n
S = S + (x_i - m) * (x_i - m_prev)
return {'mean': m, 'variance': S/n}
def naive_stats(x):
S1 = sum(x)
n = len(x)
S2 = sum([x_i**2 for x_i in x])
return {'mean': S1/n, 'variance': (S2/n - (S1/n)**2) }
x1 = [1,-1,2,3,0,4.02,5]
x2 = [x+1e9 for x in x1]
print "naive_stats:"
print naive_stats(x1)
print naive_stats(x2)
print "stats:"
print stats(x1)
print stats(x2)
결과:
naive_stats:
{'variance': 4.0114775510204073, 'mean': 2.0028571428571427}
{'variance': -128.0, 'mean': 1000000002.0028572}
stats:
{'variance': 4.0114775510204073, 'mean': 2.0028571428571431}
{'variance': 4.0114775868357446, 'mean': 1000000002.0028571}
당신은 여전히 반올림 오류가 있지만 나쁘지는 않지만 naive_stats
단지 푸킹 이라는 점에 유의하십시오 .
편집 : 방금 Knuth 알고리즘을 언급 한 Wikipedia 를 인용 한 Belisarius의 의견을 주목했습니다 .
실시간 애플리케이션을위한 신호의 평균 및 표준 편차를 찾는 이상적인 방법은 무엇입니까? 신호가 특정 시간 동안 평균에서 3 표준 편차 이상일 때 컨트롤러를 트리거 할 수 있기를 원합니다.
이와 같은 상황에서 올바른 접근 방식은 일반적으로 지수 가중 실행 평균 및 표준 편차를 계산하는 것입니다. 지수 가중 평균에서 평균 및 분산의 추정치는 가장 최근의 표본으로 편향되어 마지막 초 동안 의 평균 및 분산의 추정치를 제공합니다 . 이는 아마도 모든 표본에 대한 일반적인 산술 평균보다는 원하는 것입니다 지금까지 본.
주파수 영역에서 "지수 적으로 가중 된 실행 평균"은 단순히 실제 극입니다. 시간 영역에서 구현하는 것은 간단합니다.
시간 영역 구현
하자 mean
및 meansq
수 평균의 현재 추정하고 신호의 제곱의 의미. 매주기마다 새로운 표본으로 이러한 추정치를 업데이트하십시오 x
.
% update the estimate of the mean and the mean square:
mean = (1-a)*mean + a*x
meansq = (1-a)*meansq + a*(x^2)
% calculate the estimate of the variance:
var = meansq - mean^2;
% and, if you want standard deviation:
std = sqrt(var);
여기서 은 실행 평균의 유효 길이를 결정하는 상수입니다. a 를 선택 하는 방법 은 아래 "분석"에 설명되어 있습니다.
명령형 프로그램으로 위에서 표현 된 것은 신호 흐름 다이어그램으로 묘사 될 수도 있습니다.
분석
IIR 필터를 자체 블록으로 응축하면 다이어그램은 다음과 같습니다.
고르다
참고 문헌
0 < a < 1
. 시스템에 샘플링 tmie가 T
있고 평균 시간 상수를 원하면 tau
을 선택하십시오 a = 1 - exp (2*pi*T/tau)
.
z=1
(DC)로 대체 H(z) = a/(1-(1-a)/z)
하면 1을 얻습니다.
임베디드 처리 응용 프로그램에서 이전에 사용한 방법은 관심 신호의 합과 합의 누산기를 유지하는 것입니다.
또는 다음을 사용할 수 있습니다.
원하는 표준 편차 추정 방법에 따라 . 이 방정식은 분산 의 정의를 기반으로합니다 .
나는 과거에 이것을 성공적으로 사용했지만 (표준 편차가 아닌 분산 추정에만 관심이 있었지만) 합산하려는 경우 누산기를 유지하는 데 사용하는 숫자 유형에주의해야하지만 오랜 시간; 오버플로를 원하지 않습니다.
편집하다: 오버플로에 대한 위의 주석 외에도 부동 소수점 산술로 구현 할 때 수치 적으로 강력한 알고리즘이 아니며 추정 통계에서 큰 오류가 발생할 수 있습니다. 이 경우 더 나은 접근 방식은 Jason S의 답변을 참조하십시오.
위의 선호 답변 (Jason S.)과 유사하고 Knut (Vol.2, p 232)에서 가져온 수식에서 파생 된 것과 같이 값을 대체하는 수식을 파생시킬 수도 있습니다. 즉, 한 단계에서 값을 제거하고 추가 할 수 있습니다 . 내 테스트에 따르면 replace는 2 단계 제거 / 추가 버전보다 더 나은 정밀도를 제공합니다.
아래의 코드는 자바에, mean
그리고 s
같은, ( "글로벌"멤버 변수) 업데이 트 m
와 s
제이슨의 게시물 위. 값 count
은 창 크기를 나타냅니다 n
.
/**
* Replaces the value {@code x} currently present in this sample with the
* new value {@code y}. In a sliding window, {@code x} is the value that
* drops out and {@code y} is the new value entering the window. The sample
* count remains constant with this operation.
*
* @param x
* the value to remove
* @param y
* the value to add
*/
public void replace(double x, double y) {
final double deltaYX = y - x;
final double deltaX = x - mean;
final double deltaY = y - mean;
mean = mean + deltaYX / count;
final double deltaYp = y - mean;
final double countMinus1 = count - 1;
s = s - count / countMinus1 * (deltaX * deltaX - deltaY * deltaYp) - deltaYX * deltaYp / countMinus1;
}
Jason과 Nibot의 대답은 한 가지 중요한 측면에서 다릅니다. Jason의 방법은 전체 신호에 대한 표준 편차 및 평균을 계산하지만 (y = 0 이후) Nibot은 "실행 중"계산입니다. 먼 과거.
응용 프로그램에는 표준 개발이 필요하고 시간의 함수로 의미되기 때문에 Nibot의 방법이 아마도이 응용 프로그램에 더 적합 할 것입니다. 그러나 실제 까다로운 부분은 시간 가중치 부분을 올바르게 얻는 것입니다. Nibot의 예제는 간단한 단극 필터를 사용합니다.
저역 통과 필터의 선택은 신호에 대해 알고있는 것과 추정에 필요한 시간 분해능에 따라 결정될 수 있습니다. 차단 주파수가 낮고 차수가 높을수록 정확도는 향상되지만 응답 시간은 느려집니다.
더 복잡하게하기 위해 하나의 필터가 선형 도메인에 적용되고 다른 필터가 제곱 도메인에 적용됩니다. 제곱은 신호의 스펙트럼 내용을 크게 변경하므로 제곱 도메인에서 다른 필터를 사용할 수 있습니다.
다음은 시간의 함수로 평균, rms 및 std dev를 추정하는 방법에 대한 예입니다.
%% example
fs = 44100; n = fs; % 44.1 kHz sample rate, 1 second
% signal: white noise plus a low frequency drift at 5 Hz)
x = randn(n,1) + sin(2*pi*(0:n-1)'*5/fs);
% mean estimation filter: since we are looking for effects in the 5 Hz range we use maybe a
% 25 Hz filter, 2nd order so it's not too sluggish
[b,a] = butter(2,25*2/fs);
xmeanEst = filter(b,a,x);
% now we estimate x^2, since most frequency double we use twice the bandwidth
[b,a] = butter(2,50*2/fs);
x2Est = filter(b,a,x.^2);
% std deviation estimate
xstd = sqrt(x2Est)-xmeanEst;
% and plot it
h = plot([x, xmeanEst sqrt(x2Est) xstd]);
grid on;
legend('x','E<x>','sqrt(E<x^2>)','Std dev');
set(h(2:4),'Linewidth',2);
y1 = filter(a,[1 (1-a)],x);
.