4
votes

I'm implementing a very simple band-pass filter, and it's input arguments are a vector containing the signal, the dwell time, and the cutoff frequencies for the high-pass and low-pass filters:

typedef std::vector<double> vec;
vec bandPass(const vec& signal, double dwellTime, double lowCutoff, double highCutoff);

The obvious problem with my interface is that the function caller has to know in advance what units of time and frequency are expected, and may have to go through the annoyance of converting them appropriately, if necessary.

I figured I could maybe use std::chrono to solve my problem, but I haven't seen it being used to measure frequencies. I'd want to have:

vec bandPass(const vec& signal, milliseconds dwellTime, kHertz lowCutoff, kHertz highCutoff);

and have my function convert all units to seconds and Hertz for the computation. Ideally, multiplying milliseconds and kHz would give me the same results as multiplying seconds and Hz.

Has anyone ever come accross a similar issue? Is it legal C++ to write anything like 1/10s to refer to Hertz?

I don't have much experience with std::chrono (and with C++, for that matter) and hoped I could gather some words of wisdom here before defining my interface. Any other suggestions are also welcome.

1
I think you're looking for std::chrono::duration specifically for representing a time interval.AndyG

1 Answers

8
votes

A frequency can be treated as the duration of a cycle. So 20 Hz can be treated as 0.05 seconds.

Chrono will fully support that.

You can probably write a Hz type or frequency template that does the opposite of what periods/durations do in some contexts. Internally storing a duration doesn't work well, sadly, as an int Hz in seconds as a duration in seconds is a failure.

template<
  class Rep,
  class Period = std::ratio<1>
>
struct frequency;

template<
  class Rep,
  std::intmax_t Num,
  std::intmax_t Denom>
>
struct frequency<Rep, std::ratio<Num, Denom>>
{
  // todo!
  frequency& operator+=(const frequency& d);
  frequency& operator-=(const frequency& d);
  frequency& operator*=(const Rep& rhs);
  frequency& operator/=(const Rep& rhs);
  frequency& operator%=(const frequency& rhs);
  Rep count() const;
  friend frequency operator+(frequency lhs, frequency const& rhs);
  friend frequency operator-(frequency lhs, frequency const& rhs);
  friend frequency operator*(frequency self, Rep const& scalar);
  friend frequency operator*(Rep const& scalar, frequency self);
  friend frequency operator/(frequency self, Rep const& scalar);
  friend frequency operator%(frequency lhs, Rep const& rhs);
  friend frequency operator%(frequency lhs, frequency const& rhs);
  friend bool operator==(frequency const& lhs, frequency const& rhs);
  friend bool operator!=(frequency const& lhs, frequency const& rhs);
  friend bool operator<=(frequency const& lhs, frequency const& rhs);
  friend bool operator>=(frequency const& lhs, frequency const& rhs);
  friend bool operator<(frequency const& lhs, frequency const& rhs);
  friend bool operator>(frequency const& lhs, frequency const& rhs);
  template<class ToFrequency>
  friend ToFrequency duration_cast(frequency const& self);
  // etc
};

template<class Rep>
using hertz = frequency<Rep>;

template<class T>
hertz<T> operator "" _hz(T t) {
  return hertz<T>(std::move(t));
}

now 13_hz is an object of type frequency<int, std::ratio<1,1>>.