0.1.0 Kurtosis

This commit is contained in:
Rob Tillaart 2024-05-22 16:24:10 +02:00
parent dbe75c80d3
commit 3712c7c2a1
16 changed files with 594 additions and 0 deletions

View File

@ -0,0 +1,28 @@
platforms:
rpipico:
board: rp2040:rp2040:rpipico
package: rp2040:rp2040
gcc:
features:
defines:
- ARDUINO_ARCH_RP2040
warnings:
flags:
packages:
rp2040:rp2040:
url: https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
compile:
# Choosing to run compilation tests on 2 different Arduino platforms
platforms:
- uno
# - due
# - zero
# - leonardo
- m4
- esp32
- esp8266
# - mega2560
- rpipico

View File

@ -0,0 +1,4 @@
# These are supported funding model platforms
github: RobTillaart
custom: "https://www.paypal.me/robtillaart"

View File

@ -0,0 +1,13 @@
name: Arduino-lint
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- uses: arduino/arduino-lint-action@v1
with:
library-manager: update
compliance: strict

View File

@ -0,0 +1,17 @@
name: Arduino CI
on: [push, pull_request]
jobs:
runTest:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
ruby-version: 2.6
- run: |
gem install arduino_ci
arduino_ci.rb

View File

@ -0,0 +1,18 @@
name: JSON check
on:
push:
paths:
- '**.json'
pull_request:
jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- name: json-syntax-check
uses: limitusus/json-syntax-check@v2
with:
pattern: "\\.json$"

View File

@ -0,0 +1,11 @@
# Change Log Kurtosis
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [0.1.0] - 2024-05-21
- initial version

View File

@ -0,0 +1,96 @@
#pragma once
//
// FILE: Kurtosis.h
// AUTHOR: Rob Tillaart
// DATE: 2024-05-21
// VERSION: 0.1.0
// PURPOSE: Arduino library for calculating skewness and kurtosis of a dataset.
// URL: https://github.com/RobTillaart/Kurtosis
//
// code based upon https://www.johndcook.com/blog/skewness_kurtosis/
// documentation https://en.wikipedia.org/wiki/Kurtosis
#define KURTOSIS_LIB_VERSION "0.1.0"
class Kurtosis
{
public:
Kurtosis()
{
reset();
};
void reset()
{
_count = 0;
M1 = M2 = M3 = M4 = 0.0;
};
void add(double x)
{
uint32_t n1 = _count;
_count++;
// determine distance to the mean (so far) M1.
double delta = x - M1;
// calculate the weighted addition for M1 to the mean.
double delta_n1 = delta / _count;
// TODO calculate the square of the weighted addition (?)
double delta_n2 = delta_n1 * delta_n1;
// TODO
double term1 = delta * delta_n1 * n1;
// optimized: remove 3 float operations. ~10% gain.
M1 += delta_n1;
M4 += delta_n2 * (term1 * (_count * (_count - 3) + 3) + 6 * M2) - 4 * delta_n1 * M3;
M3 += delta_n1 * (term1 * (_count - 2) - 3 * M2);
M2 += term1;
};
uint32_t count()
{
return _count;
};
double mean()
{
return M1;
};
double variance()
{
// cache the variance as it is used for stddev too.
static uint32_t lc = 0;
if (_count > lc)
{
lc = _count;
_variance = M2 / (_count - 1.0);
}
return _variance;
};
double stddev()
{
return sqrt( variance() );
};
double skewness()
{
// optimized: replaced a DIV by a MUL
return sqrt(double(_count)) * M3 * pow(M2, -1.5);
};
double kurtosis()
{
return double(_count) * M4 / (M2 * M2) - 3.0;
}
private:
uint32_t _count;
double M1, M2, M3, M4;
double _variance = 0.0;
};
// -- END OF FILE --

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024-2024 Rob Tillaart
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,117 @@
[![Arduino CI](https://github.com/RobTillaart/Kurtosis/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci)
[![Arduino-lint](https://github.com/RobTillaart/Kurtosis/actions/workflows/arduino-lint.yml/badge.svg)](https://github.com/RobTillaart/Kurtosis/actions/workflows/arduino-lint.yml)
[![JSON check](https://github.com/RobTillaart/Kurtosis/actions/workflows/jsoncheck.yml/badge.svg)](https://github.com/RobTillaart/Kurtosis/actions/workflows/jsoncheck.yml)
[![GitHub issues](https://img.shields.io/github/issues/RobTillaart/Kurtosis.svg)](https://github.com/RobTillaart/Kurtosis/issues)
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/Kurtosis/blob/master/LICENSE)
[![GitHub release](https://img.shields.io/github/release/RobTillaart/Kurtosis.svg?maxAge=3600)](https://github.com/RobTillaart/Kurtosis/releases)
[![PlatformIO Registry](https://badges.registry.platformio.org/packages/robtillaart/library/Kurtosis.svg)](https://registry.platformio.org/libraries/robtillaart/Kurtosis)
# Kurtosis
Arduino library for calculating skewness and kurtosis of a dataset (statistics).
## Description
**Experimental**
This library was written after a request how to calculate the kurtosis of a histogram.
Diving into this question I learned Kurtosis is a statistical measurements, somewhat
related to the skewness ("is balanced") of that dataset.
Not a statistician by profession, I searched the internet and found several sources
that described the kurtosis measurement.
The code of this library is based upon the code of **John D. Cook** in the blog named
"Computing skewness and kurtosis in one pass".
See - https://www.johndcook.com/blog/skewness_kurtosis/
I adapted the code on a few places to improve performance a bit.
Furthermore I named the library Kurtosis as calculating that is the
prime purpose of this library.
For a deep technical reader about kurtosis and skewness I refer to the Wikipedia.
Links to other information is welcome.
#### Related
- https://github.com/RobTillaart/Histogram
- https://github.com/RobTillaart/Kurtosis
- https://github.com/RobTillaart/RunningAverage
- https://github.com/RobTillaart/RunningMedian
- https://github.com/RobTillaart/Statistic
- https://en.wikipedia.org/wiki/Skewness
- https://en.wikipedia.org/wiki/Kurtosis
## Performance
Time in us, platform UNO,
0.0.0 is non optimized version.
| function | 0.0.0 | 0.1.0 | Notes |
|:----------:|:-------:|:-------:|:-------:|
| add | 232 | 212 |
| variance | - | 44 |
| skewness | 416 | 352 |
| kurtosis | - | 64 |
## Interface
```cpp
#include "Kurtosis.h"
```
#### Base
- **Kurtosis()** create the Kurtosis object.
- **void reset()** resets the internal variables.
- **void add(double x)** add new value to the internal variables.
- **uint32_t count()** returns the amount of values added.
- **double mean()** returns the mean (or average) of the values added.
This function will return 0 if no values have been added, or after reset().
- **double variance()** idem.
Note this value is cached as **stddev()** uses it too.
So the performance of two consecutive calls differ in duration.
- **double stddev()** standard deviation.
- **double skewness()** returns skewness ("balanced"), negative values indicate left skew,
positive values indicate right skew. See Wikipedia for details.
- **double kurtosis()** returns the kurtosis, "tailedness" is used e.g. to detect outliers.
See Wikipedia for details.
## Future
#### Must
- improve documentation.
- understand the math in more detail.
#### Should
- extend unit tests.
- add examples to explain the purpose.
#### Could
- cache skewness and kurtosis? useful?
#### Wont
## Support
If you appreciate my libraries, you can support the development and maintenance.
Improve the quality of the libraries by providing issues and Pull Requests, or
donate through PayPal or GitHub sponsors.
Thank you,

View File

@ -0,0 +1,57 @@
//
// FILE: Kurtosis_demo.ino
// AUTHOR: Rob Tillaart
// DATE: 2024-05-21
// PURPOSE: demo determination of skewness and kurtosis
// URL: https://github.com/RobTillaart/Kurtosis
#include "Kurtosis.h"
Kurtosis K;
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.print("KURTOSIS_LIB_VERSION: ");
Serial.println(KURTOSIS_LIB_VERSION);
Serial.println();
K.reset();
for (int i = 0; i < 100; i++)
{
int x = i;
K.add(x);
}
Serial.println();
delay(100);
Serial.println();
Serial.print("COUNT:\t");
Serial.println(K.count());
Serial.print("MEAN:\t");
Serial.println(K.mean());
Serial.print("VAR:\t");
Serial.println(K.variance());
Serial.print("STDDEV:\t");
Serial.println(K.stddev());
Serial.print("SKEW:\t");
Serial.println(K.skewness());
Serial.print("KURT:\t");
Serial.println(K.kurtosis());
Serial.println();
}
void loop()
{
}
// -- END OF FILE --

View File

@ -0,0 +1,73 @@
//
// FILE: kurtosis_performance.ino
// AUTHOR: Rob Tillaart
// DATE: 2024-05-21
// PURPOSE: performance measurement skewness and kurtosis
// URL: https://github.com/RobTillaart/Kurtosis
#include "Kurtosis.h"
Kurtosis K;
volatile float x = 0;
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.print("KURTOSIS_LIB_VERSION: ");
Serial.println(KURTOSIS_LIB_VERSION);
Serial.println();
Serial.println("times in us\n");
delay(100);
K.reset();
uint32_t start = micros();
for (int i = 0; i < 1000; i++)
{
K.add(i);
}
uint32_t stop = micros();
Serial.print("ADD (1000x):\t");
Serial.println((stop - start) * 0.001, 1);
delay(100);
start = micros();
x = K.variance();
stop = micros();
Serial.print("VARIANCE 1:\t");
Serial.println(stop - start);
delay(100);
start = micros();
x = K.variance();
stop = micros();
Serial.print("VARIANCE 2:\t");
Serial.println(stop - start);
delay(100);
start = micros();
x = K.skewness();
stop = micros();
Serial.print("SKEWNESS:\t");
Serial.println(stop - start);
delay(100);
start = micros();
x = K.kurtosis();
stop = micros();
Serial.print("KURTOSIS:\t");
Serial.println(stop - start);
delay(100);
}
void loop()
{
}
// -- END OF FILE --

View File

@ -0,0 +1,13 @@
BOARD: UNO
IDE: 1.8.19
KURTOSIS_LIB_VERSION: 0.1.0
times in us
ADD (1000x): 213.7
VARIANCE 1: 44
VARIANCE 2: 4
SKEWNESS: 352
KURTOSIS: 64

View File

@ -0,0 +1,21 @@
# Syntax Colouring Map For Kurtosis
# Data types (KEYWORD1)
Kurtosis KEYWORD1
# Methods and Functions (KEYWORD2)
reset KEYWORD2
add KEYWORD2
count KEYWORD2
mean KEYWORD2
variance KEYWORD2
stddev KEYWORD2
skewness KEYWORD2
kurtosis KEYWORD2
# Constants (LITERAL1)
KURTOSIS_LIB_VERSION LITERAL1

View File

@ -0,0 +1,23 @@
{
"name": "Kurtosis",
"keywords": "symmetrical, asymmetrical, statistic",
"description": "Arduino library for calculating skewness and kurtosis of a dataset.",
"authors":
[
{
"name": "Rob Tillaart",
"email": "Rob.Tillaart@gmail.com",
"maintainer": true
}
],
"repository":
{
"type": "git",
"url": "https://github.com/RobTillaart/Kurtosis.git"
},
"version": "0.1.0",
"license": "MIT",
"frameworks": "*",
"platforms": "*",
"headers": "Kurtosis.h"
}

View File

@ -0,0 +1,11 @@
name=Kurtosis
version=0.1.0
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Arduino library for calculating skewness and kurtosis of a dataset.
paragraph=symmetrical, asymmetrical, statistic
category=Data Processing
url=https://github.com/RobTillaart/Kurtosis
architectures=*
includes=Kurtosis.h
depends=

View File

@ -0,0 +1,71 @@
//
// FILE: unit_test_001.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// DATE: 2020-12-08
// PURPOSE: unit tests for the AD520X digital potentiometers
// https://github.com/RobTillaart/AD520X
// https://github.com/Arduino-CI/arduino_ci/blob/master/REFERENCE.md
//
// supported assertions
// ----------------------------
// assertEqual(expected, actual)
// assertNotEqual(expected, actual)
// assertLess(expected, actual)
// assertMore(expected, actual)
// assertLessOrEqual(expected, actual)
// assertMoreOrEqual(expected, actual)
// assertTrue(actual)
// assertFalse(actual)
// assertNull(actual)
#include <ArduinoUnitTests.h>
#include "Arduino.h"
#include "Kurtosis.h"
unittest_setup()
{
}
unittest_teardown()
{
}
unittest(test_begin)
{
fprintf(stderr, "KURTOSIS_LIB_VERSION:\t%s\n", (char *) KURTOSIS_LIB_VERSION);
}
unittest(test_one)
{
Kurtosis K;
K.reset();
assertEqual(K.count(), 0);
for (int i = 0; i < 100; i++)
{
int x = i;
K.add(x);
}
assertEqual(K.count(), 100);
assertEqualFloat(K.mean(), 49.50, 0.01);
assertEqualFloat(K.variance(), 841.67, 0.01);
assertEqualFloat(K.stddev(), 29.01, 0.01);
assertEqualFloat(K.skewness(), 0.00, 0.01);
assertEqualFloat(K.kurtosis(), -1.20, 0.01);
}
unittest_main()
// -- END OF FILE --