Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[iOS] 여정 드로잉에 필요한 filter를 평균값을 활용하도록 수정 #315

Merged
merged 14 commits into from
Jan 23, 2024

Conversation

yoondj98
Copy link
Collaborator

@yoondj98 yoondj98 commented Dec 13, 2023

❗ 배경

작업 배경에 대한 설명을 작성합니다.
Issue에 대한 링크를 첨부합니다.

🔧 작업 내역

작업한 내용들을 나열합니다.
간결하게 리스트 업하고, 자세한 설명은 아래 리뷰 노트에서 합니다.

  • 기존에 적용하던 5m<이동거리<50m인 데이터만 반영하는 필터링 방식이 문제가 있어서 새로 평균값 필터를 적용했습니다.
  • 현재 위치로 검색을 다시 할 경우 기존에 검색되었던 여정들이 여전히 지도에 남아있는 이슈를 개선했습니다.
  • 현재 위치로부터 가까운 위치가 연속으로 들어올 경우 위치 정보를 전송하지 않도록 구현했습니다.

🧪 테스트 방법

동작을 테스트할 수 있는 방법을 설명합니다.
앱 실행 방법일 수 있고, 유닛 테스트 실행 방법일 수 있습니다.

📝 리뷰 노트

작업 내역에 대한 자세한 설명을 작성합니다.

문제 인식

  • 기존에는 여정에서 Coordinate를 찍는 방식을 단순히 5초동안 이전 위치로부터 5m<distatance<50m인지 여부를 기준으로 벗어나는 값들에 대해 필터링을 거쳤습니다.
  • 하지만 한번 이 필터를 벗어날 경우 이후로 안찍히는 이슈가 발생할 수 있었습니다.
  • 예를 들면 5초동안 4m를 이동하면 필터링으로 인해 움직이지 않았다고 판단을 하게 되고 그 다음의 5초동안 48m를 이동하면 filter는 52m를 이동했다고 인지해서 걸러버립니다.
  • 이후로는 계속해서 받아오는 위치들을 모두 필터링함으로서 정상적인 이동거리(5m<distance<50m)임에도 불구하고 걸러버리게 됩니다.
  • 이에 대한 개선을 위해 처음에는 Kalman Filter를 활용하고자 했습니다.

Kalman 필터의 필요성

  • 데이터들이 정확한 값에서 벗어니는 이슈들을 보정을 통해 최대한 정상적인 값에 가깝게 적용되도록 함.
  • MusicSpot에서는 해당 위치를 통해 짧은 거리의 오차를 줄일 수가 있음.

Kalman 필터의 문제점

  • 해당 필터를 거친다고 모든 보정이 이뤄질 수가 없음을 인지
  • 해당 필터는 표본이 쌓이는 과정을 통해 더욱 정확한 보정을 할 수 있지만 이런 Data Stacking 특성이 오히려 문제가 발생할 수 있음.
    -> ex) 데이터 내에 현재 위치로부터 많이 튀는 위치(ex) 서울 중심에서 사용 중이다가 갑자기 경기도로 찍히는 경우)가 잡히는 순간 그 이후로 받아오는 데이터들이 이 필터를 거칠 시 모두 해당 오차를 적용한 채 위치를 찍기에 오히려 잘못된 위치가 계속해서 나오게 됨.

이러한 문제가 존재하기에 Kalman 필터의 적용보다 더 나은 방식을 모색했습니다.

평균값 필터의 활용

  • 일정한 개수의 데이터를 받아와서 평균을 낸 후 해당 평균으로부터 가장 먼 데이터를 drop하는 방식을 적용함.
  • 매번 일정한 개수의 데이터를 새로 표본으로 두어 반영하기에 한번의 필터링 이슈가 이후의 데이터 필터에 영향을 끼치지 않음.
  • 기존에 사용하던 최소(5m), 최대(50m) 이동거리 기준에서 최소 값은 여전히 반영함으로서 이동하지 않고 있는 경우 데이터를 전송하지 않도록 구현.

📸 스크린샷

작업한 내용에 대한 스크린샷, 영상 등을 첨부합니다.

@yoondj98 yoondj98 added the ✨ 신규 기능 신규 기능 개발 label Dec 13, 2023
@yoondj98 yoondj98 added this to the 🏃‍♂️ 여정 기록 milestone Dec 13, 2023
@yoondj98 yoondj98 self-assigned this Dec 13, 2023
@yoondj98 yoondj98 changed the base branch from main to iOS/release December 13, 2023 01:26
@SwiftyJunnos SwiftyJunnos linked an issue Dec 13, 2023 that may be closed by this pull request
2 tasks
PushedGun
PushedGun previously approved these changes Dec 13, 2023
Copy link
Member

@PushedGun PushedGun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 코드가 생각보다 복잡하지 않아 읽기 좋군요..?

많은 고민을 해주신 것이 보입니다!
발표에 사용해도 괜찮을 것 같아요.

Copy link
Member

@SwiftyJunnos SwiftyJunnos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수고하셨습니다!
데이터 흐름이 조금 정리가 안되어 있어서 그 부분 수정만 해주시면 될 것 같습니다.

평균 필터 성능 테스트 같은 걸 적극적으로 해보고 싶은데 조금 아쉽네요..
부캠 기간 끝나고 다양한 필터들 한 번 도전해봐요..!

Comment on lines 226 to 227
self?.contentViewController.clearAnnotations()
self?.contentViewController.clearOverlays()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분 지우고 ViewModel 쪽에서

 case .refreshButtonDidTap(visibleCoordinates: (let minCoordinate, let maxCoordinate)):
            self.state.isRefreshButtonHidden.send(true)
            self.fetchJourneys(minCoordinate: minCoordinate, maxCoordinate: maxCoordinate)
            self.state.overlaysShouldBeCleared.send(true) // 👍

이렇게 호출해서 방식을 통일시켜주는 것이 더 좋을 것 같습니다.

}

public struct State {
// CurrentValue
public var previousCoordinate = CurrentValueSubject<CLLocationCoordinate2D?, Never>(nil)
public var currentCoordinate = CurrentValueSubject<CLLocationCoordinate2D?, Never>(nil)
public var recordingJourney: CurrentValueSubject<RecordingJourney, Never>
public var recordedCoordinates = CurrentValueSubject<[CLLocationCoordinate2D], Never>([])
public var filteredCoordinate = CurrentValueSubject<CLLocationCoordinate2D?, Never>(nil)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

filteredCoordinate는 5번 찍힐 때마다 단순히 값을 전달만 하는 것 같은데 맞을까요?
그렇다면 PassthroughSubject를 사용하는 것이 더 적절한 것 같은데 어떨까요?

Comment on lines 118 to 122
if let previousCoordinate = self.state.previousCoordinate.value {
if calculateDistance(from: previousCoordinate, to: coordinate) <= 5 {
return
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if let previousCoordinate = self.state.previousCoordinate.value {
if calculateDistance(from: previousCoordinate, to: coordinate) <= 5 {
return
}
}
if let previousCoordinate = self.state.previousCoordinate.value,
calculateDistance(from: previousCoordinate, to: coordinate) <= 5 {
return
}

Comment on lines 328 to 330
guard let filteredCoordinate2D = recordJourneyViewModel.state.filteredCoordinate.value else { return }
recordJourneyViewModel.trigger(.locationDidUpdated(filteredCoordinate2D))
recordJourneyViewModel.trigger(.locationsShouldRecorded([filteredCoordinate2D]))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분은 state의 값을 가져와서 다시 trigger 할거라면
이 부분이 아니라 다른 ViewModel 내부나 bind 함수쪽에서 하는 것이 더 좋아보입니다.

Base automatically changed from iOS/release to main December 14, 2023 15:34
@SwiftyJunnos SwiftyJunnos dismissed PushedGun’s stale review December 14, 2023 15:34

The base branch was changed.

auto-merge was automatically disabled December 17, 2023 16:03

Merge queue setting changed

@SwiftyJunnos SwiftyJunnos changed the base branch from main to iOS/release January 8, 2024 02:01
@SwiftyJunnos SwiftyJunnos merged commit be4b1bf into iOS/release Jan 23, 2024
31 checks passed
@SwiftyJunnos SwiftyJunnos deleted the iOS/task/Map-Polyline-Filtering branch January 23, 2024 00:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
✨ 신규 기능 신규 기능 개발
Projects
None yet
3 participants