Last active
October 1, 2019 15:00
-
-
Save lukaspili/b7930ee94874f21e8a9c65d65751b136 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:math' as math; | |
// 1. MODELS | |
enum Gender { female, male } | |
class Activity { | |
Activity({this.id, this.category, this.hours, this.frequency, this.recordings}); | |
final int id; | |
final int category; | |
// Number of hours per frequency | |
final int hours; | |
final ActivityFrequency frequency; | |
// Recordings attached to this activity | |
final List<Recording> recordings; | |
@override | |
String toString() { | |
return 'activity: $id, category: $category, recordings: ${recordings.length}'; | |
} | |
} | |
enum ActivityFrequency { daily, weekly, monthly } | |
class Recording { | |
Recording({this.duration, this.leqA}); | |
// Duration in seconds | |
final int duration; | |
// The last value of leqA calculated the recording | |
final double leqA; | |
} | |
class ActivityExposure { | |
ActivityExposure({this.activity, this.normalizedDailyDuration, this.leqA}); | |
final Activity activity; | |
final double normalizedDailyDuration; | |
final double leqA; | |
@override | |
String toString() { | |
return 'activity: ${activity.id}, normalized daily duration: $normalizedDailyDuration, leqA: ${leqA.round()} dbA'; | |
} | |
} | |
// 2. SAMPLE DATA | |
List<Activity> _createSampleData() { | |
return [ | |
Activity( | |
id: 1, | |
category: 1, | |
hours: 8, | |
frequency: ActivityFrequency.weekly, | |
recordings: [ | |
Recording(duration: 120, leqA: 50.0), | |
Recording(duration: 200, leqA: 40.0), | |
Recording(duration: 300, leqA: 80.0), | |
], | |
), | |
Activity( | |
id: 2, | |
category: 1, | |
hours: 5, | |
frequency: ActivityFrequency.daily, | |
recordings: [ | |
Recording(duration: 500, leqA: 55.0), | |
Recording(duration: 200, leqA: 65.0), | |
], | |
), | |
Activity( | |
id: 3, | |
category: 2, | |
hours: 18, | |
frequency: ActivityFrequency.monthly, | |
recordings: [ | |
Recording(duration: 120, leqA: 50.0), | |
Recording(duration: 200, leqA: 40.0), | |
Recording(duration: 300, leqA: 80.0), | |
Recording(duration: 300, leqA: 40.0), | |
Recording(duration: 300, leqA: 30.0), | |
], | |
), | |
Activity( | |
id: 4, | |
category: 2, | |
hours: 4, | |
frequency: ActivityFrequency.monthly, | |
recordings: [ | |
Recording(duration: 500, leqA: 55.0), | |
Recording(duration: 250, leqA: 65.0), | |
Recording(duration: 700, leqA: 25.0), | |
Recording(duration: 100, leqA: 95.0), | |
], | |
), | |
]; | |
} | |
// 3. MATH LAB CONVERTED FUNCTIONS | |
ActivityExposure _calculateExposurePerActivity(Activity activity) { | |
double normalizedDailyDuration; | |
switch (activity.frequency) { | |
case ActivityFrequency.daily: | |
normalizedDailyDuration = activity.hours.toDouble(); | |
break; | |
case ActivityFrequency.weekly: | |
normalizedDailyDuration = activity.hours / 7; | |
break; | |
case ActivityFrequency.monthly: | |
normalizedDailyDuration = activity.hours / 7 / 4; | |
break; | |
} | |
final leqAs = activity.recordings.map((it) => it.leqA); | |
// 10*log10(sum((10.^(0.1* mesures)))/nb) | |
// a = (0.1* mesures) | |
final a = leqAs.map((it) => 0.1 * it); | |
// b = (10.^(0.1* mesures)) | |
final b = a.map((it) => math.pow(10, it)); | |
// c = sum((10.^(0.1* mesures))) | |
final c = b.fold(0, (it1, it2) => it1 + it2); | |
// d = sum((10.^(0.1* mesures)))/nb | |
final d = c / activity.recordings.length; | |
// e = log10(sum((10.^(0.1* mesures)))/nb) | |
final e = log10(d); | |
// averageLeqA = 10*log10(sum((10.^(0.1* mesures)))/nb) | |
final averageLeqA = 10 * e; | |
return ActivityExposure( | |
activity: activity, | |
normalizedDailyDuration: normalizedDailyDuration, | |
leqA: averageLeqA, | |
); | |
} | |
double _calculateLAeq(List<ActivityExposure> exposures) { | |
final totalDuration = exposures.map((it) => it.normalizedDailyDuration).fold(0, (it1, it2) => it1 + it2); | |
// LAeq = 10*log10((1/total_duration)* sum((ActivityTab(:,1)).*10.^(0.1* ActivityTab(:,2)))); | |
// (0.1* ActivityTab(:,2)) | |
final a = exposures.map((it) => 0.1 * it.leqA).toList(); | |
// 10.^(0.1* ActivityTab(:,2)) | |
final b = a.map((it) => math.pow(10, it)).toList(); | |
// (ActivityTab(:,1)).*10.^(0.1* ActivityTab(:,2)) | |
final c = exposures.asMap().map((index, it) => MapEntry(index, it.normalizedDailyDuration * b[index])).values.toList(); | |
// sum((ActivityTab(:,1)).*10.^(0.1* ActivityTab(:,2))) | |
final d = c.fold(0, (it1, it2) => it1 + it2); | |
// (1/total_duration)* sum((ActivityTab(:,1)).*10.^(0.1* ActivityTab(:,2))) | |
final e = (1 / totalDuration) * d; | |
// log10((1/total_duration)* sum((ActivityTab(:,1)).*10.^(0.1* ActivityTab(:,2)))) | |
final f = log10(e); | |
// 10*log10((1/total_duration)* sum((ActivityTab(:,1)).*10.^(0.1* ActivityTab(:,2)))) | |
final LAeq = 10 * f; | |
return LAeq; | |
} | |
List<double> aye({ | |
Gender gender, | |
int age, | |
List<ActivityExposure> exposures, | |
}) { | |
const ISO_1999_NIPTS_3000 = [3000.0, 0.0120000000000000, 0.0370000000000000, 77.0]; | |
const ISO_1999_alpha_3000 = [3000.0, 0.0115000000000000, 0.00750000000000000]; | |
final sex = gender == Gender.male ? 0 : 1; | |
final currentAge = age; | |
final futureAge = List<int>(); | |
for (int k = 1; k <= 5; ++k) { | |
futureAge.add(currentAge + k * 5); | |
} | |
final exposureData = exposures; | |
final lex8h = _lex8h(exposureData); | |
int beginAge = currentAge; | |
final a = List<double>(); | |
for (int k = 1; k <= futureAge.length; ++k) { | |
double value; | |
if (lex8h < ISO_1999_NIPTS_3000[_indexFor(4)]) { | |
value = 0.0; | |
} else { | |
if (futureAge[_indexFor(k)] - beginAge > 10) { | |
final a = ISO_1999_NIPTS_3000[_indexFor(2)]; | |
final b = ISO_1999_NIPTS_3000[_indexFor(3)]; | |
final c = log10(futureAge[_indexFor(k)].toDouble() - beginAge); | |
final d = lex8h - ISO_1999_NIPTS_3000[_indexFor(4)]; | |
final e = math.pow(d, 2); | |
final f = ISO_1999_alpha_3000[_indexFor(sex + 2)]; | |
final g = ((a + b * c) * e) / f; | |
final h = math.sqrt(g); | |
final result = h - futureAge[_indexFor(k)] + 18; | |
value = result; | |
} else { | |
final a = log10(futureAge[_indexFor(k)] - beginAge + 1.0) / log10(11.0); | |
final b = ISO_1999_NIPTS_3000[_indexFor(2)] + ISO_1999_NIPTS_3000[_indexFor(3)] * log10(10.0); | |
final c = lex8h - ISO_1999_NIPTS_3000[_indexFor(4)]; | |
final d = math.pow(c, 2); | |
final e = ISO_1999_alpha_3000[_indexFor(sex + 2)]; | |
final f = a * (b * d) / e; | |
final g = math.sqrt(f); | |
final result = g - futureAge[_indexFor(k)] + 18; | |
value = result; | |
} | |
if (value < 0) { | |
value = 0.0; | |
} | |
} | |
a.add(value); | |
} | |
return a; | |
} | |
// Matlab array indexes start at 1, while in Dart it starts at 0 | |
int _indexFor(int index) => index - 1; | |
double _lex8h(List<ActivityExposure> exposures) { | |
final totalDuration = exposures.fold(0, (it1, it2) => it1 + it2.normalizedDailyDuration); | |
final LAeq = _calculateLAeq(exposures); | |
return LAeq + 10 * log10(totalDuration / 8.0); | |
} | |
// 4. RUN | |
void main() { | |
final List<Activity> activitiesWithRecordings = _createSampleData(); | |
printList('Activities with recordings:', activitiesWithRecordings); | |
final List<ActivityExposure> exposures = activitiesWithRecordings.map(_calculateExposurePerActivity).toList(); | |
printList('Exposures for each activity:', exposures); | |
final double LAeq = _calculateLAeq(exposures); | |
print('LAeq: $LAeq'); | |
print(''); | |
final List<double> aye1 = aye(age: 30, gender: Gender.male, exposures: exposures); | |
printList('AYE for male, 30:', aye1); | |
final List<double> aye2 = aye(age: 30, gender: Gender.female, exposures: exposures); | |
printList('AYE for female, 30:', aye2); | |
final List<double> aye3 = aye(age: 50, gender: Gender.male, exposures: exposures); | |
printList('AYE for male, 50:', aye3); | |
final List<double> aye4 = aye(age: 50, gender: Gender.female, exposures: exposures); | |
printList('AYE for female, 50:', aye4); | |
} | |
// 5. DART UTILS | |
num log10(num x) => math.log(x) / math.log(10); | |
Map<T, List<S>> groupBy<S, T>(Iterable<S> values, T key(S element)) { | |
var map = <T, List<S>>{}; | |
for (var element in values) { | |
var list = map.putIfAbsent(key(element), () => []); | |
list.add(element); | |
} | |
return map; | |
} | |
void printList(String title, List list) { | |
print(title); | |
list.forEach((it) => print(' * $it')); | |
print(''); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment