diff --git a/src/aliases.rs b/src/aliases.rs
index 5df0c95ec..7bcafe47b 100644
--- a/src/aliases.rs
+++ b/src/aliases.rs
@@ -4,6 +4,13 @@
 use crate::dimension::Dim;
 use crate::{ArcArray, Array, ArrayView, ArrayViewMut, Ix, IxDynImpl};
 
+/// Create a static-dimensional index
+#[allow(non_snake_case)]
+#[inline(always)]
+pub fn IxD<const D: usize>(ix: [Ix; D]) -> IxD<D>
+{
+    Dim::new(ix)
+}
 /// Create a zero-dimensional index
 #[allow(non_snake_case)]
 #[inline(always)]
@@ -62,6 +69,19 @@ pub fn IxDyn(ix: &[Ix]) -> IxDyn
     Dim(ix)
 }
 
+impl<const D: usize> IxD<D>
+{
+    /// Create a static-dimensional index, repeating a single index value
+    #[inline(always)]
+    pub fn repeating(i: Ix) -> Self {
+        Dim::new([i; D])
+    }
+}
+
+/// static-dimensional
+///
+/// Static generic to create arrays of any supported dimensionality (up to 6)
+pub type IxD<const D: usize> = Dim<[Ix; D]>;
 /// zero-dimensionial
 pub type Ix0 = Dim<[Ix; 0]>;
 /// one-dimensional
diff --git a/src/dimension/broadcast.rs b/src/dimension/broadcast.rs
index d277cfea2..53f9415dd 100644
--- a/src/dimension/broadcast.rs
+++ b/src/dimension/broadcast.rs
@@ -1,5 +1,5 @@
 use crate::error::*;
-use crate::{Dimension, Ix0, Ix1, Ix2, Ix3, Ix4, Ix5, Ix6, IxDyn};
+use crate::{Dimension, IxD, Ix0, Ix1, Ix2, Ix3, Ix4, Ix5, Ix6, IxDyn};
 
 /// Calculate the common shape for a pair of array shapes, that they can be broadcasted
 /// to. Return an error if the shapes are not compatible.
@@ -48,6 +48,20 @@ impl<D: Dimension> DimMax<D> for D
     type Output = D;
 }
 
+/// Any static type dimension can be broadcast to a dynamic dimension
+impl<const D: usize> DimMax<IxDyn> for IxD<D>
+where IxD<D>: Dimension
+{
+    type Output = IxDyn;
+}
+
+/// Any static type dimension can be broadcast to a dynamic dimension
+impl<const D: usize> DimMax<IxD<D>> for IxDyn
+where IxD<D>: Dimension
+{
+    type Output = IxDyn;
+}
+
 macro_rules! impl_broadcast_distinct_fixed {
     ($smaller:ty, $larger:ty) => {
         impl DimMax<$larger> for $smaller {
@@ -81,13 +95,6 @@ impl_broadcast_distinct_fixed!(Ix3, Ix6);
 impl_broadcast_distinct_fixed!(Ix4, Ix5);
 impl_broadcast_distinct_fixed!(Ix4, Ix6);
 impl_broadcast_distinct_fixed!(Ix5, Ix6);
-impl_broadcast_distinct_fixed!(Ix0, IxDyn);
-impl_broadcast_distinct_fixed!(Ix1, IxDyn);
-impl_broadcast_distinct_fixed!(Ix2, IxDyn);
-impl_broadcast_distinct_fixed!(Ix3, IxDyn);
-impl_broadcast_distinct_fixed!(Ix4, IxDyn);
-impl_broadcast_distinct_fixed!(Ix5, IxDyn);
-impl_broadcast_distinct_fixed!(Ix6, IxDyn);
 
 #[cfg(test)]
 #[cfg(feature = "std")]
diff --git a/src/dimension/conversion.rs b/src/dimension/conversion.rs
index 0cf2e1296..fa74db5c9 100644
--- a/src/dimension/conversion.rs
+++ b/src/dimension/conversion.rs
@@ -87,6 +87,53 @@ impl IntoDimension for Vec<Ix>
     }
 }
 
+impl<const D: usize> IntoDimension for [Ix; D]
+where Dim<[Ix; D]> : Dimension
+{
+    type Dim = Dim<[Ix; D]>;
+    #[inline(always)]
+    fn into_dimension(self) -> Self::Dim
+    {
+        Dim::new(self)
+    }
+}
+
+impl<const D: usize> Index<usize> for Dim<[Ix; D]>
+where Dim<[Ix; D]>: Dimension
+{
+    type Output = usize;
+    #[inline(always)]
+    fn index(&self, index: usize) -> &Self::Output
+    {
+        &self.ix()[index]
+    }
+}
+
+impl<const D: usize> IndexMut<usize> for Dim<[Ix; D]>
+where Dim<[Ix; D]>: Dimension
+{
+    #[inline(always)]
+    fn index_mut(&mut self, index: usize) -> &mut Self::Output
+    {
+        &mut self.ixm()[index]
+    }
+}
+
+impl<const D: usize> Zero for Dim<[Ix; D]>
+where Dim<[Ix; D]>: Dimension
+{
+    #[inline]
+    fn zero() -> Self
+    {
+        Self::repeating(0)
+    }
+
+    fn is_zero(&self) -> bool
+    {
+        self.slice().iter().all(|x| *x == 0)
+    }
+}
+
 pub trait Convert
 {
     type To;
@@ -117,12 +164,6 @@ macro_rules! array_expr {
     );
 }
 
-macro_rules! array_zero {
-    ([] $($index:tt)*) => (
-        [$(sub!($index 0), )*]
-    );
-}
-
 macro_rules! tuple_to_array {
     ([] $($n:tt)*) => {
         $(
@@ -134,14 +175,6 @@ macro_rules! tuple_to_array {
             }
         }
 
-        impl IntoDimension for [Ix; $n] {
-            type Dim = Dim<[Ix; $n]>;
-            #[inline(always)]
-            fn into_dimension(self) -> Self::Dim {
-                Dim::new(self)
-            }
-        }
-
         impl IntoDimension for index!(tuple_type [Ix] $n) {
             type Dim = Dim<[Ix; $n]>;
             #[inline(always)]
@@ -150,31 +183,6 @@ macro_rules! tuple_to_array {
             }
         }
 
-        impl Index<usize> for Dim<[Ix; $n]> {
-            type Output = usize;
-            #[inline(always)]
-            fn index(&self, index: usize) -> &Self::Output {
-                &self.ix()[index]
-            }
-        }
-
-        impl IndexMut<usize> for Dim<[Ix; $n]> {
-            #[inline(always)]
-            fn index_mut(&mut self, index: usize) -> &mut Self::Output {
-                &mut self.ixm()[index]
-            }
-        }
-
-        impl Zero for Dim<[Ix; $n]> {
-            #[inline]
-            fn zero() -> Self {
-                Dim::new(index!(array_zero [] $n))
-            }
-            fn is_zero(&self) -> bool {
-                self.slice().iter().all(|x| *x == 0)
-            }
-        }
-
         )*
     };
 }
diff --git a/src/prelude.rs b/src/prelude.rs
index acf39da1a..908e3c1c2 100644
--- a/src/prelude.rs
+++ b/src/prelude.rs
@@ -42,7 +42,7 @@ pub use crate::{
 };
 
 #[doc(no_inline)]
-pub use crate::{Ix0, Ix1, Ix2, Ix3, Ix4, Ix5, Ix6, IxDyn};
+pub use crate::{IxD, Ix0, Ix1, Ix2, Ix3, Ix4, Ix5, Ix6, IxDyn};
 
 #[doc(no_inline)]
 pub use crate::{arr0, arr1, arr2, aview0, aview1, aview2, aview_mut1};
diff --git a/tests/ixd.rs b/tests/ixd.rs
new file mode 100644
index 000000000..b06acd536
--- /dev/null
+++ b/tests/ixd.rs
@@ -0,0 +1,36 @@
+#![allow(
+    clippy::many_single_char_names, clippy::deref_addrof, clippy::unreadable_literal, clippy::many_single_char_names,
+    clippy::float_cmp
+)]
+
+use ndarray::Array;
+use ndarray::IxD;
+use ndarray::Ix2;
+
+#[test]
+fn test_ixd()
+{
+    // Check that IxD creats a static index based on the provided array size
+    let mut a = Array::zeros(IxD([2, 3]));
+    assert_eq!(a.raw_dim(), Ix2(2, 3));
+
+    assert_eq!(a[(1, 1)], 0.);
+
+    a[(1, 1)] = 3.;
+    assert_eq!(a[(1, 1)], 3.);
+
+    // Wrong index dimension is caught by the type checker
+    // a[(1, 1, 1)] = 4.;
+}
+
+#[test]
+fn test_ixd_repeating()
+{
+    // Check that repeating creates an array of a specified dimension
+    let mut a = Array::zeros(IxD::<2>::repeating(2));
+    assert_eq!(a.raw_dim(), Ix2(2, 2));
+
+    a[(1, 1)] = 2.;
+    assert_eq!(a[(1, 1)], 2.);
+}
+