상세 컨텐츠

본문 제목

[Python] 전압 한주기를 자동으로 찾아내는 소스코드 개발

프로그래밍/Python

by 척척석사 민준 2020. 8. 26. 12:01

본문

728x90

생각보다 간단했다

오실로스코프에 보면 피크값과 피크값 사이의 주기를 자동으로 알려주는 기능이 있다. 당연히 파이썬에서도 있지 않을까? 찾아봤는데 방법들이 너무 복잡하다. scipy모듈을 사용해 피크를 찾아서 피크값사이의 거리를 측정한다. 나는 전압의 한주기를 0점에서 0점으로 잡아야 하는데 이 경우에는 사용할 수가 없다.

주기의 정의가 뭔지를 생각했다. 주기는 일정하게 반복되는 상황에서 반복이 일어날 때 걸리는 시간 간격을 주기라고 한다. (출처 : 네이버 물리학백과) 전압은 계속해서 반복되고 그 정보는 시계열로 저장된다. 그럼 그 시간간격을 컴퓨터가 알게 하면 컴퓨터가 알아서 한주기를 찾아줄 것이다. 이런 아이디어에서 시작되어 코드를 작성했다. 

코드블록의 진행순서

매트랩의 find가 있다면 파이썬엔 where가 있다 : numpy.where 함수

매트랩의 find 함수의 정의는 0이 아닌 데이터의 인덱스를 찾는 함수였다. 그래서 find(~V)로 V의 0인점을 찾았는데 파이썬의 numpy 라이브러리속에 있는 where함수는 더 쓰기가 간편했다. 결과값이 튜플로 나오는것만 빼면 말이다. 

zero_idx = np.where(V==0) % where함수로 전압이 0인 점의 위치를 모두 찾아낸다
zero_idx = np.array(list(zero_idx)) % 튜플로 나온 결과를 데이터 처리가 쉬운 list로 바꾼후 array로 변환해준다

자료형에 대해서 어떻게 다뤄야하는지 몰라서 쉽게 가려고 튜플자료형을 리스트로 변환했다. 

잠깐 튜플과 리스트 자료형에 대해서 말하면, 

튜플 자료형 (tuple)은 변경 및 수정이 되지 않는 자료형이다. 주민등록번호 같이 변하면 안되는 정보를 넣을때 사용한다. 리스트 자료형(list)는 변경 및 수정이 자유로운 자료형이다. 연구에 사용하려면 자유롭게 데이터를 처리해야하는데 튜플녀석때문에 자꾸 오류떠서 그냥 리스트로 전부 바꿔버렸다. 튜플과 리스트는 서로 자유롭게 바꿀 수 있다.

A = [ 1, 2, 3, 4] % 리스트 A 생성
B = tuple(A) % 리스트 A를 튜플로 변환
C = list(B) % 튜플 B를 리스트로 변환

numpy에서는 array가 사용하기 편해서 array로 리스트자료형을 array로 다시 변환했다.

 

diff 함수를 이용해서 인덱스 위치사이의 '간격'을 찾자 : numpy.diff 함수

diff 함수는 다음값과의 차이를 반환하는 함수이다. 어렵게 말하면 미분이고 쉽게 말하면 값과 값 사이 간격을 얻는 함수이다. A = [0, 1, 2, 3, 4, 5, 100] 일 때, diff(A) = [1, 1, 1, 1, 1, 95]가 된다. 인덱스 사이 간격이 1이나 3이 되는 값은 0인 점들이 연속되어 있는 것이다. 데이터를 어느 간격으로 얻는지에 따라 다르겠지만 한 주기의 전압 데이터가 1000개는 넘을 것이므로, 인덱스 간격이 100 이상인 경우는 연속되지 않고 반주기 간격으로 떨어져 있는 경우일 것이다. 

출처 : https://www.mathsisfun.com/algebra/trig-sin-cos-tan-graphs.html

위의 Sine 그래프를 봐도, V = 0 인점들 사이의 간격은 주기의 반이다. (주기가 2π 일때 V = 0 인 점은 -2π, π,  0, π, 2π이다)

그래서 zero_point_idx[0] 가 의미하는 첫번째 점은 주기의 시작점이다. zero_point_idx[1] 가 의미하는 두번째 점은 반주기점이다. zero_point_idx[2] 가 의미하는 바 세번째 점은 한주기의 끝점이다. (where로 찾았더니 첫 행에 값도 같이 찾아줘서 인덱스만 가지고 첫행은 버렸다)

zero_idx = np.where(V==0) % where로 V == 0 인점을 찾는다 
zero_idx = np.array(list(zero_idx)) 

diff_zero_idx = np.diff(zero_idx) % diff 함수로 인덱스 사이의 간격을 조사한다

zero_point_idx = np.where(diff_zero_idx > 100) % 다시 where로 인덱스 사이 간격이 큰 지점만 조사한다

zero_point_idx = list(zero_point_idx[1]) % 변수정보를 봤더니 zero_point_idx[0]에 쓸데없는 값이 들어있어서 걍 빼버림

이제 한 주기를 찾아보자

찾아낸 zero_point_idx 인덱스 정보를 t1과 t2에 저장하면, 전류 전압 데이터에서 이 인덱스를 이용해 한 주기를 슬라이싱 할 수 있다. 

t1 = zero_idx[0][zero_point_idx[0]]
t2 = zero_idx[0][zero_point_idx[2]]

전류한주기와 전압한주기, 그리고 주기를 계산하는 코드는 다음과 같다. 

V_1cyc = V[t1:t2]
I_1cyc = I[t1:t2]
T_1cyc = T[t1:t2]
Period = len(T_1cyc)*dt

전압 한주기가 잘 나왔나 그래프로 확인해보았다

전류도 그래프로 확인해 보았다

한주기씩 잘 슬라이싱 되었다는 것을 확인할 수 있었다. 

728x90

관련글 더보기