C rand() is really a bad choice for a random number generator in DSP applications. It is not thread-safe (which is extensively documented), and the C standard makes no statement on the generator itself – it can be any algorithm, no matter how bad.
So, this is not surprising; as a matter of fact, my system's C library documentation (man 3 rand) even explicitly states this:
Do not use this function in applications intended to be portable when good randomness is needed. (Use random(3) instead.)
Now, I agree with the first part, and disagree with the parentheses – random() is better, but not great, either (their randomness leaves things to be desired, they have relatively short sequence length and on top, they are slow, in case of my C library. Your C library will probably be not any better).
Simply use a different random generator. If you're using C++¹, std::random has alternatives. But for portable C, Xoroshiro (code on the right half of the page) is a good family of generators both for integer and floating point generations. In GNU Radio, we use the Xoroshiro128+ algorithm in code where I extracted the state, so that one can have arbitrarily many parallel random generators in parallel (if you're using C++ distribution shapers, you can also use XOROSHIRO generator there).
A former student of mine has implemented Xoroshiro128+ in digital logic on an FPGA to generate fixed-point normally-distributed numbers² at 38 GS/s. This thing is plenty compact and fast enough (and the student was really good).
Another thing: you're doing srand(time(0)). That is not an appropriate seed. I know this has been appearing in examples probably since the 1970s, but it's just a really really bad idea, and I don't know why it has still survived. If you want reproducible random number generation (e.g. for testing, or for pseudorandom correlation sequences or such), seed deterministically (seed "4 was chosen by fair dice roll"); if you need truly random, almost certainly-different-every-time, then, well using the second as seed is about the worst thing you can choose (it being predictably the same for 1s, in which your computer can do many billion operations).
So, when seeding: If you're doing C++, your OS (or just the HAL) usually implements std::random_device, which you can use for getting a good random seed. If you don't have such amenities, figure out how your embedded device produces real random bits (it might, for example, just have a CPU register that contains a truly-random number when read). If you're running a unixoid embedded operating system (Linux, *BSD, QNX, …), you might just be able to read bytes out of /dev/random; on Windows, Android, iOS, Zephyr etc, there's operating system APIs to get random seeds.
¹ I mention C++ although your question says C because you're writing C for embedded, but are making use of one of the "fatter" libc features, so chances are you actually have a full C++ runtime at hand, by the way.
² which was necessary because we were testing things that might be sensitive to repetitive input, so the digital design-typical BERT tester PRNGs didn't cut it
mersenne_twister_enginein C++'s standard library does in conjuction with thenormal_distributionshaper (note though, that while excellent, Mersenne twisters are very state-space intense and slow; they do fall out of favor for a lot of small-device implementations). I don't know your compiler suite of choice, but if you have GCC, and look into the (equivalent on your OS of) … $\endgroup$mersenne_twister_engine's methodoperator(), which gives you a random number. Its implementation is in …/bits/random.tcc ; look for_M_gen_rand(void)in that. that C++ is, as far as I can tell, "nearly valid C", when you replace thetemplate<typename _UIntType…with a simpletypedef uint64_t _UIntType(and remember that_M_xis just a classical C array containing the generator's state). $\endgroup$