Skip to content

Commit 879b61c

Browse files
authored
Add six new waves (#9)
- add **float sinusDiode(float t)** - add **float sinusRectified(float t)** - add **float trapezium1(float t)** with duty cycle. - add **float trapezium2(float t)** with duty cycle. - add **float heartBeat(float t)** - add **float freeWave(float t, int16_t arr, int size)** arbitrary wave generator. - update **functionGeneratorPerformance.ino** - add examples for **freeWave()** - fix Arduino-lint.yml (long library name error) - update readme.md - minor edits
1 parent 6f02ab6 commit 879b61c

14 files changed

+1502
-55
lines changed

.github/workflows/arduino-lint.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,4 @@ jobs:
1010
- uses: arduino/arduino-lint-action@v1
1111
with:
1212
library-manager: update
13-
compliance: strict
13+
# compliance: strict

CHANGELOG.md

+16-2
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,24 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
66
and this project adheres to [Semantic Versioning](http://semver.org/).
77

88

9-
## [0.2.5] - 2023-11-02
9+
## [0.3.0] - 2024-07-05
10+
- add **float sinusDiode(float t)**
11+
- add **float sinusRectified(float t)**
12+
- add **float trapezium1(float t)** with duty cycle.
13+
- add **float trapezium2(float t)** with duty cycle.
14+
- add **float heartBeat(float t)**
15+
- add **float freeWave(float t, int16_t arr, int size)** arbitrary wave generator.
16+
- update **functionGeneratorPerformance.ino**
17+
- add examples for **freeWave()**
18+
- fix Arduino-lint.yml (long library name error)
1019
- update readme.md
11-
- update keywords.txt (align)
20+
- minor edits
21+
22+
----
1223

24+
## [0.2.6] - 2023-11-02
25+
- update readme.md
26+
- update keywords.txt (align)
1327

1428
## [0.2.5] - 2023-03-25
1529
- add **setDutyCycle()**, **getDutyCycle()**

README.md

+95-33
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,15 @@ In practice the generator is useful for low frequencies,
2727
Note: this class generates float values, performance wise this can be optimized,
2828
to achieve higher speeds at cost of accuracy / precision.
2929

30+
As always, feedback and ideas are welcome.
3031

31-
#### Performance
3232

33-
Indication of what performance can be expected (based upon 0.2.1 version).
33+
### Performance
34+
35+
You always have to verify your own performance measurements to see if
36+
your requirements are met by this library.
37+
38+
**Indication** of what performance can be expected (based upon 0.2.1 version).
3439
Note that the values need to be transported to a DAC or serial port too.
3540
Numbers based on performance example, for one single signal.
3641

@@ -72,55 +77,67 @@ have become slightly slower.
7277
| Arduino UNO | 16 MHz | square | 57 | 1000 Hz |
7378
| Arduino UNO | 16 MHz | random_DC | 68 | 500 Hz |
7479

80+
See **functionGeneratorPerformance.ino**
81+
7582

76-
#### Accuracy
83+
### Accuracy
7784

7885
If the time parameter **t** grows large, the internal math may have rounding
7986
problems after some time. This can and will affect the quality of the output.
87+
It is advised to reset **t** after a number (e.g. 100) full periods
8088

8189
Needs further investigations.
8290

91+
### Related
92+
93+
- https://github.com/RobTillaart/AD9833 hardware waveform generator.
94+
- https://github.com/RobTillaart/AD985X hardware waveform generator.
95+
- https://github.com/RobTillaart/functionGenerator software waveform generator.
96+
- https://pages.mtu.edu/~suits/notefreqs.html frequency table for notes.
97+
8398

8499
## Interface
85100

86101
```cpp
87102
#include "functionGenerator.h"
88103
```
89104

90-
#### Constructor
105+
### Constructor
91106

92107
- **funcgen(float period = 1.0, float amplitude = 1.0, float phase = 0.0, float yShift = 0.0)**
93108
All parameters (except duty cycle) can be set in the constructor but also later in configuration.
94109
Default dutyCycle is 50%.
95110

96111

97-
#### Configuration
112+
### Configuration
98113

99-
- **void setPeriod(float period = 1.0)** set the period of the wave in seconds.
114+
- **void setPeriod(float period = 1.0)** set the period of the wave in seconds.
115+
This is the inverse of the frequency.
100116
- **float getPeriod()** returns the set period.
101-
- **void setFrequency(float frequency = 1.0)** set the frequency of the wave in Hertz (1/s).
117+
- **void setFrequency(float frequency = 1.0)** set the frequency of the wave in Hertz (1/s).
118+
This is the inverse of the period.
102119
- **float getFrequency()** returns the set frequency in Hertz.
103-
- **void setAmplitude(float amplitude = 1.0)** sets the amplitude of the wave.
120+
- **void setAmplitude(float amplitude = 1.0)** sets the amplitude of the wave.
104121
The range is from **-amplitude** to **+amplitude**.
105122
Setting the amplitude to 0 gives effectively a zero signal.
106123
Setting the amplitude to a negative value effectively inverts the signal.
107124
- **float getAmplitude()** returns the set amplitude.
108-
- **void setPhase(float phase = 0.0)** shifts the phase of the wave.
125+
- **void setPhase(float phase = 0.0)** shifts the phase of the wave.
109126
Will only be noticeable when compared with other waves.
110127
Phase is also known as the X- or horizontal shift.
111128
- **float getPhase()** returns the set phase.
112-
- **void setYShift(float yShift = 0.0)** sets an Y-shift or vertical offset in amplitude.
129+
- **void setYShift(float yShift = 0.0)** sets an Y-shift or vertical offset in amplitude.
113130
This allows to set e.g. the zero level.
114131
- **float getYShift()** returns the set Y-shift.
115-
- **void setDutyCycle(float percentage = 100)** sets the duty cycle of the signal.
132+
- **void setDutyCycle(float percentage = 100)** sets the duty cycle of the signal.
116133
Experimental, not all waveforms have a duty cycle or interpret it differently, see below.
117134
Duty cycle must be between 0 and 100% and will be clipped otherwise.
118-
- **float getDutyCycle()** returns the set duty cycle.
119-
- **void setRandomSeed(uint32_t a, uint32_t b = 314159265)** sets the initial seeds for the
135+
- **float getDutyCycle()** returns the set (clipped) duty cycle.
136+
- **void setRandomSeed(uint32_t a, uint32_t b = 314159265)** sets the initial seeds for the
120137
(Marsaglia) random number generator. The first is mandatory, the second is optional.
121138

122139

123-
#### Wave forms
140+
### Wave forms
124141

125142
The variable t == time in seconds.
126143

@@ -129,11 +146,12 @@ The variable t == time in seconds.
129146
- mode == 1 ==> sawtooth |\\. Effectively equals inverting the amplitude.
130147
- **float triangle(float t)** triangle form, duty cycle default 50%.
131148
- **float square(float t)** square wave with duty cycle default 50%.
132-
- **float sinus(float t)** sinus wave, has no duty cycle.
149+
- **float sinus(float t)** sinus wave, has no duty cycle.
133150
- **float stair(float t, uint16_t steps = 8, uint8_t mode = 0)** defaults to 8 steps up.
134151
- mode = 0 ==> steps up
135152
- mode = 1 ==> steps down. Effectively equals inverting the amplitude.
136-
- **float random()** random noise generation.
153+
- **float random()** random noise generation between 0 and amplitude.
154+
Uses Marsaglia random generator.
137155
- **float line()** constant voltage line.
138156
Height depends on the YShift and amplitude.
139157
- **float zero()** constant zero.
@@ -142,7 +160,29 @@ The functions **line()** and **zero()** can be used to drive a constant voltage
142160
from a DAC and can be used to calibrate the generator / DAC combination.
143161

144162

145-
#### Duty Cycle
163+
Experimental 0.2.7
164+
165+
- **float sinusDiode(float t)** sinus wave, only positive pulses.
166+
(better name welcome).
167+
- **float sinusRectified(float t)** sinus wave, with "abs(negative pulses)".
168+
(better name welcome).
169+
- **float trapezium1(float t)** trapezium wave.
170+
DutyCycle changes steepness of the falling and rising edge.
171+
The wave changes from a square wave, via trapezium to a triangle wave.
172+
- **float trapezium2(float t)** trapezium wave.
173+
DutyCycle changes duration HIGH vs LOW, wave stays trapezium like.
174+
Note at 50% DC the two trapezium functions are identical.
175+
- **float heartBeat(float t)** simplified heartbeat wave.
176+
To get a regular BPM heartbeat one should **setFrequency(BPM/60.0)** e.g 72/60 = 1.2.
177+
- **float freeWave(float t, int16_t arr, int16_t N)** define a free wave form.
178+
It uses an array of **N+1** values, dividing a full period in **N** equidistant steps.
179+
The last value should equal the first value to have a smooth transition.
180+
The values of the array normally vary between -10000 and +10000 to manage
181+
the set the relative amplitude in small steps.
182+
These are scaled back to -1.0 to +1.0 times the amplitude.
183+
184+
185+
### Duty Cycle
146186

147187
Since 0.2.5 the library has **experimental** support for duty cycle.
148188
The meaning of duty cycle differs per wave form.
@@ -160,7 +200,16 @@ with respect to previous value.
160200
Implemented as a weighed average between new and previous value.
161201
Made a separate function as handling the duty cycle slows performance substantial.
162202
Initial starts at zero and can be adjusted with **YShift()**.
203+
- **float trapezium1(float t)** The duty cycle changes the steepness of the rising
204+
and falling edges. This changes the form from square wave to trapezium to triangle.
205+
The length of the HIGH LOW level go from 0 to half a period.
206+
- **float trapezium2(float t)** The duty cycle determines the length of the HIGH level,
207+
which is 0 for 0% DC and half a period for 100% DC.
208+
The rising and falling edges stay same.
209+
- **float heartBeat(float t)** The duty cycle determines the part of the period
210+
that the signal ~zero.
163211

212+
### No duty cycle
164213

165214
The other functions need to be investigated what duty cycle means.
166215
Current ideas that are **NOT** implemented:
@@ -171,41 +220,52 @@ Think of it as the halve of the triangle wave.
171220
- **stair()** like sawtooth??
172221
- **line()** has no period so does not make sense (yet).
173222
- **zero()** has no period so does not make sense (yet).
174-
175-
Feedback and ideas are welcome.
176-
223+
- **float sinusDiode(float t)**
224+
- **float sinusRectified(float t)**
225+
- **float freeWave(float t, int16_t arr, int16_t N)**
177226

178227
## Future
179228

180-
181229
#### Must
182230

183-
- documentation
184-
- quality of signals - after substantial time t
185-
- max freq per wave form etc.
186-
Should this be in the library?
187-
231+
- improve documentation
232+
- reorganize
233+
- section per function might be better.
188234

189235
#### Should
190236

191237
- smart reseed needed for random().
192-
- initialize random generator with compile time.
193-
238+
- initialize random generator with compile file + date + time.
239+
- use function values for seed bits.
240+
- stand-alone functions in separate .h
241+
- clean up code
194242

195243
#### Could
196244

197-
- waves
198-
- trapezium wave (could merge square and triangle and sawtooth)
199-
- white noise, pink noise etc.
200-
- RC function curve.
245+
- ASDR wave
246+
- https://en.wikipedia.org/wiki/Envelope_(music)
247+
- **float ADSR(float t, float A, float D, float S, float R)**
248+
- ADSR are percentages, A + D + R < 1.0
249+
- S = % of amplitude.
201250
- external clock to synchronize two or more software function generators.
202-
- stand-alone functions in separate .h
203251
- check for synergy with https://github.com/RobTillaart/AD985X
204252
- investigate performance.
205253
- algorithms for DAC specific gains e.g. 10-12-16 bit.
206254
- improve performance sin() lookup table.
207255
- add float variable for ```_perDC = _period * _dutyCycle```
208256
- do we need **freq4** ? not since DC.
257+
- heartBeat
258+
- small noise/variation parameter on amplitude and frequency.
259+
- reduce footprint ==> wrapper around freeWave()
260+
- waves
261+
- white noise, pink noise (better done with hardware)
262+
- min() + max() => return +-amplitude + yshift?
263+
- RC function curve.
264+
- Gamma curve.
265+
- create a function table? with what?
266+
- create an example program to sample an arbitrary wave form
267+
- output in the right format.
268+
- slow sampling vs real time.
209269

210270

211271
#### Examples
@@ -228,6 +288,8 @@ Feedback and ideas are welcome.
228288
- **float stairDC()**
229289
- Bezier curve? (too complex)
230290
- record a signal and play back ==> separate class
291+
- document max frequency per wave form etc.
292+
Should this be in the library? differs per board.
231293

232294

233295
## Support
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
//
2+
// FILE: funcGenFreeWavePlotter.ino
3+
// AUTHOR: Rob Tillaart
4+
// PURPOSE: demo function generators
5+
// URL: https://github.com/RobTillaart/FunctionGenerator
6+
//
7+
// use a Serial plotter to show the data
8+
9+
10+
#include "functionGenerator.h"
11+
12+
funcgen gen;
13+
14+
// sin(t).
15+
int16_t arr_sin[101] =
16+
{
17+
0, 627, 1253, 1873, 2486, 3090,
18+
3681, 4257, 4817, 5358, 5877,
19+
6374, 6845, 7289, 7705, 8090,
20+
8443, 8763, 9048, 9297, 9510,
21+
9685, 9822, 9921, 9980, 10000,
22+
9980, 9921, 9822, 9685, 9510,
23+
9297, 9048, 8763, 8443, 8090,
24+
7705, 7289, 6845, 6374, 5877,
25+
5358, 4817, 4257, 3681, 3090,
26+
2486, 1873, 1253, 627, 0,
27+
-627, -1253, -1873, -2486, -3090,
28+
-3681, -4257, -4817, -5358, -5877,
29+
-6374, -6845, -7289, -7705, -8090,
30+
-8443, -8763, -9048, -9297, -9510,
31+
-9685, -9822, -9921, -9980, -10000,
32+
-9980, -9921, -9822, -9685, -9510,
33+
-9297, -9048, -8763, -8443, -8090,
34+
-7705, -7289, -6845, -6374, -5877,
35+
-5358, -4817, -4257, -3681, -3090,
36+
-2486, -1873, -1253, -627, 0,
37+
};
38+
39+
40+
// sin(t) + 0.25 * sin(5t)
41+
int16_t arr_two_sin[101] =
42+
{
43+
0, 1120, 2178, 3117, 3891, 4472,
44+
4847, 5024, 5029, 4904, 4702,
45+
4481, 4300, 4213, 4261, 4472,
46+
4852, 5392, 6063, 6820, 7608,
47+
8366, 9033, 9554, 9886, 10000,
48+
9886, 9554, 9033, 8366, 7608,
49+
6820, 6063, 5392, 4852, 4472,
50+
4261, 4213, 4300, 4481, 4702,
51+
4904, 5029, 5024, 4847, 4472,
52+
3891, 3117, 2178, 1120, 0,
53+
-1120, -2178, -3117, -3891, -4472,
54+
-4847, -5024, -5029, -4904, -4702,
55+
-4481, -4300, -4213, -4261, -4472,
56+
-4852, -5392, -6063, -6820, -7608,
57+
-8366, -9033, -9554, -9886, -10000,
58+
-9886, -9554, -9033, -8366, -7608,
59+
-6820, -6063, -5392, -4852, -4472,
60+
-4261, -4213, -4300, -4481, -4702,
61+
-4904, -5029, -5024, -4847, -4472,
62+
-3891, -3117, -2178, -1120, 0,
63+
};
64+
65+
66+
67+
void setup()
68+
{
69+
Serial.begin(115200);
70+
// Serial.println(__FILE__);
71+
// Serial.print("FUNCTIONGENERATOR_LIB_VERSION: ");
72+
// Serial.println(FUNCTIONGENERATOR_LIB_VERSION);
73+
// Serial.println();
74+
75+
gen.setAmplitude(80);
76+
gen.setFrequency(0.5);
77+
gen.setDutyCycle(50);
78+
}
79+
80+
81+
void loop()
82+
{
83+
float t = millis() * 0.001;
84+
85+
Serial.print(80);
86+
Serial.print("\t");
87+
Serial.print(-80);
88+
Serial.print("\t");
89+
Serial.print(gen.freeWave(t, arr_two_sin, 100));
90+
Serial.println();
91+
delay(10);
92+
}
93+
94+
95+
// -- END OF FILE --

0 commit comments

Comments
 (0)