blob: a9f5049ddaad1d07d9cac0fb00bef1dafc843c6a [file] [log] [blame]
alexander3c798932021-03-26 21:42:19 +00001/*
2 * Copyright (c) 2021 Arm Limited. All rights reserved.
3 * SPDX-License-Identifier: Apache-2.0
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17#include "PlatformMath.hpp"
18
19#if 0 == ARM_DSP_AVAILABLE
20 #include <cmath>
21 #include <numeric>
22#endif /* 0 == ARM_DSP_AVAILABLE */
23
24namespace arm {
25namespace app {
26namespace math {
27
28 float MathUtils::CosineF32(float radians)
29 {
30#if ARM_DSP_AVAILABLE
31 return arm_cos_f32(radians);
32#else /* ARM_DSP_AVAILABLE */
33 return cos(radians);
34#endif /* ARM_DSP_AVAILABLE */
35 }
36
37 float MathUtils::SqrtF32(float input)
38 {
39#if ARM_DSP_AVAILABLE
40 float output = 0.f;
41 arm_sqrt_f32(input, &output);
42 return output;
43#else /* ARM_DSP_AVAILABLE */
44 return sqrtf(input);
45#endif /* ARM_DSP_AVAILABLE */
46 }
47
48 float MathUtils::MeanF32(float* ptrSrc, const uint32_t srcLen)
49 {
50 if (!srcLen) {
51 return 0.f;
52 }
53
54#if ARM_DSP_AVAILABLE
55 float result = 0.f;
56 arm_mean_f32(ptrSrc, srcLen, &result);
57 return result;
58#else /* ARM_DSP_AVAILABLE */
59 float acc = std::accumulate(ptrSrc, ptrSrc + srcLen, 0.0);
60 return acc/srcLen;
61#endif /* ARM_DSP_AVAILABLE */
62 }
63
64 float MathUtils::StdDevF32(float* ptrSrc, const uint32_t srcLen,
65 const float mean)
66 {
67 if (!srcLen) {
68 return 0.f;
69 }
70#if ARM_DSP_AVAILABLE
71 /**
72 * Note Standard deviation calculation can be off
73 * by > 0.01 but less than < 0.1, according to
74 * preliminary findings.
75 **/
76 UNUSED(mean);
77 float stdDev = 0;
78 arm_std_f32(ptrSrc, srcLen, &stdDev);
79 return stdDev;
80#else /* ARM_DSP_AVAILABLE */
81 auto VarianceFunction = [=](float acc, const float value) {
82 return acc + (((value - mean) * (value - mean))/ srcLen);
83 };
84
85 float acc = std::accumulate(ptrSrc, ptrSrc + srcLen, 0.0,
86 VarianceFunction);
87
88 return sqrtf(acc);
89#endif /* ARM_DSP_AVAILABLE */
90 }
91
92 bool MathUtils::FftInitF32(const uint16_t fftLen, arm::app::math::FftInstance& fftInstance)
93 {
94#if ARM_DSP_AVAILABLE
95 if (!fftInstance.initialised) {
96 arm_status status = arm_rfft_fast_init_f32(&fftInstance.instance, fftLen);
97
98 if (ARM_MATH_SUCCESS != status) {
99 return false;
100 }
101 fftInstance.initialised = true;
102 }
103#else
104 UNUSED(fftLen);
105 UNUSED(fftInstance);
106#endif /* ARM_DSP_AVAILABLE */
107 return true;
108 }
109
110 void MathUtils::FftF32(std::vector<float>& input,
111 std::vector<float>& fftOutput,
112 arm::app::math::FftInstance& fftInstance)
113 {
114#if ARM_DSP_AVAILABLE
115 arm_rfft_fast_f32(&fftInstance.instance, input.data(), fftOutput.data(), 0);
116#else
117 UNUSED(fftInstance);
118 const int inputLength = input.size();
119
120 for (int k = 0; k <= inputLength / 2; k++) {
121 float sumReal = 0, sumImag = 0;
122
123 for (int t = 0; t < inputLength; t++) {
124 float angle = 2 * M_PI * t * k / inputLength;
125 sumReal += input[t] * cosf(angle);
126 sumImag += -input[t] * sinf(angle);
127 }
128
129 /* Arrange output to [real0, realN/2, real1, im1, real2, im2, ...] */
130 if (k == 0) {
131 fftOutput[0] = sumReal;
132 } else if (k == inputLength / 2) {
133 fftOutput[1] = sumReal;
134 } else {
135 fftOutput[k*2] = sumReal;
136 fftOutput[k*2 + 1] = sumImag;
137 };
138 }
139#endif /* ARM_DSP_AVAILABLE */
140 }
141
142 void MathUtils::VecLogarithmF32(std::vector <float>& input,
143 std::vector <float>& output)
144 {
145#if ARM_DSP_AVAILABLE
146 arm_vlog_f32(input.data(), output.data(),
147 output.size());
148#else /* ARM_DSP_AVAILABLE */
149 for (auto in = input.begin(), out = output.begin();
150 in != input.end(); ++in, ++out) {
151 *out = logf(*in);
152 }
153#endif /* ARM_DSP_AVAILABLE */
154 }
155
156 float MathUtils::DotProductF32(float* srcPtrA, float* srcPtrB,
157 const uint32_t srcLen)
158 {
159 float output = 0.f;
160
161#if ARM_DSP_AVAILABLE
162 arm_dot_prod_f32(srcPtrA, srcPtrB, srcLen, &output);
163#else /* ARM_DSP_AVAILABLE */
164 for (uint32_t i = 0; i < srcLen; ++i) {
165 output += *srcPtrA++ * *srcPtrB++;
166 }
167#endif /* ARM_DSP_AVAILABLE */
168
169 return output;
170 }
171
172 bool MathUtils::ComplexMagnitudeSquaredF32(float* ptrSrc,
173 const uint32_t srcLen,
174 float* ptrDst,
175 const uint32_t dstLen)
176 {
177 if (dstLen < srcLen/2) {
178 printf_err("dstLen must be greater than srcLen/2");
179 return false;
180 }
181
182#if ARM_DSP_AVAILABLE
183 arm_cmplx_mag_squared_f32(ptrSrc, ptrDst, srcLen/2);
184#else /* ARM_DSP_AVAILABLE */
185 for (uint32_t j = 0; j < srcLen; ++j) {
186 const float real = *ptrSrc++;
187 const float im = *ptrSrc++;
188 *ptrDst++ = real*real + im*im;
189 }
190#endif /* ARM_DSP_AVAILABLE */
191 return true;
192 }
193
194} /* namespace math */
195} /* namespace app */
196} /* namespace arm */